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      }