1 cananian 1.1.2.4 // Translate.java, created Wed Dec 9 00:19:51 1998 by cananian 2 cananian 1.1.2.1 // Copyright (C) 1998 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1.2.1 package harpoon.IR.Quads; 5 cananian 1.1.2.1 6 cananian 1.1.2.7 import harpoon.ClassFile.HClass; 7 cananian 1.1.2.20 import harpoon.ClassFile.HCodeElement; 8 cananian 1.1.2.7 import harpoon.ClassFile.HMethod; 9 cananian 1.1.2.1 import harpoon.IR.Bytecode.Op; 10 cananian 1.1.2.1 import harpoon.IR.Bytecode.Operand; 11 cananian 1.1.2.1 import harpoon.IR.Bytecode.OpClass; 12 cananian 1.1.2.1 import harpoon.IR.Bytecode.OpConstant; 13 cananian 1.1.2.1 import harpoon.IR.Bytecode.OpField; 14 cananian 1.1.2.1 import harpoon.IR.Bytecode.OpLocalVariable; 15 cananian 1.1.2.1 import harpoon.IR.Bytecode.OpMethod; 16 cananian 1.1.2.1 import harpoon.IR.Bytecode.Instr; 17 cananian 1.1.2.1 import harpoon.IR.Bytecode.InGen; 18 cananian 1.1.2.1 import harpoon.IR.Bytecode.InCti; 19 cananian 1.1.2.1 import harpoon.IR.Bytecode.InMerge; 20 cananian 1.1.2.4 import harpoon.IR.Bytecode.InRet; 21 cananian 1.1.2.1 import harpoon.IR.Bytecode.InSwitch; 22 cananian 1.1.2.1 import harpoon.IR.Bytecode.Code.ExceptionEntry; 23 cananian 1.1.2.12 import harpoon.IR.Bytecode.Liveness; // liveness analysis on local variables 24 cananian 1.1.2.4 import harpoon.IR.Quads.HANDLER.ProtectedSet; 25 cananian 1.1.2.4 import harpoon.Temp.Temp; 26 cananian 1.1.2.4 import harpoon.Temp.TempFactory; 27 cananian 1.9 import net.cscott.jutil.AbstractMapEntry; 28 cananian 1.9 import net.cscott.jutil.UnmodifiableIterator; 29 cananian 1.9 import net.cscott.jutil.Default; 30 cananian 1.1.2.30 import harpoon.Util.MapComparator; 31 cananian 1.1.2.1 import harpoon.Util.Util; 32 cananian 1.1.2.1 33 cananian 1.1.2.1 import java.lang.reflect.Modifier; 34 cananian 1.1.2.12 import java.util.AbstractMap; 35 cananian 1.1.2.12 import java.util.AbstractSet; 36 cananian 1.1.2.11 import java.util.ArrayList; 37 cananian 1.1.2.13 import java.util.Arrays; 38 cananian 1.1.2.13 import java.util.Collections; 39 cananian 1.1.2.21 import java.util.Comparator; 40 cananian 1.1.2.11 import java.util.HashMap; 41 cananian 1.1.2.11 import java.util.HashSet; 42 cananian 1.1.2.11 import java.util.Iterator; 43 cananian 1.1.2.11 import java.util.List; 44 cananian 1.1.2.11 import java.util.Map; 45 cananian 1.1.2.12 import java.util.NoSuchElementException; 46 cananian 1.1.2.11 import java.util.Set; 47 cananian 1.1.2.15 import java.util.SortedMap; 48 cananian 1.1.2.1 import java.util.Stack; 49 cananian 1.1.2.15 import java.util.TreeMap; 50 cananian 1.1.2.1 51 cananian 1.1.2.1 /** 52 cananian 1.1.2.4 * <code>Translate</code> is a utility class which implements a 53 cananian 1.1.2.4 * bytecode-to-quad translation. The result is a simple quad 54 cananian 1.1.2.4 * form with no phi/sigma functions or exception handlers. 55 cananian 1.1.2.1 * 56 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 57 cananian 1.10 * @version $Id: Translate.java,v 1.10 2004/02/08 03:21:24 cananian Exp $ 58 cananian 1.1.2.1 */ 59 cananian 1.1.2.4 final class Translate { // not public. 60 cananian 1.1.2.4 static final private class StaticState { 61 cananian 1.1.2.4 /** <code>QuadFactory</code> to use for this method. 62 cananian 1.1.2.4 * (contains <code>TempFactory</code> to use for this method.) */ 63 cananian 1.1.2.4 final QuadFactory qf; 64 cananian 1.1.2.4 /** <code>Temp</code>s representing the bytecode stack. */ 65 cananian 1.1.2.4 final Temp[] stack; 66 cananian 1.1.2.4 /** <code>Temp</code>s used for local variables. */ 67 cananian 1.1.2.4 final Temp lv[]; 68 cananian 1.1.2.4 /** Extra <code>Temp</code>s used for temporary values during 69 cananian 1.1.2.4 * translation. */ 70 cananian 1.1.2.11 final List extra; 71 cananian 1.1.2.4 /** HEADER quad for method. */ 72 cananian 1.1.2.4 final HEADER header; 73 cananian 1.1.2.4 /** Try block information from original bytecode. */ 74 cananian 1.1.2.4 final ExceptionEntry[] tryBlocks; 75 cananian 1.1.2.4 /** Mapping from <code>InMerge</code>s to corresponding 76 cananian 1.1.2.4 * <code>PHI</code>s. */ 77 cananian 1.1.2.4 final MergeMap mergeMap; 78 cananian 1.1.2.12 /** Liveness information from bytecode. */ 79 cananian 1.1.2.12 final Liveness liveness; 80 cananian 1.1.2.15 /** Mapping from <tryBlock,CallStack> to a HANDLER. */ 81 cananian 1.1.2.15 final SortedMap transHandler; 82 cananian 1.1.2.15 /** To-do list for HANDLER construction. */ 83 cananian 1.1.2.15 final Stack todoHandler; 84 cananian 1.1.2.1 85 cananian 1.1.2.4 /** Constructor. */ 86 cananian 1.1.2.4 StaticState(QuadFactory qf, int max_stack, int max_locals, 87 cananian 1.1.2.12 ExceptionEntry[] tryBlocks, HEADER header, 88 cananian 1.1.2.12 Liveness liveness) { 89 cananian 1.1.2.4 this.qf = qf; 90 cananian 1.1.2.4 stack = new Temp[max_stack]; 91 cananian 1.1.2.4 for (int i=0; i<max_stack; i++) 92 cananian 1.1.2.4 stack[i] = new Temp(qf.tempFactory(), "stk"+i+"_"); 93 cananian 1.1.2.4 lv = new Temp[max_locals]; 94 cananian 1.1.2.4 for (int i=0; i<max_locals; i++) 95 cananian 1.1.2.4 lv[i] = new Temp(qf.tempFactory(), "lv"+i+"_"); 96 cananian 1.1.2.11 extra = new ArrayList(); 97 cananian 1.1.2.4 98 cananian 1.1.2.4 this.tryBlocks = tryBlocks; 99 cananian 1.1.2.4 this.header = header; 100 cananian 1.1.2.4 this.mergeMap = new MergeMap(); 101 cananian 1.1.2.12 this.liveness = liveness; 102 cananian 1.1.2.15 this.transHandler = 103 cananian 1.1.2.21 new TreeMap(new Comparator() { 104 cananian 1.1.2.30 final Comparator mapComparator = 105 cananian 1.1.2.30 new MapComparator(null,null); 106 cananian 1.1.2.21 public int compare(Object o1, Object o2) { 107 cananian 1.1.2.30 List l1 = (List) o1, l2 = (List) o2; 108 cananian 1.3.2.1 assert l1.size()==l2.size() && l1.size()==2; 109 cananian 1.1.2.30 ExceptionEntry e1 = (ExceptionEntry) l1.get(0); 110 cananian 1.1.2.30 ExceptionEntry e2 = (ExceptionEntry) l2.get(0); 111 cananian 1.1.2.21 // null is larger than anything else. 112 cananian 1.1.2.21 if (e1==null) return (e2==null)?0:1; 113 cananian 1.1.2.21 if (e2==null) return (e1==null)?0:-1; 114 cananian 1.1.2.30 int c = e1.compareTo(e2); 115 cananian 1.1.2.30 if (c!=0) return c; 116 cananian 1.1.2.30 Map m1 = (Map) l1.get(1); 117 cananian 1.1.2.30 Map m2 = (Map) l2.get(1); 118 cananian 1.1.2.30 return mapComparator.compare(m1, m2); 119 cananian 1.1.2.21 } 120 cananian 1.1.2.21 }); 121 cananian 1.1.2.15 this.todoHandler = new Stack(); 122 cananian 1.1.2.4 } 123 cananian 1.1.2.4 /** Get an "extra" <code>Temp</code>. */ 124 cananian 1.1.2.4 final Temp extra(int n) { 125 cananian 1.1.2.4 while (n >= extra.size()) 126 cananian 1.1.2.11 extra.add(new Temp(qf.tempFactory(), 127 cananian 1.1.2.11 "extra"+extra.size()+"_")); 128 cananian 1.1.2.11 return (Temp)extra.get(n); 129 cananian 1.1.2.1 } 130 cananian 1.1.2.1 } 131 cananian 1.1.2.4 /** Auxillary class to implement mergeMap. */ 132 cananian 1.1.2.4 static final private class MergeMap { 133 cananian 1.1.2.11 private final Map h = new HashMap(); 134 cananian 1.1.2.13 private List getList(InMerge m, Map calls) { 135 cananian 1.1.2.13 return (List) h.get(Arrays.asList(new Object[] {m, calls })); 136 cananian 1.1.2.13 } 137 cananian 1.1.2.13 138 cananian 1.1.2.13 boolean contains(InMerge m, Map calls) { 139 cananian 1.1.2.13 return (getList(m, calls)!=null); 140 cananian 1.1.2.13 } 141 cananian 1.1.2.13 PHI get(InMerge m, Map calls) { 142 cananian 1.1.2.13 return (PHI) getList(m, calls).get(0); 143 cananian 1.1.2.13 } 144 cananian 1.1.2.13 int arity(InMerge m, Map calls) { 145 cananian 1.1.2.13 return ((Integer) getList(m, calls).get(1)).intValue(); 146 cananian 1.1.2.13 } 147 cananian 1.7 State state(InMerge m, Map calls) { 148 cananian 1.7 return (State) getList(m, calls).get(2); 149 cananian 1.7 } 150 cananian 1.7 void put(InMerge m, Map calls, PHI p, int arity, State s) { 151 cananian 1.1.2.13 h.put(Arrays.asList(new Object[] { m, calls }), 152 cananian 1.7 Arrays.asList(new Object[] { p, new Integer(arity), s})); 153 cananian 1.1.2.13 } 154 cananian 1.1.2.14 public String toString() { return h.toString(); } 155 cananian 1.1.2.14 156 cananian 1.7 void fixupPhis() { // eliminate null limbs 157 cananian 1.10 for (Object meO : h.entrySet()) { 158 cananian 1.10 Map.Entry me = (Map.Entry) meO; 159 cananian 1.1.2.13 InMerge in= (InMerge) ((List)me.getKey()).get(0); 160 cananian 1.1.2.13 PHI phi = (PHI) ((List)me.getValue()).get(0); 161 cananian 1.1.2.13 int arity =((Integer) ((List)me.getValue()).get(1)).intValue(); 162 cananian 1.7 State s = (State) ((List)me.getValue()).get(2); 163 cananian 1.1.2.13 164 cananian 1.1.2.4 while (arity < phi.arity()) 165 cananian 1.1.2.4 phi = phi.shrink(phi.arity()-1); // null branch. 166 cananian 1.1.2.4 // might as well kill one-input phi functions while we're at it 167 cananian 1.1.2.4 if (arity==1) 168 cananian 1.1.2.4 Quad.addEdge(phi.prev(0), phi.prevEdge(0).which_succ(), 169 cananian 1.1.2.4 phi.next(0), phi.nextEdge(0).which_pred()); 170 cananian 1.1.2.4 else s.recordHandler(in, phi, phi); 171 cananian 1.1.2.4 172 cananian 1.1.2.4 } 173 cananian 1.1.2.1 } 174 cananian 1.1.2.1 } 175 cananian 1.1.2.4 /** Auxillary stack to track JSR return addresses on the main stack. */ 176 cananian 1.1.2.4 static final private class JSRStack { 177 cananian 1.1.2.4 /** Index of return address on the stack, or local variable. */ 178 cananian 1.1.2.4 final int index; 179 cananian 1.1.2.4 /** Target of the JSR. */ 180 cananian 1.1.2.4 final Instr target; 181 cananian 1.1.2.4 /** Link to rest of the list. */ 182 cananian 1.1.2.4 final JSRStack next; 183 cananian 1.1.2.4 /** Constructor. Indices are always in increasing order. */ 184 cananian 1.1.2.4 JSRStack(int index, Instr target, JSRStack next) { 185 cananian 1.1.2.4 this.index=index; this.target=target; this.next=next; 186 cananian 1.3.2.1 assert next==null || index > next.index; 187 cananian 1.3.2.1 assert target!=null; 188 cananian 1.1.2.4 } 189 cananian 1.1.2.4 /** Find index. */ 190 cananian 1.1.2.4 static Instr getTarget(JSRStack js, int index) { 191 cananian 1.1.2.4 if (js==null || index > js.index) return null; 192 cananian 1.1.2.4 if (js.index==index) return js.target; 193 cananian 1.1.2.4 return getTarget(js.next, index); 194 cananian 1.1.2.4 } 195 cananian 1.1.2.4 /** Insert index into stack. */ 196 cananian 1.1.2.4 static JSRStack insert(JSRStack js, int index, Instr target) { 197 cananian 1.1.2.4 if (js==null || index > js.index) 198 cananian 1.1.2.4 return new JSRStack(index, target, js); 199 cananian 1.1.2.4 return new JSRStack(js.index, js.target, 200 cananian 1.1.2.4 insert(js.next, index, target)); 201 cananian 1.1.2.4 } 202 cananian 1.1.2.4 /** Remove index from stack. */ 203 cananian 1.1.2.4 static JSRStack remove(JSRStack js, int index) { 204 cananian 1.1.2.4 if (js==null || index > js.index) return js; 205 cananian 1.1.2.4 if (js.index==index) return js.next; 206 cananian 1.1.2.4 JSRStack nnxt = remove(js.next, index); 207 cananian 1.1.2.4 if (js.next == nnxt) return js; 208 cananian 1.1.2.4 return new JSRStack(js.index, js.target, nnxt); 209 cananian 1.1.2.4 } 210 cananian 1.1.2.14 /** Human-readable string for debugging. */ 211 cananian 1.1.2.13 public String toString() { return asMap(this).toString(); } 212 cananian 1.1.2.12 /** Collection view of target <code>Instr</code>s in stack. */ 213 cananian 1.1.2.12 static Map asMap(final JSRStack js) { 214 cananian 1.1.2.12 return new AbstractMap () { 215 cananian 1.1.2.12 public Set entrySet() { 216 cananian 1.1.2.12 return new AbstractSet() { 217 cananian 1.1.2.12 public int size() { 218 cananian 1.1.2.12 int size=0; 219 cananian 1.1.2.12 for (JSRStack jsp=js; jsp!=null; jsp=jsp.next) 220 cananian 1.1.2.12 size++; 221 cananian 1.1.2.12 return size; 222 cananian 1.1.2.12 } 223 cananian 1.1.2.12 public boolean isEmpty() { return js==null; } 224 cananian 1.1.2.12 public Iterator iterator() { 225 cananian 1.1.2.17 return new UnmodifiableIterator() { 226 cananian 1.1.2.12 private JSRStack jsp=js; 227 cananian 1.1.2.12 public boolean hasNext() { return jsp!=null; } 228 cananian 1.1.2.12 public Object next() { 229 cananian 1.1.2.12 if (jsp==null) 230 cananian 1.1.2.12 throw new NoSuchElementException(); 231 cananian 1.1.2.12 final JSRStack oldjsp = jsp; 232 cananian 1.1.2.12 jsp = jsp.next; 233 cananian 1.1.2.12 return new AbstractMapEntry() { 234 cananian 1.1.2.12 public Object getKey() { 235 cananian 1.1.2.12 return new Integer(oldjsp.index); 236 cananian 1.1.2.12 } 237 cananian 1.1.2.12 public Object getValue() { 238 cananian 1.1.2.12 return oldjsp.target; 239 cananian 1.1.2.12 } 240 cananian 1.1.2.12 }; // END anonymous Map.Entry 241 cananian 1.1.2.12 } 242 cananian 1.1.2.12 }; // END anonymous Iterator 243 cananian 1.1.2.12 } 244 cananian 1.1.2.12 }; // END anonymous AbstractSet 245 cananian 1.1.2.12 } 246 cananian 1.1.2.12 }; // END anonymous AbstractMap 247 cananian 1.1.2.12 } 248 cananian 1.1.2.4 } 249 cananian 1.1.2.4 /** Auxilliary stack to track LONG values on main stack. */ 250 cananian 1.1.2.4 static final private class LongStack { 251 cananian 1.1.2.4 /** Index of topmost LONG value on main stack. */ 252 cananian 1.1.2.4 final int index; 253 cananian 1.1.2.4 /** Link to the rest of the LongStack. */ 254 cananian 1.1.2.4 final LongStack next; 255 cananian 1.1.2.1 /** Constructor. */ 256 cananian 1.1.2.4 LongStack(int index, LongStack next) { 257 cananian 1.1.2.4 this.index = index; this.next = next; 258 cananian 1.1.2.14 } 259 cananian 1.1.2.14 /** Make data human-readable for debugging. */ 260 cananian 1.1.2.14 public String toString() { 261 cananian 1.1.2.14 StringBuffer sb=new StringBuffer("["); 262 cananian 1.1.2.14 for (LongStack lsp = this; lsp!=null; lsp=lsp.next) { 263 cananian 1.1.2.14 sb.append(lsp.index); 264 cananian 1.1.2.14 if (lsp.next!=null) sb.append(", "); 265 cananian 1.1.2.14 } 266 cananian 1.1.2.14 sb.append("]"); 267 cananian 1.1.2.14 return sb.toString(); 268 cananian 1.1.2.4 } 269 cananian 1.1.2.4 } 270 cananian 1.1.2.4 static final private class State { 271 cananian 1.1.2.4 /** Pointer to the static state for this method. */ 272 cananian 1.1.2.4 private final StaticState ss; 273 cananian 1.1.2.4 /** Current size of the stack. */ 274 cananian 1.1.2.4 private final int stackSize; 275 cananian 1.1.2.4 /** LongStack to track long values on the stack. */ 276 cananian 1.1.2.4 private final LongStack ls; 277 cananian 1.1.2.4 /** JSRStack to track jsr targets. */ 278 cananian 1.1.2.4 private final JSRStack js; 279 cananian 1.1.2.4 /** JSRStack to track jsr targets in local variables. */ 280 cananian 1.1.2.4 private final JSRStack jlv; 281 cananian 1.1.2.13 /** Keep track of JSR call stack during translation. */ 282 cananian 1.1.2.13 private final Map calls; // unmodifiable. 283 cananian 1.1.2.13 284 cananian 1.1.2.4 /** private constructor */ 285 cananian 1.1.2.4 private State(StaticState ss, int stackSize, 286 cananian 1.1.2.13 LongStack ls, JSRStack js, JSRStack jlv, 287 cananian 1.1.2.13 Map calls) { 288 cananian 1.1.2.4 this.ss = ss; this.stackSize = stackSize; 289 cananian 1.1.2.4 this.ls = ls; this.js = js; this.jlv = jlv; 290 cananian 1.1.2.13 this.calls = calls; 291 cananian 1.1.2.4 } 292 cananian 1.1.2.4 /** public constructor */ 293 cananian 1.1.2.4 State(QuadFactory qf, int max_stack, int max_locals, 294 cananian 1.1.2.12 ExceptionEntry[] tryBlocks, HEADER header, Liveness liveness) { 295 cananian 1.1.2.4 this.ss = new StaticState(qf, max_stack, max_locals, tryBlocks, 296 cananian 1.1.2.12 header, liveness); 297 cananian 1.1.2.4 this.stackSize = 0; 298 cananian 1.1.2.4 this.ls = null; 299 cananian 1.1.2.4 this.js = null; 300 cananian 1.1.2.4 this.jlv= null; 301 cananian 1.1.2.21 this.calls = Default.EMPTY_MAP; 302 cananian 1.1.2.4 } 303 cananian 1.7 public String toString() { 304 cananian 1.7 return "<"+ss+", "+stackSize+", "+ls+", "+ 305 cananian 1.7 js+", "+jlv+", "+calls+">"; 306 cananian 1.7 } 307 cananian 1.1.2.4 308 cananian 1.1.2.4 State pop() { return pop(1); } 309 cananian 1.1.2.4 State pop(int n) { 310 cananian 1.1.2.4 LongStack lsp = ls; 311 cananian 1.1.2.4 while (lsp!=null && lsp.index >= stackSize-n) lsp=lsp.next; 312 cananian 1.1.2.4 JSRStack jsp = js; 313 cananian 1.1.2.4 while (jsp!=null && jsp.index >= stackSize-n) jsp=jsp.next; 314 cananian 1.1.2.13 return new State(ss, stackSize-n, lsp, jsp, jlv, calls); 315 cananian 1.1.2.4 } 316 cananian 1.1.2.4 State push() { return push(1); } 317 cananian 1.1.2.13 State push(int n) { 318 cananian 1.1.2.13 return new State(ss, stackSize+n, ls, js, jlv, calls); 319 cananian 1.1.2.13 } 320 cananian 1.1.2.4 State pushLong() { 321 cananian 1.1.2.4 return new State(ss, stackSize+2, 322 cananian 1.1.2.13 new LongStack(stackSize+1, ls), js, jlv, calls); 323 cananian 1.1.2.4 } 324 cananian 1.1.2.13 private State pushRetAddr(Instr target) { // called from enterJSR 325 cananian 1.1.2.4 return new State(ss, stackSize+1, ls, 326 cananian 1.1.2.13 new JSRStack(stackSize, target, js), jlv, calls); 327 cananian 1.1.2.4 } 328 cananian 1.1.2.4 329 cananian 1.1.2.4 Temp stack(int n) { return ss.stack[stackSize-n-1]; } 330 cananian 1.1.2.4 Temp extra(int n) { return ss.extra(n); } 331 cananian 1.1.2.4 Temp lv (int n) { return ss.lv[n]; } 332 cananian 1.1.2.4 333 cananian 1.1.2.4 boolean isLong(int n) { 334 cananian 1.1.2.4 int i = stackSize-n-1; 335 cananian 1.1.2.4 for (LongStack lp = ls; lp!=null && lp.index>=i; lp=lp.next) 336 cananian 1.1.2.4 if (lp.index==i) return true; 337 cananian 1.1.2.4 return false; 338 cananian 1.1.2.4 } 339 cananian 1.1.2.4 340 cananian 1.1.2.4 /** mark a local variable as *not* containing a return address. */ 341 cananian 1.1.2.4 State clearLV(int lvIndex) { 342 cananian 1.1.2.4 JSRStack jlvp = JSRStack.remove(jlv, lvIndex); 343 cananian 1.1.2.13 return (jlv==jlvp) ? this : 344 cananian 1.1.2.13 new State(ss, stackSize, ls, js, jlvp, calls); 345 cananian 1.1.2.4 } 346 cananian 1.1.2.4 /** track a return address going from local variables to the stack */ 347 cananian 1.1.2.4 State trackLV2S(int lvFrom, int stkTo) { 348 cananian 1.1.2.4 if (!isRetAddrLV(lvFrom)) return this; 349 cananian 1.1.2.4 JSRStack jsp=JSRStack.insert(js, stackSize-stkTo-1, 350 cananian 1.1.2.4 getJSRtargetLV(lvFrom)); 351 cananian 1.1.2.13 return new State(ss, stackSize, ls, jsp, jlv, calls); 352 cananian 1.1.2.4 } 353 cananian 1.1.2.4 /** track a return address going from the stack to a local variable */ 354 cananian 1.1.2.4 State trackS2LV(int stkFrom, int lvTo) { 355 cananian 1.1.2.4 // lv is being rewritten either way, so remove lvTo from lv state. 356 cananian 1.1.2.4 JSRStack jlvp = JSRStack.remove(jlv, lvTo); 357 cananian 1.1.2.4 if (isRetAddrS(stkFrom)) 358 cananian 1.1.2.18 jlvp = JSRStack.insert(jlvp, lvTo, getJSRtargetS(stkFrom)); 359 cananian 1.1.2.13 return (jlv==jlvp) ? this : 360 cananian 1.1.2.13 new State(ss, stackSize, ls, js, jlvp, calls); 361 cananian 1.1.2.4 } 362 cananian 1.1.2.4 /** track a return address going from the stack to the stack. */ 363 cananian 1.1.2.4 State trackS2S(State old, int oldFrom, int newTo) { 364 cananian 1.1.2.4 if (!old.isRetAddrS(oldFrom)) return this; 365 cananian 1.1.2.4 JSRStack jsp = JSRStack.insert(js, stackSize-newTo-1, 366 cananian 1.1.2.4 old.getJSRtargetS(oldFrom)); 367 cananian 1.1.2.13 return new State(ss, stackSize, ls, jsp, jlv, calls); 368 cananian 1.1.2.4 } 369 cananian 1.1.2.4 boolean isRetAddrS(int n) 370 cananian 1.1.2.4 { return JSRStack.getTarget(js, stackSize-n-1)!=null; } 371 cananian 1.1.2.4 boolean isRetAddrLV(int n) 372 cananian 1.1.2.4 { return JSRStack.getTarget(jlv, n)!=null; } 373 cananian 1.1.2.4 Instr getJSRtargetLV(int n) 374 cananian 1.1.2.4 { return JSRStack.getTarget(jlv, n); } 375 cananian 1.1.2.4 Instr getJSRtargetS(int n) 376 cananian 1.1.2.4 { return JSRStack.getTarget(js, stackSize-n-1); } 377 cananian 1.1.2.4 378 cananian 1.1.2.4 QuadFactory qf() { return ss.qf; } 379 cananian 1.1.2.4 TempFactory tf() { return ss.qf.tempFactory(); } 380 cananian 1.1.2.4 381 cananian 1.1.2.4 HEADER header() { return ss.header; } 382 cananian 1.1.2.4 METHOD method() { return (METHOD) ss.header.next(1); } 383 cananian 1.1.2.4 FOOTER footer() { return (FOOTER) ss.header.next(0); } 384 cananian 1.1.2.4 385 cananian 1.1.2.4 MergeMap mergeMap() { return ss.mergeMap; } 386 cananian 1.1.2.4 387 cananian 1.1.2.11 Iterator targets() { 388 pnkfelix 1.1.2.8 final Set s = new HashSet(); 389 cananian 1.1.2.4 targets2set(js, s); 390 cananian 1.1.2.4 targets2set(jlv,s); 391 cananian 1.1.2.11 return s.iterator(); 392 cananian 1.1.2.4 } 393 cananian 1.1.2.4 private void targets2set(final JSRStack jp, final Set s) { 394 cananian 1.1.2.4 for (JSRStack p = jp; p!=null; p=p.next) 395 cananian 1.1.2.11 s.add(p.target); 396 cananian 1.1.2.4 } 397 cananian 1.1.2.4 398 cananian 1.1.2.13 State enterCatch() { return new State(ss, 1, null, null, jlv, calls); } 399 cananian 1.1.2.15 400 cananian 1.1.2.15 Stack todoHandler() { return ss.todoHandler; } 401 cananian 1.1.2.15 402 cananian 1.1.2.15 METHOD fixupHandlers() { 403 cananian 1.1.2.15 // use the transHandler map to add proper edges from METHOD to 404 cananian 1.1.2.15 // all known HANDLER nodes. 405 cananian 1.1.2.15 METHOD qMold = method(); 406 cananian 1.1.2.15 METHOD qM = new METHOD(qf(), qMold, qMold.params(), 407 cananian 1.1.2.15 1 + ss.transHandler.size()/*arity*/); 408 cananian 1.1.2.15 // link up. 409 cananian 1.1.2.15 Edge e = qMold.nextEdge(0); 410 cananian 1.1.2.15 Quad.addEdge(qM, 0, (Quad)e.to(), e.which_pred()); 411 cananian 1.1.2.15 Quad.addEdge(header(), 1, qM, 0); 412 cananian 1.1.2.15 // iterate through handlers, linking them. 413 cananian 1.1.2.15 int i=1; 414 cananian 1.1.2.15 for (Iterator it=ss.transHandler.values().iterator();it.hasNext();) 415 cananian 1.1.2.15 Quad.addEdge(qM, i++, (HANDLER)it.next(), 0); 416 cananian 1.1.2.15 return qM; 417 cananian 1.1.2.15 } 418 cananian 1.1.2.15 HANDLER getHandler(ExceptionEntry tryBlock) { 419 cananian 1.1.2.15 List pair = Arrays.asList(new Object[] { tryBlock, this.calls }); 420 cananian 1.1.2.15 // look up <tryBlock, callStack> tuple. 421 cananian 1.1.2.15 if (ss.transHandler.containsKey(pair)) 422 cananian 1.1.2.15 return (HANDLER) ss.transHandler.get(pair); 423 cananian 1.1.2.15 // ok, hafta make it from scratch. 424 cananian 1.1.2.15 State hS = this.enterCatch(); // preserve callstack. 425 cananian 1.1.2.20 HANDLER h = newHandler(hS, pair, tryBlock.handler(), 426 cananian 1.1.2.20 tryBlock.caughtException()); 427 cananian 1.1.2.15 TransState ts = new TransState(hS, tryBlock.handler(), h, 0); 428 cananian 1.1.2.15 // add handler to 'todo' list. 429 cananian 1.1.2.15 ss.todoHandler.add(ts); 430 cananian 1.1.2.20 // return new handler. 431 cananian 1.1.2.20 return h; 432 cananian 1.1.2.20 } 433 cananian 1.1.2.20 HANDLER newHandler(State s, List hpair, 434 cananian 1.1.2.20 HCodeElement src, HClass caughtException) { 435 cananian 1.1.2.20 HANDLER h = new HANDLER(ss.qf, src, s.stack(0), caughtException, 436 cananian 1.1.2.27 new HANDLER.HashProtectSet()); 437 cananian 1.1.2.21 // null hpair is special: it means we're synthesizing an outer 438 cananian 1.1.2.21 // handler context for a synchronized method. 439 cananian 1.1.2.21 if (hpair==null) 440 cananian 1.1.2.21 hpair=Arrays.asList(new Object[] { null, Default.EMPTY_MAP }); 441 cananian 1.1.2.15 // add <tryBlock, callStack> mapping. 442 cananian 1.1.2.20 ss.transHandler.put(hpair, h); 443 cananian 1.1.2.15 // return new handler. 444 cananian 1.1.2.15 return h; 445 cananian 1.1.2.15 } 446 cananian 1.1.2.4 HandlerSet handlers(Instr orig) { 447 cananian 1.1.2.4 HandlerSet hs = null; 448 cananian 1.1.2.4 for (int i=0; i<ss.tryBlocks.length; i++) 449 cananian 1.1.2.4 if (ss.tryBlocks[i].inTry(orig)) { 450 cananian 1.1.2.15 HANDLER h = getHandler(ss.tryBlocks[i]); 451 cananian 1.1.2.4 hs = new HandlerSet(h, hs); 452 cananian 1.1.2.4 } 453 cananian 1.1.2.4 return hs; 454 cananian 1.1.2.4 } 455 cananian 1.1.2.4 void recordHandler(Instr orig, Quad start, Quad end) { 456 cananian 1.1.2.5 for (HandlerSet hs=handlers(orig); hs!=null; hs=hs.next) 457 cananian 1.1.2.20 recordHandler(hs.h, start, end); 458 cananian 1.1.2.20 } 459 cananian 1.1.2.20 void recordHandler(HANDLER h, Quad start, Quad end) { 460 pnkfelix 1.1.2.8 recordHandler(new HashSet(), start, end, 461 cananian 1.1.2.27 h.protectedSet); 462 cananian 1.1.2.4 } 463 cananian 1.1.2.13 private void recordHandler(Set done, Quad start, Quad end, 464 cananian 1.1.2.27 ProtectedSet s) { 465 cananian 1.1.2.27 s.insert(start); done.add(start); 466 cananian 1.1.2.4 if (start!=end) { 467 cananian 1.1.2.4 Quad next[] = start.next(); 468 cananian 1.1.2.4 for (int i=0; i<next.length; i++) 469 cananian 1.1.2.4 if (!done.contains(next[i])) 470 cananian 1.1.2.4 recordHandler(done, next[i], end, s); 471 cananian 1.1.2.4 } 472 cananian 1.1.2.1 } 473 cananian 1.1.2.13 /** update state when we reach a phi (remove dead return addresses) */ 474 cananian 1.1.2.13 State purgeDead(Instr phi) { 475 cananian 1.1.2.13 Map lv_targets = new HashMap(JSRStack.asMap(jlv)); 476 cananian 1.1.2.13 // remove any targets that are not live at this phi. 477 cananian 1.1.2.13 lv_targets.keySet().retainAll(ss.liveness.liveSet(phi)); 478 cananian 1.1.2.13 // add in targets live in the stack. 479 cananian 1.1.2.13 Set targets = new HashSet(JSRStack.asMap(js).values()); 480 cananian 1.1.2.13 targets.addAll(lv_targets.values()); 481 cananian 1.1.2.13 // now retain only those entries in the call stack 482 cananian 1.1.2.13 // corresponding to live targets. 483 cananian 1.1.2.13 Map ncalls = new HashMap(calls); 484 cananian 1.1.2.13 ncalls.keySet().retainAll(targets); 485 cananian 1.1.2.13 // for efficiency, don't create a new state if maps are identical. 486 cananian 1.1.2.13 return (calls.equals(ncalls)) ? this : 487 cananian 1.1.2.13 new State(ss, stackSize, ls, js, jlv, 488 cananian 1.1.2.13 Collections.unmodifiableMap(ncalls)); 489 cananian 1.1.2.13 } 490 cananian 1.1.2.13 /** return (unmodifiable) call state map. */ 491 cananian 1.1.2.13 Map calls() { return calls; } 492 cananian 1.1.2.13 /** create a new state when we enter a subroutine. */ 493 cananian 1.1.2.13 State enterJSR(InCti jsr, Instr target) { 494 cananian 1.3.2.1 assert !calls.containsKey(target); // no recursiveness. 495 cananian 1.1.2.13 Map ncalls = new HashMap(calls); 496 cananian 1.1.2.13 ncalls.put(target, jsr); 497 cananian 1.1.2.13 return new State(ss, stackSize, ls, js, jlv, 498 cananian 1.1.2.13 Collections.unmodifiableMap(ncalls)) 499 cananian 1.1.2.13 .pushRetAddr(target); 500 cananian 1.1.2.13 } 501 cananian 1.1.2.1 } 502 cananian 1.1.2.4 503 cananian 1.1.2.1 /** Extended state to keep track of translation process. */ 504 cananian 1.1.2.4 static final private class TransState { 505 cananian 1.1.2.4 /** Initial state for translation. */ 506 cananian 1.1.2.4 final State initialState; 507 cananian 1.1.2.4 /** <code>Instr</code> to translate. */ 508 cananian 1.1.2.4 final Instr in; 509 cananian 1.1.2.4 /** <code>Quad</code> to which to append the translation. */ 510 cananian 1.1.2.4 final Quad header; 511 cananian 1.1.2.4 /** Exit edge of <code>header</code> to which to append the 512 cananian 1.1.2.4 * translation. */ 513 cananian 1.1.2.4 final int which_succ; 514 cananian 1.1.2.1 /** Constructor. */ 515 cananian 1.1.2.1 TransState(State initialState, Instr in, Quad header, int which_succ) { 516 cananian 1.1.2.1 this.initialState = initialState; 517 cananian 1.1.2.1 this.in = in; 518 cananian 1.1.2.1 this.header = header; 519 cananian 1.1.2.1 this.which_succ = which_succ; 520 cananian 1.1.2.11 } 521 cananian 1.7 public String toString() { 522 cananian 1.7 return "<"+initialState+", "+ 523 cananian 1.7 "#"+in.getID()+":"+in+", "+ 524 cananian 1.7 "#"+header.getID()+":"+header+", "+which_succ+">"; 525 cananian 1.7 } 526 cananian 1.1.2.1 } 527 cananian 1.1.2.1 528 cananian 1.1.2.4 /** Return a <code>Quad</code> representation of the method code 529 cananian 1.1.2.4 * in <code>bytecode</code>. */ 530 cananian 1.1.2.4 static final Quad trans(harpoon.IR.Bytecode.Code bytecode, 531 cananian 1.1.2.4 harpoon.IR.Quads.Code parent) { 532 cananian 1.1.2.4 HMethod method = bytecode.getMethod(); 533 cananian 1.1.2.4 boolean isStatic = method.isStatic(); 534 cananian 1.1.2.4 int offset = isStatic?0:1; 535 cananian 1.1.2.4 536 cananian 1.1.2.4 ExceptionEntry[] tb = bytecode.getTryBlocks(); 537 cananian 1.1.2.4 538 cananian 1.1.2.4 // Make QuadFactory. 539 cananian 1.1.2.4 QuadFactory qf = parent.qf; 540 cananian 1.1.2.4 541 cananian 1.1.2.4 // Find first bytecode instruction, make header and footer quads. 542 cananian 1.1.2.4 Instr firstInstr = (Instr) bytecode.getRootElement(); 543 cananian 1.1.2.4 544 cananian 1.1.2.4 FOOTER footer = new FOOTER(qf, firstInstr, 1); 545 cananian 1.1.2.4 HEADER header = new HEADER(qf, firstInstr); 546 cananian 1.1.2.4 Quad.addEdge(header, 0, footer, 0); 547 cananian 1.1.2.4 548 cananian 1.1.2.25 // deterimine if this is a synchronized method. 549 cananian 1.1.2.25 boolean isSynchronized=Modifier.isSynchronized(method.getModifiers()); 550 cananian 1.1.2.25 551 cananian 1.1.2.25 // find how much stack to allocate. when translating a synchronized 552 cananian 1.1.2.25 // method, we need at least one stack space (for a constructed try 553 cananian 1.1.2.25 // block) even if the original method needed none. 554 cananian 1.1.2.25 int maxstack = bytecode.getMaxStack(); 555 cananian 1.1.2.25 if (isSynchronized && maxstack < 1) maxstack=1; 556 cananian 1.1.2.25 557 cananian 1.1.2.1 // set up initial state. 558 cananian 1.1.2.25 State s=new State(qf, maxstack, bytecode.getMaxLocals(), 559 cananian 1.1.2.4 tb /* exception handling information */, 560 cananian 1.1.2.12 header /* header quad for method. */, 561 cananian 1.1.2.12 new Liveness(bytecode) /*local variable liveness*/); 562 cananian 1.1.2.4 563 cananian 1.1.2.4 // Make parameter array, then make METHOD. 564 cananian 1.1.2.3 HClass[] paramTypes = method.getParameterTypes(); 565 cananian 1.1.2.4 Temp[] params = new Temp[paramTypes.length+offset]; 566 cananian 1.1.2.1 567 cananian 1.1.2.4 for (int i=0, j=0; i<params.length; i++) { 568 cananian 1.1.2.4 params[i] = s.lv(i+j); 569 cananian 1.1.2.4 if (i>=offset && isLongDouble(paramTypes[i-offset])) j++; 570 cananian 1.1.2.4 } 571 cananian 1.1.2.15 /** Make METHOD with arity 1; we'll fill in the proper arity later. */ 572 cananian 1.1.2.15 METHOD qM = new METHOD(qf, firstInstr, params, 1); 573 cananian 1.1.2.4 Quad.addEdge(header, 1, qM, 0); 574 cananian 1.1.2.4 575 cananian 1.1.2.1 /* From section 8.4.3.5 of the Java Language Specification: */ 576 cananian 1.1.2.1 /* A synchronized method acquires a lock (17.1) before it 577 cananian 1.1.2.1 * executes. For a class (static) method, the lock associated 578 cananian 1.1.2.1 * with the Class object (20.3) for the method's class is 579 cananian 1.1.2.1 * used. For an instance method, the lock associated with 580 cananian 1.1.2.1 * 'this' (the object for which the method was invoked) is 581 cananian 1.1.2.1 * used. These are the same locks that can be used by the 582 cananian 1.1.2.1 * synchronized statement (14.17). */ 583 cananian 1.1.2.1 /* In particular, static synchronized methods are equivalent to: 584 cananian 1.1.2.1 * synchronized (Class.forName("CLASSNAME")) { ...method body... } 585 cananian 1.1.2.1 * wrapped in a catch of ClassNotFoundException. */ 586 cananian 1.1.2.4 587 cananian 1.1.2.1 Temp lock = null; 588 cananian 1.1.2.1 589 cananian 1.1.2.1 // if method is synchronized, place MONITORENTER at top. 590 cananian 1.1.2.4 Quad q = qM; 591 cananian 1.1.2.1 if (isSynchronized) { 592 cananian 1.1.2.1 if (!isStatic) { // virtual synchronized is easy. 593 cananian 1.1.2.4 lock = s.lv(0); // 'this' 594 cananian 1.1.2.3 q = new MONITORENTER(qf, firstInstr, lock); 595 cananian 1.1.2.4 Quad.addEdge(qM, 0, q, 0); 596 cananian 1.1.2.1 } else { // static synchronized, what a kludge. 597 cananian 1.1.2.3 // lock is Class.forName(this.class) 598 cananian 1.1.2.4 lock = new Temp(s.tf(), "lock"); 599 cananian 1.1.2.29 Quad qq1 = new CONST(qf, q, lock, method.getDeclaringClass(), 600 cananian 1.1.2.29 qf.getLinker().forClass(Class.class)); 601 cananian 1.1.2.20 Quad qq2 = new MONITORENTER(qf, q, lock); 602 cananian 1.1.2.1 // okay, link 'em up. 603 cananian 1.1.2.29 Quad.addEdges(new Quad[] { qM, qq1, qq2 }); 604 cananian 1.1.2.20 q = qq2; 605 cananian 1.1.2.1 } 606 cananian 1.1.2.1 } 607 cananian 1.1.2.1 608 cananian 1.1.2.1 // translate using state. 609 cananian 1.1.2.15 trans(new TransState(s, firstInstr, q, 0)); 610 cananian 1.1.2.20 // make new handler for MONITOREXIT if synchronized 611 cananian 1.1.2.20 HANDLER exithand = isSynchronized ? 612 cananian 1.1.2.25 // creating this new handler requires one stack space. 613 cananian 1.1.2.20 s.newHandler(s.enterCatch(), null, q, null) : null; 614 cananian 1.1.2.15 // fixup initial METHOD block to link to the proper # of HANDLERs. 615 cananian 1.1.2.15 qM = s.fixupHandlers(); 616 cananian 1.1.2.1 617 cananian 1.1.2.20 // if method is synchronized, make inclusive HANDLER w/ MONITOREXIT 618 cananian 1.1.2.1 if (isSynchronized) { 619 cananian 1.3.2.1 assert lock!=null; 620 cananian 1.1.2.20 // make HANDLER for all throw exits 621 cananian 1.1.2.20 Quad Qm = new MONITOREXIT(qf, exithand, lock); 622 cananian 1.1.2.20 Quad Qt = new THROW(qf, Qm, exithand.exceptionTemp()); 623 cananian 1.1.2.20 Quad.addEdges(new Quad[] { exithand, Qm, Qt }); 624 cananian 1.1.2.20 s.footer().attach(Qt, 0); 625 cananian 1.1.2.20 // add just about everything to the handler set 626 cananian 1.1.2.20 s.recordHandler(exithand, q.next(0), s.footer()); 627 cananian 1.1.2.20 for (int i=1; i < qM.nextLength(); i++) 628 cananian 1.1.2.22 if (qM.next(i)!=exithand) 629 cananian 1.1.2.22 s.recordHandler(exithand, qM.next(i), s.footer()); 630 cananian 1.8 // don't forget to protect against failures in MONITOREXIT 631 cananian 1.8 exithand.protectedSet.insert(Qm); 632 cananian 1.1.2.20 // now insert MONITOREXIT for all RETURN predecessors of FOOTER 633 cananian 1.1.2.4 for (int i=1; i < s.footer().arity(); i++) { // skip HEADER edge 634 cananian 1.1.2.20 if (!(s.footer().prev(i) instanceof RETURN)) continue; 635 cananian 1.1.2.20 // put a MONITOREXIT before the return. 636 cananian 1.1.2.4 Quad Qexit = s.footer().prev(i); 637 cananian 1.3.2.1 assert Qexit.prev.length==1; // only one predecessor. 638 cananian 1.1.2.20 Qm = new MONITOREXIT(qf, Qexit, lock); 639 cananian 1.1.2.1 Edge e = Qexit.prevEdge(0); 640 cananian 1.1.2.4 Quad.addEdge((Quad)e.from(), e.which_succ(), Qm, 0); 641 cananian 1.1.2.4 Quad.addEdge(Qm, 0, (Quad)e.to(), e.which_pred()); 642 cananian 1.8 exithand.protectedSet.insert(Qm); // protect MONITOREXIT, too. 643 cananian 1.1.2.1 } 644 cananian 1.1.2.1 } 645 cananian 1.1.2.1 646 cananian 1.1.2.1 // return result. 647 cananian 1.1.2.4 return header; 648 cananian 1.1.2.1 } 649 cananian 1.1.2.1 650 cananian 1.1.2.4 /** Translate blocks starting with the given <code>TransState</code>s.<p> 651 cananian 1.1.2.15 * Start at <code>ts0.in</code> using <code>ts0.initialState</code>. */ 652 cananian 1.1.2.15 static final void trans(TransState ts0) { 653 cananian 1.1.2.15 State s = ts0.initialState; // abbreviation. 654 cananian 1.1.2.15 655 cananian 1.1.2.4 Stack todo = new Stack(); 656 cananian 1.1.2.15 todo.push(ts0); 657 cananian 1.1.2.1 658 cananian 1.1.2.15 // pull stuff to do from todo stack and handler todo stack. 659 cananian 1.1.2.15 while (! (todo.empty() && s.todoHandler().empty())) { 660 cananian 1.1.2.15 TransState ts = (TransState) 661 cananian 1.1.2.15 ( (!todo.empty()) ? todo.pop() : s.todoHandler().pop() ); 662 cananian 1.1.2.1 663 cananian 1.1.2.4 TransState nts[] = transInstr(ts); 664 cananian 1.1.2.4 for (int i=nts.length-1; i>=0; i--) 665 cananian 1.1.2.4 todo.push(nts[i]); 666 cananian 1.1.2.4 } 667 cananian 1.1.2.13 // JSR/RETs leave null edges into PHIs 668 cananian 1.7 s.mergeMap().fixupPhis(); 669 cananian 1.5 // XXX: Email me <cananian@mit.edu> if you see these assertions fail! 670 cananian 1.7 // The com.sun.media.jai.util.Service class from Sun JAI 671 cananian 1.7 // used to expose this bug: fixupPhis() ended up adding new 672 cananian 1.7 // handlers to todoHandler via its call to s.recordHandler(), 673 cananian 1.7 // requiring *more* fixup. BUT this was (in this case, at 674 cananian 1.7 // least) because the state fixupPhis() was using was bogus. 675 cananian 1.7 // I don't *think* there is any valid case where fixupPhis() 676 cananian 1.7 // with the correct State will create a new handler, but if 677 cananian 1.7 // there is, these assertions will fail and someone will let 678 cananian 1.7 // me know. Right? 679 cananian 1.5 assert todo.empty(); 680 cananian 1.5 assert s.todoHandler().empty(); 681 cananian 1.1.2.1 // done. 682 cananian 1.1.2.1 return; 683 cananian 1.1.2.1 } 684 cananian 1.1.2.1 685 cananian 1.1.2.4 /** Translate a single instruction. 686 cananian 1.1.2.1 * @return the <code>TransState</code>s of the following instructions. 687 cananian 1.1.2.1 */ 688 cananian 1.1.2.4 static final TransState[] transInstr(TransState ts) { 689 cananian 1.1.2.4 Instr in = ts.in; byte opc = in.getOpcode(); 690 cananian 1.1.2.1 // Dispatch to correct specific function. 691 cananian 1.1.2.4 if (in instanceof InGen) return transInGen(ts); 692 cananian 1.1.2.4 if (in instanceof InSwitch) return transInSwitch(ts); 693 cananian 1.1.2.4 if (in instanceof InCti) return transInCti(ts); 694 cananian 1.1.2.4 if (in instanceof InMerge) return transInMerge(ts); 695 cananian 1.1.2.1 throw new Error("Unknown Instr type."); 696 cananian 1.1.2.1 } 697 cananian 1.1.2.1 698 cananian 1.1.2.1 /** Translate an <code>InGen</code>. 699 cananian 1.1.2.4 * @return a <code>TransState[]</code> of length one. */ 700 cananian 1.1.2.4 static final TransState[] transInGen(TransState ts) { 701 cananian 1.1.2.4 QuadFactory qf = ts.initialState.qf(); 702 cananian 1.1.2.1 InGen in = (InGen) ts.in; 703 cananian 1.3.2.1 Instr inNext = in.next(0); // assert in.next().length==1; 704 cananian 1.1.2.4 byte opcode = in.getOpcode(); 705 cananian 1.1.2.1 State s = ts.initialState; 706 cananian 1.1.2.4 TransState[] r = null; 707 cananian 1.1.2.1 State ns; 708 cananian 1.1.2.1 Quad q; 709 cananian 1.1.2.1 Quad last = null; int which_succ = 0; 710 cananian 1.1.2.1 711 cananian 1.1.2.4 switch(opcode) { 712 cananian 1.1.2.1 case Op.AALOAD: 713 cananian 1.1.2.1 case Op.BALOAD: 714 cananian 1.1.2.1 case Op.CALOAD: 715 cananian 1.1.2.1 case Op.DALOAD: 716 cananian 1.1.2.1 case Op.FALOAD: 717 cananian 1.1.2.1 case Op.IALOAD: 718 cananian 1.1.2.1 case Op.LALOAD: 719 cananian 1.1.2.1 case Op.SALOAD: 720 cananian 1.1.2.1 { 721 cananian 1.1.2.4 if (opcode==Op.DALOAD || 722 cananian 1.1.2.4 opcode==Op.LALOAD) 723 cananian 1.1.2.4 ns = s.pop(2).pushLong(); // 64-bit val. 724 cananian 1.1.2.1 else 725 cananian 1.1.2.1 ns = s.pop(2).push(); // 32-bit val 726 cananian 1.1.2.28 HClass type; 727 cananian 1.1.2.28 switch(opcode) { 728 cananian 1.1.2.28 case Op.BALOAD: type = HClass.Byte; break; 729 cananian 1.1.2.28 case Op.CALOAD: type = HClass.Char; break; 730 cananian 1.1.2.28 case Op.DALOAD: type = HClass.Double; break; 731 cananian 1.1.2.28 case Op.FALOAD: type = HClass.Float; break; 732 cananian 1.1.2.28 case Op.IALOAD: type = HClass.Int; break; 733 cananian 1.1.2.28 case Op.LALOAD: type = HClass.Long; break; 734 cananian 1.1.2.28 case Op.SALOAD: type = HClass.Short; break; 735 cananian 1.1.2.28 case Op.AALOAD: type = qf.getLinker().forName("java.lang.Object"); 736 cananian 1.1.2.28 break; 737 cananian 1.1.2.28 default: throw new Error("impossible"); 738 cananian 1.1.2.28 } 739 cananian 1.1.2.1 Temp Tobj = s.stack(1); 740 cananian 1.1.2.1 Temp Tindex= s.stack(0); 741 cananian 1.1.2.28 q = new AGET(qf, in, ns.stack(0), Tobj, Tindex, type); 742 cananian 1.1.2.1 break; 743 cananian 1.1.2.1 } 744 cananian 1.1.2.1 case Op.AASTORE: 745 cananian 1.1.2.1 case Op.BASTORE: 746 cananian 1.1.2.1 case Op.CASTORE: 747 cananian 1.1.2.1 case Op.DASTORE: 748 cananian 1.1.2.1 case Op.FASTORE: 749 cananian 1.1.2.1 case Op.IASTORE: 750 cananian 1.1.2.1 case Op.LASTORE: 751 cananian 1.1.2.1 case Op.SASTORE: 752 cananian 1.1.2.1 { 753 cananian 1.1.2.28 HClass type; 754 cananian 1.1.2.28 switch(opcode) { 755 cananian 1.1.2.28 case Op.BASTORE: type = HClass.Byte; break; 756 cananian 1.1.2.28 case Op.CASTORE: type = HClass.Char; break; 757 cananian 1.1.2.28 case Op.DASTORE: type = HClass.Double; break; 758 cananian 1.1.2.28 case Op.FASTORE: type = HClass.Float; break; 759 cananian 1.1.2.28 case Op.IASTORE: type = HClass.Int; break; 760 cananian 1.1.2.28 case Op.LASTORE: type = HClass.Long; break; 761 cananian 1.1.2.28 case Op.SASTORE: type = HClass.Short; break; 762 cananian 1.1.2.28 case Op.AASTORE: type = qf.getLinker().forName("java.lang.Object"); 763 cananian 1.1.2.28 break; 764 cananian 1.1.2.28 default: throw new Error("impossible"); 765 cananian 1.1.2.28 } 766 cananian 1.1.2.1 Temp Tobj, Tindex, Tsrc; 767 cananian 1.1.2.4 if (opcode==Op.DASTORE || 768 cananian 1.1.2.4 opcode==Op.LASTORE) { // 64-bit val. 769 cananian 1.1.2.1 ns = s.pop(4); 770 cananian 1.1.2.1 Tobj = s.stack(3); 771 cananian 1.1.2.1 Tindex = s.stack(2); 772 cananian 1.1.2.1 Tsrc = s.stack(0); 773 cananian 1.1.2.1 } else { // 32-bit val. 774 cananian 1.1.2.1 ns = s.pop(3); 775 cananian 1.1.2.1 Tobj = s.stack(2); 776 cananian 1.1.2.1 Tindex = s.stack(1); 777 cananian 1.1.2.1 Tsrc = s.stack(0); 778 cananian 1.1.2.1 } 779 cananian 1.1.2.1 780 cananian 1.1.2.1 // the actual operation. 781 cananian 1.1.2.28 q = new ASET(qf, in, Tobj, Tindex, Tsrc, type); 782 cananian 1.1.2.1 break; 783 cananian 1.1.2.1 } 784 cananian 1.1.2.1 case Op.ACONST_NULL: 785 cananian 1.1.2.4 ns = s.push(); 786 cananian 1.1.2.4 q = new CONST(qf, in, ns.stack(0), null, HClass.Void); 787 cananian 1.1.2.1 break; 788 cananian 1.1.2.1 case Op.ALOAD: 789 cananian 1.1.2.1 case Op.ALOAD_0: 790 cananian 1.1.2.1 case Op.ALOAD_1: 791 cananian 1.1.2.1 case Op.ALOAD_2: 792 cananian 1.1.2.1 case Op.ALOAD_3: 793 cananian 1.1.2.1 { 794 cananian 1.1.2.1 OpLocalVariable opd = (OpLocalVariable) in.getOperand(0); 795 cananian 1.1.2.4 // could be a return address, so fix up the stack. 796 cananian 1.1.2.4 ns = s.push().trackLV2S(opd.getIndex(), 0); 797 cananian 1.1.2.4 q = new MOVE(qf, in, ns.stack(0), s.lv(opd.getIndex())); 798 cananian 1.1.2.1 break; 799 cananian 1.1.2.1 } 800 cananian 1.1.2.1 case Op.ANEWARRAY: 801 cananian 1.1.2.1 { 802 cananian 1.1.2.1 OpClass opd = (OpClass) in.getOperand(0); 803 cananian 1.1.2.26 HClass hc = qf.getLinker().forDescriptor("[" + 804 cananian 1.1.2.1 opd.value().getDescriptor()); 805 cananian 1.1.2.1 ns = s.pop().push(); 806 cananian 1.1.2.4 q = new ANEW(qf, in, ns.stack(0), hc, 807 cananian 1.1.2.4 new Temp[] { s.stack(0) }); 808 cananian 1.1.2.1 break; 809 cananian 1.1.2.1 } 810 cananian 1.1.2.1 case Op.ARRAYLENGTH: 811 cananian 1.1.2.1 { 812 cananian 1.1.2.1 ns = s.pop().push(); 813 cananian 1.1.2.4 q = new ALENGTH(qf, in, ns.stack(0), s.stack(0)); 814 cananian 1.1.2.1 break; 815 cananian 1.1.2.1 } 816 cananian 1.1.2.1 case Op.ASTORE: 817 cananian 1.1.2.1 case Op.ASTORE_0: 818 cananian 1.1.2.1 case Op.ASTORE_1: 819 cananian 1.1.2.1 case Op.ASTORE_2: 820 cananian 1.1.2.1 case Op.ASTORE_3: 821 cananian 1.1.2.1 { 822 cananian 1.1.2.1 OpLocalVariable opd = (OpLocalVariable) in.getOperand(0); 823 cananian 1.1.2.4 // value could be return address so track it. 824 cananian 1.1.2.4 ns = s.trackS2LV(0, opd.getIndex()).pop(); 825 cananian 1.1.2.4 q = new MOVE(qf, in, ns.lv(opd.getIndex()), s.stack(0)); 826 cananian 1.1.2.1 break; 827 cananian 1.1.2.1 } 828 cananian 1.1.2.1 case Op.BIPUSH: 829 cananian 1.1.2.1 case Op.SIPUSH: 830 cananian 1.1.2.1 { 831 cananian 1.1.2.4 OpConstant opd = (OpConstant) in.getOperand(0); 832 cananian 1.1.2.4 int val = ((Number)opd.getValue()).intValue(); 833 cananian 1.1.2.4 ns = s.push(); 834 cananian 1.1.2.4 q = new CONST(qf, in, ns.stack(0), new Integer(val), HClass.Int); 835 cananian 1.1.2.4 break; 836 cananian 1.1.2.1 } 837 cananian 1.1.2.1 case Op.CHECKCAST: 838 cananian 1.1.2.1 { 839 cananian 1.1.2.4 OpClass opd = (OpClass) in.getOperand(0); 840 cananian 1.1.2.4 Temp Tobj = s.stack(0); 841 cananian 1.1.2.6 q = new TYPECAST(qf, in, Tobj, opd.value()); 842 cananian 1.1.2.4 ns = s; 843 cananian 1.1.2.4 break; 844 cananian 1.1.2.1 } 845 cananian 1.1.2.1 case Op.D2F: 846 cananian 1.1.2.1 case Op.D2I: 847 cananian 1.1.2.1 case Op.L2F: 848 cananian 1.1.2.1 case Op.L2I: 849 cananian 1.3.2.1 ns = s.pop(2).push(); assert s.isLong(0); 850 cananian 1.1.2.4 q = new OPER(qf, in, Qop.forString(Op.toString(opcode)), 851 cananian 1.1.2.1 ns.stack(0), new Temp[] { s.stack(0) }); 852 cananian 1.1.2.1 break; 853 cananian 1.1.2.1 case Op.D2L: 854 cananian 1.1.2.1 case Op.L2D: 855 cananian 1.3.2.1 ns = s.pop(2).pushLong(); assert s.isLong(0) && ns.isLong(0); 856 cananian 1.1.2.4 q = new OPER(qf, in, Qop.forString(Op.toString(opcode)), 857 cananian 1.1.2.1 ns.stack(0), new Temp[] { s.stack(0) }); 858 cananian 1.1.2.1 break; 859 cananian 1.1.2.1 case Op.DADD: 860 cananian 1.1.2.1 case Op.DDIV: 861 cananian 1.1.2.1 case Op.DMUL: 862 cananian 1.1.2.1 case Op.DREM: 863 cananian 1.1.2.1 case Op.LADD: 864 cananian 1.1.2.1 case Op.LAND: 865 cananian 1.1.2.1 case Op.LMUL: 866 cananian 1.1.2.1 case Op.LOR: 867 cananian 1.1.2.1 case Op.LXOR: 868 cananian 1.1.2.4 case Op.LDIV: 869 cananian 1.1.2.4 case Op.LREM: 870 cananian 1.1.2.4 ns = s.pop(4).pushLong(); 871 cananian 1.3.2.1 assert ns.isLong(0) && s.isLong(0) && s.isLong(2); 872 cananian 1.1.2.4 q = new OPER(qf, in, Qop.forString(Op.toString(opcode)), 873 cananian 1.1.2.1 ns.stack(0), new Temp[] { s.stack(2), s.stack(0) }); 874 cananian 1.1.2.1 break; 875 cananian 1.1.2.9 case Op.DSUB: 876 cananian 1.1.2.9 case Op.LSUB: 877 cananian 1.1.2.9 { 878 cananian 1.1.2.9 ns = s.pop(4).pushLong(); 879 cananian 1.3.2.1 assert ns.isLong(0) && s.isLong(0) && s.isLong(2); 880 cananian 1.1.2.9 Quad q0 = new OPER(qf, in, (opcode==Op.DSUB)?Qop.DNEG:Qop.LNEG, 881 cananian 1.1.2.9 s.stack(0), new Temp[] { s.stack(0) }); 882 cananian 1.1.2.9 Quad q1 = new OPER(qf, in, (opcode==Op.DSUB)?Qop.DADD:Qop.LADD, 883 cananian 1.1.2.9 ns.stack(0), new Temp[]{s.stack(2),s.stack(0)}); 884 cananian 1.1.2.9 Quad.addEdge(q0, 0, q1, 0); 885 cananian 1.1.2.9 q = q0; last = q1; 886 cananian 1.1.2.9 break; 887 cananian 1.1.2.9 } 888 cananian 1.1.2.1 case Op.DCMPG: 889 cananian 1.1.2.1 case Op.DCMPL: 890 cananian 1.1.2.4 switch (inNext.getOpcode()) { 891 cananian 1.1.2.4 case Op.IFLT: case Op.IFGT: // special cases. 892 cananian 1.1.2.4 case Op.IFLE: case Op.IFGE: 893 cananian 1.1.2.4 case Op.IFEQ: case Op.IFNE: 894 cananian 1.1.2.4 { 895 cananian 1.1.2.4 boolean invert = false, swap = false; 896 cananian 1.1.2.4 int op; 897 cananian 1.1.2.4 switch (inNext.getOpcode()) { 898 cananian 1.1.2.4 case Op.IFNE: invert = true; 899 cananian 1.1.2.4 case Op.IFEQ: op = Qop.DCMPEQ; break; 900 cananian 1.1.2.4 case Op.IFLT: swap = true; 901 cananian 1.1.2.4 case Op.IFGT: op = Qop.DCMPGT; break; 902 cananian 1.1.2.4 case Op.IFLE: swap = true; 903 cananian 1.1.2.4 case Op.IFGE: op = Qop.DCMPGE; break; 904 cananian 1.1.2.4 default: throw new Error("Impossible!"); 905 cananian 1.1.2.4 } 906 cananian 1.1.2.4 // NaN handling. 907 cananian 1.1.2.4 if (op!=Qop.DCMPEQ && 908 cananian 1.1.2.4 ((opcode==Op.DCMPG && !swap) || 909 cananian 1.1.2.4 (opcode==Op.DCMPL && swap) ) ) { // swap handling of NaN 910 cananian 1.1.2.4 swap=!swap; invert=true; 911 cananian 1.1.2.4 op=(op==Qop.DCMPGT)?Qop.DCMPGE:Qop.DCMPGT; 912 cananian 1.1.2.4 } 913 cananian 1.1.2.4 ns = s.pop(4); // IF?? pops off result of DCMP? 914 cananian 1.1.2.4 q = new OPER(qf, in, op, ns.extra(0), 915 cananian 1.1.2.4 swap 916 cananian 1.1.2.4 ? new Temp[] { s.stack(0), s.stack(2) } 917 cananian 1.1.2.4 : new Temp[] { s.stack(2), s.stack(0) } ); 918 cananian 1.1.2.4 last = new CJMP(qf, in, ns.extra(0), new Temp[0]); 919 cananian 1.1.2.4 Quad.addEdge(q, 0, last, 0); 920 cananian 1.1.2.4 r = new TransState[] { 921 cananian 1.1.2.4 new TransState(ns, inNext.next(0), last, invert?1:0), 922 cananian 1.1.2.4 new TransState(ns, inNext.next(1), last, invert?0:1) 923 cananian 1.1.2.4 }; 924 cananian 1.1.2.4 break; // done translating. 925 cananian 1.1.2.4 } 926 cananian 1.1.2.4 default: // use full expansion of dcmp 927 cananian 1.1.2.1 { 928 cananian 1.1.2.4 boolean isDCMPG = (opcode==Op.DCMPG); 929 cananian 1.3.2.1 ns = s.pop(4).push(); assert s.isLong(0) && s.isLong(2); 930 cananian 1.1.2.3 Quad q0 = new OPER(qf, in, Qop.DCMPGT, s.extra(0), 931 cananian 1.1.2.1 isDCMPG ? 932 cananian 1.1.2.1 new Temp[] { s.stack(0), s.stack(2) } : 933 cananian 1.1.2.1 new Temp[] { s.stack(2), s.stack(0) } ); 934 cananian 1.1.2.3 Quad q1 = new CJMP(qf, in, q0.def()[0], new Temp[0]); 935 cananian 1.1.2.3 Quad q2 = new OPER(qf, in, Qop.DCMPEQ, s.extra(0), 936 cananian 1.1.2.1 new Temp[] { s.stack(2), s.stack(0) }); 937 cananian 1.1.2.3 Quad q3 = new CJMP(qf, in, q2.def()[0], new Temp[0]); 938 cananian 1.1.2.3 Quad q4 = new CONST(qf, in, ns.stack(0), new Integer(-1), HClass.Int); 939 cananian 1.1.2.3 Quad q5 = new CONST(qf, in, ns.stack(0), new Integer( 0), HClass.Int); 940 cananian 1.1.2.3 Quad q6 = new CONST(qf, in, ns.stack(0), new Integer( 1), HClass.Int); 941 cananian 1.1.2.3 Quad q7 = new PHI(qf, in, new Temp[0], 3); 942 cananian 1.1.2.1 // link. 943 cananian 1.1.2.1 Quad.addEdge(q0, 0, q1, 0); 944 cananian 1.1.2.1 Quad.addEdge(q1, 0, q2, 0); 945 cananian 1.1.2.1 Quad.addEdge(q1, 1, isDCMPG?q4:q6, 0); 946 cananian 1.1.2.1 Quad.addEdge(q2, 0, q3, 0); 947 cananian 1.1.2.1 Quad.addEdge(q3, 0, isDCMPG?q6:q4, 0); 948 cananian 1.1.2.1 Quad.addEdge(q3, 1, q5, 0); 949 cananian 1.1.2.1 Quad.addEdge(q4, 0, q7, 0); 950 cananian 1.1.2.1 Quad.addEdge(q5, 0, q7, 1); 951 cananian 1.1.2.1 Quad.addEdge(q6, 0, q7, 2); 952 cananian 1.1.2.1 // setup next state. 953 cananian 1.1.2.1 q = q0; last = q7; 954 cananian 1.1.2.1 break; 955 cananian 1.1.2.1 } 956 cananian 1.1.2.4 } 957 cananian 1.1.2.4 break; 958 cananian 1.1.2.1 case Op.DCONST_0: 959 cananian 1.1.2.1 case Op.DCONST_1: 960 cananian 1.1.2.1 case Op.LCONST_0: 961 cananian 1.1.2.1 case Op.LCONST_1: 962 cananian 1.1.2.1 { 963 cananian 1.1.2.1 OpConstant opd = (OpConstant) in.getOperand(0); 964 cananian 1.1.2.4 ns = s.pushLong(); 965 cananian 1.1.2.4 q = new CONST(qf, in, ns.stack(0), 966 cananian 1.1.2.4 opd.getValue(), opd.getType()); 967 cananian 1.1.2.1 break; 968 cananian 1.1.2.1 } 969 cananian 1.1.2.1 case Op.DLOAD: 970 cananian 1.1.2.1 case Op.DLOAD_0: 971 cananian 1.1.2.1 case Op.DLOAD_1: 972 cananian 1.1.2.1 case Op.DLOAD_2: 973 cananian 1.1.2.1 case Op.DLOAD_3: 974 cananian 1.1.2.1 case Op.LLOAD: 975 cananian 1.1.2.1 case Op.LLOAD_0: 976 cananian 1.1.2.1 case Op.LLOAD_1: 977 cananian 1.1.2.1 case Op.LLOAD_2: 978 cananian 1.1.2.1 case Op.LLOAD_3: 979 cananian 1.1.2.1 { 980 cananian 1.1.2.1 OpLocalVariable opd = (OpLocalVariable) in.getOperand(0); 981 cananian 1.1.2.4 ns = s.pushLong(); 982 cananian 1.1.2.4 q = new MOVE(qf, in, ns.stack(0), s.lv(opd.getIndex())); 983 cananian 1.1.2.1 break; 984 cananian 1.1.2.1 } 985 cananian 1.1.2.1 case Op.DNEG: 986 cananian 1.1.2.1 case Op.LNEG: 987 cananian 1.3.2.1 ns = s.pop(2).pushLong(); assert s.isLong(0); 988 cananian 1.1.2.4 q = new OPER(qf, in, Qop.forString(Op.toString(opcode)), 989 cananian 1.1.2.1 ns.stack(0), new Temp[] {s.stack(0)}); 990 cananian 1.1.2.1 break; 991 cananian 1.1.2.1 case Op.DSTORE: 992 cananian 1.1.2.1 case Op.DSTORE_0: 993 cananian 1.1.2.1 case Op.DSTORE_1: 994 cananian 1.1.2.1 case Op.DSTORE_2: 995 cananian 1.1.2.1 case Op.DSTORE_3: 996 cananian 1.1.2.1 case Op.LSTORE: 997 cananian 1.1.2.1 case Op.LSTORE_0: 998 cananian 1.1.2.1 case Op.LSTORE_1: 999 cananian 1.1.2.1 case Op.LSTORE_2: 1000 cananian 1.1.2.1 case Op.LSTORE_3: 1001 cananian 1.1.2.1 { 1002 cananian 1.1.2.1 OpLocalVariable opd = (OpLocalVariable) in.getOperand(0); 1003 cananian 1.1.2.4 // values can't be return addresses, so clear tag in stack. 1004 cananian 1.3.2.1 ns = s.pop(2).clearLV(opd.getIndex()); assert s.isLong(0); 1005 cananian 1.1.2.4 q = new MOVE(qf, in, ns.lv(opd.getIndex()), s.stack(0)); 1006 cananian 1.1.2.1 break; 1007 cananian 1.1.2.1 } 1008 cananian 1.1.2.1 case Op.DUP: 1009 cananian 1.1.2.4 // value could be a return address so track it. 1010 cananian 1.3.2.1 ns = s.push().trackS2S(s, 0, 0); assert !s.isLong(0); 1011 cananian 1.1.2.4 q = new MOVE(qf, in, ns.stack(0), s.stack(0)); 1012 cananian 1.1.2.1 break; 1013 cananian 1.1.2.1 case Op.DUP_X1: 1014 cananian 1.1.2.4 { 1015 cananian 1.3.2.1 ns = s.pop(2).push(3); assert !s.isLong(0) && !s.isLong(1); 1016 cananian 1.1.2.4 Quad q0 = new MOVE(qf, in, ns.stack(0), s.stack(0)); 1017 cananian 1.1.2.4 Quad q1 = new MOVE(qf, in, ns.stack(1), s.stack(1)); 1018 cananian 1.1.2.4 Quad q2 = new MOVE(qf, in, ns.stack(2), ns.stack(0)); 1019 cananian 1.1.2.4 Quad.addEdges(new Quad[] { q0, q1, q2 }); 1020 cananian 1.1.2.4 q = q0; 1021 cananian 1.1.2.4 last = q2; 1022 cananian 1.1.2.4 // track possible return addresses 1023 cananian 1.1.2.4 ns = ns.trackS2S(s, 0, 0).trackS2S(s, 1, 1).trackS2S(s, 0, 2); 1024 cananian 1.1.2.4 break; 1025 cananian 1.1.2.4 } 1026 cananian 1.1.2.4 case Op.DUP_X2: // operates differently if stack contains a long value 1027 cananian 1.1.2.4 { 1028 cananian 1.3.2.1 assert !s.isLong(0); 1029 cananian 1.1.2.4 // don't forget to track possible return addresses. 1030 cananian 1.1.2.4 if (s.isLong(1)) { 1031 cananian 1.1.2.4 ns = s.pop(3).push().pushLong().push(); 1032 cananian 1.1.2.4 ns = ns.trackS2S(s, 0, 0).trackS2S(s, 0, 3); // retadd != long 1033 cananian 1.1.2.4 } else { 1034 cananian 1.1.2.4 ns = s.pop(3).push(4); 1035 cananian 1.1.2.4 ns = ns.trackS2S(s, 0, 0).trackS2S(s, 1, 1) 1036 cananian 1.1.2.4 .trackS2S(s, 2, 2).trackS2S(s, 0, 3); 1037 cananian 1.1.2.4 } 1038 cananian 1.1.2.4 Quad q0 = new MOVE(qf, in, ns.stack(0), s.stack(0)); 1039 cananian 1.1.2.4 Quad q1 = new MOVE(qf, in, ns.stack(1), s.stack(1)); 1040 cananian 1.1.2.4 Quad q2 = new MOVE(qf, in, ns.stack(2), s.stack(2)); 1041 cananian 1.1.2.4 Quad q3 = new MOVE(qf, in, ns.stack(3), ns.stack(0)); 1042 cananian 1.1.2.4 if (s.isLong(1)) 1043 cananian 1.1.2.4 Quad.addEdges(new Quad[] { q0, q1, q3 }); 1044 cananian 1.1.2.4 else 1045 cananian 1.1.2.4 Quad.addEdges(new Quad[] { q0, q1, q2, q3 }); 1046 cananian 1.1.2.4 q = q0; last = q3; 1047 cananian 1.1.2.1 break; 1048 cananian 1.1.2.4 } 1049 cananian 1.1.2.4 case Op.DUP2: // either dup two short values or one long value. 1050 cananian 1.1.2.4 if (s.isLong(0)) { 1051 cananian 1.1.2.4 ns = s.pushLong(); 1052 cananian 1.1.2.4 q = new MOVE(qf, in, ns.stack(0), s.stack(0)); 1053 cananian 1.1.2.4 } else { 1054 cananian 1.1.2.4 // could be return address. 1055 cananian 1.1.2.4 ns = s.push(2).trackS2S(s, 0, 0).trackS2S(s, 1, 1); 1056 cananian 1.1.2.4 Quad q0 = new MOVE(qf, in, ns.stack(0), s.stack(0)); 1057 cananian 1.1.2.4 Quad q1 = new MOVE(qf, in, ns.stack(1), s.stack(1)); 1058 cananian 1.1.2.4 Quad.addEdges(new Quad[] { q0, q1 } ); 1059 cananian 1.1.2.4 q = q0; last = q1; 1060 cananian 1.1.2.4 } 1061 cananian 1.1.2.4 break; 1062 cananian 1.1.2.4 case Op.DUP2_X1: // again, different if top value is long. 1063 cananian 1.3.2.1 assert !s.isLong(2); 1064 cananian 1.1.2.4 if (s.isLong(0)) { // only !long in center could be ret addr. 1065 cananian 1.1.2.4 ns = s.pop(3).pushLong().push().pushLong().trackS2S(s, 2, 2); 1066 cananian 1.1.2.4 Quad q0 = new MOVE(qf, in, ns.stack(0), s.stack(0)); 1067 cananian 1.1.2.4 Quad q1 = new MOVE(qf, in, ns.stack(2), s.stack(2)); 1068 cananian 1.1.2.4 Quad q2 = new MOVE(qf, in, ns.stack(3), ns.stack(0)); 1069 cananian 1.1.2.4 Quad.addEdges(new Quad[] { q0, q1, q2 }); 1070 cananian 1.1.2.4 q = q0; last = q2; 1071 cananian 1.1.2.4 } else { // ack. lots of possible return addresses. 1072 cananian 1.1.2.4 ns = s.pop(3).push(5); 1073 cananian 1.1.2.4 ns = ns.trackS2S(s, 0, 0).trackS2S(s, 1, 1).trackS2S(s, 2, 2) 1074 cananian 1.1.2.4 .trackS2S(s, 0, 3).trackS2S(s, 1, 4); 1075 cananian 1.1.2.4 Quad q0 = new MOVE(qf, in, ns.stack(0), s.stack(0)); 1076 cananian 1.1.2.4 Quad q1 = new MOVE(qf, in, ns.stack(1), s.stack(1)); 1077 cananian 1.1.2.4 Quad q2 = new MOVE(qf, in, ns.stack(2), s.stack(2)); 1078 cananian 1.1.2.4 Quad q3 = new MOVE(qf, in, ns.stack(3), ns.stack(0)); 1079 cananian 1.1.2.4 Quad q4 = new MOVE(qf, in, ns.stack(4), ns.stack(1)); 1080 cananian 1.1.2.4 Quad.addEdges(new Quad[] { q0, q1, q2, q3, q4 }); 1081 cananian 1.1.2.4 q = q0; last = q4; 1082 cananian 1.1.2.4 } 1083 cananian 1.1.2.4 break; 1084 cananian 1.1.2.4 case Op.DUP2_X2: // ack. top and next could both be long. 1085 cananian 1.1.2.4 { 1086 cananian 1.1.2.4 if (s.isLong(0)) 1087 cananian 1.1.2.4 ns = s.isLong(2) 1088 cananian 1.1.2.4 ? s.pushLong() 1089 cananian 1.1.2.4 : s.pop(4).pushLong().push(2).pushLong() 1090 cananian 1.1.2.4 .trackS2S(s, 2, 2).trackS2S(s, 3, 3); 1091 cananian 1.1.2.4 else 1092 cananian 1.1.2.4 ns = s.isLong(2) 1093 cananian 1.1.2.4 ? s.pop(4).push(2).pushLong().push(2) 1094 cananian 1.1.2.4 .trackS2S(s, 0, 0).trackS2S(s, 1, 1) 1095 cananian 1.1.2.4 .trackS2S(s, 0, 4).trackS2S(s, 1, 5) 1096 cananian 1.1.2.4 : s.pop(4).push(6) // ack. lots of possible ret addresses 1097 cananian 1.1.2.4 .trackS2S(s, 0, 0).trackS2S(s, 1, 1) 1098 cananian 1.1.2.4 .trackS2S(s, 2, 2).trackS2S(s, 3, 3) 1099 cananian 1.1.2.4 .trackS2S(s, 0, 4).trackS2S(s, 1, 5); 1100 cananian 1.1.2.4 Quad q0 = new MOVE(qf, in, ns.stack(0), s.stack(0)); 1101 cananian 1.1.2.4 Quad q1 = new MOVE(qf, in, ns.stack(1), s.stack(1)); 1102 cananian 1.1.2.4 Quad q2 = new MOVE(qf, in, ns.stack(2), s.stack(2)); 1103 cananian 1.1.2.4 Quad q3 = new MOVE(qf, in, ns.stack(3), s.stack(3)); 1104 cananian 1.1.2.4 Quad q4 = new MOVE(qf, in, ns.stack(4), ns.stack(0)); 1105 cananian 1.1.2.4 Quad q5 = new MOVE(qf, in, ns.stack(5), ns.stack(1)); 1106 cananian 1.1.2.4 if (s.isLong(0)) 1107 cananian 1.1.2.4 Quad.addEdge(q0, 0, q2, 0); 1108 cananian 1.1.2.4 else { 1109 cananian 1.1.2.4 Quad.addEdges(new Quad[] { q0, q1, q2 }); 1110 cananian 1.1.2.4 Quad.addEdge(q4, 0, q5, 0); 1111 cananian 1.1.2.4 } 1112 cananian 1.1.2.4 if (s.isLong(2)) 1113 cananian 1.1.2.4 Quad.addEdge(q2, 0, q4, 0); 1114 cananian 1.1.2.4 else 1115 cananian 1.1.2.4 Quad.addEdges(new Quad[] { q2, q3, q4 }); 1116 cananian 1.1.2.4 q = q0; 1117 cananian 1.1.2.4 last = s.isLong(0)?q4:q5; 1118 cananian 1.3.2.1 assert s.isLong(0)==ns.isLong(0); 1119 cananian 1.3.2.1 assert s.isLong(0)==ns.isLong(4); 1120 cananian 1.3.2.1 assert s.isLong(2)==ns.isLong(2); 1121 cananian 1.1.2.1 break; 1122 cananian 1.1.2.4 } 1123 cananian 1.1.2.1 case Op.F2D: 1124 cananian 1.1.2.1 case Op.F2L: 1125 cananian 1.1.2.1 case Op.I2D: 1126 cananian 1.1.2.1 case Op.I2L: 1127 cananian 1.1.2.4 ns = s.pop().pushLong(); 1128 cananian 1.1.2.4 q = new OPER(qf, in, Qop.forString(Op.toString(opcode)), 1129 cananian 1.1.2.1 ns.stack(0), new Temp[] {s.stack(0)}); 1130 cananian 1.1.2.1 break; 1131 cananian 1.1.2.1 case Op.F2I: 1132 cananian 1.1.2.1 case Op.I2B: 1133 cananian 1.1.2.1 case Op.I2C: 1134 cananian 1.1.2.1 case Op.I2F: 1135 cananian 1.1.2.1 case Op.I2S: 1136 cananian 1.1.2.1 ns = s.pop().push(); 1137 cananian 1.1.2.4 q = new OPER(qf, in, Qop.forString(Op.toString(opcode)), 1138 cananian 1.1.2.1 ns.stack(0), new Temp[] {s.stack(0)}); 1139 cananian 1.1.2.1 break; 1140 cananian 1.1.2.1 case Op.FADD: 1141 cananian 1.1.2.1 case Op.FDIV: 1142 cananian 1.1.2.1 case Op.FMUL: 1143 cananian 1.1.2.1 case Op.FREM: 1144 cananian 1.1.2.1 case Op.IADD: 1145 cananian 1.1.2.1 case Op.IAND: 1146 cananian 1.1.2.1 case Op.IMUL: 1147 cananian 1.1.2.1 case Op.IOR: 1148 cananian 1.1.2.1 case Op.ISHL: 1149 cananian 1.1.2.1 case Op.ISHR: 1150 cananian 1.1.2.1 case Op.IUSHR: 1151 cananian 1.1.2.1 case Op.IXOR: 1152 cananian 1.1.2.1 case Op.IDIV: 1153 cananian 1.1.2.1 case Op.IREM: 1154 cananian 1.1.2.1 ns = s.pop(2).push(); 1155 cananian 1.1.2.4 q = new OPER(qf, in, Qop.forString(Op.toString(opcode)), 1156 cananian 1.1.2.4 ns.stack(0), new Temp[] {s.stack(1), s.stack(0)}); 1157 cananian 1.1.2.1 break; 1158 cananian 1.1.2.9 case Op.FSUB: 1159 cananian 1.1.2.9 case Op.ISUB: 1160 cananian 1.1.2.9 { 1161 cananian 1.1.2.9 ns = s.pop(2).push(); 1162 cananian 1.1.2.9 Quad q0 = new OPER(qf, in, (opcode==Op.FSUB)?Qop.FNEG:Qop.INEG, 1163 cananian 1.1.2.9 s.stack(0), new Temp[] { s.stack(0) }); 1164 cananian 1.1.2.9 Quad q1 = new OPER(qf, in, (opcode==Op.FSUB)?Qop.FADD:Qop.IADD, 1165 cananian 1.1.2.9 ns.stack(0), new Temp[]{s.stack(1),s.stack(0)}); 1166 cananian 1.1.2.9 Quad.addEdge(q0, 0, q1, 0); 1167 cananian 1.1.2.9 q = q0; last = q1; 1168 cananian 1.1.2.9 break; 1169 cananian 1.1.2.9 } 1170 cananian 1.1.2.1 case Op.FCMPG: 1171 cananian 1.1.2.1 case Op.FCMPL: 1172 cananian 1.1.2.4 switch (inNext.getOpcode()) { // break this into FCMPGT,etc 1173 cananian 1.1.2.4 case Op.IFLT: case Op.IFGT: // special cases. 1174 cananian 1.1.2.4 case Op.IFLE: case Op.IFGE: 1175 cananian 1.1.2.4 case Op.IFEQ: case Op.IFNE: 1176 cananian 1.1.2.4 { 1177 cananian 1.1.2.4 boolean invert = false, swap = false; 1178 cananian 1.1.2.4 int op; 1179 cananian 1.1.2.4 switch (inNext.getOpcode()) { 1180 cananian 1.1.2.4 case Op.IFNE: invert = true; 1181 cananian 1.1.2.4 case Op.IFEQ: op = Qop.FCMPEQ; break; 1182 cananian 1.1.2.4 case Op.IFLT: swap = true; 1183 cananian 1.1.2.4 case Op.IFGT: op = Qop.FCMPGT; break; 1184 cananian 1.1.2.4 case Op.IFLE: swap = true; 1185 cananian 1.1.2.4 case Op.IFGE: op = Qop.FCMPGE; break; 1186 cananian 1.1.2.4 default: throw new Error("Impossible!"); 1187 cananian 1.1.2.4 } 1188 cananian 1.1.2.4 // NaN handling. 1189 cananian 1.1.2.4 if (op!=Qop.FCMPEQ && 1190 cananian 1.1.2.4 ((opcode==Op.FCMPG && !swap) || 1191 cananian 1.1.2.4 (opcode==Op.FCMPL && swap) ) ) { // swap handling of NaN 1192 cananian 1.1.2.4 swap=!swap; invert=true; 1193 cananian 1.1.2.4 op=(op==Qop.FCMPGT)?Qop.FCMPGE:Qop.FCMPGT; 1194 cananian 1.1.2.4 } 1195 cananian 1.1.2.4 ns = s.pop(2); // IF?? pops off result of FCMP? 1196 cananian 1.1.2.4 q = new OPER(qf, in, op, ns.extra(0), 1197 cananian 1.1.2.4 swap 1198 cananian 1.1.2.4 ? new Temp[] { s.stack(0), s.stack(1) } 1199 cananian 1.1.2.4 : new Temp[] { s.stack(1), s.stack(0) } ); 1200 cananian 1.1.2.4 last = new CJMP(qf, in, ns.extra(0), new Temp[0]); 1201 cananian 1.1.2.4 Quad.addEdge(q, 0, last, 0); 1202 cananian 1.1.2.4 r = new TransState[] { 1203 cananian 1.1.2.4 new TransState(ns, inNext.next(0), last, invert?1:0), 1204 cananian 1.1.2.4 new TransState(ns, inNext.next(1), last, invert?0:1) 1205 cananian 1.1.2.4 }; 1206 cananian 1.1.2.4 break; // done translating. 1207 cananian 1.1.2.4 } 1208 cananian 1.1.2.4 default: // use full expansion of fcmp 1209 cananian 1.1.2.1 { 1210 cananian 1.1.2.4 boolean isFCMPG = (opcode==Op.FCMPG); 1211 cananian 1.1.2.1 ns = s.pop(2).push(); 1212 cananian 1.1.2.3 Quad q0 = new OPER(qf, in, Qop.FCMPGT, s.extra(0), 1213 cananian 1.1.2.1 isFCMPG ? 1214 cananian 1.1.2.1 new Temp[] { s.stack(0), s.stack(1) } : 1215 cananian 1.1.2.1 new Temp[] { s.stack(1), s.stack(0) } ); 1216 cananian 1.1.2.3 Quad q1 = new CJMP(qf, in, q0.def()[0], new Temp[0]); 1217 cananian 1.1.2.3 Quad q2 = new OPER(qf, in, Qop.FCMPEQ, s.extra(0), 1218 cananian 1.1.2.1 new Temp[] { s.stack(1), s.stack(0) }); 1219 cananian 1.1.2.3 Quad q3 = new CJMP(qf, in, q2.def()[0], new Temp[0]); 1220 cananian 1.1.2.3 Quad q4 = new CONST(qf, in, ns.stack(0), new Integer(-1), HClass.Int); 1221 cananian 1.1.2.3 Quad q5 = new CONST(qf, in, ns.stack(0), new Integer( 0), HClass.Int); 1222 cananian 1.1.2.3 Quad q6 = new CONST(qf, in, ns.stack(0), new Integer( 1), HClass.Int); 1223 cananian 1.1.2.3 Quad q7 = new PHI(qf, in, new Temp[0], 3); 1224 cananian 1.1.2.1 // link. 1225 cananian 1.1.2.1 Quad.addEdge(q0, 0, q1, 0); 1226 cananian 1.1.2.1 Quad.addEdge(q1, 0, q2, 0); 1227 cananian 1.1.2.1 Quad.addEdge(q1, 1, isFCMPG?q4:q6, 0); 1228 cananian 1.1.2.1 Quad.addEdge(q2, 0, q3, 0); 1229 cananian 1.1.2.1 Quad.addEdge(q3, 0, isFCMPG?q6:q4, 0); 1230 cananian 1.1.2.1 Quad.addEdge(q3, 1, q5, 0); 1231 cananian 1.1.2.1 Quad.addEdge(q4, 0, q7, 0); 1232 cananian 1.1.2.1 Quad.addEdge(q5, 0, q7, 1); 1233 cananian 1.1.2.1 Quad.addEdge(q6, 0, q7, 2); 1234 cananian 1.1.2.1 // setup next state. 1235 cananian 1.1.2.1 q = q0; last = q7; 1236 cananian 1.1.2.1 break; 1237 cananian 1.1.2.1 } 1238 cananian 1.1.2.4 } 1239 cananian 1.1.2.4 break; 1240 cananian 1.1.2.1 case Op.FCONST_0: 1241 cananian 1.1.2.1 case Op.FCONST_1: 1242 cananian 1.1.2.1 case Op.FCONST_2: 1243 cananian 1.1.2.1 case Op.ICONST_M1: 1244 cananian 1.1.2.1 case Op.ICONST_0: 1245 cananian 1.1.2.1 case Op.ICONST_1: 1246 cananian 1.1.2.1 case Op.ICONST_2: 1247 cananian 1.1.2.1 case Op.ICONST_3: 1248 cananian 1.1.2.1 case Op.ICONST_4: 1249 cananian 1.1.2.1 case Op.ICONST_5: 1250 cananian 1.1.2.1 { 1251 cananian 1.1.2.1 OpConstant opd = (OpConstant) in.getOperand(0); 1252 cananian 1.1.2.1 ns = s.push(); 1253 cananian 1.1.2.4 q = new CONST(qf, in, ns.stack(0), 1254 cananian 1.1.2.4 opd.getValue(), opd.getType()); 1255 cananian 1.1.2.1 break; 1256 cananian 1.1.2.1 } 1257 cananian 1.1.2.1 case Op.FLOAD: 1258 cananian 1.1.2.1 case Op.FLOAD_0: 1259 cananian 1.1.2.1 case Op.FLOAD_1: 1260 cananian 1.1.2.1 case Op.FLOAD_2: 1261 cananian 1.1.2.1 case Op.FLOAD_3: 1262 cananian 1.1.2.1 case Op.ILOAD: 1263 cananian 1.1.2.1 case Op.ILOAD_0: 1264 cananian 1.1.2.1 case Op.ILOAD_1: 1265 cananian 1.1.2.1 case Op.ILOAD_2: 1266 cananian 1.1.2.1 case Op.ILOAD_3: 1267 cananian 1.1.2.1 { 1268 cananian 1.1.2.1 OpLocalVariable opd = (OpLocalVariable) in.getOperand(0); 1269 cananian 1.1.2.4 ns = s.push(); 1270 cananian 1.1.2.4 q = new MOVE(qf, in, ns.stack(0), s.lv(opd.getIndex())); 1271 cananian 1.1.2.1 break; 1272 cananian 1.1.2.1 } 1273 cananian 1.1.2.1 case Op.FNEG: 1274 cananian 1.1.2.1 case Op.INEG: 1275 cananian 1.1.2.1 ns = s.pop().push(); 1276 cananian 1.1.2.4 q = new OPER(qf, in, Qop.forString(Op.toString(opcode)), 1277 cananian 1.1.2.1 ns.stack(0), new Temp[] {s.stack(0)}); 1278 cananian 1.1.2.1 break; 1279 cananian 1.1.2.1 case Op.FSTORE: 1280 cananian 1.1.2.1 case Op.FSTORE_0: 1281 cananian 1.1.2.1 case Op.FSTORE_1: 1282 cananian 1.1.2.1 case Op.FSTORE_2: 1283 cananian 1.1.2.1 case Op.FSTORE_3: 1284 cananian 1.1.2.1 case Op.ISTORE: 1285 cananian 1.1.2.1 case Op.ISTORE_0: 1286 cananian 1.1.2.1 case Op.ISTORE_1: 1287 cananian 1.1.2.1 case Op.ISTORE_2: 1288 cananian 1.1.2.1 case Op.ISTORE_3: 1289 cananian 1.1.2.1 { 1290 cananian 1.1.2.1 OpLocalVariable opd = (OpLocalVariable) in.getOperand(0); 1291 cananian 1.1.2.4 ns = s.pop().clearLV(opd.getIndex()); // not a return address 1292 cananian 1.1.2.4 q = new MOVE(qf, in, ns.lv(opd.getIndex()), s.stack(0)); 1293 cananian 1.1.2.1 break; 1294 cananian 1.1.2.1 } 1295 cananian 1.1.2.1 case Op.GETFIELD: 1296 cananian 1.1.2.1 { 1297 cananian 1.1.2.1 OpField opd = (OpField) in.getOperand(0); 1298 cananian 1.1.2.1 if (isLongDouble(opd.value().getType())) // 64-bit value. 1299 cananian 1.1.2.4 ns = s.pop().pushLong(); 1300 cananian 1.1.2.1 else // 32-bit value. 1301 cananian 1.1.2.1 ns = s.pop().push(); 1302 cananian 1.1.2.1 1303 cananian 1.1.2.4 q = new GET(qf, in, ns.stack(0), opd.value(), s.stack(0)); 1304 cananian 1.1.2.1 break; 1305 cananian 1.1.2.1 } 1306 cananian 1.1.2.1 case Op.GETSTATIC: 1307 cananian 1.1.2.1 { 1308 cananian 1.1.2.1 OpField opd = (OpField) in.getOperand(0); 1309 cananian 1.1.2.1 if (isLongDouble(opd.value().getType())) // 64-bit value. 1310 cananian 1.1.2.4 ns = s.pushLong(); 1311 cananian 1.1.2.1 else // 32-bit value. 1312 cananian 1.1.2.1 ns = s.push(); 1313 cananian 1.1.2.4 q = new GET(qf, in, ns.stack(0), opd.value(),null/*no objectref*/); 1314 cananian 1.1.2.1 break; 1315 cananian 1.1.2.1 } 1316 cananian 1.1.2.1 case Op.IINC: 1317 cananian 1.1.2.1 { 1318 cananian 1.1.2.4 OpLocalVariable opd0 = (OpLocalVariable) in.getOperand(0); 1319 cananian 1.1.2.4 OpConstant opd1 = (OpConstant) in.getOperand(1); 1320 cananian 1.1.2.4 Temp Tc = s.extra(0); 1321 cananian 1.1.2.4 ns = s; 1322 cananian 1.1.2.4 Quad q0 = new CONST(qf, in, Tc, 1323 cananian 1.1.2.4 opd1.getValue(), opd1.getType()); 1324 cananian 1.1.2.4 Quad q1 = new OPER(qf, in, Qop.IADD, ns.lv(opd0.getIndex()), 1325 cananian 1.1.2.4 new Temp[] { s.lv(opd0.getIndex()), Tc}); 1326 cananian 1.1.2.4 Quad.addEdge(q0, 0, q1, 0); 1327 cananian 1.1.2.4 q = q0; last = q1; 1328 cananian 1.1.2.4 break; 1329 cananian 1.1.2.1 } 1330 cananian 1.1.2.1 case Op.INSTANCEOF: 1331 cananian 1.1.2.6 { // no protection for <code>null</code>. 1332 cananian 1.1.2.1 OpClass opd = (OpClass) in.getOperand(0); 1333 cananian 1.1.2.1 ns = s.pop().push(); 1334 cananian 1.1.2.5 Quad q0 = new INSTANCEOF(qf, in, 1335 cananian 1.1.2.5 ns.stack(0), s.stack(0), opd.value()); 1336 cananian 1.1.2.23 q = q0; last = q0; 1337 cananian 1.1.2.1 break; 1338 cananian 1.1.2.1 } 1339 cananian 1.1.2.1 case Op.INVOKEINTERFACE: 1340 cananian 1.1.2.1 case Op.INVOKESPECIAL: 1341 cananian 1.1.2.1 case Op.INVOKESTATIC: 1342 cananian 1.1.2.1 case Op.INVOKEVIRTUAL: 1343 cananian 1.1.2.1 { 1344 cananian 1.1.2.4 boolean isVirtual = (opcode!=Op.INVOKESPECIAL); 1345 cananian 1.1.2.4 boolean isStatic = (opcode==Op.INVOKESTATIC); 1346 cananian 1.1.2.1 OpMethod opd = (OpMethod) in.getOperand(0); 1347 cananian 1.1.2.1 HClass paramtypes[] = opd.value().getParameterTypes(); 1348 cananian 1.1.2.1 Temp param[] = new Temp[paramtypes.length+(isStatic?0:1)]; 1349 cananian 1.1.2.1 int j=0; // count number of entries on the stack. 1350 cananian 1.1.2.1 for (int i=paramtypes.length-1; i>=0; i--, j++) { 1351 cananian 1.1.2.1 param[i+(isStatic?0:1)] = s.stack(j); 1352 cananian 1.1.2.1 if (isLongDouble(paramtypes[i])) j++; 1353 cananian 1.1.2.1 } 1354 cananian 1.1.2.1 if (!isStatic) param[0]=s.stack(j++); // objectref. 1355 cananian 1.1.2.1 Temp Tret; 1356 cananian 1.1.2.1 if (opd.value().getReturnType()==HClass.Void) { 1357 cananian 1.1.2.1 // no return value. 1358 cananian 1.1.2.1 ns = s.pop(j); 1359 cananian 1.1.2.1 Tret = null; 1360 cananian 1.1.2.1 } else if (!isLongDouble(opd.value().getReturnType())) { 1361 cananian 1.1.2.1 // 32-bit return value. 1362 cananian 1.1.2.1 ns = s.pop(j).push(); 1363 cananian 1.1.2.1 Tret = ns.stack(0); 1364 cananian 1.1.2.1 } else { 1365 cananian 1.1.2.1 // 64-bit return value. 1366 cananian 1.1.2.4 ns = s.pop(j).pushLong(); 1367 cananian 1.1.2.1 Tret = ns.stack(0); 1368 cananian 1.1.2.1 } 1369 cananian 1.1.2.1 // Create CALL quad. 1370 cananian 1.1.2.20 q = new CALL(qf, in, opd.value(), param, Tret, null, isVirtual, 1371 cananian 1.1.2.24 false /* tail call */, new Temp[0]); 1372 cananian 1.1.2.1 break; 1373 cananian 1.1.2.4 } 1374 cananian 1.1.2.1 case Op.LCMP: // break this up into lcmpeq, lcmpgt, etc. 1375 cananian 1.1.2.4 switch (inNext.getOpcode()) { 1376 cananian 1.1.2.4 case Op.IFEQ: case Op.IFGT: case Op.IFGE: // special cases. 1377 cananian 1.1.2.4 case Op.IFNE: case Op.IFLT: case Op.IFLE: 1378 cananian 1.1.2.4 { 1379 cananian 1.1.2.4 boolean invert = false, swap = false; 1380 cananian 1.1.2.4 int op; 1381 cananian 1.1.2.4 switch (inNext.getOpcode()) { 1382 cananian 1.1.2.4 case Op.IFNE: invert=true; 1383 cananian 1.1.2.4 case Op.IFEQ: op = Qop.LCMPEQ; 1384 cananian 1.1.2.4 break; 1385 cananian 1.1.2.4 case Op.IFGE: invert=true; 1386 cananian 1.1.2.4 case Op.IFLT: swap=true; op=Qop.LCMPGT; 1387 cananian 1.1.2.4 break; 1388 cananian 1.1.2.4 case Op.IFLE: invert=true; 1389 cananian 1.1.2.4 case Op.IFGT: op = Qop.LCMPGT; 1390 cananian 1.1.2.4 break; 1391 cananian 1.1.2.4 default: throw new Error("Impossible!"); 1392 cananian 1.1.2.4 } 1393 cananian 1.1.2.4 ns = s.pop(4); // IF?? pops off result of LCMP. 1394 cananian 1.1.2.4 q = new OPER(qf, in, op, ns.extra(0), 1395 cananian 1.1.2.4 swap 1396 cananian 1.1.2.4 ? new Temp[] {s.stack(0), s.stack(2)} 1397 cananian 1.1.2.4 : new Temp[] {s.stack(2), s.stack(0)} ); 1398 cananian 1.1.2.4 last = new CJMP(qf, in, ns.extra(0), new Temp[0]); 1399 cananian 1.1.2.4 Quad.addEdge(q, 0, last, 0); 1400 cananian 1.1.2.4 r = new TransState[] { 1401 cananian 1.1.2.4 new TransState(ns, inNext.next(0), last, invert?1:0), 1402 cananian 1.1.2.4 new TransState(ns, inNext.next(1), last, invert?0:1) 1403 cananian 1.1.2.4 }; 1404 cananian 1.1.2.4 break; // done translating. 1405 cananian 1.1.2.4 } 1406 cananian 1.1.2.4 default: // use full expansion of lcmp 1407 cananian 1.1.2.1 { // optimization doesn't work well on this, unfortunately. 1408 cananian 1.3.2.1 ns = s.pop(4).push(); assert s.isLong(0) && s.isLong(2); 1409 cananian 1.1.2.3 Quad q0 = new OPER(qf, in, Qop.LCMPEQ, s.extra(0), 1410 cananian 1.1.2.1 new Temp[] { s.stack(2), s.stack(0) }); 1411 cananian 1.1.2.3 Quad q1 = new CJMP(qf, in, q0.def()[0], new Temp[0]); 1412 cananian 1.1.2.3 Quad q2 = new OPER(qf, in, Qop.LCMPGT, s.extra(0), 1413 cananian 1.1.2.1 new Temp[] { s.stack(2), s.stack(0) }); 1414 cananian 1.1.2.3 Quad q3 = new CJMP(qf, in, q2.def()[0], new Temp[0]); 1415 cananian 1.1.2.3 Quad q4 = new CONST(qf, in, ns.stack(0), new Integer(-1), HClass.Int); 1416 cananian 1.1.2.3 Quad q5 = new CONST(qf, in, ns.stack(0), new Integer(0), HClass.Int); 1417 cananian 1.1.2.3 Quad q6 = new CONST(qf, in, ns.stack(0), new Integer(1), HClass.Int); 1418 cananian 1.1.2.3 Quad q7 = new PHI(qf, in, new Temp[0], 3); 1419 cananian 1.1.2.1 // link. 1420 cananian 1.1.2.1 Quad.addEdges(new Quad[] { q0, q1, q2, q3, q4, q7}); 1421 cananian 1.1.2.1 Quad.addEdge(q1, 1, q5, 0); 1422 cananian 1.1.2.1 Quad.addEdge(q3, 1, q6, 0); 1423 cananian 1.1.2.1 Quad.addEdge(q5, 0, q7, 1); 1424 cananian 1.1.2.1 Quad.addEdge(q6, 0, q7, 2); 1425 cananian 1.1.2.1 // setup next state. 1426 cananian 1.1.2.1 q = q0; last = q7; 1427 cananian 1.1.2.1 break; 1428 cananian 1.1.2.1 } 1429 cananian 1.1.2.4 } 1430 cananian 1.1.2.4 break; 1431 cananian 1.1.2.1 case Op.LDC: 1432 cananian 1.1.2.1 case Op.LDC_W: 1433 cananian 1.1.2.1 case Op.LDC2_W: 1434 cananian 1.1.2.1 { 1435 cananian 1.1.2.1 OpConstant opd = (OpConstant) in.getOperand(0); 1436 cananian 1.1.2.1 if (isLongDouble(opd.getType())) 1437 cananian 1.1.2.4 ns = s.pushLong(); 1438 cananian 1.1.2.1 else 1439 cananian 1.1.2.1 ns = s.push(); 1440 cananian 1.1.2.3 q = new CONST(qf, in, ns.stack(0), opd.getValue(), opd.getType()); 1441 cananian 1.1.2.1 break; 1442 cananian 1.1.2.1 } 1443 cananian 1.1.2.1 case Op.LSHL: 1444 cananian 1.1.2.1 case Op.LSHR: 1445 cananian 1.1.2.1 case Op.LUSHR: 1446 cananian 1.3.2.1 ns = s.pop(3).pushLong(); assert s.isLong(1); 1447 cananian 1.1.2.4 q = new OPER(qf, in, Qop.forString(Op.toString(opcode)), 1448 cananian 1.1.2.1 ns.stack(0), new Temp[] { s.stack(1), s.stack(0) }); 1449 cananian 1.1.2.1 break; 1450 cananian 1.1.2.1 case Op.MONITORENTER: 1451 cananian 1.1.2.1 ns = s.pop(); 1452 cananian 1.1.2.4 q = new MONITORENTER(qf, in, s.stack(0)); 1453 cananian 1.1.2.1 break; 1454 cananian 1.1.2.1 case Op.MONITOREXIT: 1455 cananian 1.1.2.1 ns = s.pop(); 1456 cananian 1.1.2.4 q = new MONITOREXIT(qf, in, s.stack(0)); 1457 cananian 1.1.2.1 break; 1458 cananian 1.1.2.1 case Op.MULTIANEWARRAY: 1459 cananian 1.1.2.1 { 1460 cananian 1.1.2.1 OpClass opd0 = (OpClass) in.getOperand(0); 1461 cananian 1.1.2.1 OpConstant opd1 = (OpConstant) in.getOperand(1); 1462 cananian 1.1.2.1 int dims = ((Integer) opd1.getValue()).intValue(); 1463 cananian 1.1.2.1 ns = s.pop(dims).push(); 1464 cananian 1.1.2.1 Temp Tdims[] = new Temp[dims]; 1465 cananian 1.1.2.1 for (int i=0; i<dims; i++) 1466 cananian 1.1.2.1 Tdims[i] = s.stack((dims-1)-i); 1467 cananian 1.1.2.4 1468 cananian 1.1.2.4 q = new ANEW(qf, in, ns.stack(0), opd0.value(), Tdims); 1469 cananian 1.1.2.1 break; 1470 cananian 1.1.2.1 } 1471 cananian 1.1.2.1 case Op.NEWARRAY: 1472 cananian 1.1.2.1 { 1473 cananian 1.1.2.1 final byte T_BOOLEAN = 4; 1474 cananian 1.1.2.1 final byte T_CHAR = 5; 1475 cananian 1.1.2.1 final byte T_FLOAT = 6; 1476 cananian 1.1.2.1 final byte T_DOUBLE = 7; 1477 cananian 1.1.2.1 final byte T_BYTE = 8; 1478 cananian 1.1.2.1 final byte T_SHORT = 9; 1479 cananian 1.1.2.1 final byte T_INT = 10; 1480 cananian 1.1.2.1 final byte T_LONG = 11; 1481 cananian 1.1.2.1 1482 cananian 1.1.2.1 OpConstant opd = (OpConstant) in.getOperand(0); 1483 cananian 1.1.2.1 byte type = ((Byte) opd.getValue()).byteValue(); 1484 cananian 1.1.2.1 HClass arraytype; 1485 cananian 1.1.2.1 switch(type) { 1486 cananian 1.1.2.1 case T_BOOLEAN: 1487 cananian 1.1.2.26 arraytype = qf.getLinker().forDescriptor("[Z"); break; 1488 cananian 1.1.2.1 case T_CHAR: 1489 cananian 1.1.2.26 arraytype = qf.getLinker().forDescriptor("[C"); break; 1490 cananian 1.1.2.1 case T_FLOAT: 1491 cananian 1.1.2.26 arraytype = qf.getLinker().forDescriptor("[F"); break; 1492 cananian 1.1.2.1 case T_DOUBLE: 1493 cananian 1.1.2.26 arraytype = qf.getLinker().forDescriptor("[D"); break; 1494 cananian 1.1.2.1 case T_BYTE: 1495 cananian 1.1.2.26 arraytype = qf.getLinker().forDescriptor("[B"); break; 1496 cananian 1.1.2.1 case T_SHORT: 1497 cananian 1.1.2.26 arraytype = qf.getLinker().forDescriptor("[S"); break; 1498 cananian 1.1.2.1 case T_INT: 1499 cananian 1.1.2.26 arraytype = qf.getLinker().forDescriptor("[I"); break; 1500 cananian 1.1.2.1 case T_LONG: 1501 cananian 1.1.2.26 arraytype = qf.getLinker().forDescriptor("[J"); break; 1502 cananian 1.1.2.1 default: 1503 cananian 1.1.2.1 throw new Error("Illegal NEWARRAY component type: "+type); 1504 cananian 1.1.2.1 } 1505 cananian 1.1.2.1 1506 cananian 1.1.2.1 ns = s.pop().push(); 1507 cananian 1.1.2.4 q = new ANEW(qf, in, ns.stack(0), arraytype, 1508 cananian 1.1.2.4 new Temp[] { s.stack(0) }); 1509 cananian 1.1.2.4 // crunch down array initializers. 1510 cananian 1.1.2.4 HClass comptype = arraytype.getComponentType(); 1511 cananian 1.1.2.4 TransState r0 = new TransState(ns, inNext, q, 0); 1512 cananian 1.1.2.4 for (TransState rOld = null; r0!=rOld; ) { 1513 cananian 1.1.2.4 rOld = r0; r0 = processArrayInitializers(r0, comptype); 1514 cananian 1.1.2.4 } 1515 cananian 1.1.2.4 r = new TransState[] { r0 }; 1516 cananian 1.1.2.4 last = q; // only record handlers for q. 1517 cananian 1.1.2.1 break; 1518 cananian 1.1.2.1 } 1519 cananian 1.1.2.1 case Op.NEW: 1520 cananian 1.1.2.1 { 1521 cananian 1.1.2.1 OpClass opd = (OpClass) in.getOperand(0); 1522 cananian 1.1.2.1 ns = s.push(); 1523 cananian 1.1.2.3 q = new NEW(qf, in, ns.stack(0), opd.value()); 1524 cananian 1.1.2.1 break; 1525 cananian 1.1.2.1 } 1526 cananian 1.1.2.1 case Op.NOP: 1527 cananian 1.1.2.4 ns = s; 1528 cananian 1.1.2.4 q = null; // new NOP(qf, in); 1529 cananian 1.1.2.1 break; 1530 cananian 1.1.2.1 case Op.POP: 1531 cananian 1.1.2.1 ns = s.pop(); q = null; 1532 cananian 1.1.2.1 break; 1533 cananian 1.1.2.1 case Op.POP2: 1534 cananian 1.1.2.1 ns = s.pop(2); q = null; 1535 cananian 1.1.2.1 break; 1536 cananian 1.1.2.1 case Op.PUTFIELD: 1537 cananian 1.1.2.1 { 1538 cananian 1.1.2.1 OpField opd = (OpField) in.getOperand(0); 1539 cananian 1.1.2.4 Temp Tobj; 1540 cananian 1.1.2.1 if (isLongDouble(opd.value().getType())) { // 64-bit value. 1541 cananian 1.3.2.1 assert s.isLong(0) && !s.isLong(2); 1542 cananian 1.1.2.1 ns = s.pop(3); 1543 cananian 1.1.2.4 Tobj = s.stack(2); 1544 cananian 1.1.2.1 } 1545 cananian 1.1.2.1 else { 1546 cananian 1.3.2.1 assert !s.isLong(0) && !s.isLong(1); 1547 cananian 1.1.2.1 ns = s.pop(2); 1548 cananian 1.1.2.4 Tobj = s.stack(1); 1549 cananian 1.1.2.1 } 1550 cananian 1.1.2.4 q = new SET(qf, in, opd.value(), Tobj, s.stack(0)); 1551 cananian 1.1.2.1 break; 1552 cananian 1.1.2.1 } 1553 cananian 1.1.2.1 case Op.PUTSTATIC: 1554 cananian 1.1.2.1 { 1555 cananian 1.1.2.1 OpField opd = (OpField) in.getOperand(0); 1556 cananian 1.1.2.1 if (isLongDouble(opd.value().getType())) // 64-bit value. 1557 cananian 1.1.2.1 ns = s.pop(2); 1558 cananian 1.1.2.1 else 1559 cananian 1.1.2.1 ns = s.pop(1); 1560 cananian 1.1.2.3 q = new SET(qf, in, opd.value(), null/*objectref*/, s.stack(0)); 1561 cananian 1.1.2.1 break; 1562 cananian 1.1.2.1 } 1563 cananian 1.1.2.1 case Op.SWAP: 1564 cananian 1.1.2.4 { 1565 cananian 1.3.2.1 assert !s.isLong(0) && !s.isLong(1); 1566 cananian 1.1.2.4 ns = s.pop(2).push(2).trackS2S(s, 0, 1).trackS2S(s, 1, 0); 1567 cananian 1.1.2.4 Quad q0 = new MOVE(qf, in, s.extra(0), s.stack(0)); 1568 cananian 1.1.2.4 Quad q1 = new MOVE(qf, in, ns.stack(0), s.stack(1)); 1569 cananian 1.1.2.4 Quad q2 = new MOVE(qf, in, ns.stack(1), s.extra(0)); 1570 cananian 1.1.2.4 Quad.addEdges(new Quad[] { q0, q1, q2 }); 1571 cananian 1.1.2.4 q = q0; last = q2; 1572 cananian 1.1.2.1 break; 1573 cananian 1.1.2.4 } 1574 cananian 1.1.2.1 default: 1575 cananian 1.1.2.1 throw new Error("Unknown InGen opcode."); 1576 cananian 1.1.2.1 } 1577 cananian 1.1.2.1 if (last == null) last = q; 1578 cananian 1.1.2.4 1579 cananian 1.1.2.4 // Link new quad if necessary. 1580 cananian 1.1.2.4 if (q!=null) 1581 cananian 1.1.2.1 Quad.addEdge(ts.header, ts.which_succ, q, 0); 1582 cananian 1.1.2.4 else { 1583 cananian 1.1.2.4 last = ts.header; which_succ = ts.which_succ; 1584 cananian 1.1.2.1 } 1585 cananian 1.1.2.4 1586 cananian 1.1.2.4 // Cover these quads with the proper try handler. 1587 cananian 1.1.2.4 if (q!=null) ns.recordHandler(in, q, last); 1588 cananian 1.1.2.4 1589 cananian 1.1.2.4 // return next translation state. 1590 cananian 1.1.2.4 if (r==null) 1591 cananian 1.1.2.4 r=new TransState[]{new TransState(ns, inNext, last, which_succ)}; 1592 cananian 1.1.2.4 return r; 1593 cananian 1.1.2.1 } 1594 cananian 1.1.2.1 1595 cananian 1.1.2.1 /** 1596 cananian 1.1.2.13 * Translate a single <code>InMerge</code>. 1597 cananian 1.1.2.1 */ 1598 cananian 1.1.2.4 static final TransState[] transInMerge(TransState ts) { 1599 cananian 1.1.2.13 State s0 = ts.initialState; 1600 cananian 1.1.2.4 InMerge in = (InMerge) ts.in; 1601 cananian 1.1.2.13 QuadFactory qf = s0.qf(); 1602 cananian 1.1.2.4 TransState[] r; 1603 cananian 1.1.2.1 1604 cananian 1.1.2.13 // purge dead return addresses. 1605 cananian 1.1.2.13 State s = s0.purgeDead(in); 1606 cananian 1.1.2.13 Map calls = s.calls(); 1607 cananian 1.1.2.13 1608 cananian 1.1.2.13 PHI phi; 1609 cananian 1.1.2.4 int arity = 0; 1610 cananian 1.1.2.13 if (!s.mergeMap().contains(in, calls)) { // no previous PHI 1611 cananian 1.1.2.3 phi = new PHI(qf, in, new Temp[0], in.arity()); 1612 cananian 1.1.2.4 r = new TransState[]{new TransState(s, in.next(0), phi, 0)}; 1613 cananian 1.1.2.4 s.recordHandler(in, phi, phi); 1614 cananian 1.1.2.4 } else { 1615 cananian 1.1.2.13 phi = s.mergeMap().get(in, calls); 1616 cananian 1.1.2.13 arity = s.mergeMap().arity(in, calls); 1617 cananian 1.1.2.4 r = new TransState[0]; 1618 cananian 1.1.2.4 } 1619 cananian 1.1.2.13 // code duplication while translating JSRs can cause more than the 1620 cananian 1.1.2.13 // expected number of entries into a phi. 1621 cananian 1.1.2.13 if (arity == phi.arity()) 1622 cananian 1.1.2.13 phi = phi.grow(new Temp[0], arity); // increase capacity by 1. 1623 cananian 1.1.2.13 1624 cananian 1.1.2.4 Quad.addEdge(ts.header, ts.which_succ, phi, arity); 1625 cananian 1.7 s.mergeMap().put(in, calls, phi, arity+1, s); 1626 cananian 1.1.2.4 return r; 1627 cananian 1.1.2.1 } 1628 cananian 1.1.2.4 1629 cananian 1.1.2.1 /** Translate a single <code>InSwitch</code>. */ 1630 cananian 1.1.2.4 static final TransState[] transInSwitch(TransState ts) { 1631 cananian 1.1.2.4 QuadFactory qf = ts.initialState.qf(); 1632 cananian 1.1.2.1 InSwitch in = (InSwitch) ts.in; 1633 cananian 1.1.2.1 State s = ts.initialState; 1634 cananian 1.1.2.1 State ns = s.pop(); 1635 cananian 1.1.2.1 Instr nxt[] = in.next(); 1636 cananian 1.1.2.10 // determine length of keys array 1637 cananian 1.1.2.10 int klen=0, map[] = new int[nxt.length-1]; 1638 cananian 1.1.2.10 for (int i=1; i<nxt.length; i++) 1639 cananian 1.1.2.10 if (nxt[i] != nxt[0]) 1640 cananian 1.1.2.10 map[klen++] = i; // only key entries for non-default targets. 1641 cananian 1.1.2.1 // make keys array. 1642 cananian 1.1.2.10 int keys[] = new int[klen]; 1643 cananian 1.1.2.10 for (int i=0; i<klen; i++) 1644 cananian 1.1.2.10 keys[i] = in.key(map[i]); 1645 cananian 1.1.2.1 // make & link SWITCH quad. 1646 cananian 1.1.2.3 Quad q = new SWITCH(qf, in, s.stack(0), keys, new Temp[0]); 1647 cananian 1.1.2.1 Quad.addEdge(ts.header, ts.which_succ, q, 0); 1648 cananian 1.1.2.1 // Make next states. 1649 cananian 1.1.2.10 TransState[] r = new TransState[klen+1]; 1650 cananian 1.1.2.10 for (int i=0; i<klen; i++) 1651 cananian 1.1.2.10 r[i] = new TransState(ns, nxt[map[i]], q, i); 1652 cananian 1.1.2.10 r[klen] = new TransState(ns, nxt[0], q, klen); 1653 cananian 1.1.2.4 // record try info 1654 cananian 1.1.2.4 ns.recordHandler(in, q, q); 1655 cananian 1.1.2.1 return r; 1656 cananian 1.1.2.1 } 1657 cananian 1.1.2.4 1658 cananian 1.1.2.1 /** Translate a single <code>InCti</code>. */ 1659 cananian 1.1.2.4 static final TransState[] transInCti(TransState ts) { 1660 cananian 1.1.2.4 QuadFactory qf = ts.initialState.qf(); 1661 cananian 1.1.2.1 InCti in = (InCti) ts.in; 1662 cananian 1.1.2.1 State s = ts.initialState; 1663 cananian 1.1.2.4 Quad q, last=null; 1664 cananian 1.1.2.1 TransState[] r; 1665 cananian 1.1.2.4 1666 cananian 1.1.2.4 byte opcode = in.getOpcode(); 1667 cananian 1.1.2.4 switch(opcode) { 1668 cananian 1.1.2.1 case Op.ARETURN: 1669 cananian 1.1.2.1 case Op.DRETURN: 1670 cananian 1.1.2.1 case Op.FRETURN: 1671 cananian 1.1.2.1 case Op.IRETURN: 1672 cananian 1.1.2.1 case Op.LRETURN: 1673 cananian 1.1.2.4 case Op.RETURN: // RETURN has no return value. 1674 cananian 1.1.2.4 q = new RETURN(qf, in, (opcode==Op.RETURN)? null : s.stack(0)); 1675 cananian 1.1.2.1 r = new TransState[0]; 1676 cananian 1.1.2.4 s.footer().attach(q, 0); 1677 cananian 1.1.2.1 break; 1678 cananian 1.1.2.1 case Op.ATHROW: 1679 cananian 1.1.2.4 q = new THROW(qf, in, s.stack(0)); 1680 cananian 1.1.2.4 r = new TransState[0]; 1681 cananian 1.1.2.4 s.footer().attach(q, 0); 1682 cananian 1.1.2.1 break; 1683 cananian 1.1.2.1 case Op.GOTO: 1684 cananian 1.1.2.1 case Op.GOTO_W: 1685 cananian 1.1.2.1 q = null; 1686 cananian 1.1.2.4 r = new TransState[] { new TransState(s, in.next(0), 1687 cananian 1.1.2.1 ts.header, ts.which_succ) }; 1688 cananian 1.1.2.1 break; 1689 cananian 1.1.2.1 case Op.IF_ACMPEQ: 1690 cananian 1.1.2.1 case Op.IF_ACMPNE: 1691 cananian 1.1.2.1 { 1692 cananian 1.1.2.1 State ns = s.pop(2); 1693 cananian 1.1.2.3 q = new OPER(qf, in, Qop.ACMPEQ, s.extra(0), 1694 cananian 1.1.2.1 new Temp[] { s.stack(1), s.stack(0) }); 1695 cananian 1.1.2.4 Quad q2 = new CJMP(qf, in, s.extra(0), new Temp[0]); 1696 cananian 1.1.2.1 Quad.addEdge(q, 0, q2, 0); 1697 cananian 1.1.2.1 int iffalse=0, iftrue=1; 1698 cananian 1.1.2.4 if (opcode == Op.IF_ACMPNE) { // invert things for NE. 1699 cananian 1.1.2.1 iffalse=1; iftrue=0; 1700 cananian 1.1.2.1 } 1701 cananian 1.1.2.1 r = new TransState[] { 1702 cananian 1.1.2.4 new TransState(ns, in.next(0), q2, iffalse), 1703 cananian 1.1.2.4 new TransState(ns, in.next(1), q2, iftrue) 1704 cananian 1.1.2.1 }; 1705 cananian 1.1.2.4 last = q2; 1706 cananian 1.1.2.1 break; 1707 cananian 1.1.2.1 } 1708 cananian 1.1.2.1 case Op.IFNULL: 1709 cananian 1.1.2.1 case Op.IFNONNULL: 1710 cananian 1.1.2.1 { 1711 cananian 1.1.2.1 State ns = s.pop(); 1712 cananian 1.1.2.4 Quad q0 = new CONST(qf, in, s.extra(0), null, HClass.Void); 1713 cananian 1.1.2.4 Quad q1 = new OPER(qf, in, Qop.ACMPEQ, s.extra(0), 1714 cananian 1.1.2.4 new Temp[] { s.stack(0), s.extra(0) }); 1715 cananian 1.1.2.4 Quad q2 = new CJMP(qf, in, s.extra(0), new Temp[0]); 1716 cananian 1.1.2.4 Quad.addEdges(new Quad[] { q0, q1, q2 }); 1717 cananian 1.1.2.4 1718 cananian 1.1.2.1 int iffalse=0, iftrue=1; 1719 cananian 1.1.2.4 if (opcode == Op.IFNONNULL) { // invert things 1720 cananian 1.1.2.1 iffalse=1; iftrue=0; 1721 cananian 1.1.2.1 } 1722 cananian 1.1.2.4 q = q0; last = q2; 1723 cananian 1.1.2.1 r = new TransState[] { 1724 cananian 1.1.2.4 new TransState(ns, in.next(0), q2, iffalse), 1725 cananian 1.1.2.4 new TransState(ns, in.next(1), q2, iftrue) 1726 cananian 1.1.2.1 }; 1727 cananian 1.1.2.1 break; 1728 cananian 1.1.2.1 } 1729 cananian 1.1.2.1 case Op.IFEQ: 1730 cananian 1.1.2.1 case Op.IFNE: 1731 cananian 1.1.2.23 { 1732 cananian 1.1.2.23 // optimize this case. 1733 cananian 1.1.2.23 State ns = s.pop(); 1734 cananian 1.1.2.23 boolean invert = (opcode==Op.IFEQ); 1735 cananian 1.1.2.23 q = last = new CJMP(qf, in, s.stack(0), new Temp[0]); 1736 cananian 1.1.2.23 r = new TransState[] { 1737 cananian 1.1.2.23 new TransState(ns, in.next(0), last, invert?1:0), 1738 cananian 1.1.2.23 new TransState(ns, in.next(1), last, invert?0:1) 1739 cananian 1.1.2.23 }; 1740 cananian 1.1.2.23 break; 1741 cananian 1.1.2.23 } 1742 cananian 1.1.2.1 case Op.IFLT: 1743 cananian 1.1.2.1 case Op.IFGE: 1744 cananian 1.1.2.1 case Op.IFGT: 1745 cananian 1.1.2.1 case Op.IFLE: 1746 cananian 1.1.2.1 case Op.IF_ICMPEQ: 1747 cananian 1.1.2.1 case Op.IF_ICMPNE: 1748 cananian 1.1.2.1 case Op.IF_ICMPLT: 1749 cananian 1.1.2.1 case Op.IF_ICMPGE: 1750 cananian 1.1.2.1 case Op.IF_ICMPGT: 1751 cananian 1.1.2.1 case Op.IF_ICMPLE: 1752 cananian 1.1.2.1 { 1753 cananian 1.1.2.1 State ns; 1754 cananian 1.1.2.1 1755 cananian 1.1.2.1 boolean invert = false; 1756 cananian 1.1.2.4 boolean swap = false; 1757 cananian 1.1.2.4 int op; 1758 cananian 1.1.2.1 switch (opcode) { 1759 cananian 1.1.2.1 case Op.IFNE: 1760 cananian 1.1.2.1 case Op.IF_ICMPNE: 1761 cananian 1.1.2.1 invert = true; 1762 cananian 1.1.2.1 case Op.IFEQ: 1763 cananian 1.1.2.1 case Op.IF_ICMPEQ: 1764 cananian 1.1.2.1 op = Qop.ICMPEQ; 1765 cananian 1.1.2.1 break; 1766 cananian 1.1.2.1 case Op.IFGE: 1767 cananian 1.1.2.1 case Op.IF_ICMPGE: 1768 cananian 1.1.2.4 invert = true; 1769 cananian 1.1.2.4 case Op.IFLT: 1770 cananian 1.1.2.4 case Op.IF_ICMPLT: 1771 cananian 1.1.2.4 swap = true; 1772 cananian 1.1.2.4 op = Qop.ICMPGT; 1773 cananian 1.1.2.1 break; 1774 cananian 1.1.2.1 case Op.IFLE: 1775 cananian 1.1.2.1 case Op.IF_ICMPLE: 1776 cananian 1.1.2.1 invert = true; 1777 cananian 1.1.2.1 case Op.IFGT: 1778 cananian 1.1.2.1 case Op.IF_ICMPGT: 1779 cananian 1.1.2.1 op = Qop.ICMPGT; 1780 cananian 1.1.2.1 break; 1781 cananian 1.1.2.4 default: throw new Error("Impossible!"); 1782 cananian 1.1.2.1 } 1783 cananian 1.1.2.1 if (opcode>=Op.IFEQ && opcode<=Op.IFLE) { 1784 cananian 1.1.2.1 ns = s.pop(); 1785 cananian 1.1.2.4 q = new CONST(qf, in, s.extra(0), 1786 cananian 1.1.2.4 new Integer(0), HClass.Int); 1787 cananian 1.1.2.4 last = new OPER(qf, in, op, ns.extra(0), 1788 cananian 1.1.2.4 swap 1789 cananian 1.1.2.4 ?new Temp[] { s.extra(0), s.stack(0) } 1790 cananian 1.1.2.4 :new Temp[] { s.stack(0), s.extra(0) }); 1791 cananian 1.1.2.4 Quad.addEdge(q, 0, last, 0); 1792 cananian 1.1.2.1 } else { 1793 cananian 1.1.2.1 ns = s.pop(2); 1794 cananian 1.1.2.3 q = new OPER(qf, in, op, ns.extra(0), 1795 cananian 1.1.2.4 swap 1796 cananian 1.1.2.4 ?new Temp[] { s.stack(0), s.stack(1) } 1797 cananian 1.1.2.4 :new Temp[] { s.stack(1), s.stack(0) } ); 1798 cananian 1.1.2.4 last = q; 1799 cananian 1.1.2.1 } 1800 cananian 1.1.2.4 Quad Qc = new CJMP(qf, in, ns.extra(0), new Temp[0]); 1801 cananian 1.1.2.4 Quad.addEdge(last, 0, Qc, 0); 1802 cananian 1.1.2.1 r = new TransState[] { 1803 cananian 1.1.2.4 new TransState(ns, in.next(0), Qc, invert?1:0), 1804 cananian 1.1.2.4 new TransState(ns, in.next(1), Qc, invert?0:1) 1805 cananian 1.1.2.1 }; 1806 cananian 1.1.2.4 last = Qc; 1807 cananian 1.1.2.1 break; 1808 cananian 1.1.2.1 } 1809 cananian 1.1.2.1 case Op.JSR: 1810 cananian 1.1.2.1 case Op.JSR_W: 1811 cananian 1.1.2.4 { 1812 cananian 1.1.2.13 // futz with the state when we reach the JSR, and continue 1813 cananian 1.1.2.13 // at the merge. The new call state will ensure that the 1814 cananian 1.1.2.13 // subroutine isn't merged with code outside the subroutine. 1815 cananian 1.1.2.4 Instr target = in.next(1); 1816 cananian 1.1.2.13 State ns = s.enterJSR(in, target); 1817 cananian 1.1.2.13 // put a null in the stack location where the return address 1818 cananian 1.1.2.13 // usually goes. 1819 cananian 1.1.2.13 q = new CONST(qf, in, ns.stack(0), null, HClass.Void); 1820 cananian 1.1.2.4 // translate starting at jsr target. 1821 cananian 1.1.2.13 r = new TransState[] { new TransState(ns, target, q, 0) }; 1822 cananian 1.1.2.4 break; 1823 cananian 1.1.2.4 } 1824 cananian 1.1.2.1 case Op.RET: 1825 cananian 1.1.2.4 { 1826 cananian 1.1.2.13 // go back to the caller, purging now-dead ret-addr. 1827 cananian 1.1.2.4 OpLocalVariable opd = ((InRet)in).getOperand(); 1828 cananian 1.1.2.4 Instr target = s.getJSRtargetLV(opd.getIndex()); 1829 cananian 1.3.2.1 assert target!=null : "Unable to determine RET subroutine."; 1830 cananian 1.1.2.13 Instr jsr = (Instr) s.calls().get(target); 1831 cananian 1.1.2.13 Instr nxt = jsr.next(0); 1832 cananian 1.1.2.13 State ns = s.purgeDead(nxt); 1833 cananian 1.1.2.13 q = null; // no quad equivalent. 1834 cananian 1.1.2.13 // translate starting from instruction after jsr. 1835 cananian 1.1.2.13 r = new TransState[] { new TransState(ns, nxt, 1836 cananian 1.1.2.13 ts.header, ts.which_succ) }; 1837 cananian 1.1.2.4 break; 1838 cananian 1.1.2.4 } 1839 cananian 1.1.2.1 default: 1840 cananian 1.1.2.1 throw new Error("Unknown InCti: "+in.toString()); 1841 cananian 1.1.2.1 } 1842 cananian 1.1.2.4 if (q!=null) { 1843 cananian 1.1.2.1 Quad.addEdge(ts.header, ts.which_succ, q, 0); 1844 cananian 1.1.2.4 s.recordHandler(in, q, last==null?q:last); 1845 cananian 1.1.2.4 } 1846 cananian 1.1.2.1 return r; 1847 cananian 1.1.2.1 } 1848 cananian 1.1.2.1 1849 cananian 1.1.2.4 // Match array initializer 1850 cananian 1.1.2.4 private static final TransState processArrayInitializers(TransState ts, 1851 cananian 1.1.2.4 HClass type) 1852 cananian 1.1.2.1 { 1853 cananian 1.1.2.4 Instr in = ts.in; // instruction after array creation. 1854 cananian 1.1.2.4 State s = ts.initialState; 1855 cananian 1.1.2.4 HandlerSet hs = s.handlers(in); 1856 cananian 1.1.2.11 List v = new ArrayList(); // array initializers. 1857 cananian 1.1.2.4 int offset = 0; 1858 cananian 1.1.2.16 boolean integerify = false; 1859 cananian 1.1.2.16 // BASTORE takes integer/byte args, stores in byte/boolean array. 1860 cananian 1.1.2.16 // SASTORE takes integer/byte/short args, stores in short array. 1861 cananian 1.1.2.16 // CASTORE takes integer/byte/short args, stores in character array. 1862 cananian 1.1.2.16 if (type==HClass.Boolean || type==HClass.Byte || 1863 cananian 1.1.2.16 type==HClass.Short || type==HClass.Char) 1864 cananian 1.1.2.16 integerify = true; 1865 cananian 1.1.2.1 1866 cananian 1.1.2.4 do { // iterate over initialization instructions. 1867 cananian 1.1.2.4 if (in.getOpcode() != Op.DUP) break; // in should be dup. 1868 cananian 1.1.2.4 Instr in1 = in.next(0); // iconst, bipush, sipush, or ldc 1869 cananian 1.1.2.4 if (extractConstType(in1) != HClass.Int) break; 1870 cananian 1.1.2.4 Instr in2 = in1.next(0); // constant value of array init. 1871 cananian 1.1.2.16 if ( integerify && extractConstType(in2) != HClass.Int) break; 1872 cananian 1.1.2.16 if (!integerify && extractConstType(in2) != type) break; 1873 cananian 1.1.2.4 Instr in3 = in2.next(0); // ?astore 1874 cananian 1.1.2.4 if (!isXASTORE(in3)) break; 1875 cananian 1.1.2.4 // finally, check that all handlers are the same. 1876 cananian 1.1.2.4 if (!HandlerSet.equals(hs, s.handlers(in ))) break; 1877 cananian 1.1.2.4 if (!HandlerSet.equals(hs, s.handlers(in1))) break; 1878 cananian 1.1.2.4 if (!HandlerSet.equals(hs, s.handlers(in2))) break; 1879 cananian 1.1.2.4 if (!HandlerSet.equals(hs, s.handlers(in3))) break; 1880 cananian 1.1.2.4 // allow only sequential initializers. 1881 cananian 1.1.2.4 Number index = (Number) extractConst(in1).getValue(); 1882 cananian 1.1.2.4 if (v.size()==0) offset=index.intValue(); 1883 cananian 1.1.2.4 else if (index.intValue()!=offset+v.size()) break; 1884 cananian 1.1.2.4 // okay, this is element N of array initializer. 1885 cananian 1.1.2.19 Number value = (Number) extractConst(in2).getValue(); 1886 cananian 1.1.2.19 if (in2.getOpcode()==Op.BIPUSH || in2.getOpcode()==Op.SIPUSH) 1887 cananian 1.1.2.19 value = new Integer(value.intValue()); 1888 cananian 1.1.2.19 v.add(value); 1889 cananian 1.1.2.4 in = in3.next(0); 1890 cananian 1.1.2.4 } while (true); 1891 cananian 1.1.2.4 if (v.size()==0) return ts; 1892 cananian 1.1.2.4 // else... 1893 cananian 1.1.2.11 Object[] oa = v.toArray(); 1894 cananian 1.1.2.16 if (integerify) unintegerify(oa, type); 1895 cananian 1.1.2.4 Quad q=new ARRAYINIT(ts.initialState.qf(), ts.in, 1896 cananian 1.1.2.4 ts.initialState.stack(0), offset, type, oa); 1897 cananian 1.1.2.4 Quad.addEdge(ts.header, ts.which_succ, q, 0); 1898 cananian 1.1.2.4 s.recordHandler(ts.in, q, q); // record the proper hanlder. 1899 cananian 1.1.2.4 return new TransState(ts.initialState, in, q, 0); 1900 cananian 1.1.2.16 } 1901 cananian 1.1.2.16 private static final void unintegerify(Object[] oa, HClass type) { 1902 cananian 1.1.2.16 for (int i=0; i<oa.length; i++) { 1903 cananian 1.1.2.16 if (type==HClass.Boolean) 1904 cananian 1.1.2.16 oa[i] = new Boolean(0!=((Number)oa[i]).intValue()); 1905 cananian 1.1.2.16 if (type==HClass.Byte) 1906 cananian 1.1.2.16 oa[i] = new Byte(((Number)oa[i]).byteValue()); 1907 cananian 1.1.2.16 if (type==HClass.Short) 1908 cananian 1.1.2.16 oa[i] = new Short(((Number)oa[i]).shortValue()); 1909 cananian 1.1.2.16 if (type==HClass.Char) 1910 cananian 1.1.2.16 oa[i] = new Character((char)((Number)oa[i]).intValue()); 1911 cananian 1.1.2.16 } 1912 cananian 1.1.2.1 } 1913 cananian 1.1.2.4 private static final boolean isXASTORE(Instr in) { 1914 cananian 1.1.2.4 byte opcode = in.getOpcode(); 1915 cananian 1.1.2.4 switch(opcode) { 1916 cananian 1.1.2.4 case Op.BASTORE: 1917 cananian 1.1.2.4 case Op.CASTORE: 1918 cananian 1.1.2.4 case Op.DASTORE: 1919 cananian 1.1.2.4 case Op.FASTORE: 1920 cananian 1.1.2.4 case Op.IASTORE: 1921 cananian 1.1.2.4 case Op.LASTORE: 1922 cananian 1.1.2.4 case Op.SASTORE: 1923 cananian 1.1.2.4 return true; 1924 cananian 1.1.2.4 default: 1925 cananian 1.1.2.4 return false; 1926 cananian 1.1.2.4 } 1927 cananian 1.1.2.1 } 1928 cananian 1.1.2.4 private static final OpConstant extractConst(Instr in) { 1929 cananian 1.1.2.4 if (in instanceof InGen && in.getOpcode()!=Op.NEWARRAY) { 1930 cananian 1.1.2.4 Operand[] op = ((InGen)in).getOperands(); 1931 cananian 1.1.2.4 if (op.length==1 && op[0] instanceof OpConstant) 1932 cananian 1.1.2.4 return (OpConstant) op[0]; 1933 cananian 1.1.2.4 } 1934 cananian 1.1.2.4 return null; 1935 cananian 1.1.2.1 } 1936 cananian 1.1.2.4 // BIPUSH and SIPUSH return odd type info. 1937 cananian 1.1.2.4 private static final HClass extractConstType(Instr in) { 1938 cananian 1.1.2.4 OpConstant opc = extractConst(in); 1939 cananian 1.1.2.4 if (opc==null) return null; 1940 cananian 1.1.2.4 if (in.getOpcode()==Op.BIPUSH || in.getOpcode()==Op.SIPUSH) 1941 cananian 1.1.2.4 return HClass.Int; 1942 cananian 1.1.2.4 return opc.getType(); 1943 cananian 1.1.2.1 } 1944 cananian 1.1.2.1 1945 cananian 1.1.2.1 // Miscellaneous utility functions. /////////////////////////// 1946 cananian 1.1.2.1 1947 cananian 1.1.2.1 /** Determine if an HClass needs to be represented by one or two bytecode 1948 cananian 1.1.2.1 * stack entries. */ 1949 cananian 1.1.2.1 private static final boolean isLongDouble(HClass hc) { 1950 cananian 1.1.2.1 if (hc == HClass.Long || hc == HClass.Double) 1951 cananian 1.1.2.1 return true; 1952 cananian 1.1.2.1 return false; 1953 cananian 1.1.2.1 } 1954 cananian 1.2 }