View Javadoc

1   // BytecodeToQuad.java, created Fri Jan 11 16:42:38 2002 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.Compiler.Quad;
5   
6   import java.util.HashMap;
7   import java.util.Iterator;
8   import java.util.LinkedList;
9   import joeq.Class.PrimordialClassLoader;
10  import joeq.Class.jq_Array;
11  import joeq.Class.jq_Class;
12  import joeq.Class.jq_InstanceField;
13  import joeq.Class.jq_InstanceMethod;
14  import joeq.Class.jq_Method;
15  import joeq.Class.jq_NameAndDesc;
16  import joeq.Class.jq_Primitive;
17  import joeq.Class.jq_Reference;
18  import joeq.Class.jq_StaticField;
19  import joeq.Class.jq_StaticMethod;
20  import joeq.Class.jq_TryCatchBC;
21  import joeq.Class.jq_Type;
22  import joeq.Compiler.CompilationState;
23  import joeq.Compiler.BytecodeAnalysis.BytecodeVisitor;
24  import joeq.Compiler.Quad.Operand.AConstOperand;
25  import joeq.Compiler.Quad.Operand.ConditionOperand;
26  import joeq.Compiler.Quad.Operand.DConstOperand;
27  import joeq.Compiler.Quad.Operand.FConstOperand;
28  import joeq.Compiler.Quad.Operand.FieldOperand;
29  import joeq.Compiler.Quad.Operand.IConstOperand;
30  import joeq.Compiler.Quad.Operand.LConstOperand;
31  import joeq.Compiler.Quad.Operand.MethodOperand;
32  import joeq.Compiler.Quad.Operand.PConstOperand;
33  import joeq.Compiler.Quad.Operand.RegisterOperand;
34  import joeq.Compiler.Quad.Operand.TargetOperand;
35  import joeq.Compiler.Quad.Operand.TypeOperand;
36  import joeq.Compiler.Quad.Operand.UnnecessaryGuardOperand;
37  import joeq.Compiler.Quad.Operator.ALength;
38  import joeq.Compiler.Quad.Operator.ALoad;
39  import joeq.Compiler.Quad.Operator.AStore;
40  import joeq.Compiler.Quad.Operator.Binary;
41  import joeq.Compiler.Quad.Operator.BoundsCheck;
42  import joeq.Compiler.Quad.Operator.CheckCast;
43  import joeq.Compiler.Quad.Operator.Getfield;
44  import joeq.Compiler.Quad.Operator.Getstatic;
45  import joeq.Compiler.Quad.Operator.Goto;
46  import joeq.Compiler.Quad.Operator.InstanceOf;
47  import joeq.Compiler.Quad.Operator.IntIfCmp;
48  import joeq.Compiler.Quad.Operator.Invoke;
49  import joeq.Compiler.Quad.Operator.Jsr;
50  import joeq.Compiler.Quad.Operator.LookupSwitch;
51  import joeq.Compiler.Quad.Operator.MemLoad;
52  import joeq.Compiler.Quad.Operator.MemStore;
53  import joeq.Compiler.Quad.Operator.Monitor;
54  import joeq.Compiler.Quad.Operator.Move;
55  import joeq.Compiler.Quad.Operator.New;
56  import joeq.Compiler.Quad.Operator.NewArray;
57  import joeq.Compiler.Quad.Operator.NullCheck;
58  import joeq.Compiler.Quad.Operator.Putfield;
59  import joeq.Compiler.Quad.Operator.Putstatic;
60  import joeq.Compiler.Quad.Operator.Ret;
61  import joeq.Compiler.Quad.Operator.Return;
62  import joeq.Compiler.Quad.Operator.Special;
63  import joeq.Compiler.Quad.Operator.StoreCheck;
64  import joeq.Compiler.Quad.Operator.TableSwitch;
65  import joeq.Compiler.Quad.Operator.Unary;
66  import joeq.Compiler.Quad.Operator.ZeroCheck;
67  import joeq.Compiler.Quad.RegisterFactory.Register;
68  import joeq.Main.jq;
69  import joeq.Memory.Address;
70  import joeq.Memory.HeapAddress;
71  import joeq.Memory.StackAddress;
72  import joeq.Runtime.Reflection;
73  import joeq.UTF.Utf8;
74  import jwutil.strings.Strings;
75  import jwutil.util.Assert;
76  
77  /***
78   * Converts stack-based Java bytecode to Quad intermediate format.
79   * This utilizes the ControlFlowGraph in the BytecodeAnalysis package to build
80   * up a control flow graph, then iterates over the graph to generate the Quad
81   * code.
82   *
83   * @see  BytecodeVisitor
84   * @see  joeq.Compiler.BytecodeAnalysis.ControlFlowGraph
85   * @author  John Whaley <jwhaley@alum.mit.edu>
86   * @version $Id: BytecodeToQuad.java 2465 2006-06-07 23:03:17Z joewhaley $
87   */
88  public class BytecodeToQuad extends BytecodeVisitor {
89      
90      private ControlFlowGraph quad_cfg;
91      private BasicBlock quad_bb;
92      private joeq.Compiler.BytecodeAnalysis.ControlFlowGraph bc_cfg;
93      private joeq.Compiler.BytecodeAnalysis.BasicBlock bc_bb;
94      private BasicBlock[] quad_bbs;
95      private RegisterFactory rf;
96      
97      private boolean[] visited;
98      private LinkedList regenerate;
99  
100     private HashMap quad2bci = new HashMap();
101 
102     public static boolean ALWAYS_TRACE = false;
103 
104     /*** Initializes the conversion from bytecode to quad format for the given method.
105      * @param  method the method to convert. */
106     public BytecodeToQuad(jq_Method method) {
107         this(CompilationState.DEFAULT, method);
108     }
109     
110     /*** Initializes the conversion from bytecode to quad format for the given method.
111      * @param  method the method to convert. */
112     public BytecodeToQuad(CompilationState state, jq_Method method) {
113         super(state, method);
114         TRACE = ALWAYS_TRACE;
115     }
116     
117     /*** Returns a string with the name of the pass and the method being converted.
118      * @return  a string with the name of the pass and the method being converted. */
119     public String toString() {
120         return "BC2Q/"+Strings.left(method.getName().toString(), 10);
121     }
122     /*** Perform conversion process from bytecode to quad.
123      * @return  the control flow graph of the resulting quad representation. */
124     public ControlFlowGraph convert() {
125         bc_cfg = joeq.Compiler.BytecodeAnalysis.ControlFlowGraph.computeCFG(method);
126         
127         // initialize register factory
128         this.rf = new RegisterFactory(method);
129         
130         // copy bytecode cfg to quad cfg
131         jq_TryCatchBC[] exs = method.getExceptionTable();
132         this.quad_cfg = new ControlFlowGraph(method, bc_cfg.getExit().getNumberOfPredecessors(),
133                                                  exs.length, this.rf);
134         quad_bbs = new BasicBlock[bc_cfg.getNumberOfBasicBlocks()];
135         quad_bbs[0] = this.quad_cfg.entry();
136         quad_bbs[1] = this.quad_cfg.exit();
137         for (int i=2; i<quad_bbs.length; ++i) {
138             joeq.Compiler.BytecodeAnalysis.BasicBlock bc_bb = bc_cfg.getBasicBlock(i);
139             int n_pred = bc_bb.getNumberOfPredecessors();
140             int n_succ = bc_bb.getNumberOfSuccessors();
141             int n_inst = bc_bb.getEnd() - bc_bb.getStart() + 1; // estimate
142             quad_bbs[i] = BasicBlock.createBasicBlock(i, n_pred, n_succ, n_inst);
143         }
144         this.quad_cfg.updateBBcounter(quad_bbs.length);
145 
146         // add exception handlers.
147         for (int i=exs.length-1; i>=0; --i) {
148             jq_TryCatchBC ex = exs[i];
149             joeq.Compiler.BytecodeAnalysis.BasicBlock bc_bb = bc_cfg.getBasicBlockByBytecodeIndex(ex.getStartPC());
150             Assert._assert(bc_bb.getStart() < ex.getEndPC());
151             BasicBlock ex_handler = quad_bbs[bc_cfg.getBasicBlockByBytecodeIndex(ex.getHandlerPC()).id];
152             ex_handler.setExceptionHandlerEntry();
153             int numOfProtectedBlocks = (ex.getEndPC()==method.getBytecode().length?quad_bbs.length:bc_cfg.getBasicBlockByBytecodeIndex(ex.getEndPC()).id) - bc_bb.id;
154             ExceptionHandler eh = new ExceptionHandler(ex.getExceptionType(), numOfProtectedBlocks, ex_handler);
155             quad_cfg.addExceptionHandler(eh);
156             ExceptionHandlerList ehs = new ExceptionHandlerList(eh, null);
157             BasicBlock bb = quad_bbs[bc_bb.id];
158             bb.addExceptionHandler_first(ehs);
159             for (;;) {
160                 bc_bb = bc_cfg.getBasicBlock(bc_bb.id+1);
161                 bb = quad_bbs[bc_bb.id];
162                 if (bc_bb.getStart() >= ex.getEndPC()) break;
163                 ehs = bb.addExceptionHandler(ehs);
164             }
165         }
166         this.start_states = new AbstractState[quad_bbs.length];
167         for (int i=0; i<quad_bbs.length; ++i) {
168             joeq.Compiler.BytecodeAnalysis.BasicBlock bc_bb = bc_cfg.getBasicBlock(i);
169             BasicBlock bb = quad_bbs[i];
170             for (int j=0; j<bc_bb.getNumberOfPredecessors(); ++j) {
171                 bb.addPredecessor(quad_bbs[bc_bb.getPredecessor(j).id]);
172             }
173             for (int j=0; j<bc_bb.getNumberOfSuccessors(); ++j) {
174                 bb.addSuccessor(quad_bbs[bc_bb.getSuccessor(j).id]);
175             }
176             // --> start state allocated on demand in merge
177             //this.start_states[i] = new AbstractState(max_stack, max_locals);
178         }
179 
180         // initialize start state
181         this.start_states[2] = allocateInitialState();
182         this.current_state = allocateEmptyState();
183         
184         regenerate = new LinkedList();
185         visited = new boolean[quad_bbs.length];
186         // traverse reverse post-order over basic blocks to generate instructions
187         joeq.Compiler.BytecodeAnalysis.ControlFlowGraph.RPOBasicBlockIterator rpo = bc_cfg.reversePostOrderIterator();
188         joeq.Compiler.BytecodeAnalysis.BasicBlock first_bb = rpo.nextBB();
189         Assert._assert(first_bb == bc_cfg.getEntry());
190         while (rpo.hasNext()) {
191             joeq.Compiler.BytecodeAnalysis.BasicBlock bc_bb = rpo.nextBB();
192             visited[bc_bb.id] = true;
193             this.traverseBB(bc_bb);
194         }
195         while (!regenerate.isEmpty()) {
196             if (TRACE) out.println("Blocks to regenerate: "+regenerate);
197             joeq.Compiler.BytecodeAnalysis.BasicBlock bc_bb =
198                 (joeq.Compiler.BytecodeAnalysis.BasicBlock)regenerate.removeFirst();
199             visited[bc_bb.id] = true;
200             this.traverseBB(bc_bb);
201         }
202         if (quad_cfg.removeUnreachableBasicBlocks()) {
203             if (TRACE) out.println("Unreachable code in "+method);
204         }
205         // TODO: need to fix cfg's with infinite loops.
206         return this.quad_cfg;
207     }
208 
209     private boolean endBasicBlock;
210     private boolean endsWithRET;
211     
212     /***
213      * @param  bc_bb  */
214     public void traverseBB(joeq.Compiler.BytecodeAnalysis.BasicBlock bc_bb) {
215         if (start_states[bc_bb.id] == null) {
216             // unreachable block!
217             if (TRACE) out.println("Basic block "+bc_bb+" is unreachable!");
218             return;
219         }
220         if (bc_bb.getStart() == -1) {
221             return; // entry or exit
222         }
223         if (TRACE) out.println("Visiting "+bc_bb);
224         this.quad_bb = quad_bbs[bc_bb.id];
225         for (Iterator i = this.quad_bb.iterator(); i.hasNext(); ) {
226             Object o = i.next();
227             Object old = this.quad2bci.remove(o);
228             if (old == null) {
229                 // GET_EXCEPTION has no bytecode index.
230                 //System.out.println(o+" was not in bcmap.");
231             }
232         }
233         this.quad_bb.removeAllQuads();
234         this.bc_bb = bc_bb;
235         this.current_state.overwriteWith(start_states[bc_bb.id]);
236         if (this.quad_bb.isExceptionHandlerEntry()) {
237             // TODO: find non-exceptional branches to exception handler entries and split the basic block.
238             jq_Type type = ((RegisterOperand)this.current_state.peekStack(0)).getType();
239             RegisterOperand t = getStackRegister(type, 0);
240             this.quad_bb.appendQuad(Special.create(quad_cfg.getNewQuadID(), Special.GET_EXCEPTION.INSTANCE, t));
241         }
242         if (TRACE) this.current_state.dumpState();
243         this.endBasicBlock = false;
244         this.endsWithRET = false;
245         for (i_end=bc_bb.getStart()-1; ; ) {
246             i_start = i_end+1;
247             if (isEndOfBB()) break;
248             this.visitBytecode();
249         }
250         saveStackIntoRegisters();
251         if (!endsWithRET) {
252             for (int i=0; i<bc_bb.getNumberOfSuccessors(); ++i) {
253                 this.mergeStateWith(bc_bb.getSuccessor(i));
254             }
255         }
256         if (TRACE) out.println("Finished visiting "+bc_bb);
257     }
258     
259     private boolean isEndOfBB() {
260         return i_start > bc_bb.getEnd() || endBasicBlock;
261     }
262     
263     private void mergeStateWith(joeq.Compiler.BytecodeAnalysis.BasicBlock bc_bb) {
264         if (start_states[bc_bb.id] == null) {
265             if (TRACE) out.println("Copying current state to "+bc_bb);
266             start_states[bc_bb.id] = current_state.copy();
267         } else {
268             if (TRACE) out.println("Merging current state with "+bc_bb);
269             if (start_states[bc_bb.id].merge(current_state, rf)) {
270                 if (TRACE) out.println("in set of "+bc_bb+" changed");
271                 if (visited[bc_bb.id]) {
272                     if (TRACE) out.println("must regenerate code for "+bc_bb);
273                     if (!regenerate.contains(bc_bb)) {
274                         regenerate.add(bc_bb);
275                         start_states[bc_bb.id].rebuildStack();
276                     }
277                     visited[bc_bb.id] = false;
278                 }
279             }
280         }
281     }
282     private void mergeStateWith(joeq.Compiler.BytecodeAnalysis.ExceptionHandler eh) {
283         joeq.Compiler.BytecodeAnalysis.BasicBlock bc_bb = eh.getEntry();
284         if (start_states[bc_bb.id] == null) {
285             if (TRACE) out.println("Copying exception state to "+bc_bb);
286             start_states[bc_bb.id] = current_state.copyExceptionHandler(eh.getExceptionType(), rf);
287         } else {
288             if (TRACE) out.println("Merging exception state with "+bc_bb);
289             if (start_states[bc_bb.id].mergeExceptionHandler(current_state, eh.getExceptionType(), rf)) {
290                 if (TRACE) out.println("in set of exception handler "+bc_bb+" changed");
291                 if (visited[bc_bb.id]) {
292                     if (TRACE) out.println("must regenerate code for "+bc_bb);
293                     if (!regenerate.contains(bc_bb)) {
294                         regenerate.add(bc_bb);
295                         start_states[bc_bb.id].rebuildStack();
296                     }
297                     visited[bc_bb.id] = false;
298                 }
299             }
300         }
301     }
302 
303     private void saveStackIntoRegisters() {
304         for (int i=0; i<current_state.getStackSize(); ++i) {
305             Operand op = current_state.peekStack(i);
306             if (op instanceof DummyOperand) continue;
307             if (op instanceof RegisterOperand) {
308                 RegisterOperand rop = (RegisterOperand)op;
309                 Register r = rf.getOrCreateStack(current_state.getStackSize()-i-1, rop.getType());
310                 if (rop.getRegister() == r)
311                     continue;
312             }
313             jq_Type type = getTypeOf(op);
314             RegisterOperand t = getStackRegister(type, i);
315             Quad q = Move.create(quad_cfg.getNewQuadID(), Move.getMoveOp(type), t, op);
316             appendQuad(q);
317             current_state.pokeStack(i, t.copy());
318         }
319     }
320 
321     public boolean isLocal(Operand op, int index, jq_Type type) {
322         if (op instanceof RegisterOperand) {
323             Register r = ((RegisterOperand)op).getRegister();
324             if (r.isTemp()) return false;
325             return rf.getOrCreateLocal(index, type) == r;
326         }
327         return false;
328     }
329     
330     private void replaceLocalsOnStack(int index, jq_Type type) {
331         for (int i=0; i<current_state.getStackSize(); ++i) {
332             Operand op = current_state.peekStack(i);
333             if (isLocal(op, index, type)) {
334                 RegisterOperand rop = (RegisterOperand)op;
335                 RegisterOperand t = getStackRegister(type, i);
336                 t.setFlags(rop.getFlags()); t.scratchObject = rop.scratchObject;
337                 Quad q = Move.create(quad_cfg.getNewQuadID(), Move.getMoveOp(type), t, rop);
338                 appendQuad(q);
339                 current_state.pokeStack(i, t.copy());
340             }
341         }
342     }
343     
344     void appendQuad(Quad q) {
345         if (TRACE) out.println(q.toString());
346         quad_bb.appendQuad(q);
347         quad2bci.put(q, new Integer(i_start));
348     }
349     
350     /***
351      * return quad->bytecode map, may be incomplete
352      * @return Map<Quad, Integer> 
353      */
354     java.util.Map getQuadToBytecodeMap() {
355         return quad2bci;
356     }
357     
358     RegisterOperand getStackRegister(jq_Type type, int i) {
359         if (current_state.getStackSize()-i-1 < 0) {
360             System.out.println("Error in "+method+" offset "+i_start);
361             current_state.dumpState();
362         }
363         return new RegisterOperand(rf.getOrCreateStack(current_state.getStackSize()-i-1, type), type);
364     }
365     
366     RegisterOperand getStackRegister(jq_Type type) {
367         return getStackRegister(type, -1);
368     }
369 
370     RegisterOperand makeLocal(int i, jq_Type type) {
371         return new RegisterOperand(rf.getOrCreateLocal(i, type), type);
372     }
373     
374     RegisterOperand makeLocal(int i, RegisterOperand rop) {
375         jq_Type type = rop.getType();
376         return new RegisterOperand(rf.getOrCreateLocal(i, type), type, rop.getFlags());
377     }
378     
379     static boolean hasGuard(RegisterOperand rop) { return rop.scratchObject != null; }
380     static void setGuard(RegisterOperand rop, Operand guard) { rop.scratchObject = guard; }
381     
382     static Operand getGuard(Operand op) {
383         if (op instanceof RegisterOperand) {
384             RegisterOperand rop = (RegisterOperand)op;
385             return (Operand)rop.scratchObject;
386         }
387         Assert._assert(op instanceof AConstOperand);
388         return new UnnecessaryGuardOperand();
389     }
390     
391     Operand currentGuard;
392     
393     void setCurrentGuard(Operand guard) { currentGuard = guard; }
394     void clearCurrentGuard() { currentGuard = null; }
395     Operand getCurrentGuard() { if (currentGuard == null) return null; return currentGuard.copy(); }
396     
397     private AbstractState[] start_states;
398     private AbstractState current_state;
399     
400     public void visitNOP() {
401         super.visitNOP();
402         // do nothing
403     }
404     public void visitACONST(Object s) {
405         super.visitACONST(s);
406         current_state.push_A(new AConstOperand(s));
407     }
408     public void visitICONST(int c) {
409         super.visitICONST(c);
410         current_state.push_I(new IConstOperand(c));
411     }
412     public void visitLCONST(long c) {
413         super.visitLCONST(c);
414         current_state.push_L(new LConstOperand(c));
415     }
416     public void visitFCONST(float c) {
417         super.visitFCONST(c);
418         current_state.push_F(new FConstOperand(c));
419     }
420     public void visitDCONST(double c) {
421         super.visitDCONST(c);
422         current_state.push_D(new DConstOperand(c));
423     }
424     public void visitILOAD(int i) {
425         super.visitILOAD(i);
426         current_state.push_I(current_state.getLocal_I(i));
427     }
428     public void visitLLOAD(int i) {
429         super.visitLLOAD(i);
430         current_state.push_L(current_state.getLocal_L(i));
431     }
432     public void visitFLOAD(int i) {
433         super.visitFLOAD(i);
434         current_state.push_F(current_state.getLocal_F(i));
435     }
436     public void visitDLOAD(int i) {
437         super.visitDLOAD(i);
438         current_state.push_D(current_state.getLocal_D(i));
439     }
440     public void visitALOAD(int i) {
441         super.visitALOAD(i);
442         // could be A or R
443         current_state.push(current_state.getLocal(i));
444     }
445     private void STOREhelper(int i, jq_Type type) {
446         replaceLocalsOnStack(i, type);
447         Operand op1 = current_state.pop(type);
448         Operand local_value;
449         RegisterOperand op0;
450         if (op1 instanceof RegisterOperand) {
451             // move from one local variable to another.
452             local_value = op0 = makeLocal(i, (RegisterOperand)op1); // copy attributes.
453         } else {
454             // move a constant to a local variable.
455             local_value = op1;
456             op0 = makeLocal(i, type);
457         }
458         if (type.getReferenceSize() == 8) current_state.setLocalDual(i, local_value);
459         else current_state.setLocal(i, local_value);
460         Quad q = Move.create(quad_cfg.getNewQuadID(), Move.getMoveOp(type), op0, op1);
461         appendQuad(q);
462     }
463     public void visitISTORE(int i) {
464         super.visitISTORE(i);
465         STOREhelper(i, jq_Primitive.INT);
466     }
467     public void visitLSTORE(int i) {
468         super.visitLSTORE(i);
469         STOREhelper(i, jq_Primitive.LONG);
470     }
471     public void visitFSTORE(int i) {
472         super.visitFSTORE(i);
473         STOREhelper(i, jq_Primitive.FLOAT);
474     }
475     public void visitDSTORE(int i) {
476         super.visitDSTORE(i);
477         STOREhelper(i, jq_Primitive.DOUBLE);
478     }
479     public void visitASTORE(int i) {
480         super.visitASTORE(i);
481         Operand op1 = current_state.peekStack(0);
482         STOREhelper(i, getTypeOf(op1));
483     }
484     private void ALOADhelper(ALoad operator, jq_Type t) {
485         Operand index = current_state.pop_I();
486         Operand ref = current_state.pop_A();
487         clearCurrentGuard();
488         if (performNullCheck(ref)) {
489             if (TRACE) System.out.println("Null check triggered on "+ref);
490             return;
491         }
492         if (performBoundsCheck(ref, index)) {
493             if (TRACE) System.out.println("Bounds check triggered on "+ref+" "+index);
494             return;
495         }
496         if (t.isReferenceType()) {
497             // refine type.
498             t = getArrayElementTypeOf(ref);
499             Assert._assert(!t.isAddressType());
500         }
501         RegisterOperand r = getStackRegister(t);
502         Quad q = ALoad.create(quad_cfg.getNewQuadID(), operator, r, ref, index, getCurrentGuard());
503         appendQuad(q);
504         current_state.push(r.copy(), t);
505     }
506     public void visitIALOAD() {
507         super.visitIALOAD();
508         ALOADhelper(ALoad.ALOAD_I.INSTANCE, jq_Primitive.INT);
509     }
510     public void visitLALOAD() {
511         super.visitLALOAD();
512         ALOADhelper(ALoad.ALOAD_L.INSTANCE, jq_Primitive.LONG);
513     }
514     public void visitFALOAD() {
515         super.visitFALOAD();
516         ALOADhelper(ALoad.ALOAD_F.INSTANCE, jq_Primitive.FLOAT);
517     }
518     public void visitDALOAD() {
519         super.visitDALOAD();
520         ALOADhelper(ALoad.ALOAD_D.INSTANCE, jq_Primitive.DOUBLE);
521     }
522     public void visitAALOAD() {
523         super.visitAALOAD();
524         Operand index = current_state.pop_I();
525         Operand ref = current_state.pop_A();
526         clearCurrentGuard();
527         if (performNullCheck(ref)) {
528             if (TRACE) System.out.println("Null check triggered on "+ref);
529             return;
530         }
531         if (performBoundsCheck(ref, index)) {
532             if (TRACE) System.out.println("Bounds check triggered on "+ref+" "+index);
533             return;
534         }
535         jq_Type t = getArrayElementTypeOf(ref);
536         ALoad operator = t.isAddressType()?(ALoad)ALoad.ALOAD_P.INSTANCE:ALoad.ALOAD_A.INSTANCE;
537         RegisterOperand r = getStackRegister(t);
538         Quad q = ALoad.create(quad_cfg.getNewQuadID(), operator, r, ref, index, getCurrentGuard());
539         appendQuad(q);
540         current_state.push(r.copy(), t);
541     }
542     public void visitBALOAD() {
543         super.visitBALOAD();
544         ALOADhelper(ALoad.ALOAD_B.INSTANCE, jq_Primitive.BYTE);
545     }
546     public void visitCALOAD() {
547         super.visitCALOAD();
548         ALOADhelper(ALoad.ALOAD_C.INSTANCE, jq_Primitive.CHAR);
549     }
550     public void visitSALOAD() {
551         super.visitSALOAD();
552         ALOADhelper(ALoad.ALOAD_S.INSTANCE, jq_Primitive.SHORT);
553     }
554     private void ASTOREhelper(AStore operator, jq_Type t) {
555         Operand val = current_state.pop(t);
556         Operand index = current_state.pop_I();
557         Operand ref = current_state.pop_A();
558         clearCurrentGuard();
559         if (performNullCheck(ref)) {
560             if (TRACE) System.out.println("Null check triggered on "+ref);
561             return;
562         }
563         if (performBoundsCheck(ref, index)) {
564             if (TRACE) System.out.println("Bounds check triggered on "+ref+" "+index);
565             return;
566         }
567         if (t.isReferenceType() && ref instanceof RegisterOperand) {
568             // perform checkstore
569             if (performCheckStore((RegisterOperand)ref, val)) return;
570             Assert._assert(!t.isAddressType());
571         }
572         Quad q = AStore.create(quad_cfg.getNewQuadID(), operator, val, ref, index, getCurrentGuard());
573         appendQuad(q);
574     }
575     public void visitIASTORE() {
576         super.visitIASTORE();
577         ASTOREhelper(AStore.ASTORE_I.INSTANCE, jq_Primitive.INT);
578     }
579     public void visitLASTORE() {
580         super.visitLASTORE();
581         ASTOREhelper(AStore.ASTORE_L.INSTANCE, jq_Primitive.LONG);
582     }
583     public void visitFASTORE() {
584         super.visitFASTORE();
585         ASTOREhelper(AStore.ASTORE_F.INSTANCE, jq_Primitive.FLOAT);
586     }
587     public void visitDASTORE() {
588         super.visitDASTORE();
589         ASTOREhelper(AStore.ASTORE_D.INSTANCE, jq_Primitive.DOUBLE);
590     }
591     public void visitAASTORE() {
592         // could be A or R
593         Operand val = current_state.pop();
594         Operand index = current_state.pop_I();
595         Operand ref = current_state.pop_A();
596         clearCurrentGuard();
597         if (performNullCheck(ref)) {
598             if (TRACE) System.out.println("Null check triggered on "+ref);
599             return;
600         }
601         if (performBoundsCheck(ref, index)) {
602             if (TRACE) System.out.println("Bounds check triggered on "+ref+" "+index);
603             return;
604         }
605         jq_Type arrayElemType = getArrayElementTypeOf(ref);
606         AStore operator = arrayElemType.isAddressType()?(AStore)AStore.ASTORE_P.INSTANCE:AStore.ASTORE_A.INSTANCE;
607         if (ref instanceof RegisterOperand) {
608             // perform checkstore
609             if (performCheckStore((RegisterOperand)ref, val)) return;
610         }
611         Quad q = AStore.create(quad_cfg.getNewQuadID(), operator, val, ref, index, getCurrentGuard());
612         appendQuad(q);
613     }
614     public void visitBASTORE() {
615         super.visitBASTORE();
616         ASTOREhelper(AStore.ASTORE_B.INSTANCE, jq_Primitive.BYTE);
617     }
618     public void visitCASTORE() {
619         super.visitCASTORE();
620         ASTOREhelper(AStore.ASTORE_C.INSTANCE, jq_Primitive.CHAR);
621     }
622     public void visitSASTORE() {
623         super.visitSASTORE();
624         ASTOREhelper(AStore.ASTORE_S.INSTANCE, jq_Primitive.SHORT);
625     }
626     public void visitPOP() {
627         super.visitPOP();
628         current_state.pop();
629     }
630     public void visitPOP2() {
631         super.visitPOP2();
632         current_state.pop(); current_state.pop();
633     }
634     public void visitDUP() {
635         super.visitDUP();
636         Operand op = current_state.pop();
637         int d = current_state.getStackSize();
638         jq_Type type = getTypeOf(op);
639         RegisterOperand t = new RegisterOperand(rf.getOrCreateStack(d+1, type), type);
640         Quad q = Move.create(quad_cfg.getNewQuadID(), Move.getMoveOp(type), t, op);
641         appendQuad(q);
642         current_state.push(op.copy(), type);
643         current_state.push(t.copy(), type);
644     }
645     private void do_DUP_x1() {
646         Operand op1 = current_state.pop();
647         Operand op2 = current_state.pop();
648         int d = current_state.getStackSize();
649         jq_Type type1 = getTypeOf(op1);
650         jq_Type type2 = getTypeOf(op2);
651         RegisterOperand t1 = new RegisterOperand(rf.getOrCreateStack(d+2, type1), type1);
652         Quad q1 = Move.create(quad_cfg.getNewQuadID(), Move.getMoveOp(type1), t1, op1);
653         appendQuad(q1);
654         RegisterOperand t2 = new RegisterOperand(rf.getOrCreateStack(d+1, type2), type2);
655         Quad q2 = Move.create(quad_cfg.getNewQuadID(), Move.getMoveOp(type2), t2, op2);
656         appendQuad(q2);
657         RegisterOperand t3 = new RegisterOperand(rf.getOrCreateStack(d, type1), type1);
658         Quad q3 = Move.create(quad_cfg.getNewQuadID(), Move.getMoveOp(type1), t3, t1.copy());
659         appendQuad(q3);
660         current_state.push(t3.copy(), type1);
661         current_state.push(t2.copy(), type2);
662         current_state.push(t1.copy(), type1);
663     }
664     public void visitDUP_x1() {
665         super.visitDUP_x1();
666         do_DUP_x1();
667     }
668     public void visitDUP_x2() {
669         super.visitDUP_x2();
670         Operand op1 = current_state.pop();
671         Operand op2 = current_state.pop();
672         Operand op3 = current_state.pop();
673         int d = current_state.getStackSize();
674         jq_Type type1 = getTypeOf(op1);
675         RegisterOperand t1 = new RegisterOperand(rf.getOrCreateStack(d+3, type1), type1);
676         Quad q1 = Move.create(quad_cfg.getNewQuadID(), Move.getMoveOp(type1), t1, op1);
677         appendQuad(q1);
678         RegisterOperand t2 = null; jq_Type type2 = null;
679         if (op2 != DummyOperand.DUMMY) {
680             type2 = getTypeOf(op2);
681             t2 = new RegisterOperand(rf.getOrCreateStack(d+2, type2), type2);
682             Quad q2 = Move.create(quad_cfg.getNewQuadID(), Move.getMoveOp(type2), t2, op2);
683             appendQuad(q2);
684         }
685         jq_Type type3 = getTypeOf(op3);
686         RegisterOperand t3 = new RegisterOperand(rf.getOrCreateStack(d+1, type3), type3);
687         Quad q3 = Move.create(quad_cfg.getNewQuadID(), Move.getMoveOp(type3), t3, op3);
688         appendQuad(q3);
689         RegisterOperand t4 = new RegisterOperand(rf.getOrCreateStack(d, type1), type1);
690         Quad q4 = Move.create(quad_cfg.getNewQuadID(), Move.getMoveOp(type1), t4, t1.copy());
691         appendQuad(q4);
692         current_state.push(t4.copy(), type1);
693         current_state.push(t3.copy(), type3);
694         if (op2 != DummyOperand.DUMMY)
695             current_state.push(t2.copy(), type2);
696         current_state.push(t1.copy(), type1);
697     }
698     public void visitDUP2() {
699         super.visitDUP2();
700         Operand op1 = current_state.pop();
701         Operand op2 = current_state.pop();
702         int d = current_state.getStackSize();
703         RegisterOperand t1 = null; jq_Type type1 = null;
704         if (op1 != DummyOperand.DUMMY) {
705             type1 = getTypeOf(op1);
706             t1 = new RegisterOperand(rf.getOrCreateStack(d+3, type1), type1);
707             Quad q1 = Move.create(quad_cfg.getNewQuadID(), Move.getMoveOp(type1), t1, op1);
708             appendQuad(q1);
709         }
710         jq_Type type2 = getTypeOf(op2);
711         RegisterOperand t2 = new RegisterOperand(rf.getOrCreateStack(d+2, type2), type2);
712         Quad q2 = Move.create(quad_cfg.getNewQuadID(), Move.getMoveOp(type2), t2, op2);
713         appendQuad(q2);
714         current_state.push(t2.copy(), type2);
715         if (op1 != DummyOperand.DUMMY)
716             current_state.push(t1.copy(), type1);
717         current_state.push(op2.copy(), type2);
718         if (op1 != DummyOperand.DUMMY)
719             current_state.push(op1.copy(), type1);
720     }
721     public void visitDUP2_x1() {
722         super.visitDUP2_x1();
723         // TODO: do this correctly.
724         Operand op1 = current_state.pop();
725         Operand op2 = current_state.pop();
726         Operand op3 = current_state.pop();
727         current_state.push(op2);
728         current_state.push(op1);
729         current_state.push(op3);
730         current_state.push(op2.copy());
731         current_state.push(op1.copy());
732     }
733     public void visitDUP2_x2() {
734         super.visitDUP2_x2();
735         // TODO: do this correctly.
736         Operand op1 = current_state.pop();
737         Operand op2 = current_state.pop();
738         Operand op3 = current_state.pop();
739         Operand op4 = current_state.pop();
740         current_state.push(op2);
741         current_state.push(op1);
742         current_state.push(op4);
743         current_state.push(op3);
744         current_state.push(op2.copy());
745         current_state.push(op1.copy());
746     }
747     public void visitSWAP() {
748         super.visitSWAP();
749         do_DUP_x1();
750         current_state.pop();
751     }
752     private void BINOPhelper(Binary operator, jq_Type tr, jq_Type t1, jq_Type t2, boolean zero_check) {
753         Operand op2 = current_state.pop(t2);
754         Operand op1 = current_state.pop(t1);
755         if (zero_check && performZeroCheck(op2)) {
756             if (TRACE) System.out.println("Zero check triggered on "+op2);
757             return;
758         }
759         RegisterOperand r = getStackRegister(tr);
760         Quad q = Binary.create(quad_cfg.getNewQuadID(), operator, r, op1, op2);
761         appendQuad(q);
762         current_state.push(r.copy(), tr);
763     }
764     public void visitIBINOP(byte op) {
765         super.visitIBINOP(op);
766         Binary operator=null; boolean zero_check = false;
767         switch (op) {
768             case BINOP_ADD: operator = Binary.ADD_I.INSTANCE; break;
769             case BINOP_SUB: operator = Binary.SUB_I.INSTANCE; break;
770             case BINOP_MUL: operator = Binary.MUL_I.INSTANCE; break;
771             case BINOP_DIV: operator = Binary.DIV_I.INSTANCE; zero_check = true; break;
772             case BINOP_REM: operator = Binary.REM_I.INSTANCE; zero_check = true; break;
773             case BINOP_AND: operator = Binary.AND_I.INSTANCE; break;
774             case BINOP_OR: operator = Binary.OR_I.INSTANCE; break;
775             case BINOP_XOR: operator = Binary.XOR_I.INSTANCE; break;
776             default: Assert.UNREACHABLE(); break;
777         }
778         BINOPhelper(operator, jq_Primitive.INT, jq_Primitive.INT, jq_Primitive.INT, zero_check);
779     }
780     public void visitLBINOP(byte op) {
781         super.visitLBINOP(op);
782         Binary operator=null; boolean zero_check = false;
783         switch (op) {
784             case BINOP_ADD: operator = Binary.ADD_L.INSTANCE; break;
785             case BINOP_SUB: operator = Binary.SUB_L.INSTANCE; break;
786             case BINOP_MUL: operator = Binary.MUL_L.INSTANCE; break;
787             case BINOP_DIV: operator = Binary.DIV_L.INSTANCE; zero_check = true; break;
788             case BINOP_REM: operator = Binary.REM_L.INSTANCE; zero_check = true; break;
789             case BINOP_AND: operator = Binary.AND_L.INSTANCE; break;
790             case BINOP_OR: operator = Binary.OR_L.INSTANCE; break;
791             case BINOP_XOR: operator = Binary.XOR_L.INSTANCE; break;
792             default: Assert.UNREACHABLE(); break;
793         }
794         BINOPhelper(operator, jq_Primitive.LONG, jq_Primitive.LONG, jq_Primitive.LONG, zero_check);
795     }
796     public void visitFBINOP(byte op) {
797         super.visitFBINOP(op);
798         Binary operator=null;
799         switch (op) {
800             case BINOP_ADD: operator = Binary.ADD_F.INSTANCE; break;
801             case BINOP_SUB: operator = Binary.SUB_F.INSTANCE; break;
802             case BINOP_MUL: operator = Binary.MUL_F.INSTANCE; break;
803             case BINOP_DIV: operator = Binary.DIV_F.INSTANCE; break;
804             case BINOP_REM: operator = Binary.REM_F.INSTANCE; break;
805             default: Assert.UNREACHABLE(); break;
806         }
807         BINOPhelper(operator, jq_Primitive.FLOAT, jq_Primitive.FLOAT, jq_Primitive.FLOAT, false);
808     }
809     public void visitDBINOP(byte op) {
810         super.visitDBINOP(op);
811         Binary operator=null;
812         switch (op) {
813             case BINOP_ADD: operator = Binary.ADD_D.INSTANCE; break;
814             case BINOP_SUB: operator = Binary.SUB_D.INSTANCE; break;
815             case BINOP_MUL: operator = Binary.MUL_D.INSTANCE; break;
816             case BINOP_DIV: operator = Binary.DIV_D.INSTANCE; break;
817             case BINOP_REM: operator = Binary.REM_D.INSTANCE; break;
818             default: Assert.UNREACHABLE(); break;
819         }
820         BINOPhelper(operator, jq_Primitive.DOUBLE, jq_Primitive.DOUBLE, jq_Primitive.DOUBLE, false);
821     }
822     public void UNOPhelper(Unary operator, jq_Type tr, jq_Type t1) {
823         Operand op1 = current_state.pop(t1);
824         RegisterOperand r = getStackRegister(tr);
825         Quad q = Unary.create(quad_cfg.getNewQuadID(), operator, r, op1);
826         appendQuad(q);
827         current_state.push(r.copy(), tr);
828     }
829     public void visitIUNOP(byte op) {
830         super.visitIUNOP(op);
831         Unary operator=null;
832         switch (op) {
833             case UNOP_NEG: operator = Unary.NEG_I.INSTANCE; break;
834             default: Assert.UNREACHABLE(); break;
835         }
836         UNOPhelper(operator, jq_Primitive.INT, jq_Primitive.INT);
837     }
838     public void visitLUNOP(byte op) {
839         super.visitLUNOP(op);
840         Unary operator=null;
841         switch (op) {
842             case UNOP_NEG: operator = Unary.NEG_L.INSTANCE; break;
843             default: Assert.UNREACHABLE(); break;
844         }
845         UNOPhelper(operator, jq_Primitive.LONG, jq_Primitive.LONG);
846     }
847     public void visitFUNOP(byte op) {
848         super.visitFUNOP(op);
849         Unary operator=null;
850         switch (op) {
851             case UNOP_NEG: operator = Unary.NEG_F.INSTANCE; break;
852             default: Assert.UNREACHABLE(); break;
853         }
854         UNOPhelper(operator, jq_Primitive.FLOAT, jq_Primitive.FLOAT);
855     }
856     public void visitDUNOP(byte op) {
857         super.visitDUNOP(op);
858         Unary operator=null;
859         switch (op) {
860             case UNOP_NEG: operator = Unary.NEG_D.INSTANCE; break;
861             default: Assert.UNREACHABLE(); break;
862         }
863         UNOPhelper(operator, jq_Primitive.DOUBLE, jq_Primitive.DOUBLE);
864     }
865     public void visitISHIFT(byte op) {
866         super.visitISHIFT(op);
867         Binary operator=null;
868         switch (op) {
869             case SHIFT_LEFT: operator = Binary.SHL_I.INSTANCE; break;
870             case SHIFT_RIGHT: operator = Binary.SHR_I.INSTANCE; break;
871             case SHIFT_URIGHT: operator = Binary.USHR_I.INSTANCE; break;
872             default: Assert.UNREACHABLE(); break;
873         }
874         BINOPhelper(operator, jq_Primitive.INT, jq_Primitive.INT, jq_Primitive.INT, false);
875     }
876     public void visitLSHIFT(byte op) {
877         super.visitLSHIFT(op);
878         Binary operator=null;
879         switch (op) {
880             case SHIFT_LEFT: operator = Binary.SHL_L.INSTANCE; break;
881             case SHIFT_RIGHT: operator = Binary.SHR_L.INSTANCE; break;
882             case SHIFT_URIGHT: operator = Binary.USHR_L.INSTANCE; break;
883             default: Assert.UNREACHABLE(); break;
884         }
885         BINOPhelper(operator, jq_Primitive.LONG, jq_Primitive.LONG, jq_Primitive.INT, false);
886     }
887     public void visitIINC(int i, int v) {
888         super.visitIINC(i, v);
889         Operand op1 = current_state.getLocal_I(i);
890         replaceLocalsOnStack(i, jq_Primitive.INT);
891         RegisterOperand op0 = makeLocal(i, jq_Primitive.INT);
892         Quad q = Binary.create(quad_cfg.getNewQuadID(), Binary.ADD_I.INSTANCE, op0, op1, new IConstOperand(v));
893         appendQuad(q);
894         current_state.setLocal(i, op0.copy());
895     }
896     public void visitI2L() {
897         super.visitI2L();
898         UNOPhelper(Unary.INT_2LONG.INSTANCE, jq_Primitive.LONG, jq_Primitive.INT);
899     }
900     public void visitI2F() {
901         super.visitI2F();
902         UNOPhelper(Unary.INT_2FLOAT.INSTANCE, jq_Primitive.FLOAT, jq_Primitive.INT);
903     }
904     public void visitI2D() {
905         super.visitI2D();
906         UNOPhelper(Unary.INT_2DOUBLE.INSTANCE, jq_Primitive.DOUBLE, jq_Primitive.INT);
907     }
908     public void visitL2I() {
909         super.visitL2I();
910         UNOPhelper(Unary.LONG_2INT.INSTANCE, jq_Primitive.INT, jq_Primitive.LONG);
911     }
912     public void visitL2F() {
913         super.visitL2F();
914         UNOPhelper(Unary.LONG_2FLOAT.INSTANCE, jq_Primitive.FLOAT, jq_Primitive.LONG);
915     }
916     public void visitL2D() {
917         super.visitL2D();
918         UNOPhelper(Unary.LONG_2DOUBLE.INSTANCE, jq_Primitive.DOUBLE, jq_Primitive.LONG);
919     }
920     public void visitF2I() {
921         super.visitF2I();
922         UNOPhelper(Unary.FLOAT_2INT.INSTANCE, jq_Primitive.INT, jq_Primitive.FLOAT);
923     }
924     public void visitF2L() {
925         super.visitF2L();
926         UNOPhelper(Unary.FLOAT_2LONG.INSTANCE, jq_Primitive.LONG, jq_Primitive.FLOAT);
927     }
928     public void visitF2D() {
929         super.visitF2D();
930         UNOPhelper(Unary.FLOAT_2DOUBLE.INSTANCE, jq_Primitive.DOUBLE, jq_Primitive.FLOAT);
931     }
932     public void visitD2I() {
933         super.visitD2I();
934         UNOPhelper(Unary.DOUBLE_2INT.INSTANCE, jq_Primitive.INT, jq_Primitive.DOUBLE);
935     }
936     public void visitD2L() {
937         super.visitD2L();
938         UNOPhelper(Unary.DOUBLE_2LONG.INSTANCE, jq_Primitive.LONG, jq_Primitive.DOUBLE);
939     }
940     public void visitD2F() {
941         super.visitD2F();
942         UNOPhelper(Unary.DOUBLE_2FLOAT.INSTANCE, jq_Primitive.FLOAT, jq_Primitive.DOUBLE);
943     }
944     public void visitI2B() {
945         super.visitI2B();
946         UNOPhelper(Unary.INT_2BYTE.INSTANCE, jq_Primitive.BYTE, jq_Primitive.INT);
947     }
948     public void visitI2C() {
949         super.visitI2C();
950         UNOPhelper(Unary.INT_2CHAR.INSTANCE, jq_Primitive.CHAR, jq_Primitive.INT);
951     }
952     public void visitI2S() {
953         super.visitI2S();
954         UNOPhelper(Unary.INT_2SHORT.INSTANCE, jq_Primitive.SHORT, jq_Primitive.INT);
955     }
956     public void visitLCMP2() {
957         super.visitLCMP2();
958         BINOPhelper(Binary.CMP_L.INSTANCE, jq_Primitive.INT, jq_Primitive.LONG, jq_Primitive.LONG, false);
959     }
960     public void visitFCMP2(byte op) {
961         super.visitFCMP2(op);
962         Binary o = op==CMP_L?(Binary)Binary.CMP_FL.INSTANCE:(Binary)Binary.CMP_FG.INSTANCE;
963         BINOPhelper(o, jq_Primitive.INT, jq_Primitive.FLOAT, jq_Primitive.FLOAT, false);
964     }
965     public void visitDCMP2(byte op) {
966         super.visitDCMP2(op);
967         Binary o = op==CMP_L?(Binary)Binary.CMP_DL.INSTANCE:(Binary)Binary.CMP_DG.INSTANCE;
968         BINOPhelper(o, jq_Primitive.INT, jq_Primitive.DOUBLE, jq_Primitive.DOUBLE, false);
969     }
970     public void visitIF(byte op, int target) {
971         super.visitIF(op, target);
972         Operand op0 = current_state.pop_I();
973         saveStackIntoRegisters();
974         BasicBlock target_bb = quad_bbs[bc_cfg.getBasicBlockByBytecodeIndex(target).id];
975         ConditionOperand cond = new ConditionOperand(op);
976         Quad q = IntIfCmp.create(quad_cfg.getNewQuadID(), IntIfCmp.IFCMP_I.INSTANCE, op0, new IConstOperand(0), cond, new TargetOperand(target_bb));
977         appendQuad(q);
978     }
979     public void visitIFREF(byte op, int target) {
980         super.visitIFREF(op, target);
981         // could be A or R
982         Operand op0 = current_state.pop();
983         saveStackIntoRegisters();
984         BasicBlock target_bb = quad_bbs[bc_cfg.getBasicBlockByBytecodeIndex(target).id];
985         ConditionOperand cond = new ConditionOperand(op);
986         jq_Type t = getTypeOf(op0);
987         IntIfCmp operator = t.isAddressType()?(IntIfCmp)IntIfCmp.IFCMP_P.INSTANCE:IntIfCmp.IFCMP_A.INSTANCE;
988         Operand op1 = t.isAddressType()?(Operand)new PConstOperand(null):new AConstOperand(null);
989         Quad q = IntIfCmp.create(quad_cfg.getNewQuadID(), operator, op0, op1, cond, new TargetOperand(target_bb));
990         appendQuad(q);
991     }
992     public void visitIFCMP(byte op, int target) {
993         super.visitIFCMP(op, target);
994         Operand op1 = current_state.pop_I();
995         Operand op0 = current_state.pop_I();
996         saveStackIntoRegisters();
997         BasicBlock target_bb = quad_bbs[bc_cfg.getBasicBlockByBytecodeIndex(target).id];
998         ConditionOperand cond = new ConditionOperand(op);
999         Quad q = IntIfCmp.create(quad_cfg.getNewQuadID(), IntIfCmp.IFCMP_I.INSTANCE, op0, op1, cond, new TargetOperand(target_bb));
1000         appendQuad(q);
1001     }
1002     public void visitIFREFCMP(byte op, int target) {
1003         super.visitIFREFCMP(op, target);
1004         // could be A or R
1005         Operand op1 = current_state.pop();
1006         // could be A or R
1007         Operand op0 = current_state.pop();
1008         saveStackIntoRegisters();
1009         BasicBlock target_bb = quad_bbs[bc_cfg.getBasicBlockByBytecodeIndex(target).id];
1010         ConditionOperand cond = new ConditionOperand(op);
1011         jq_Type t1 = getTypeOf(op1);
1012         jq_Type t0 = getTypeOf(op0);
1013         IntIfCmp operator;
1014         if (t1.isAddressType()) {
1015             if (!t0.isAddressType() && t0 != jq_Reference.jq_NullType.NULL_TYPE) {
1016                 Assert.UNREACHABLE("comparing address type "+op1+" with non-address type "+op0);
1017             }
1018             operator = IntIfCmp.IFCMP_P.INSTANCE;
1019         } else if (t0.isAddressType()) {
1020             if (t1 != jq_Reference.jq_NullType.NULL_TYPE) {
1021                 Assert.UNREACHABLE("comparing address type "+op0+" with non-address type "+op1);
1022             }
1023             operator = IntIfCmp.IFCMP_P.INSTANCE;
1024         } else {
1025             operator = IntIfCmp.IFCMP_A.INSTANCE;
1026         }
1027         Quad q = IntIfCmp.create(quad_cfg.getNewQuadID(), operator, op0, op1, cond, new TargetOperand(target_bb));
1028         appendQuad(q);
1029     }
1030     public void visitGOTO(int target) {
1031         super.visitGOTO(target);
1032         saveStackIntoRegisters();
1033         BasicBlock target_bb = quad_bbs[bc_cfg.getBasicBlockByBytecodeIndex(target).id];
1034         Quad q = Goto.create(quad_cfg.getNewQuadID(), Goto.GOTO.INSTANCE, new TargetOperand(target_bb));
1035         appendQuad(q);
1036     }
1037     java.util.Map jsr_states = new java.util.HashMap();
1038     void setJSRState(joeq.Compiler.BytecodeAnalysis.BasicBlock bb, AbstractState s) {
1039         jsr_states.put(bb, s.copyAfterJSR());
1040     }
1041     AbstractState getJSRState(joeq.Compiler.BytecodeAnalysis.BasicBlock bb) {
1042         return (AbstractState)jsr_states.get(bb);
1043     }
1044     public void visitJSR(int target) {
1045         super.visitJSR(target);
1046         joeq.Compiler.BytecodeAnalysis.BasicBlock target_bcbb = bc_cfg.getBasicBlockByBytecodeIndex(target);
1047         BasicBlock target_bb = quad_bbs[target_bcbb.id];
1048         BasicBlock successor_bb = quad_bbs[bc_bb.id+1];
1049         joeq.Compiler.BytecodeAnalysis.JSRInfo jsrinfo = bc_cfg.getJSRInfo(target_bcbb);
1050         if (jsrinfo == null) {
1051             if (TRACE) out.println("jsr with no ret! converting to GOTO.");
1052             // push a null constant in place of the return address,
1053             // in case the return address is stored into a local variable.
1054             current_state.push_A(new AConstOperand(null));
1055             saveStackIntoRegisters();
1056             Quad q = Goto.create(quad_cfg.getNewQuadID(), Goto.GOTO.INSTANCE, new TargetOperand(target_bb));
1057             appendQuad(q);
1058             return;
1059         }
1060         Assert._assert(quad_bbs[jsrinfo.entry_block.id] == target_bb);
1061         BasicBlock last_bb = quad_bbs[jsrinfo.exit_block.id];
1062         JSRInfo q_jsrinfo = new JSRInfo(target_bb, last_bb, jsrinfo.changedLocals);
1063         this.quad_cfg.addJSRInfo(q_jsrinfo);
1064         saveStackIntoRegisters();
1065         RegisterOperand op0 = getStackRegister(jq_ReturnAddressType.INSTANCE);
1066         Quad q = Jsr.create(quad_cfg.getNewQuadID(), Jsr.JSR.INSTANCE, op0, new TargetOperand(target_bb), new TargetOperand(successor_bb));
1067         appendQuad(q);
1068         joeq.Compiler.BytecodeAnalysis.BasicBlock next_bb = bc_cfg.getBasicBlock(bc_bb.id+1);
1069         joeq.Compiler.BytecodeAnalysis.BasicBlock ret_bb = jsrinfo.exit_block;
1070         setJSRState(next_bb, current_state);
1071         // we need to visit the ret block even when it has been visited before,
1072         // so that when we visit its ret instruction, next_bb will get updated
1073         // with the new jsr state
1074         if (visited[ret_bb.id]) {
1075             if (TRACE) out.println("marking ret bb "+ret_bb+" for regeneration.");
1076             if (!regenerate.contains(ret_bb)) {
1077                 regenerate.add(ret_bb);
1078                 start_states[ret_bb.id].rebuildStack();
1079             }
1080             visited[ret_bb.id] = false;
1081         }
1082         current_state.push(op0.copy());
1083     }
1084     public void visitRET(int i) {
1085         super.visitRET(i);
1086         saveStackIntoRegisters();
1087         RegisterOperand op0 = makeLocal(i, jq_ReturnAddressType.INSTANCE);
1088         Quad q = Ret.create(quad_cfg.getNewQuadID(), Ret.RET.INSTANCE, op0);
1089         appendQuad(q);
1090         current_state.setLocal(i, null);
1091         endsWithRET = true;
1092         // get JSR info
1093         joeq.Compiler.BytecodeAnalysis.JSRInfo jsrinfo = bc_cfg.getJSRInfo(bc_bb);
1094         // find all callers to this subroutine.
1095         for (int j=0; j<bc_bb.getNumberOfSuccessors(); ++j) {
1096             joeq.Compiler.BytecodeAnalysis.BasicBlock caller_next = bc_bb.getSuccessor(j);
1097             AbstractState caller_state = getJSRState(caller_next);
1098             if (caller_state == null) {
1099                 if (TRACE) out.println("haven't seen jsr call from "+caller_next+" yet.");
1100                 Assert._assert(!visited[caller_next.id]);
1101                 if (!regenerate.contains(caller_next)) {
1102                     regenerate.add(caller_next);
1103                 }
1104                 continue;
1105             }
1106             caller_state.mergeAfterJSR(jsrinfo.changedLocals, current_state);
1107             if (start_states[caller_next.id] == null) {
1108                 if (TRACE) out.println("Copying jsr state to "+caller_next);
1109                 start_states[caller_next.id] = caller_state.copy();
1110                 if (visited[caller_next.id]) {
1111                     if (TRACE) out.println("must regenerate code for "+caller_next);
1112                     if (!regenerate.contains(caller_next)) {
1113                         regenerate.add(caller_next);
1114                         start_states[caller_next.id].rebuildStack();
1115                     }
1116                     visited[caller_next.id] = false;
1117                 }
1118             } else {
1119                 if (TRACE) out.println("Merging jsr state with "+caller_next);
1120                 if (start_states[caller_next.id].merge(caller_state, rf)) {
1121                     if (TRACE) out.println("in set of "+caller_next+" changed");
1122                     if (visited[caller_next.id]) {
1123                         if (TRACE) out.println("must regenerate code for "+caller_next);
1124                         if (!regenerate.contains(caller_next)) {
1125                             regenerate.add(caller_next);
1126                             start_states[caller_next.id].rebuildStack();
1127                         }
1128                         visited[caller_next.id] = false;
1129                     }
1130                 }
1131             }
1132         }
1133     }
1134     public void visitTABLESWITCH(int default_target, int low, int high, int[] targets) {
1135         super.visitTABLESWITCH(default_target, low, high, targets);
1136         Operand op0 = current_state.pop_I();
1137         saveStackIntoRegisters();
1138         BasicBlock target_bb = quad_bbs[bc_cfg.getBasicBlockByBytecodeIndex(default_target).id];
1139         Assert._assert(high-low+1 == targets.length);
1140         Quad q = TableSwitch.create(quad_cfg.getNewQuadID(), TableSwitch.TABLESWITCH.INSTANCE, op0, new IConstOperand(low),
1141                                     new TargetOperand(target_bb), targets.length);
1142         for (int i = 0; i < targets.length; ++i) {
1143             target_bb = quad_bbs[bc_cfg.getBasicBlockByBytecodeIndex(targets[i]).id];
1144             TableSwitch.setTarget(q, i, target_bb);
1145         }
1146         appendQuad(q);
1147     }
1148     public void visitLOOKUPSWITCH(int default_target, int[] values, int[] targets) {
1149         super.visitLOOKUPSWITCH(default_target, values, targets);
1150         Operand op0 = current_state.pop_I();
1151         saveStackIntoRegisters();
1152         BasicBlock target_bb = quad_bbs[bc_cfg.getBasicBlockByBytecodeIndex(default_target).id];
1153         Quad q = LookupSwitch.create(quad_cfg.getNewQuadID(), LookupSwitch.LOOKUPSWITCH.INSTANCE, op0, new TargetOperand(target_bb), values.length);
1154         for (int i = 0; i < values.length; ++i) {
1155             LookupSwitch.setMatch(q, i, values[i]);
1156             target_bb = quad_bbs[bc_cfg.getBasicBlockByBytecodeIndex(targets[i]).id];
1157             LookupSwitch.setTarget(q, i, target_bb);
1158         }
1159         appendQuad(q);
1160     }
1161     public void visitIRETURN() {
1162         super.visitIRETURN();
1163         Operand op0 = current_state.pop_I();
1164         Quad q = Return.create(quad_cfg.getNewQuadID(), Return.RETURN_I.INSTANCE, op0);
1165         appendQuad(q);
1166         current_state.clearStack();
1167     }
1168     public void visitLRETURN() {
1169         super.visitLRETURN();
1170         Operand op0 = current_state.pop_L();
1171         Quad q = Return.create(quad_cfg.getNewQuadID(), Return.RETURN_L.INSTANCE, op0);
1172         appendQuad(q);
1173         current_state.clearStack();
1174     }
1175     public void visitFRETURN() {
1176         super.visitFRETURN();
1177         Operand op0 = current_state.pop_F();
1178         Quad q = Return.create(quad_cfg.getNewQuadID(), Return.RETURN_F.INSTANCE, op0);
1179         appendQuad(q);
1180         current_state.clearStack();
1181     }
1182     public void visitDRETURN() {
1183         super.visitDRETURN();
1184         Operand op0 = current_state.pop_D();
1185         Quad q = Return.create(quad_cfg.getNewQuadID(), Return.RETURN_D.INSTANCE, op0);
1186         appendQuad(q);
1187         current_state.clearStack();
1188     }
1189     public void visitARETURN() {
1190         super.visitARETURN();
1191         // could be A or R
1192         Operand op0 = current_state.pop();
1193         jq_Type t = getTypeOf(op0);
1194         Return operator;
1195         if (method.getReturnType().isAddressType()) {
1196             operator = Return.RETURN_P.INSTANCE;
1197             Assert._assert(t.isAddressType() ||
1198                       t == jq_Reference.jq_NullType.NULL_TYPE ||
1199                       state.isSubtype(t, Address._class) != NO, t.toString());
1200         } else {
1201             operator = t.isAddressType()?(Return)Return.RETURN_P.INSTANCE:Return.RETURN_A.INSTANCE;
1202         }
1203         Quad q = Return.create(quad_cfg.getNewQuadID(), operator, op0);
1204         appendQuad(q);
1205         current_state.clearStack();
1206     }
1207     public void visitVRETURN() {
1208         super.visitVRETURN();
1209         Quad q = Return.create(quad_cfg.getNewQuadID(), Return.RETURN_V.INSTANCE);
1210         appendQuad(q);
1211         current_state.clearStack();
1212     }
1213     private void GETSTATIChelper(jq_StaticField f, Getstatic oper1, Getstatic oper2) {
1214         f = tryResolve(f);
1215         boolean dynlink = state.needsDynamicLink(method, f);
1216         Getstatic operator = dynlink?oper1:oper2;
1217         jq_Type t = f.getType();
1218         RegisterOperand op0 = getStackRegister(t);
1219         Quad q = Getstatic.create(quad_cfg.getNewQuadID(), operator, op0, new FieldOperand(f));
1220         appendQuad(q);
1221         current_state.push(op0.copy(), t);
1222     }
1223     public void visitIGETSTATIC(jq_StaticField f) {
1224         super.visitIGETSTATIC(f);
1225         GETSTATIChelper(f, Getstatic.GETSTATIC_I_DYNLINK.INSTANCE, Getstatic.GETSTATIC_I.INSTANCE);
1226     }
1227     public void visitLGETSTATIC(jq_StaticField f) {
1228         super.visitLGETSTATIC(f);
1229         GETSTATIChelper(f, Getstatic.GETSTATIC_L_DYNLINK.INSTANCE, Getstatic.GETSTATIC_L.INSTANCE);
1230     }
1231     public void visitFGETSTATIC(jq_StaticField f) {
1232         super.visitFGETSTATIC(f);
1233         GETSTATIChelper(f, Getstatic.GETSTATIC_F_DYNLINK.INSTANCE, Getstatic.GETSTATIC_F.INSTANCE);
1234     }
1235     public void visitDGETSTATIC(jq_StaticField f) {
1236         super.visitDGETSTATIC(f);
1237         GETSTATIChelper(f, Getstatic.GETSTATIC_D_DYNLINK.INSTANCE, Getstatic.GETSTATIC_D.INSTANCE);
1238     }
1239     public void visitAGETSTATIC(jq_StaticField f) {
1240         super.visitAGETSTATIC(f);
1241         Getstatic operator1 = f.getType().isAddressType()?(Getstatic)Getstatic.GETSTATIC_P_DYNLINK.INSTANCE:Getstatic.GETSTATIC_A_DYNLINK.INSTANCE;
1242         Getstatic operator2 = f.getType().isAddressType()?(Getstatic)Getstatic.GETSTATIC_P.INSTANCE:Getstatic.GETSTATIC_A.INSTANCE;
1243         GETSTATIChelper(f, operator1, operator2);
1244     }
1245     public void visitZGETSTATIC(jq_StaticField f) {
1246         super.visitZGETSTATIC(f);
1247         GETSTATIChelper(f, Getstatic.GETSTATIC_Z_DYNLINK.INSTANCE, Getstatic.GETSTATIC_Z.INSTANCE);
1248     }
1249     public void visitBGETSTATIC(jq_StaticField f) {
1250         super.visitBGETSTATIC(f);
1251         GETSTATIChelper(f, Getstatic.GETSTATIC_B_DYNLINK.INSTANCE, Getstatic.GETSTATIC_B.INSTANCE);
1252     }
1253     public void visitCGETSTATIC(jq_StaticField f) {
1254         super.visitCGETSTATIC(f);
1255         GETSTATIChelper(f, Getstatic.GETSTATIC_C_DYNLINK.INSTANCE, Getstatic.GETSTATIC_C.INSTANCE);
1256     }
1257     public void visitSGETSTATIC(jq_StaticField f) {
1258         super.visitSGETSTATIC(f);
1259         GETSTATIChelper(f, Getstatic.GETSTATIC_S_DYNLINK.INSTANCE, Getstatic.GETSTATIC_S.INSTANCE);
1260     }
1261     private void PUTSTATIChelper(jq_StaticField f, Putstatic oper1, Putstatic oper2) {
1262         f = tryResolve(f);
1263         boolean dynlink = state.needsDynamicLink(method, f);
1264         Putstatic operator = dynlink?oper1:oper2;
1265         jq_Type t = f.getType();
1266         Operand op0 = current_state.pop(t);
1267         Quad q = Putstatic.create(quad_cfg.getNewQuadID(), operator, op0, new FieldOperand(f));
1268         appendQuad(q);
1269     }
1270     public void visitIPUTSTATIC(jq_StaticField f) {
1271         super.visitIPUTSTATIC(f);
1272         PUTSTATIChelper(f, Putstatic.PUTSTATIC_I_DYNLINK.INSTANCE, Putstatic.PUTSTATIC_I.INSTANCE);
1273     }
1274     public void visitLPUTSTATIC(jq_StaticField f) {
1275         super.visitLPUTSTATIC(f);
1276         PUTSTATIChelper(f, Putstatic.PUTSTATIC_L_DYNLINK.INSTANCE, Putstatic.PUTSTATIC_L.INSTANCE);
1277     }
1278     public void visitFPUTSTATIC(jq_StaticField f) {
1279         super.visitFPUTSTATIC(f);
1280         PUTSTATIChelper(f, Putstatic.PUTSTATIC_F_DYNLINK.INSTANCE, Putstatic.PUTSTATIC_F.INSTANCE);
1281     }
1282     public void visitDPUTSTATIC(jq_StaticField f) {
1283         super.visitDPUTSTATIC(f);
1284         PUTSTATIChelper(f, Putstatic.PUTSTATIC_D_DYNLINK.INSTANCE, Putstatic.PUTSTATIC_D.INSTANCE);
1285     }
1286     public void visitAPUTSTATIC(jq_StaticField f) {
1287         super.visitAPUTSTATIC(f);
1288         Putstatic operator1 = f.getType().isAddressType()?(Putstatic)Putstatic.PUTSTATIC_P_DYNLINK.INSTANCE:Putstatic.PUTSTATIC_A_DYNLINK.INSTANCE;
1289         Putstatic operator2 = f.getType().isAddressType()?(Putstatic)Putstatic.PUTSTATIC_P.INSTANCE:Putstatic.PUTSTATIC_A.INSTANCE;
1290         PUTSTATIChelper(f, operator1, operator2);
1291     }
1292     public void visitZPUTSTATIC(jq_StaticField f) {
1293         super.visitZPUTSTATIC(f);
1294         PUTSTATIChelper(f, Putstatic.PUTSTATIC_Z_DYNLINK.INSTANCE, Putstatic.PUTSTATIC_Z.INSTANCE);
1295     }
1296     public void visitBPUTSTATIC(jq_StaticField f) {
1297         super.visitBPUTSTATIC(f);
1298         PUTSTATIChelper(f, Putstatic.PUTSTATIC_B_DYNLINK.INSTANCE, Putstatic.PUTSTATIC_B.INSTANCE);
1299     }
1300     public void visitCPUTSTATIC(jq_StaticField f) {
1301         super.visitCPUTSTATIC(f);
1302         PUTSTATIChelper(f, Putstatic.PUTSTATIC_C_DYNLINK.INSTANCE, Putstatic.PUTSTATIC_C.INSTANCE);
1303     }
1304     public void visitSPUTSTATIC(jq_StaticField f) {
1305         super.visitSPUTSTATIC(f);
1306         PUTSTATIChelper(f, Putstatic.PUTSTATIC_S_DYNLINK.INSTANCE, Putstatic.PUTSTATIC_S.INSTANCE);
1307     }
1308     private void GETFIELDhelper(jq_InstanceField f, Getfield oper1, Getfield oper2) {
1309         f = tryResolve(f);
1310         boolean dynlink = state.needsDynamicLink(method, f);
1311         Operand op1 = current_state.pop_A();
1312         clearCurrentGuard();
1313         if (performNullCheck(op1)) {
1314             if (TRACE) System.out.println("Null check triggered on "+op1);
1315             return;
1316         }
1317         jq_Type t = f.getType();
1318         RegisterOperand op0 = getStackRegister(t);
1319         Getfield operator = dynlink?oper1:oper2;
1320         Quad q = Getfield.create(quad_cfg.getNewQuadID(), operator, op0, op1, new FieldOperand(f), getCurrentGuard());
1321         appendQuad(q);
1322         current_state.push(op0.copy(), t);
1323     }
1324     public void visitIGETFIELD(jq_InstanceField f) {
1325         super.visitIGETFIELD(f);
1326         GETFIELDhelper(f, Getfield.GETFIELD_I_DYNLINK.INSTANCE, Getfield.GETFIELD_I.INSTANCE);
1327     }
1328     public void visitLGETFIELD(jq_InstanceField f) {
1329         super.visitLGETFIELD(f);
1330         GETFIELDhelper(f, Getfield.GETFIELD_L_DYNLINK.INSTANCE, Getfield.GETFIELD_L.INSTANCE);
1331     }
1332     public void visitFGETFIELD(jq_InstanceField f) {
1333         super.visitFGETFIELD(f);
1334         GETFIELDhelper(f, Getfield.GETFIELD_F_DYNLINK.INSTANCE, Getfield.GETFIELD_F.INSTANCE);
1335     }
1336     public void visitDGETFIELD(jq_InstanceField f) {
1337         super.visitDGETFIELD(f);
1338         GETFIELDhelper(f, Getfield.GETFIELD_D_DYNLINK.INSTANCE, Getfield.GETFIELD_D.INSTANCE);
1339     }
1340     public void visitAGETFIELD(jq_InstanceField f) {
1341         super.visitAGETFIELD(f);
1342         Getfield operator1 = f.getType().isAddressType()?(Getfield)Getfield.GETFIELD_P_DYNLINK.INSTANCE:Getfield.GETFIELD_A_DYNLINK.INSTANCE;
1343         Getfield operator2 = f.getType().isAddressType()?(Getfield)Getfield.GETFIELD_P.INSTANCE:Getfield.GETFIELD_A.INSTANCE;
1344         GETFIELDhelper(f, operator1, operator2);
1345     }
1346     public void visitBGETFIELD(jq_InstanceField f) {
1347         super.visitBGETFIELD(f);
1348         GETFIELDhelper(f, Getfield.GETFIELD_B_DYNLINK.INSTANCE, Getfield.GETFIELD_B.INSTANCE);
1349     }
1350     public void visitCGETFIELD(jq_InstanceField f) {
1351         super.visitCGETFIELD(f);
1352         GETFIELDhelper(f, Getfield.GETFIELD_C_DYNLINK.INSTANCE, Getfield.GETFIELD_C.INSTANCE);
1353     }
1354     public void visitSGETFIELD(jq_InstanceField f) {
1355         super.visitSGETFIELD(f);
1356         GETFIELDhelper(f, Getfield.GETFIELD_S_DYNLINK.INSTANCE, Getfield.GETFIELD_S.INSTANCE);
1357     }
1358     public void visitZGETFIELD(jq_InstanceField f) {
1359         super.visitZGETFIELD(f);
1360         GETFIELDhelper(f, Getfield.GETFIELD_Z_DYNLINK.INSTANCE, Getfield.GETFIELD_Z.INSTANCE);
1361     }
1362     private void PUTFIELDhelper(jq_InstanceField f, Putfield oper1, Putfield oper2) {
1363         f = tryResolve(f);
1364         boolean dynlink = state.needsDynamicLink(method, f);
1365         Operand op0 = current_state.pop(f.getType());
1366         Operand op1 = current_state.pop_A();
1367         clearCurrentGuard();
1368         if (performNullCheck(op1)) {    
1369             if (TRACE) System.out.println("Null check triggered on "+op1);
1370             return;
1371         }
1372         Putfield operator = dynlink?oper1:oper2;
1373         Quad q = Putfield.create(quad_cfg.getNewQuadID(), operator, op1, new FieldOperand(f), op0, getCurrentGuard());
1374         appendQuad(q);
1375     }
1376     public void visitIPUTFIELD(jq_InstanceField f) {
1377         super.visitIPUTFIELD(f);
1378         PUTFIELDhelper(f, Putfield.PUTFIELD_I_DYNLINK.INSTANCE, Putfield.PUTFIELD_I.INSTANCE);
1379     }
1380     public void visitLPUTFIELD(jq_InstanceField f) {
1381         super.visitLPUTFIELD(f);
1382         PUTFIELDhelper(f, Putfield.PUTFIELD_L_DYNLINK.INSTANCE, Putfield.PUTFIELD_L.INSTANCE);
1383     }
1384     public void visitFPUTFIELD(jq_InstanceField f) {
1385         super.visitFPUTFIELD(f);
1386         PUTFIELDhelper(f, Putfield.PUTFIELD_F_DYNLINK.INSTANCE, Putfield.PUTFIELD_F.INSTANCE);
1387     }
1388     public void visitDPUTFIELD(jq_InstanceField f) {
1389         super.visitDPUTFIELD(f);
1390         PUTFIELDhelper(f, Putfield.PUTFIELD_D_DYNLINK.INSTANCE, Putfield.PUTFIELD_D.INSTANCE);
1391     }
1392     public void visitAPUTFIELD(jq_InstanceField f) {
1393         super.visitAPUTFIELD(f);
1394         Putfield operator1 = f.getType().isAddressType()?(Putfield)Putfield.PUTFIELD_P_DYNLINK.INSTANCE:Putfield.PUTFIELD_A_DYNLINK.INSTANCE;
1395         Putfield operator2 = f.getType().isAddressType()?(Putfield)Putfield.PUTFIELD_P.INSTANCE:Putfield.PUTFIELD_A.INSTANCE;
1396         PUTFIELDhelper(f, operator1, operator2);
1397     }
1398     public void visitBPUTFIELD(jq_InstanceField f) {
1399         super.visitBPUTFIELD(f);
1400         PUTFIELDhelper(f, Putfield.PUTFIELD_B_DYNLINK.INSTANCE, Putfield.PUTFIELD_B.INSTANCE);
1401     }
1402     public void visitCPUTFIELD(jq_InstanceField f) {
1403         super.visitCPUTFIELD(f);
1404         PUTFIELDhelper(f, Putfield.PUTFIELD_C_DYNLINK.INSTANCE, Putfield.PUTFIELD_C.INSTANCE);
1405     }
1406     public void visitSPUTFIELD(jq_InstanceField f) {
1407         super.visitSPUTFIELD(f);
1408         PUTFIELDhelper(f, Putfield.PUTFIELD_S_DYNLINK.INSTANCE, Putfield.PUTFIELD_S.INSTANCE);
1409     }
1410     public void visitZPUTFIELD(jq_InstanceField f) {
1411         super.visitZPUTFIELD(f);
1412         PUTFIELDhelper(f, Putfield.PUTFIELD_Z_DYNLINK.INSTANCE, Putfield.PUTFIELD_Z.INSTANCE);
1413     }
1414     public static final Utf8 peek = Utf8.get("peek");
1415     public static final Utf8 peek1 = Utf8.get("peek1");
1416     public static final Utf8 peek2 = Utf8.get("peek2");
1417     public static final Utf8 peek4 = Utf8.get("peek4");
1418     public static final Utf8 peek8 = Utf8.get("peek8");
1419     public static final Utf8 poke = Utf8.get("poke");
1420     public static final Utf8 poke1 = Utf8.get("poke1");
1421     public static final Utf8 poke2 = Utf8.get("poke2");
1422     public static final Utf8 poke4 = Utf8.get("poke4");
1423     public static final Utf8 poke8 = Utf8.get("poke8");
1424     public static final Utf8 offset = Utf8.get("offset");
1425     public static final Utf8 align = Utf8.get("align");
1426     public static final Utf8 difference = Utf8.get("difference");
1427     public static final Utf8 isNull = Utf8.get("isNull");
1428     public static final Utf8 addressOf = Utf8.get("addressOf");
1429     public static final Utf8 address32 = Utf8.get("address32");
1430     public static final Utf8 asObject = Utf8.get("asObject");
1431     public static final Utf8 asReferenceType = Utf8.get("asReferenceType");
1432     public static final Utf8 to32BitValue = Utf8.get("to32BitValue");
1433     public static final Utf8 stringRep = Utf8.get("stringRep");
1434     public static final Utf8 getNull = Utf8.get("getNull");
1435     public static final Utf8 size = Utf8.get("size");
1436     public static final Utf8 getBasePointer = Utf8.get("getBasePointer");
1437     public static final Utf8 getStackPointer = Utf8.get("getStackPointer");
1438     public static final Utf8 alloca = Utf8.get("alloca");
1439     public static final Utf8 atomicAdd = Utf8.get("atomicAdd");
1440     public static final Utf8 atomicSub = Utf8.get("atomicSub");
1441     public static final Utf8 atomicCas4 = Utf8.get("atomicCas4");
1442     public static final Utf8 atomicCas8 = Utf8.get("atomicCas8");
1443     public static final Utf8 atomicAnd = Utf8.get("atomicAnd");
1444     public static final Utf8 min = Utf8.get("min");
1445     public static final Utf8 max = Utf8.get("max");
1446     private void ADDRESShelper(jq_Method m, Invoke oper) {
1447         Utf8 name = m.getName();
1448         Quad q;
1449         if (name == poke) {
1450             Operand val = current_state.pop_P();
1451             Operand loc = current_state.pop_P();
1452             q = MemStore.create(quad_cfg.getNewQuadID(), MemStore.POKE_P.INSTANCE, loc, val);
1453         } else if (name == poke1) {
1454             Operand val = current_state.pop_I();
1455             Operand loc = current_state.pop_P();
1456             q = MemStore.create(quad_cfg.getNewQuadID(), MemStore.POKE_1.INSTANCE, loc, val);
1457         } else if (name == poke2) {
1458             Operand val = current_state.pop_I();
1459             Operand loc = current_state.pop_P();
1460             q = MemStore.create(quad_cfg.getNewQuadID(), MemStore.POKE_2.INSTANCE, loc, val);
1461         } else if (name == poke4) {
1462             Operand val = current_state.pop_I();
1463             Operand loc = current_state.pop_P();
1464             q = MemStore.create(quad_cfg.getNewQuadID(), MemStore.POKE_4.INSTANCE, loc, val);
1465         } else if (name == poke8) {
1466             Operand val = current_state.pop_L();
1467             Operand loc = current_state.pop_P();
1468             q = MemStore.create(quad_cfg.getNewQuadID(), MemStore.POKE_8.INSTANCE, loc, val);
1469         } else if (name == peek) {
1470             Operand loc = current_state.pop_P();
1471             RegisterOperand res = getStackRegister(Address._class);
1472             q = MemLoad.create(quad_cfg.getNewQuadID(), MemLoad.PEEK_P.INSTANCE, res, loc);
1473             current_state.push_P(res.copy());
1474         } else if (name == peek1) {
1475             Operand loc = current_state.pop_P();
1476             RegisterOperand res = getStackRegister(jq_Primitive.BYTE);
1477             q = MemLoad.create(quad_cfg.getNewQuadID(), MemLoad.PEEK_1.INSTANCE, res, loc);
1478             current_state.push_I(res.copy());
1479         } else if (name == peek2) {
1480             Operand loc = current_state.pop_P();
1481             RegisterOperand res = getStackRegister(jq_Primitive.SHORT);
1482             q = MemLoad.create(quad_cfg.getNewQuadID(), MemLoad.PEEK_2.INSTANCE, res, loc);
1483             current_state.push_I(res.copy());
1484         } else if (name == peek4) {
1485             Operand loc = current_state.pop_P();
1486             RegisterOperand res = getStackRegister(jq_Primitive.INT);
1487             q = MemLoad.create(quad_cfg.getNewQuadID(), MemLoad.PEEK_4.INSTANCE, res, loc);
1488             current_state.push_I(res.copy());
1489         } else if (name == peek8) {
1490             Operand loc = current_state.pop_P();
1491             RegisterOperand res = getStackRegister(jq_Primitive.LONG);
1492             q = MemLoad.create(quad_cfg.getNewQuadID(), MemLoad.PEEK_8.INSTANCE, res, loc);
1493             current_state.push_L(res.copy());
1494         } else if (name == offset) {
1495             Operand val = current_state.pop_I();
1496             Operand loc = current_state.pop_P();
1497             RegisterOperand res = getStackRegister(Address._class);
1498             q = Binary.create(quad_cfg.getNewQuadID(), Binary.ADD_P.INSTANCE, res, loc, val);
1499             current_state.push_P(res.copy());
1500         } else if (name == align) {
1501             Operand val = current_state.pop_I();
1502             Operand loc = current_state.pop_P();
1503             RegisterOperand res = getStackRegister(Address._class);
1504             q = Binary.create(quad_cfg.getNewQuadID(), Binary.ALIGN_P.INSTANCE, res, loc, val);
1505             current_state.push_P(res.copy());
1506         } else if (name == difference) {
1507             Operand val = current_state.pop_P();
1508             Operand loc = current_state.pop_P();
1509             RegisterOperand res = getStackRegister(jq_Primitive.INT);
1510             q = Binary.create(quad_cfg.getNewQuadID(), Binary.SUB_P.INSTANCE, res, loc, val);
1511             current_state.push_I(res.copy());
1512         } else if (name == alloca) {
1513             Operand amt = current_state.pop_I();
1514             RegisterOperand res = getStackRegister(StackAddress._class);
1515             q = Special.create(quad_cfg.getNewQuadID(), Special.ALLOCA.INSTANCE, res, amt);
1516             current_state.push_P(res.copy());
1517         } else if (name == isNull) {
1518             Operand loc = current_state.pop_P();
1519             RegisterOperand res = getStackRegister(jq_Primitive.BOOLEAN);
1520             q = Unary.create(quad_cfg.getNewQuadID(), Unary.ISNULL_P.INSTANCE, res, loc);
1521             current_state.push_I(res.copy());
1522         } else if (name == addressOf) {
1523             Operand loc = current_state.pop_A();
1524             RegisterOperand res = getStackRegister(Address._class);
1525             q = Unary.create(quad_cfg.getNewQuadID(), Unary.OBJECT_2ADDRESS.INSTANCE, res, loc);
1526             current_state.push_P(res.copy());
1527         } else if (name == address32) {
1528             Operand loc = current_state.pop_I();
1529             RegisterOperand res = getStackRegister(Address._class);
1530             q = Unary.create(quad_cfg.getNewQuadID(), Unary.INT_2ADDRESS.INSTANCE, res, loc);
1531             current_state.push_P(res.copy());
1532         } else if (name == asObject) {
1533             Operand loc = current_state.pop_P();
1534             RegisterOperand res = getStackRegister(PrimordialClassLoader.getJavaLangObject());
1535             q = Unary.create(quad_cfg.getNewQuadID(), Unary.ADDRESS_2OBJECT.INSTANCE, res, loc);
1536             current_state.push_A(res.copy());
1537         } else if (name == asReferenceType) {
1538             Operand loc = current_state.pop_P();
1539             RegisterOperand res = getStackRegister(jq_Reference._class);
1540             q = Unary.create(quad_cfg.getNewQuadID(), Unary.ADDRESS_2OBJECT.INSTANCE, res, loc);
1541             current_state.push_A(res.copy());
1542         } else if (name == to32BitValue) {
1543             Operand loc = current_state.pop_P();
1544             RegisterOperand res = getStackRegister(jq_Primitive.INT);
1545             q = Unary.create(quad_cfg.getNewQuadID(), Unary.ADDRESS_2INT.INSTANCE, res, loc);
1546             current_state.push_I(res.copy());
1547         } else if (name == stringRep) {
1548             Operand loc = current_state.pop_P();
1549             RegisterOperand res = getStackRegister(jq_Primitive.INT);
1550             q = Unary.create(quad_cfg.getNewQuadID(), Unary.ADDRESS_2INT.INSTANCE, res, loc);
1551             current_state.push_I(res.copy());
1552             appendQuad(q);
1553             
1554             jq_Class k = (jq_Class) PrimordialClassLoader.loader.getOrCreateBSType("Ljwutil/strings/Strings;");
1555             jq_StaticMethod sm = k.getOrCreateStaticMethod("hex8", "(I)Ljava/lang/String;");
1556             INVOKEhelper(Invoke.INVOKESTATIC_A.INSTANCE, sm, sm.getReturnType(), false);
1557             return;
1558         } else if (name == getNull) {
1559             PConstOperand p = new PConstOperand(null);
1560             current_state.push_P(p);
1561             return;
1562         } else if (name == size) {
1563             IConstOperand p = new IConstOperand(HeapAddress.size());
1564             current_state.push_I(p);
1565             return;
1566         } else if (name == getBasePointer) {
1567             RegisterOperand res = getStackRegister(StackAddress._class);
1568             q = Special.create(quad_cfg.getNewQuadID(), Special.GET_BASE_POINTER.INSTANCE, res);
1569             current_state.push_P(res.copy());
1570         } else if (name == getStackPointer) {
1571             RegisterOperand res = getStackRegister(StackAddress._class);
1572             q = Special.create(quad_cfg.getNewQuadID(), Special.GET_STACK_POINTER.INSTANCE, res);
1573             current_state.push_P(res.copy());
1574         } else if (name == atomicAdd) {
1575             Operand val = current_state.pop_I();
1576             Operand loc = current_state.pop_P();
1577             q = Special.create(quad_cfg.getNewQuadID(), Special.ATOMICADD_I.INSTANCE, loc, val);
1578         } else if (name == atomicSub) {
1579             Operand val = current_state.pop_I();
1580             Operand loc = current_state.pop_P();
1581             q = Special.create(quad_cfg.getNewQuadID(), Special.ATOMICSUB_I.INSTANCE, loc, val);
1582         } else if (name == atomicAnd) {
1583             Operand val = current_state.pop_I();
1584             Operand loc = current_state.pop_P();
1585             q = Special.create(quad_cfg.getNewQuadID(), Special.ATOMICAND_I.INSTANCE, loc, val);
1586         } else if (name == atomicCas4) {
1587             Operand val2 = current_state.pop_I();
1588             Operand val1 = current_state.pop_I();
1589             Operand loc = current_state.pop_P();
1590             RegisterOperand res = getStackRegister(jq_Primitive.INT);
1591             q = Special.create(quad_cfg.getNewQuadID(), Special.ATOMICCAS4.INSTANCE, res, loc, val1, val2);
1592             current_state.push_I(res.copy());
1593         } else if (name == atomicCas8) {
1594             Operand val2 = current_state.pop_L();
1595             Operand val1 = current_state.pop_L();
1596             Operand loc = current_state.pop_P();
1597             RegisterOperand res = getStackRegister(jq_Primitive.LONG);
1598             q = Special.create(quad_cfg.getNewQuadID(), Special.ATOMICCAS8.INSTANCE, res, loc, val1, val2);
1599             current_state.push_L(res.copy());
1600         } else {
1601             // TODO
1602             INVOKEhelper(oper, m, m.getReturnType(), false);
1603             return;
1604         }
1605         appendQuad(q);
1606         mergeStateWithAllExHandlers(false);
1607     }
1608     private void UNSAFEhelper(jq_Method m, Invoke oper) {
1609         if (_unsafe.handleMethod(this, quad_cfg, current_state, m, oper)) {
1610             mergeStateWithAllExHandlers(false);
1611             if (_unsafe.endsBB(m)) {
1612                 endBasicBlock = true;
1613             }
1614         } else {
1615             // TODO
1616             INVOKEhelper(oper, m, m.getReturnType(), false);
1617             return;
1618         }
1619     }
1620     private void INVOKEhelper(Invoke oper, jq_Method f, jq_Type returnType, boolean instance_call) {
1621         jq_Type[] paramTypes = f.getParamTypes();
1622         RegisterOperand result;
1623         if (returnType == jq_Primitive.VOID) result = null;
1624         else result = getStackRegister(returnType, f.getParamWords()-1);
1625         Quad q = Invoke.create(quad_cfg.getNewQuadID(), oper, result, new MethodOperand(f), paramTypes.length);
1626         Operand op = null;
1627         for (int i = paramTypes.length; --i >= 0; ) {
1628             jq_Type ptype = paramTypes[i];
1629             op = current_state.pop(ptype);
1630             RegisterOperand rop;
1631             if (op instanceof RegisterOperand) rop = (RegisterOperand)op;
1632             else {
1633                 rop = getStackRegister(ptype);
1634                 Quad q2 = Move.create(quad_cfg.getNewQuadID(), Move.getMoveOp(ptype), (RegisterOperand) rop.copy(), op);
1635                 appendQuad(q2);
1636             }
1637             Invoke.setParam(q, i, rop);
1638         }
1639         clearCurrentGuard();
1640         if (instance_call && performNullCheck(op)) {
1641             if (TRACE) System.out.println("Null check triggered on "+op);
1642             return;
1643         }
1644         appendQuad(q);
1645         mergeStateWithAllExHandlers(false);
1646         if (result != null) current_state.push(result.copy(), returnType);
1647     }
1648     public void visitIINVOKE(byte op, jq_Method f) {
1649         super.visitIINVOKE(op, f);
1650         if (_unsafe.isUnsafe(f)) {
1651             UNSAFEhelper(f, Invoke.INVOKESTATIC_I.INSTANCE);
1652             return;
1653         }
1654         if (f.getDeclaringClass().isAddressType()) {
1655             ADDRESShelper(f, f.isStatic()?(Invoke)Invoke.INVOKESTATIC_I.INSTANCE:Invoke.INVOKEVIRTUAL_I.INSTANCE);
1656             return;
1657         }
1658         f = (jq_Method) tryResolve(f);
1659         boolean dynlink = state.needsDynamicLink(method, f);
1660         Invoke oper;
1661         boolean instance_call;
1662         switch (op) {
1663             case INVOKE_VIRTUAL:
1664                 instance_call = true;
1665                 if (dynlink)
1666                     oper = Invoke.INVOKEVIRTUAL_I_DYNLINK.INSTANCE;
1667                 else {
1668                     oper = Invoke.INVOKEVIRTUAL_I.INSTANCE;
1669                 }
1670                 //f.getDeclaringClass().load();
1671                 //jq.Assert(!f.getDeclaringClass().isInterface());
1672                 break;
1673             case INVOKE_STATIC:
1674                 instance_call = false;
1675                 if (dynlink)
1676                     oper = Invoke.INVOKESTATIC_I_DYNLINK.INSTANCE;
1677                 else {
1678                     oper = Invoke.INVOKESTATIC_I.INSTANCE;
1679                 }
1680                 break;
1681             case INVOKE_SPECIAL:
1682                 instance_call = true;
1683                 Assert._assert(f instanceof jq_InstanceMethod);
1684                 if (dynlink)
1685                     oper = Invoke.INVOKESPECIAL_I_DYNLINK.INSTANCE;
1686                 else {
1687                     f = jq_Class.getInvokespecialTarget(clazz, (jq_InstanceMethod)f);
1688                     oper = Invoke.INVOKESTATIC_I.INSTANCE;
1689                 }
1690                 break;
1691             case INVOKE_INTERFACE:
1692                 instance_call = true;
1693                 oper = Invoke.INVOKEINTERFACE_I.INSTANCE;
1694                 break;
1695             default:
1696                 throw new InternalError();
1697         }
1698         INVOKEhelper(oper, f, jq_Primitive.INT, instance_call);
1699     }
1700     public void visitLINVOKE(byte op, jq_Method f) {
1701         super.visitLINVOKE(op, f);
1702         if (_unsafe.isUnsafe(f)) {
1703             UNSAFEhelper(f, Invoke.INVOKESTATIC_L.INSTANCE);
1704             return;
1705         }
1706         if (f.getDeclaringClass().isAddressType()) {
1707             ADDRESShelper(f, f.isStatic()?(Invoke)Invoke.INVOKESTATIC_L.INSTANCE:Invoke.INVOKEVIRTUAL_L.INSTANCE);
1708             return;
1709         }
1710         f = (jq_Method) tryResolve(f);
1711         boolean dynlink = state.needsDynamicLink(method, f);
1712         Invoke oper;
1713         boolean instance_call;
1714         switch (op) {
1715             case INVOKE_VIRTUAL:
1716                 instance_call = true;
1717                 if (dynlink)
1718                     oper = Invoke.INVOKEVIRTUAL_L_DYNLINK.INSTANCE;
1719                 else {
1720                     oper = Invoke.INVOKEVIRTUAL_L.INSTANCE;
1721                 }
1722                 break;
1723             case INVOKE_STATIC:
1724                 instance_call = false;
1725                 if (dynlink)
1726                     oper = Invoke.INVOKESTATIC_L_DYNLINK.INSTANCE;
1727                 else {
1728                     oper = Invoke.INVOKESTATIC_L.INSTANCE;
1729                 }
1730                 break;
1731             case INVOKE_SPECIAL:
1732                 instance_call = true;
1733                 Assert._assert(f instanceof jq_InstanceMethod);
1734                 if (dynlink)
1735                     oper = Invoke.INVOKESPECIAL_L_DYNLINK.INSTANCE;
1736                 else {
1737                     f = jq_Class.getInvokespecialTarget(clazz, (jq_InstanceMethod)f);
1738                     oper = Invoke.INVOKESTATIC_L.INSTANCE;
1739                 }
1740                 break;
1741             case INVOKE_INTERFACE:
1742                 instance_call = true;
1743                 oper = Invoke.INVOKEINTERFACE_L.INSTANCE;
1744                 break;
1745             default:
1746                 throw new InternalError();
1747         }
1748         INVOKEhelper(oper, f, jq_Primitive.LONG, instance_call);
1749     }
1750     public void visitFINVOKE(byte op, jq_Method f) {
1751         super.visitFINVOKE(op, f);
1752         if (_unsafe.isUnsafe(f)) {
1753             UNSAFEhelper(f, Invoke.INVOKESTATIC_F.INSTANCE);
1754             return;
1755         }
1756         if (f.getDeclaringClass().isAddressType()) {
1757             ADDRESShelper(f, f.isStatic()?(Invoke)Invoke.INVOKESTATIC_F.INSTANCE:Invoke.INVOKEVIRTUAL_F.INSTANCE);
1758             return;
1759         }
1760         f = (jq_Method) tryResolve(f);
1761         boolean dynlink = state.needsDynamicLink(method, f);
1762         Invoke oper;
1763         boolean instance_call;
1764         switch (op) {
1765             case INVOKE_VIRTUAL:
1766                 instance_call = true;
1767                 if (dynlink)
1768                     oper = Invoke.INVOKEVIRTUAL_F_DYNLINK.INSTANCE;
1769                 else {
1770                     oper = Invoke.INVOKEVIRTUAL_F.INSTANCE;
1771                 }
1772                 break;
1773             case INVOKE_STATIC:
1774                 instance_call = false;
1775                 if (dynlink)
1776                     oper = Invoke.INVOKESTATIC_F_DYNLINK.INSTANCE;
1777                 else {
1778                     oper = Invoke.INVOKESTATIC_F.INSTANCE;
1779                 }
1780                 break;
1781             case INVOKE_SPECIAL:
1782                 instance_call = true;
1783                 Assert._assert(f instanceof jq_InstanceMethod);
1784                 if (dynlink)
1785                     oper = Invoke.INVOKESPECIAL_F_DYNLINK.INSTANCE;
1786                 else {
1787                     f = jq_Class.getInvokespecialTarget(clazz, (jq_InstanceMethod)f);
1788                     oper = Invoke.INVOKESTATIC_F.INSTANCE;
1789                 }
1790                 break;
1791             case INVOKE_INTERFACE:
1792                 instance_call = true;
1793                 oper = Invoke.INVOKEINTERFACE_F.INSTANCE;
1794                 break;
1795             default:
1796                 throw new InternalError();
1797         }
1798         INVOKEhelper(oper, f, jq_Primitive.FLOAT, instance_call);
1799     }
1800     public void visitDINVOKE(byte op, jq_Method f) {
1801         super.visitDINVOKE(op, f);
1802         if (_unsafe.isUnsafe(f)) {
1803             UNSAFEhelper(f, Invoke.INVOKESTATIC_D.INSTANCE);
1804             return;
1805         }
1806         if (f.getDeclaringClass().isAddressType()) {
1807             ADDRESShelper(f, f.isStatic()?(Invoke)Invoke.INVOKESTATIC_D.INSTANCE:Invoke.INVOKEVIRTUAL_D.INSTANCE);
1808             return;
1809         }
1810         f = (jq_Method) tryResolve(f);
1811         boolean dynlink = state.needsDynamicLink(method, f);
1812         Invoke oper;
1813         boolean instance_call;
1814         switch (op) {
1815             case INVOKE_VIRTUAL:
1816                 instance_call = true;
1817                 if (dynlink)
1818                     oper = Invoke.INVOKEVIRTUAL_D_DYNLINK.INSTANCE;
1819                 else {
1820                     oper = Invoke.INVOKEVIRTUAL_D.INSTANCE;
1821                 }
1822                 break;
1823             case INVOKE_STATIC:
1824                 instance_call = false;
1825                 if (dynlink)
1826                     oper = Invoke.INVOKESTATIC_D_DYNLINK.INSTANCE;
1827                 else {
1828                     oper = Invoke.INVOKESTATIC_D.INSTANCE;
1829                 }
1830                 break;
1831             case INVOKE_SPECIAL:
1832                 instance_call = true;
1833                 Assert._assert(f instanceof jq_InstanceMethod);
1834                 if (dynlink)
1835                     oper = Invoke.INVOKESPECIAL_D_DYNLINK.INSTANCE;
1836                 else {
1837                     f = jq_Class.getInvokespecialTarget(clazz, (jq_InstanceMethod)f);
1838                     oper = Invoke.INVOKESTATIC_D.INSTANCE;
1839                 }
1840                 break;
1841             case INVOKE_INTERFACE:
1842                 instance_call = true;
1843                 oper = Invoke.INVOKEINTERFACE_D.INSTANCE;
1844                 break;
1845             default:
1846                 throw new InternalError();
1847         }
1848         INVOKEhelper(oper, f, jq_Primitive.DOUBLE, instance_call);
1849     }
1850     public void visitAINVOKE(byte op, jq_Method f) {
1851         super.visitAINVOKE(op, f);
1852         if (_unsafe.isUnsafe(f)) {
1853             UNSAFEhelper(f, f.getReturnType().isAddressType()?(Invoke)Invoke.INVOKESTATIC_P.INSTANCE:Invoke.INVOKESTATIC_A.INSTANCE);
1854             return;
1855         }
1856         if (f.getDeclaringClass().isAddressType()) {
1857             Invoke oper;
1858             if (f.isStatic()) {
1859                 oper = f.getReturnType().isAddressType()?(Invoke)Invoke.INVOKESTATIC_P.INSTANCE:Invoke.INVOKESTATIC_A.INSTANCE;
1860             } else {
1861                 oper = f.getReturnType().isAddressType()?(Invoke)Invoke.INVOKEVIRTUAL_P.INSTANCE:Invoke.INVOKEVIRTUAL_A.INSTANCE;
1862             }
1863             ADDRESShelper(f, oper);
1864             return;
1865         }
1866         f = (jq_Method) tryResolve(f);
1867         boolean dynlink = state.needsDynamicLink(method, f);
1868         Invoke oper;
1869         boolean instance_call;
1870         switch (op) {
1871             case INVOKE_VIRTUAL:
1872                 instance_call = true;
1873                 if (dynlink)
1874                     oper = f.getReturnType().isAddressType()?(Invoke)Invoke.INVOKEVIRTUAL_P_DYNLINK.INSTANCE:Invoke.INVOKEVIRTUAL_A_DYNLINK.INSTANCE;
1875                 else {
1876                     oper = f.getReturnType().isAddressType()?(Invoke)Invoke.INVOKEVIRTUAL_P.INSTANCE:Invoke.INVOKEVIRTUAL_A.INSTANCE;
1877                 }
1878                 break;
1879             case INVOKE_STATIC:
1880                 instance_call = false;
1881                 if (dynlink)
1882                     oper = f.getReturnType().isAddressType()?(Invoke)Invoke.INVOKESTATIC_P_DYNLINK.INSTANCE:Invoke.INVOKESTATIC_A_DYNLINK.INSTANCE;
1883                 else {
1884                     oper = f.getReturnType().isAddressType()?(Invoke)Invoke.INVOKESTATIC_P.INSTANCE:Invoke.INVOKESTATIC_A.INSTANCE;
1885                 }
1886                 break;
1887             case INVOKE_SPECIAL:
1888                 instance_call = true;
1889                 Assert._assert(f instanceof jq_InstanceMethod);
1890                 if (dynlink)
1891                     oper = f.getReturnType().isAddressType()?(Invoke)Invoke.INVOKESPECIAL_P_DYNLINK.INSTANCE:Invoke.INVOKESPECIAL_A_DYNLINK.INSTANCE;
1892                 else {
1893                     f = jq_Class.getInvokespecialTarget(clazz, (jq_InstanceMethod)f);
1894                     oper = f.getReturnType().isAddressType()?(Invoke)Invoke.INVOKESTATIC_P.INSTANCE:Invoke.INVOKESTATIC_A.INSTANCE;
1895                 }
1896                 break;
1897             case INVOKE_INTERFACE:
1898                 instance_call = true;
1899                 oper = f.getReturnType().isAddressType()?(Invoke)Invoke.INVOKEINTERFACE_P.INSTANCE:Invoke.INVOKEINTERFACE_A.INSTANCE;
1900                 break;
1901             default:
1902                 throw new InternalError();
1903         }
1904         INVOKEhelper(oper, f, f.getReturnType(), instance_call);
1905     }
1906     public void visitVINVOKE(byte op, jq_Method f) {
1907         super.visitVINVOKE(op, f);
1908         if (_unsafe.isUnsafe(f)) {
1909             UNSAFEhelper(f, Invoke.INVOKESTATIC_V.INSTANCE);
1910             return;
1911         }
1912         if (f.getDeclaringClass().isAddressType()) {
1913             ADDRESShelper(f, f.isStatic()?(Invoke)Invoke.INVOKESTATIC_V.INSTANCE:Invoke.INVOKEVIRTUAL_V.INSTANCE);
1914             return;
1915         }
1916         f = (jq_Method) tryResolve(f);
1917         boolean dynlink = state.needsDynamicLink(method, f);
1918         Invoke oper;
1919         boolean instance_call;
1920         switch (op) {
1921             case INVOKE_VIRTUAL:
1922                 instance_call = true;
1923                 if (dynlink)
1924                     oper = Invoke.INVOKEVIRTUAL_V_DYNLINK.INSTANCE;
1925                 else {
1926                     oper = Invoke.INVOKEVIRTUAL_V.INSTANCE;
1927                 }
1928                 break;
1929             case INVOKE_STATIC:
1930                 instance_call = false;
1931                 if (dynlink)
1932                     oper = Invoke.INVOKESTATIC_V_DYNLINK.INSTANCE;
1933                 else {
1934                     oper = Invoke.INVOKESTATIC_V.INSTANCE;
1935                 }
1936                 break;
1937             case INVOKE_SPECIAL:
1938                 instance_call = true;
1939                 Assert._assert(f instanceof jq_InstanceMethod);
1940                 if (dynlink)
1941                     oper = Invoke.INVOKESPECIAL_V_DYNLINK.INSTANCE;
1942                 else {
1943                     f = jq_Class.getInvokespecialTarget(clazz, (jq_InstanceMethod)f);
1944                     oper = Invoke.INVOKESTATIC_V.INSTANCE;
1945                 }
1946                 break;
1947             case INVOKE_INTERFACE:
1948                 instance_call = true;
1949                 oper = Invoke.INVOKEINTERFACE_V.INSTANCE;
1950                 break;
1951             default:
1952                 throw new InternalError();
1953         }
1954         INVOKEhelper(oper, f, f.getReturnType(), instance_call);
1955     }
1956     public void visitNEW(jq_Type f) {
1957         super.visitNEW(f);
1958         RegisterOperand res = getStackRegister(f);
1959         Quad q = New.create(quad_cfg.getNewQuadID(), New.NEW.INSTANCE, res, new TypeOperand(f));
1960         appendQuad(q);
1961         current_state.push_A(res.copy());
1962     }
1963     public void visitNEWARRAY(jq_Array f) {
1964         super.visitNEWARRAY(f);
1965         Operand size = current_state.pop_I();
1966         RegisterOperand res = getStackRegister(f);
1967         Quad q = NewArray.create(quad_cfg.getNewQuadID(), NewArray.NEWARRAY.INSTANCE, res, size, new TypeOperand(f));
1968         appendQuad(q);
1969         mergeStateWithAllExHandlers(false);
1970         current_state.push_A(res.copy());
1971     }
1972     public void visitCHECKCAST(jq_Type f) {
1973         super.visitCHECKCAST(f);
1974         Operand op = current_state.pop(); // could be P or A
1975         RegisterOperand res = getStackRegister(f);
1976         if (!f.isAddressType()) {
1977             Quad q = CheckCast.create(quad_cfg.getNewQuadID(), CheckCast.CHECKCAST.INSTANCE, res, op, new TypeOperand(f));
1978             appendQuad(q);
1979             mergeStateWithAllExHandlers(false);
1980             current_state.push_A(res.copy());
1981         } else {
1982             current_state.push_P(res);
1983         }
1984     }
1985     public void visitINSTANCEOF(jq_Type f) {
1986         super.visitINSTANCEOF(f);
1987         Assert._assert(!f.isAddressType(), method.toString());
1988         Operand op = current_state.pop_A();
1989         RegisterOperand res = getStackRegister(jq_Primitive.BOOLEAN);
1990         Quad q = InstanceOf.create(quad_cfg.getNewQuadID(), InstanceOf.INSTANCEOF.INSTANCE, res, op, new TypeOperand(f));
1991         appendQuad(q);
1992         current_state.push_I(res.copy());
1993     }
1994     public void visitARRAYLENGTH() {
1995         super.visitARRAYLENGTH();
1996         Operand op = current_state.pop_A();
1997         clearCurrentGuard();
1998         if (performNullCheck(op)) {
1999             if (TRACE) System.out.println("Null check triggered on "+op);
2000             return;
2001         }
2002         RegisterOperand res = getStackRegister(jq_Primitive.INT);
2003         Quad q = ALength.create(quad_cfg.getNewQuadID(), ALength.ARRAYLENGTH.INSTANCE, res, op);
2004         appendQuad(q);
2005         current_state.push_I(res.copy());
2006     }
2007     public void visitATHROW() {
2008         super.visitATHROW();
2009         Operand op0 = current_state.pop_A();
2010         Quad q = Return.create(quad_cfg.getNewQuadID(), Return.THROW_A.INSTANCE, op0);
2011         appendQuad(q);
2012         current_state.clearStack();
2013     }
2014     public void visitMONITOR(byte op) {
2015         super.visitMONITOR(op);
2016         Operand op0 = current_state.pop_A();
2017         Monitor oper = op==MONITOR_ENTER ? (Monitor)Monitor.MONITORENTER.INSTANCE : (Monitor)Monitor.MONITOREXIT.INSTANCE;
2018         Quad q = Monitor.create(quad_cfg.getNewQuadID(), oper, op0);
2019         appendQuad(q);
2020         mergeStateWithAllExHandlers(false);
2021     }
2022     public void visitMULTINEWARRAY(jq_Type f, char dim) {
2023         super.visitMULTINEWARRAY(f, dim);
2024         RegisterOperand result = getStackRegister(f, dim-1);
2025         Quad q = Invoke.create(quad_cfg.getNewQuadID(), Invoke.INVOKESTATIC_A.INSTANCE, result, new MethodOperand(joeq.Runtime.Arrays._multinewarray), dim+2);
2026         RegisterOperand rop = new RegisterOperand(rf.getOrCreateStack(current_state.getStackSize(), jq_Primitive.INT), jq_Primitive.INT);
2027         Quad q2 = Move.create(quad_cfg.getNewQuadID(), Move.MOVE_I.INSTANCE, rop, new IConstOperand(dim));
2028         appendQuad(q2);
2029         Invoke.setParam(q, 0, (RegisterOperand) rop.copy());
2030         rop = new RegisterOperand(rf.getOrCreateStack(current_state.getStackSize()+1, jq_Type._class), jq_Type._class);
2031         q2 = Move.create(quad_cfg.getNewQuadID(), Move.MOVE_A.INSTANCE, rop, new AConstOperand(f));
2032         appendQuad(q2);
2033         Invoke.setParam(q, 1, (RegisterOperand) rop.copy());
2034         for (int i=0; i<dim; ++i) {
2035             Operand op = current_state.pop_I();
2036             if (op instanceof RegisterOperand) rop = (RegisterOperand)op;
2037             else {
2038                 rop = getStackRegister(jq_Primitive.INT);
2039                 q2 = Move.create(quad_cfg.getNewQuadID(), Move.MOVE_I.INSTANCE, (RegisterOperand) rop.copy(), op);
2040                 appendQuad(q2);
2041             }
2042             Invoke.setParam(q, i+2, rop);
2043         }
2044         appendQuad(q);
2045         mergeStateWithAllExHandlers(false);
2046         current_state.push(result.copy(), f);
2047     }
2048 
2049     public static final boolean ELIM_NULL_CHECKS = true;
2050     
2051     boolean performNullCheck(Operand op) {
2052         if (op instanceof AConstOperand) {
2053             Object val = ((AConstOperand)op).getValue();
2054             if (val != null) {
2055                 setCurrentGuard(new UnnecessaryGuardOperand());
2056                 return false;
2057             } else {
2058                 Quad q = NullCheck.create(quad_cfg.getNewQuadID(), NullCheck.NULL_CHECK.INSTANCE, null, op.copy());
2059                 appendQuad(q);
2060                 if (false) {
2061                     endBasicBlock = true;
2062                     mergeStateWithNullPtrExHandler(true);
2063                     return true;
2064                 } else {
2065                     mergeStateWithNullPtrExHandler(false);
2066                     return false;
2067                 }
2068             }
2069         }
2070         RegisterOperand rop = (RegisterOperand)op;
2071         if (ELIM_NULL_CHECKS) {
2072             if (hasGuard(rop)) {
2073                 Operand guard = getGuard(rop);
2074                 setCurrentGuard(guard);
2075                 return false;
2076             }
2077         }
2078         RegisterOperand guard = makeGuardReg();
2079         Quad q = NullCheck.create(quad_cfg.getNewQuadID(), NullCheck.NULL_CHECK.INSTANCE, guard, rop.copy());
2080         appendQuad(q);
2081         mergeStateWithNullPtrExHandler(false);
2082         setCurrentGuard(guard);
2083         setGuard(rop, guard);
2084         
2085         jq_Type type = rop.getType();
2086         if (type.isAddressType()) {
2087             // occurs when we compile Address.<init>, etc.
2088             return false;
2089         }
2090         int number = getLocalNumber(rop.getRegister(), type);
2091         if (isLocal(rop, number, type)) {
2092             Operand op2 = current_state.getLocal_A(number);
2093             if (op2 instanceof RegisterOperand) {
2094                 setGuard((RegisterOperand)op2, guard);
2095             }
2096             current_state.setLocal(number, op2);
2097             replaceLocalsOnStack(number, type);
2098         }
2099         return false;
2100     }
2101     
2102     boolean performBoundsCheck(Operand ref, Operand index) {
2103         Quad q = BoundsCheck.create(quad_cfg.getNewQuadID(), BoundsCheck.BOUNDS_CHECK.INSTANCE, ref.copy(), index.copy(), getCurrentGuard());
2104         appendQuad(q);
2105         mergeStateWithArrayBoundsExHandler(false);
2106         return false;
2107     }
2108     
2109     boolean performCheckStore(RegisterOperand ref, Operand elem) {
2110         jq_Type type = getTypeOf(elem);
2111         if (type == jq_Reference.jq_NullType.NULL_TYPE) return false;
2112         jq_Type arrayElemType = getArrayElementTypeOf(ref);
2113         if (arrayElemType.isAddressType()) {
2114             if (type.isAddressType() || type == jq_Reference.jq_NullType.NULL_TYPE)
2115                 return false;
2116             Assert.UNREACHABLE("Storing non-address value into address array! Array: "+ref+" Type: "+type);
2117         }
2118         if (type.isAddressType()) {
2119             Assert.UNREACHABLE("Storing address value into non-address array! Array: "+ref+" Type: "+type);
2120         }
2121         if (ref.isExactType()) {
2122             if (state.isSubtype(type, arrayElemType) == YES)
2123                 return false;
2124         }
2125         jq_Type arrayElemType2 = arrayElemType;
2126         if (arrayElemType.isArrayType()) {
2127             arrayElemType2 = ((jq_Array)arrayElemType).getInnermostElementType();
2128         }
2129         if (arrayElemType2.isLoaded() && arrayElemType2.isFinal()) {
2130             if (arrayElemType == type)
2131                 return false;
2132         }
2133         Quad q = StoreCheck.create(quad_cfg.getNewQuadID(), StoreCheck.ASTORE_CHECK.INSTANCE, ref.copy(), elem.copy(), getCurrentGuard());
2134         appendQuad(q);
2135         mergeStateWithObjArrayStoreExHandler(false);
2136         return false;
2137     }
2138 
2139     boolean performZeroCheck(Operand op) {
2140         if (op instanceof IConstOperand) {
2141             int val = ((IConstOperand)op).getValue();
2142             if (val != 0) {
2143                 setCurrentGuard(new UnnecessaryGuardOperand());
2144                 return false;
2145             } else {
2146                 Quad q = ZeroCheck.create(quad_cfg.getNewQuadID(), ZeroCheck.ZERO_CHECK_I.INSTANCE, null, op.copy());
2147                 appendQuad(q);
2148                 if (false) {
2149                     endBasicBlock = true;
2150                     mergeStateWithArithExHandler(true);
2151                     return true;
2152                 } else {
2153                     mergeStateWithArithExHandler(false);
2154                     return false;
2155                 }
2156             }
2157         }
2158         if (op instanceof LConstOperand) {
2159             long val = ((LConstOperand)op).getValue();
2160             if (val != 0) {
2161                 setCurrentGuard(new UnnecessaryGuardOperand());
2162                 return false;
2163             } else {
2164                 Quad q = ZeroCheck.create(quad_cfg.getNewQuadID(), ZeroCheck.ZERO_CHECK_L.INSTANCE, null, op.copy());
2165                 appendQuad(q);
2166                 if (false) {
2167                     endBasicBlock = true;
2168                     mergeStateWithArithExHandler(true);
2169                     return true;
2170                 } else {
2171                     mergeStateWithArithExHandler(false);
2172                     return false;
2173                 }
2174             }
2175         }
2176         RegisterOperand rop = (RegisterOperand)op;
2177         if (hasGuard(rop)) {
2178             Operand guard = getGuard(rop);
2179             setCurrentGuard(guard);
2180             return false;
2181         }
2182         RegisterOperand guard = makeGuardReg();
2183         ZeroCheck oper = null;
2184         if (rop.getType() == jq_Primitive.LONG) oper = ZeroCheck.ZERO_CHECK_L.INSTANCE;
2185         else if (rop.getType().isIntLike()) oper = ZeroCheck.ZERO_CHECK_I.INSTANCE;
2186         else Assert.UNREACHABLE("Zero check on "+rop+" type "+rop.getType());
2187         Quad q = ZeroCheck.create(quad_cfg.getNewQuadID(), oper, guard, rop.copy());
2188         appendQuad(q);
2189         mergeStateWithArithExHandler(false);
2190         setCurrentGuard(guard);
2191         setGuard(rop, guard);
2192         
2193         jq_Type type = rop.getType();
2194         int number = getLocalNumber(rop.getRegister(), type);
2195         if (isLocal(rop, number, type)) {
2196             Operand op2 = null;
2197             if (type == jq_Primitive.LONG)
2198                 op2 = current_state.getLocal_L(number);
2199             else if (type.isIntLike())
2200                 op2 = current_state.getLocal_I(number);
2201             else
2202                 Assert.UNREACHABLE("Unknown type for local "+number+" "+rop+": "+type);
2203             if (TRACE) System.out.println(rop+" is a local variable of type "+type+": currently "+op2);
2204             if (op2 instanceof RegisterOperand) {
2205                 setGuard((RegisterOperand)op2, guard);
2206             }
2207             current_state.setLocal(number, op2);
2208             replaceLocalsOnStack(number, type);
2209         }
2210         return false;
2211     }
2212     
2213     static jq_Type getTypeOf(Operand op) {
2214         if (op instanceof IConstOperand) return jq_Primitive.INT;
2215         if (op instanceof FConstOperand) return jq_Primitive.FLOAT;
2216         if (op instanceof LConstOperand) return jq_Primitive.LONG;
2217         if (op instanceof DConstOperand) return jq_Primitive.DOUBLE;
2218         if (op instanceof PConstOperand) return Address._class;
2219         if (op instanceof AConstOperand) {
2220             Object val = ((AConstOperand)op).getValue();
2221             if (val == null) return jq_Reference.jq_NullType.NULL_TYPE;
2222             return Reflection.getTypeOf(val);
2223         }
2224         Assert._assert(op instanceof RegisterOperand, op.toString() + " is not a RegisterOperand");
2225         return ((RegisterOperand)op).getType();
2226     }
2227     static jq_Type getArrayElementTypeOf(Operand op) {
2228         if (op instanceof RegisterOperand) {
2229             return ((jq_Array)((RegisterOperand)op).getType()).getElementType();
2230         } else if (op instanceof AConstOperand && ((AConstOperand)op).getValue() == null) {
2231             // what is the element type of an array constant 'null'?
2232             return PrimordialClassLoader.getJavaLangObject();
2233         } else {
2234             Assert.UNREACHABLE(op.toString());
2235             return null;
2236         }
2237     }
2238     
2239     void mergeStateWithAllExHandlers(boolean cfgEdgeToExit) {
2240         joeq.Compiler.BytecodeAnalysis.ExceptionHandlerIterator i =
2241             bc_bb.getExceptionHandlers();
2242         while (i.hasNext()) {
2243             joeq.Compiler.BytecodeAnalysis.ExceptionHandler eh = i.nextEH();
2244             mergeStateWith(eh);
2245         }
2246     }
2247     void mergeStateWithNullPtrExHandler(boolean cfgEdgeToExit) {
2248         joeq.Compiler.BytecodeAnalysis.ExceptionHandlerIterator i =
2249             bc_bb.getExceptionHandlers();
2250         while (i.hasNext()) {
2251             joeq.Compiler.BytecodeAnalysis.ExceptionHandler eh = i.nextEH();
2252             jq_Class k = eh.getExceptionType();
2253             if (k == PrimordialClassLoader.getJavaLangNullPointerException() ||
2254                 k == PrimordialClassLoader.getJavaLangRuntimeException() ||
2255                 k == PrimordialClassLoader.getJavaLangException() ||
2256                 k == PrimordialClassLoader.getJavaLangThrowable() ||
2257                 k == null) {
2258                 mergeStateWith(eh);
2259                 break;
2260             }
2261         }
2262     }
2263     void mergeStateWithArithExHandler(boolean cfgEdgeToExit) {
2264         joeq.Compiler.BytecodeAnalysis.ExceptionHandlerIterator i =
2265             bc_bb.getExceptionHandlers();
2266         while (i.hasNext()) {
2267             joeq.Compiler.BytecodeAnalysis.ExceptionHandler eh = i.nextEH();
2268             jq_Class k = eh.getExceptionType();
2269             if (k == PrimordialClassLoader.getJavaLangArithmeticException() ||
2270                 k == PrimordialClassLoader.getJavaLangRuntimeException() ||
2271                 k == PrimordialClassLoader.getJavaLangException() ||
2272                 k == PrimordialClassLoader.getJavaLangThrowable() ||
2273                 k == null) {
2274                 mergeStateWith(eh);
2275                 break;
2276             }
2277         }
2278     }
2279     void mergeStateWithArrayBoundsExHandler(boolean cfgEdgeToExit) {
2280         joeq.Compiler.BytecodeAnalysis.ExceptionHandlerIterator i =
2281             bc_bb.getExceptionHandlers();
2282         while (i.hasNext()) {
2283             joeq.Compiler.BytecodeAnalysis.ExceptionHandler eh = i.nextEH();
2284             jq_Class k = eh.getExceptionType();
2285             if (k == PrimordialClassLoader.getJavaLangArrayIndexOutOfBoundsException() ||
2286                 k == PrimordialClassLoader.getJavaLangIndexOutOfBoundsException() ||
2287                 k == PrimordialClassLoader.getJavaLangRuntimeException() ||
2288                 k == PrimordialClassLoader.getJavaLangException() ||
2289                 k == PrimordialClassLoader.getJavaLangThrowable() ||
2290                 k == null) {
2291                 mergeStateWith(eh);
2292                 break;
2293             }
2294         }
2295     }
2296     void mergeStateWithObjArrayStoreExHandler(boolean cfgEdgeToExit) {
2297         joeq.Compiler.BytecodeAnalysis.ExceptionHandlerIterator i =
2298             bc_bb.getExceptionHandlers();
2299         while (i.hasNext()) {
2300             joeq.Compiler.BytecodeAnalysis.ExceptionHandler eh = i.nextEH();
2301             jq_Class k = eh.getExceptionType();
2302             if (k == PrimordialClassLoader.getJavaLangArrayStoreException() ||
2303                 k == PrimordialClassLoader.getJavaLangRuntimeException() ||
2304                 k == PrimordialClassLoader.getJavaLangException() ||
2305                 k == PrimordialClassLoader.getJavaLangThrowable() ||
2306                 k == null) {
2307                 mergeStateWith(eh);
2308                 break;
2309             }
2310         }
2311     }
2312     
2313     RegisterOperand makeGuardReg() {
2314         return RegisterFactory.makeGuardReg();
2315     }
2316     
2317     int getLocalNumber(Register r, jq_Type t) {
2318         return r.getNumber();
2319     }
2320     
2321     static class DummyOperand implements Operand {
2322         private DummyOperand() {}
2323         static final DummyOperand DUMMY = new DummyOperand();
2324         public Quad getQuad() { throw new InternalError(); }
2325         public void attachToQuad(Quad q) { throw new InternalError(); }
2326         public Operand copy() { return DUMMY; }
2327         public boolean isSimilar(Operand that) { return that == DUMMY; }
2328         public String toString() { return "<dummy>"; }
2329     }
2330     
2331     AbstractState allocateEmptyState() {
2332         // +1 because SWAP requires a temporary location.
2333         AbstractState s = new AbstractState(method.getMaxStack()+1, method.getMaxLocals());
2334         return s;
2335     }
2336     
2337     AbstractState allocateInitialState() {
2338         // +1 because SWAP requires a temporary location.
2339         AbstractState s = new AbstractState(method.getMaxStack()+1, method.getMaxLocals());
2340         jq_Type[] paramTypes = method.getParamTypes();
2341         for (int i=0, j=-1; i<paramTypes.length; ++i) {
2342             jq_Type paramType = paramTypes[i];
2343             ++j;
2344             s.locals[j] = this.makeLocal(j, paramType);
2345             if (paramType.getReferenceSize() == 8) {
2346                 s.locals[++j] = DummyOperand.DUMMY;
2347             }
2348         }
2349         return s;
2350     }
2351     
2352     /*** Class used to store the abstract state of the bytecode-to-quad converter. */
2353     public class AbstractState {
2354 
2355         private int stackptr;
2356         private Operand[] stack;
2357         private Operand[] locals;
2358         
2359         private AbstractState(int nstack, int nlocals) {
2360             this.stack = new Operand[nstack]; this.locals = new Operand[nlocals];
2361         }
2362         
2363         AbstractState copy() {
2364             AbstractState that = new AbstractState(this.stack.length, this.locals.length);
2365             System.arraycopy(this.stack, 0, that.stack, 0, this.stackptr);
2366             System.arraycopy(this.locals, 0, that.locals, 0, this.locals.length);
2367             that.stackptr = this.stackptr;
2368             return that;
2369         }
2370         
2371         AbstractState copyFull() {
2372             AbstractState that = new AbstractState(this.stack.length, this.locals.length);
2373             for (int i=0; i<stackptr; ++i) {
2374                 that.stack[i] = this.stack[i].copy();
2375             }
2376             for (int i=0; i<this.locals.length; ++i) {
2377                 if (this.locals[i] != null)
2378                     that.locals[i] = this.locals[i].copy();
2379             }
2380             that.stackptr = this.stackptr;
2381             return that;
2382         }
2383         
2384         AbstractState copyAfterJSR() {
2385             AbstractState that = new AbstractState(this.stack.length, this.locals.length);
2386             for (int i=0; i<this.locals.length; ++i) {
2387                 if (this.locals[i] != null)
2388                     that.locals[i] = this.locals[i].copy();
2389             }
2390             return that;
2391         }
2392         
2393         AbstractState copyExceptionHandler(jq_Class exType, RegisterFactory rf) {
2394             if (exType == null) exType = PrimordialClassLoader.getJavaLangThrowable();
2395             AbstractState that = new AbstractState(this.stack.length, this.locals.length);
2396             that.stackptr = 1;
2397             RegisterOperand ex = new RegisterOperand(rf.getOrCreateStack(0, exType), exType);
2398             that.stack[0] = ex;
2399             for (int i=0; i<this.locals.length; ++i) {
2400                 if (this.locals[i] != null)
2401                     that.locals[i] = this.locals[i].copy();
2402             }
2403             return that;
2404         }
2405 
2406         void overwriteWith(AbstractState that) {
2407             Assert._assert(this.stack.length == that.stack.length);
2408             Assert._assert(this.locals.length == that.locals.length);
2409             System.arraycopy(that.stack, 0, this.stack, 0, that.stackptr);
2410             System.arraycopy(that.locals, 0, this.locals, 0, that.locals.length);
2411             this.stackptr = that.stackptr;
2412         }
2413 
2414         void rebuildStack() {
2415             for (int i = 0; i < stackptr; ++i) {
2416                 if (TRACE) System.out.println("Rebuilding stack: "+stack[i]);
2417                 stack[i] = stack[i].copy();
2418             }
2419         }
2420         
2421         void mergeAfterJSR(boolean[] changedLocals, AbstractState that) {
2422             for (int j=0; j<this.locals.length; ++j) {
2423                 if (!changedLocals[j]) continue;
2424                 if (TRACE) System.out.println("local "+j+" changed in jsr to "+that.locals[j]);
2425                 if (that.locals[j] == null) this.locals[j] = null;
2426                 else this.locals[j] = that.locals[j].copy();
2427             }
2428             this.stackptr = that.stackptr;
2429             for (int i=0; i<stackptr; ++i) {
2430                 this.stack[i] = that.stack[i].copy();
2431             }
2432         }
2433         boolean merge(AbstractState that, RegisterFactory rf) {
2434             if (this.stackptr != that.stackptr) throw new VerifyError(this.stackptr+" != "+that.stackptr);
2435             Assert._assert(this.locals.length == that.locals.length);
2436             boolean change = false;
2437             for (int i=0; i<this.stackptr; ++i) {
2438                 Operand o = meet(this.stack[i], that.stack[i], true, i);
2439                 if (o != this.stack[i] && (o == null || !o.isSimilar(this.stack[i]))) change = true;
2440                 this.stack[i] = o;
2441             }
2442             for (int i=0; i<this.locals.length; ++i) {
2443                 Operand o = meet(this.locals[i], that.locals[i], false, i);
2444                 if (o != this.locals[i] && (o == null || !o.isSimilar(this.locals[i]))) change = true;
2445                 this.locals[i] = o;
2446             }
2447             return change;
2448         }
2449         
2450         boolean mergeExceptionHandler(AbstractState that, jq_Class exType, RegisterFactory rf) {
2451             if (exType == null) exType = PrimordialClassLoader.getJavaLangThrowable();
2452             Assert._assert(this.locals.length == that.locals.length);
2453             Assert._assert(this.stackptr == 1);
2454             boolean change = false;
2455             RegisterOperand ex = new RegisterOperand(rf.getOrCreateStack(0, exType), exType);
2456             Operand o = meet(this.stack[0], ex, true, 0);
2457             if (o != this.stack[0] && (o == null || !o.isSimilar(this.stack[0]))) change = true;
2458             this.stack[0] = o;
2459             for (int i=0; i<this.locals.length; ++i) {
2460                  o = meet(this.locals[i], that.locals[i], false, i);
2461                  if (o != this.locals[i] && (o == null || !o.isSimilar(this.locals[i]))) change = true;
2462                  this.locals[i] = o;
2463             }
2464             return change;
2465         }
2466 
2467         Operand meet(Operand op1, Operand op2, boolean stack, int index) {
2468             if (TRACE) System.out.println("Meeting "+op1+" with "+op2+", "+(stack?"S":"L")+index);
2469             if (op1 == op2) {
2470                 // same operand, or both null.
2471                 return op1;
2472             }
2473             if ((op1 == null) || (op2 == null)) {
2474                 // no information about one of the operands.
2475                 return null;
2476             }
2477             if (Operand.Util.isConstant(op1)) {
2478                 if (op1.isSimilar(op2)) {
2479                     // same constant value.
2480                     return op1;
2481                 }
2482                 if (op2 instanceof DummyOperand) {
2483                     return null;
2484                 }
2485                 jq_Type type = state.findCommonSuperclass(getTypeOf(op1), getTypeOf(op2));
2486                 if (type != null) {
2487                     // different constants of the same type
2488                     RegisterOperand res = new RegisterOperand(stack?rf.getOrCreateStack(index, type):rf.getOrCreateLocal(index, type), type);
2489                     return res;
2490                 } else {
2491                     // constants of incompatible types.
2492                     return null;
2493                 }
2494             }
2495             if (op1 instanceof RegisterOperand) {
2496                 if (op2 instanceof DummyOperand) {
2497                     // op1 is a register, op2 is a dummy
2498                     return null;
2499                 }
2500                 RegisterOperand rop1 = (RegisterOperand)op1;
2501                 jq_Type t1 = rop1.getType();
2502                 if (t1 == jq_ReturnAddressType.INSTANCE) {
2503                     // op1 is a return address.
2504                     if (op2 instanceof RegisterOperand &&
2505                         ((RegisterOperand)op2).getType() == jq_ReturnAddressType.INSTANCE) {
2506                         return op1;
2507                     }
2508                     return null;
2509                 }
2510                 if (op2 instanceof RegisterOperand) {
2511                     // both are registers.
2512                     RegisterOperand rop2 = (RegisterOperand)op2;
2513                     jq_Type t2 = rop2.getType();
2514                     
2515                     if (t1 == t2) {
2516                         // registers have same type.
2517                         if (rop1.hasMoreConservativeFlags(rop2)) {
2518                             // registers have compatible flags.
2519                             if ((rop1.scratchObject == null) ||
2520                                 ((Operand)rop1.scratchObject).isSimilar((Operand)rop2.scratchObject)) {
2521                                 // null guards match.
2522                                 return rop1;
2523                             }
2524                             // null guards don't match.
2525                             RegisterOperand res = new RegisterOperand(stack?rf.getOrCreateStack(index, t1):rf.getOrCreateLocal(index, t1), t1);
2526                             res.setFlags(rop1.getFlags());
2527                             return res;
2528                         }
2529                         // incompatible flags.
2530                         RegisterOperand res = new RegisterOperand(stack?rf.getOrCreateStack(index, t1):rf.getOrCreateLocal(index, t1), t1);
2531                         if ((rop1.scratchObject == null) ||
2532                             ((Operand)rop1.scratchObject).isSimilar((Operand)rop2.scratchObject)) {
2533                             // null guards match.
2534                             res.scratchObject = rop1.scratchObject;
2535                         }
2536                         res.setFlags(rop1.getFlags());
2537                         res.meetFlags(rop2.getFlags());
2538                         return res;
2539                     }
2540                     if (t2 == jq_ReturnAddressType.INSTANCE) {
2541                         // op2 is a return address, while op1 isn't.
2542                         return null;
2543                     }
2544                     if (state.isSubtype(t2, t1) == YES) {
2545                         // t2 is a subtype of t1.
2546                         if (!rop1.isExactType() && rop1.hasMoreConservativeFlags(rop2)) {
2547                             // flags and exact type matches.
2548                             if ((rop1.scratchObject == null) ||
2549                                 ((Operand)rop1.scratchObject).isSimilar((Operand)rop2.scratchObject)) {
2550                                 // null guards match.
2551                                 return rop1;
2552                             }
2553                             // null guards don't match.
2554                             RegisterOperand res = new RegisterOperand(stack?rf.getOrCreateStack(index, t1):rf.getOrCreateLocal(index, t1), t1);
2555                             res.setFlags(rop1.getFlags());
2556                             return res;
2557                         }
2558                         // doesn't match.
2559                         RegisterOperand res = new RegisterOperand(stack?rf.getOrCreateStack(index, t1):rf.getOrCreateLocal(index, t1), t1);
2560                         if ((rop1.scratchObject == null) ||
2561                             ((Operand)rop1.scratchObject).isSimilar((Operand)rop2.scratchObject)) {
2562                             // null guards match.
2563                             res.scratchObject = rop1.scratchObject;
2564                         }
2565                         res.setFlags(rop1.getFlags());
2566                         res.meetFlags(rop2.getFlags());
2567                         res.clearExactType();
2568                         return res;
2569                     }
2570                     if ((t2 = state.findCommonSuperclass(t1, t2)) != null) {
2571                         // common superclass
2572                         RegisterOperand res = new RegisterOperand(stack?rf.getOrCreateStack(index, t2):rf.getOrCreateLocal(index, t2), t2);
2573                         if (rop1.scratchObject != null) {
2574                             if (((Operand)rop1.scratchObject).isSimilar((Operand)rop2.scratchObject)) {
2575                                 // null guards match.
2576                                 res.scratchObject = rop1.scratchObject;
2577                             }
2578                         }
2579                         res.setFlags(rop1.getFlags());
2580                         res.meetFlags(rop2.getFlags());
2581                         res.clearExactType();
2582                         return res;
2583                     }
2584                     // no common superclass
2585                     return null;
2586                 }
2587                 // op2 is not a register.
2588                 jq_Type t2 = getTypeOf(op2);
2589                 if (t1 == t2) {
2590                     // same type.
2591                     if ((rop1.scratchObject == null) || (t2 != jq_Reference.jq_NullType.NULL_TYPE)) {
2592                         // null guard matches.
2593                         return rop1;
2594                     }
2595                     // null guard doesn't match.
2596                     RegisterOperand res = new RegisterOperand(stack?rf.getOrCreateStack(index, t1):rf.getOrCreateLocal(index, t1), t1);
2597                     res.setFlags(rop1.getFlags());
2598                     return res;
2599                 }
2600                 Assert._assert(t2 != jq_ReturnAddressType.INSTANCE);
2601                 if (state.isSubtype(t2, t1) == YES) {
2602                     // compatible type.
2603                     if (!rop1.isExactType()) {
2604                         if ((rop1.scratchObject == null) || (t2 != jq_Reference.jq_NullType.NULL_TYPE)) {
2605                             // null guard matches.
2606                             return rop1;
2607                         }
2608                         // null guard doesn't match.
2609                         RegisterOperand res = new RegisterOperand(stack?rf.getOrCreateStack(index, t1):rf.getOrCreateLocal(index, t1), t1);
2610                         res.setFlags(rop1.getFlags());
2611                         return res;
2612                     }
2613                     RegisterOperand res = new RegisterOperand(stack?rf.getOrCreateStack(index, t1):rf.getOrCreateLocal(index, t1), t1);
2614                     if (t2 != jq_Reference.jq_NullType.NULL_TYPE) {
2615                         // null guard matches.
2616                         res.scratchObject = rop1.scratchObject;
2617                     }
2618                     res.setFlags(rop1.getFlags());
2619                     res.clearExactType();
2620                     return res;
2621                 }
2622                 if ((t2 = state.findCommonSuperclass(t1, t2)) != null) {
2623                     // common superclass
2624                     RegisterOperand res = new RegisterOperand(stack?rf.getOrCreateStack(index, t2):rf.getOrCreateLocal(index, t2), t2);
2625                     if (t2 != jq_Reference.jq_NullType.NULL_TYPE) {
2626                         // null guard matches.
2627                         res.scratchObject = rop1.scratchObject;
2628                     }
2629                     res.setFlags(rop1.getFlags());
2630                     res.clearExactType();
2631                     return res;
2632                 }
2633                 // no common superclass
2634                 return null;
2635             }
2636             // op1 is not a register.
2637             if (op1.isSimilar(op2)) {
2638                 return op1;
2639             } else {
2640                 return null;
2641             }
2642         }
2643         
2644         int getStackSize() { return this.stackptr; }
2645         
2646         void push_I(Operand op) { Assert._assert(getTypeOf(op).isIntLike()); push(op); }
2647         void push_F(Operand op) { Assert._assert(getTypeOf(op) == jq_Primitive.FLOAT); push(op); }
2648         void push_L(Operand op) { Assert._assert(getTypeOf(op) == jq_Primitive.LONG); push(op); pushDummy(); }
2649         void push_D(Operand op) { Assert._assert(getTypeOf(op) == jq_Primitive.DOUBLE); push(op); pushDummy(); }
2650         void push_A(Operand op) { Assert._assert(getTypeOf(op).isReferenceType() && !getTypeOf(op).isAddressType()); push(op); }
2651         void push_P(Operand op) { Assert._assert(getTypeOf(op).isAddressType()); push(op); }
2652         void push(Operand op, jq_Type t) {
2653             Assert._assert(state.isSubtype(getTypeOf(op), t) == YES);
2654             push(op); if (t.getReferenceSize() == 8) pushDummy();
2655         }
2656         void pushDummy() { push(DummyOperand.DUMMY); }
2657         void push(Operand op) {
2658             if (TRACE) System.out.println("Pushing "+op+" on stack "+(this.stackptr));
2659             this.stack[this.stackptr++] = op;
2660         }
2661 
2662         Operand pop_I() { Operand op = pop(); Assert._assert(getTypeOf(op).isIntLike()); return op; }
2663         Operand pop_F() { Operand op = pop(); Assert._assert(getTypeOf(op) == jq_Primitive.FLOAT); return op; }
2664         Operand pop_L() { popDummy(); Operand op = pop(); Assert._assert(getTypeOf(op) == jq_Primitive.LONG); return op; }
2665         Operand pop_D() { popDummy(); Operand op = pop(); Assert._assert(getTypeOf(op) == jq_Primitive.DOUBLE); return op; }
2666         Operand pop_A() { Operand op = pop(); Assert._assert(getTypeOf(op).isReferenceType() && !getTypeOf(op).isAddressType()); return op; }
2667         Operand pop_P() {
2668             Operand op = pop();
2669             if (op instanceof AConstOperand) {
2670                 op = new PConstOperand(null);
2671             }
2672             Assert._assert(getTypeOf(op).isAddressType() ||
2673                       state.isSubtype(getTypeOf(op), Address._class) != NO);
2674             return op;
2675         }
2676         void popDummy() { Operand op = pop(); Assert._assert(op == DummyOperand.DUMMY); }
2677         Operand pop(jq_Type t) {
2678             if (t.getReferenceSize() == 8) popDummy();
2679             Operand op = pop();
2680             if (t.isAddressType()) {
2681                 if (op instanceof AConstOperand) {
2682                     op = new PConstOperand(null);
2683                 }
2684                 jq_Type t2 = getTypeOf(op);
2685                 Assert._assert(t2 == jq_Reference.jq_NullType.NULL_TYPE ||
2686                           t2.isAddressType() ||
2687                           state.isSubtype(t2, Address._class) != NO);
2688             }
2689             //jq.Assert(state.isSubtype(getTypeOf(op), t) != NO);
2690             return op;
2691         }
2692         Operand pop() {
2693             if (TRACE) System.out.println("Popping "+this.stack[this.stackptr-1]+" from stack "+(this.stackptr-1));
2694             return this.stack[--this.stackptr];
2695         }
2696 
2697         Operand peekStack(int i) { return this.stack[this.stackptr-i-1]; }
2698         void pokeStack(int i, Operand op) { this.stack[this.stackptr-i-1] = op; }
2699         void clearStack() { this.stackptr = 0; }
2700         
2701         Operand getLocal_I(int i) { Operand op = getLocal(i); Assert._assert(getTypeOf(op).isIntLike()); return op; }
2702         Operand getLocal_F(int i) { Operand op = getLocal(i); Assert._assert(getTypeOf(op) == jq_Primitive.FLOAT); return op; }
2703         Operand getLocal_L(int i) {
2704             Operand op = getLocal(i);
2705             Assert._assert(getTypeOf(op) == jq_Primitive.LONG);
2706             Assert._assert(getLocal(i+1) == DummyOperand.DUMMY);
2707             return op;
2708         }
2709         Operand getLocal_D(int i) {
2710             Operand op = getLocal(i);
2711             Assert._assert(getTypeOf(op) == jq_Primitive.DOUBLE);
2712             Assert._assert(getLocal(i+1) == DummyOperand.DUMMY);
2713             return op;
2714         }
2715         Operand getLocal_A(int i) {
2716             Operand op = getLocal(i);
2717             Assert._assert(getTypeOf(op).isReferenceType());
2718             Assert._assert(!getTypeOf(op).isAddressType());
2719             return op;
2720         }
2721         Operand getLocal(int i) {
2722             return this.locals[i].copy();
2723         }
2724         void setLocal(int i, Operand op) {
2725             this.locals[i] = op;
2726         }
2727         void setLocalDual(int i, Operand op) {
2728             this.locals[i] = op; this.locals[i+1] = DummyOperand.DUMMY;
2729         }
2730         void dumpState() {
2731             System.out.print("Locals:");
2732             for (int i=0; i<this.locals.length; ++i) {
2733                 if (this.locals[i] != null)
2734                     System.out.print(" L"+i+":"+this.locals[i]);
2735             }
2736             System.out.print("\nStack: ");
2737             for (int i=0; i<this.stackptr; ++i) {
2738                 System.out.print(" S"+i+":"+this.stack[i]);
2739             }
2740             System.out.println();
2741         }
2742     }
2743 
2744     public static class jq_ReturnAddressType extends jq_Reference {
2745         public static final jq_ReturnAddressType INSTANCE = new jq_ReturnAddressType();
2746         public static jq_ReturnAddressType create(BasicBlock bb) {
2747             return new jq_ReturnAddressType(bb);
2748         }
2749         private BasicBlock returnTarget;
2750         private jq_ReturnAddressType() { super(Utf8.get("L&ReturnAddress;"), PrimordialClassLoader.loader); }
2751         private jq_ReturnAddressType(BasicBlock returnTarget) {
2752             super(Utf8.get("L&ReturnAddress;"), PrimordialClassLoader.loader);
2753             this.returnTarget = returnTarget;
2754         }
2755         public boolean isAddressType() { return false; }
2756         public String getJDKName() { return desc.toString(); }
2757         public String getJDKDesc() { return getJDKName(); }
2758         public jq_Class[] getInterfaces() { Assert.UNREACHABLE(); return null; }
2759         public jq_Class getInterface(Utf8 desc) { Assert.UNREACHABLE(); return null; }
2760         public boolean implementsInterface(jq_Class k) { Assert.UNREACHABLE(); return false; }
2761         public jq_InstanceMethod getVirtualMethod(jq_NameAndDesc nd) { Assert.UNREACHABLE(); return null; }
2762         public String getName() { return "<retaddr>"; }
2763         public String shortName() { return "<retaddr>"; }
2764         public boolean isClassType() { Assert.UNREACHABLE(); return false; }
2765         public boolean isArrayType() { Assert.UNREACHABLE(); return false; }
2766         public boolean isFinal() { Assert.UNREACHABLE(); return false; }
2767         public jq_Reference getDirectPrimarySupertype() { Assert.UNREACHABLE(); return null; }
2768         public int getDepth() { Assert.UNREACHABLE(); return 0; }
2769         public void load() { Assert.UNREACHABLE(); }
2770         public void verify() { Assert.UNREACHABLE(); }
2771         public void prepare() { Assert.UNREACHABLE(); }
2772         public void sf_initialize() { Assert.UNREACHABLE(); }
2773         public void compile() { Assert.UNREACHABLE(); }
2774         public void cls_initialize() { Assert.UNREACHABLE(); }
2775         public String toString() { return "<retaddr> (target="+returnTarget+")"; }
2776         public boolean equals(Object rat) {
2777             if (!(rat instanceof jq_ReturnAddressType)) return false;
2778             BasicBlock rt = ((jq_ReturnAddressType)rat).returnTarget;
2779             if (rt == null)
2780                 return returnTarget == null;
2781             if (returnTarget == null)
2782                 return false;
2783             return ((jq_ReturnAddressType)rat).returnTarget.equals(this.returnTarget);
2784         }
2785         public int hashCode() {
2786             if (returnTarget == null) return 0;
2787             return returnTarget.hashCode();
2788         }
2789     }
2790     static interface UnsafeHelper {
2791         public boolean isUnsafe(jq_Method m);
2792         public boolean endsBB(jq_Method m);
2793         public boolean handleMethod(BytecodeToQuad b2q, ControlFlowGraph quad_cfg, BytecodeToQuad.AbstractState current_state, jq_Method m, Operator.Invoke oper);
2794     }
2795 
2796     private static UnsafeHelper _unsafe;
2797     static {
2798         /* Set up delegates. */
2799         _unsafe = null;
2800         boolean nullVM = jq.nullVM;
2801         if (!nullVM) {
2802             _unsafe = attemptDelegate("joeq.Compiler.Quad.B2QUnsafeHandler");
2803         }
2804         if (_unsafe == null) {
2805             _unsafe = new joeq.Compiler.Quad.B2QUnsafeIgnorer();
2806         }
2807     }
2808 
2809     private static UnsafeHelper attemptDelegate(String s) {
2810         //String type = "BC2Q delegate";
2811         try {
2812             Class c = Class.forName(s);
2813             return (UnsafeHelper)c.newInstance();
2814         } catch (java.lang.ClassNotFoundException x) {
2815             //System.err.println("Cannot find "+type+" "+s+": "+x);
2816         } catch (java.lang.InstantiationException x) {
2817             //System.err.println("Cannot instantiate "+type+" "+s+": "+x);
2818         } catch (java.lang.IllegalAccessException x) {
2819             //System.err.println("Cannot access "+type+" "+s+": "+x);
2820         }
2821         return null;
2822     }
2823 }