View Javadoc

1   // jq_CompiledCode.java, created Mon Feb  5 23:23:20 2001 by joewhaley
2   // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package joeq.Class;
5   
6   import java.util.Iterator;
7   import java.util.List;
8   import joeq.Main.jq;
9   import joeq.Memory.CodeAddress;
10  import joeq.Memory.StackAddress;
11  import joeq.Runtime.Debug;
12  import jwutil.util.Assert;
13  
14  /***
15   * @author  John Whaley <jwhaley@alum.mit.edu>
16   * @version $Id: jq_CompiledCode.java 1931 2004-09-22 22:17:47Z joewhaley $
17   */
18  public class jq_CompiledCode implements Comparable {
19  
20      public static /*final*/ boolean TRACE = false;
21      public static /*final*/ boolean TRACE_REDIRECT = false;
22  
23      protected final CodeAddress entrypoint;
24      protected final jq_Method method;
25      protected final CodeAddress start;
26      protected final int length;
27      protected final jq_TryCatch[] handlers;
28      protected final jq_BytecodeMap bcm;
29      protected final Object /* ExceptionDeliverer */ ed;
30      protected final int stackframesize;
31      protected final List code_reloc, data_reloc;
32  
33      public jq_CompiledCode(jq_Method method,
34                             CodeAddress start,
35                             int length,
36                             CodeAddress entrypoint,
37                             jq_TryCatch[] handlers,
38                             jq_BytecodeMap bcm,
39                             Object /*ExceptionDeliverer*/ ed,
40                             int stackframesize,
41                             List code_reloc,
42                             List data_reloc) {
43          this.method = method;
44          this.entrypoint = entrypoint;
45          this.start = start;
46          this.length = length;
47          this.handlers = handlers;
48          this.bcm = bcm;
49          this.ed = ed;
50          this.stackframesize = stackframesize;
51          this.code_reloc = code_reloc;
52          this.data_reloc = data_reloc;
53      }
54  
55      public jq_Method getMethod() {
56          return method;
57      }
58  
59      public CodeAddress getStart() {
60          return start;
61      }
62  
63      public int getLength() {
64          return length;
65      }
66  
67      public CodeAddress getEntrypoint() {
68          return entrypoint;
69      }
70  
71      public int getStackFrameSize() {
72          return stackframesize;
73      }
74      
75      public jq_TryCatch findCatchBlock(CodeAddress ip, jq_Class extype) {
76          int offset = ip.difference(start);
77          if (handlers == null) {
78              if (TRACE) Debug.writeln("no handlers in " + this);
79              return null;
80          }
81          for (int i = 0; i < handlers.length; ++i) {
82              jq_TryCatch tc = handlers[i];
83              if (TRACE) Debug.writeln("checking handler: " + tc);
84              if (tc.catches(offset, extype))
85                  return tc;
86              if (TRACE) Debug.writeln("does not catch");
87          }
88          if (TRACE) Debug.writeln("no appropriate handler found in " + this);
89          return null;
90      }
91  
92      public void deliverException(jq_TryCatch tc, StackAddress fp, Throwable x) {
93          Assert._assert(ed != null);
94          CodeAddress entry = (CodeAddress) start.offset(tc.getHandlerEntry());  
95          _delegate.deliverToStackFrame(ed, this, x, tc, entry, fp);
96      }
97  
98      public Object getThisPointer(CodeAddress ip, StackAddress fp) {
99          Assert._assert(ed != null);
100         return _delegate.getThisPointer(ed, this, ip, fp);
101     }
102 
103     public int getBytecodeIndex(CodeAddress ip) {
104         if (bcm == null) return -1;
105         return bcm.getBytecodeIndex(ip.difference(start));
106     }
107 
108     /*** Rewrite the entrypoint to branch to the given compiled code. */
109     public void redirect(jq_CompiledCode that) {
110         CodeAddress newEntrypoint = that.getEntrypoint();
111         if (TRACE_REDIRECT) Debug.writeln("redirecting " + this + " to point to " + that);
112         if (entrypoint.difference(start.offset(5)) >= 0) {
113             if (TRACE_REDIRECT) Debug.writeln("redirecting via trampoline");
114             // both should start with "push EBP"
115             Assert._assert(entrypoint.peek1() == newEntrypoint.peek1());
116             // put target address (just after push EBP)
117             entrypoint.offset(-4).poke4(newEntrypoint.difference(entrypoint) + 1);
118             // put jump instruction
119             entrypoint.offset(-5).poke1((byte) 0xE9); // JMP
120             // put backward branch to jump instruction
121             entrypoint.offset(1).poke2((short) 0xF8EB); // JMP
122         } else {
123             if (TRACE_REDIRECT) Debug.writeln("redirecting by rewriting targets");
124             Iterator it = _delegate.getCompiledMethods();
125             while (it.hasNext()) {
126                 jq_CompiledCode cc = (jq_CompiledCode) it.next();
127                 cc.patchDirectBindCalls(this.method, that);
128             }
129         }
130     }
131 
132     public String toString() {
133         return method + " address: (" + start.stringRep() + "-" + start.offset(length).stringRep() + ")";
134     }
135 
136     public boolean contains(CodeAddress address) {
137         return address.difference(start) >= 0 && address.difference(start.offset(length)) < 0;
138     }
139 
140     static interface Delegate {
141         void patchDirectBindCalls(Iterator i);
142         void patchDirectBindCalls(Iterator i, jq_Method method, jq_CompiledCode cc);
143         Iterator getCompiledMethods();
144         void deliverToStackFrame(Object ed, jq_CompiledCode t, Throwable x, jq_TryCatch tc, CodeAddress entry, StackAddress fp);
145         Object getThisPointer(Object ed, jq_CompiledCode t, CodeAddress ip, StackAddress fp);
146     }
147     
148     private static Delegate _delegate;
149 
150     public void patchDirectBindCalls() {
151         Assert._assert(jq.RunningNative);
152         if (code_reloc != null) {
153             Iterator i = code_reloc.iterator();
154             _delegate.patchDirectBindCalls(i);
155         }
156     }
157 
158     public void patchDirectBindCalls(jq_Method method, jq_CompiledCode cc) {
159         Assert._assert(jq.RunningNative);
160         if (code_reloc != null) {
161             Iterator i = code_reloc.iterator();
162             _delegate.patchDirectBindCalls(i, method, cc);
163         }
164     }
165 
166     public int compareTo(jq_CompiledCode that) {
167         if (this == that) return 0;
168         if (this.start.difference(that.start) < 0) return -1;
169         if (this.start.difference(that.start.offset(that.length)) < 0) {
170             Assert.UNREACHABLE(this + " overlaps " + that);
171         }
172         return 1;
173     }
174 
175     public int compareTo(java.lang.Object o) {
176         if (o instanceof jq_CompiledCode)
177             return compareTo((jq_CompiledCode) o);
178         else
179             return -((Comparable)o).compareTo(this);
180     }
181 
182     public boolean equals(Object o) {
183         if (o instanceof jq_CompiledCode)
184             return this == o;
185         else
186             return o.equals(this);
187     }
188 
189     /***
190      * NOTE that this violates the contract of hashCode when comparing against InstructionPointer objects!
191      */
192     public int hashCode() {
193         return super.hashCode();
194     }
195 
196     public static final jq_InstanceField _entrypoint;
197 
198     static {
199         jq_Class k = (jq_Class) PrimordialClassLoader.loader.getOrCreateBSType("Ljoeq/Class/jq_CompiledCode;");
200         _entrypoint = k.getOrCreateInstanceField("entrypoint", "Ljoeq/Memory/CodeAddress;");
201         /* Set up delegates. */
202         _delegate = null;
203         boolean nullVM = jq.nullVM;
204         if (!nullVM) {
205             _delegate = attemptDelegate("joeq.Class.Delegates$CompiledCode");
206         }
207         if (_delegate == null) {
208             _delegate = new NullDelegates.CompiledCode();
209         }
210     }
211 
212     private static Delegate attemptDelegate(String s) {
213         String type = "compiled code delegate";
214         try {
215             Class c = Class.forName(s);
216             return (Delegate)c.newInstance();
217         } catch (java.lang.ClassNotFoundException x) {
218             System.err.println("Cannot find "+type+" "+s+": "+x);
219         } catch (java.lang.InstantiationException x) {
220             System.err.println("Cannot instantiate "+type+" "+s+": "+x);
221         } catch (java.lang.IllegalAccessException x) {
222             System.err.println("Cannot access "+type+" "+s+": "+x);
223         }
224         return null;
225     }
226 }