diff agent/src/share/classes/sun/jvm/hotspot/oops/GenerateOopMap.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/GenerateOopMap.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,2323 @@
+/*
+ * Copyright 2001-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.oops;
+
+import java.io.*;
+import java.util.*;
+import sun.jvm.hotspot.interpreter.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.utilities.*;
+
+/** Minimal port of the VM's oop map generator for interpreted frames */
+
+public class GenerateOopMap {
+  interface JumpClosure {
+    public void process(GenerateOopMap c, int bcpDelta, int[] data);
+  }
+
+  // Used for debugging this code
+  private static final boolean DEBUG = false;
+
+  // These two should be removed. But requires som code to be cleaned up
+  private static final int MAXARGSIZE     =   256;      // This should be enough
+  private static final int MAX_LOCAL_VARS = 65536;      // 16-bit entry
+  private static final boolean TraceMonitorMismatch = true;
+  private static final boolean TraceOopMapRewrites = true;
+
+  // Commonly used constants
+  static CellTypeState[] epsilonCTS = { CellTypeState.bottom };
+  static CellTypeState   refCTS     = CellTypeState.ref;
+  static CellTypeState   valCTS     = CellTypeState.value;
+  static CellTypeState[]    vCTS    = { CellTypeState.value, CellTypeState.bottom };
+  static CellTypeState[]    rCTS    = { CellTypeState.ref,   CellTypeState.bottom };
+  static CellTypeState[]   rrCTS    = { CellTypeState.ref,   CellTypeState.ref,   CellTypeState.bottom };
+  static CellTypeState[]   vrCTS    = { CellTypeState.value, CellTypeState.ref,   CellTypeState.bottom };
+  static CellTypeState[]   vvCTS    = { CellTypeState.value, CellTypeState.value, CellTypeState.bottom };
+  static CellTypeState[]  rvrCTS    = { CellTypeState.ref,   CellTypeState.value, CellTypeState.ref,   CellTypeState.bottom };
+  static CellTypeState[]  vvrCTS    = { CellTypeState.value, CellTypeState.value, CellTypeState.ref,   CellTypeState.bottom };
+  static CellTypeState[]  vvvCTS    = { CellTypeState.value, CellTypeState.value, CellTypeState.value, CellTypeState.bottom };
+  static CellTypeState[] vvvrCTS    = { CellTypeState.value, CellTypeState.value, CellTypeState.value, CellTypeState.ref,   CellTypeState.bottom };
+  static CellTypeState[] vvvvCTS    = { CellTypeState.value, CellTypeState.value, CellTypeState.value, CellTypeState.value, CellTypeState.bottom };
+
+  /** Specialization of SignatureIterator - compute the effects of a call */
+  static class ComputeCallStack extends SignatureIterator {
+    CellTypeStateList _effect;
+    int _idx;
+
+    void set(CellTypeState state)         { _effect.get(_idx++).set(state); }
+    int  length()                         { return _idx; };
+
+    public void doBool  ()              { set(CellTypeState.value); }
+    public void doChar  ()              { set(CellTypeState.value); }
+    public void doFloat ()              { set(CellTypeState.value); }
+    public void doByte  ()              { set(CellTypeState.value); }
+    public void doShort ()              { set(CellTypeState.value); }
+    public void doInt   ()              { set(CellTypeState.value); }
+    public void doVoid  ()              { set(CellTypeState.bottom);}
+    public void doObject(int begin, int end) { set(CellTypeState.ref); }
+    public void doArray (int begin, int end) { set(CellTypeState.ref); }
+
+    public void doDouble()              { set(CellTypeState.value);
+                                          set(CellTypeState.value); }
+    public void doLong  ()              { set(CellTypeState.value);
+                                          set(CellTypeState.value); }
+
+    ComputeCallStack(Symbol signature) {
+      super(signature);
+    }
+
+    // Compute methods
+    int computeForParameters(boolean is_static, CellTypeStateList effect) {
+      _idx    = 0;
+      _effect = effect;
+
+      if (!is_static) {
+        effect.get(_idx++).set(CellTypeState.ref);
+      }
+
+      iterateParameters();
+
+      return length();
+    };
+
+    int computeForReturntype(CellTypeStateList effect) {
+      _idx    = 0;
+      _effect = effect;
+      iterateReturntype();
+      set(CellTypeState.bottom);  // Always terminate with a bottom state, so ppush works
+
+      return length();
+    }
+  }
+
+  /** Specialization of SignatureIterator - in order to set up first stack frame */
+  static class ComputeEntryStack extends SignatureIterator {
+    CellTypeStateList _effect;
+    int _idx;
+
+    void set(CellTypeState state)         { _effect.get(_idx++).set(state); }
+    int  length()                         { return _idx; };
+
+    public void doBool  ()              { set(CellTypeState.value); }
+    public void doChar  ()              { set(CellTypeState.value); }
+    public void doFloat ()              { set(CellTypeState.value); }
+    public void doByte  ()              { set(CellTypeState.value); }
+    public void doShort ()              { set(CellTypeState.value); }
+    public void doInt   ()              { set(CellTypeState.value); }
+    public void doVoid  ()              { set(CellTypeState.bottom);}
+    public void doObject(int begin, int end) { set(CellTypeState.makeSlotRef(_idx)); }
+    public void doArray (int begin, int end) { set(CellTypeState.makeSlotRef(_idx)); }
+
+    public void doDouble()              { set(CellTypeState.value);
+                                          set(CellTypeState.value); }
+    public void doLong  ()              { set(CellTypeState.value);
+                                          set(CellTypeState.value); }
+
+    ComputeEntryStack(Symbol signature) {
+      super(signature);
+    }
+
+    // Compute methods
+    int computeForParameters(boolean is_static, CellTypeStateList effect) {
+      _idx    = 0;
+      _effect = effect;
+
+      if (!is_static) {
+        effect.get(_idx++).set(CellTypeState.makeSlotRef(0));
+      }
+
+      iterateParameters();
+
+      return length();
+    };
+
+    int computeForReturntype(CellTypeStateList effect) {
+      _idx    = 0;
+      _effect = effect;
+      iterateReturntype();
+      set(CellTypeState.bottom);  // Always terminate with a bottom state, so ppush works
+
+      return length();
+    }
+  }
+
+  /** Contains maping between jsr targets and there return addresses.
+      One-to-many mapping. */
+  static class RetTableEntry {
+    private static int _init_nof_jsrs; // Default size of jsrs list
+    private int _target_bci;           // Target PC address of jump (bytecode index)
+    private List/*<int>*/ _jsrs;       // List of return addresses  (bytecode index)
+    private RetTableEntry _next;       // Link to next entry
+
+    RetTableEntry(int target, RetTableEntry next) {
+      _target_bci = target;
+      _jsrs = new ArrayList(_init_nof_jsrs);
+      _next = next;
+    }
+
+    // Query
+    int targetBci()  { return _target_bci; }
+    int nofJsrs()    { return _jsrs.size(); }
+    int jsrs(int i)  { return ((Integer) _jsrs.get(i)).intValue(); }
+
+    // Update entry
+    void addJsr  (int return_bci)     { _jsrs.add(new Integer(return_bci)); }
+    void addDelta(int bci, int delta) {
+      if (_target_bci > bci) {
+        _target_bci += delta;
+      }
+
+      for (int k = 0; k < nofJsrs(); k++) {
+        int jsr = jsrs(k);
+        if (jsr > bci) {
+          _jsrs.set(k, new Integer(jsr+delta));
+        }
+      }
+    }
+    RetTableEntry next()               { return _next; }
+  }
+
+  static class RetTable {
+    private RetTableEntry _first;
+    private static int _init_nof_entries;
+
+    private void addJsr(int return_bci, int target_bci) {
+      RetTableEntry entry = _first;
+
+      // Scan table for entry
+      for (;(entry != null) && (entry.targetBci() != target_bci); entry = entry.next());
+
+      if (entry == null) {
+        // Allocate new entry and put in list
+        entry = new RetTableEntry(target_bci, _first);
+        _first = entry;
+      }
+
+      // Now "entry" is set.  Make sure that the entry is initialized
+      // and has room for the new jsr.
+      entry.addJsr(return_bci);
+    }
+
+    RetTable() {}
+    void computeRetTable(Method method) {
+      BytecodeStream i = new BytecodeStream(method);
+      int bytecode;
+
+      while( (bytecode = i.next()) >= 0) {
+        switch (bytecode) {
+        case Bytecodes._jsr:
+          addJsr(i.nextBCI(), i.dest());
+          break;
+        case Bytecodes._jsr_w:
+          addJsr(i.nextBCI(), i.dest_w());
+          break;
+        }
+      }
+    }
+    void updateRetTable(int bci, int delta) {
+      RetTableEntry cur = _first;
+      while(cur != null) {
+        cur.addDelta(bci, delta);
+        cur = cur.next();
+      }
+    }
+    RetTableEntry findJsrsForTarget(int targBci) {
+      RetTableEntry cur = _first;
+
+      while(cur != null) {
+        if (Assert.ASSERTS_ENABLED) {
+          Assert.that(cur.targetBci() != -1, "sanity check");
+        }
+        if (cur.targetBci() == targBci) {
+          return cur;
+        }
+        cur = cur.next();
+      }
+      throw new RuntimeException("Should not reach here");
+    }
+  }
+
+  static class BasicBlock {
+    private boolean _changed;              // Reached a fixpoint or not
+    static final int _dead_basic_block = -2;
+    // Alive but not yet reached by analysis
+    static final int _unreached        = -1;
+    // >=0: Alive and has a merged state
+
+    int                     _bci;          // Start of basic block
+    int                     _end_bci;      // Bci of last instruction in basicblock
+    int                     _max_locals;   // Determines split between vars and stack
+    int                     _max_stack;    // Determines split between stack and monitors
+    CellTypeStateList       _state;        // State (vars, stack) at entry.
+    int                     _stack_top;    // -1 indicates bottom stack value.
+    int                     _monitor_top;  // -1 indicates bottom monitor stack value.
+
+    CellTypeStateList       vars()  { return _state; }
+    CellTypeStateList       stack() { return _state.subList(_max_locals, _state.size()); }
+
+    boolean changed()               { return _changed; }
+    void    setChanged(boolean s)   { _changed = s; }
+
+    // Analysis has reached this basicblock
+    boolean isReachable()           { return _stack_top >= 0; }
+
+    // All basicblocks that are unreachable are going to have a _stack_top == _dead_basic_block.
+    // This info. is setup in a pre-parse before the real abstract interpretation starts.
+    boolean isDead()                { return _stack_top == _dead_basic_block; }
+    boolean isAlive()               { return _stack_top != _dead_basic_block; }
+    void    markAsAlive()           {
+      if (Assert.ASSERTS_ENABLED) {
+        Assert.that(isDead(), "must be dead");
+        _stack_top = _unreached;
+      }
+    }
+  }
+
+  //----------------------------------------------------------------------
+  // Protected routines for GenerateOopMap
+  //
+
+  // _monitor_top is set to this constant to indicate that a monitor matching
+  // problem was encountered prior to this point in control flow.
+  protected static final int bad_monitors = -1;
+
+  // Main variables
+  Method   _method;         // The method we are examining
+  RetTable _rt;             // Contains the return address mappings
+  int      _max_locals;     // Cached value of no. of locals
+  int      _max_stack;      // Cached value of max. stack depth
+  int      _max_monitors;   // Cached value of max. monitor stack depth
+  boolean  _has_exceptions; // True, if exceptions exist for method
+  boolean  _got_error;      // True, if an error occured during interpretation.
+  String   _error_msg;      // Error message. Set if _got_error is true.
+  //  bool     _did_rewriting;  // was bytecodes rewritten
+  //  bool     _did_relocation; // was relocation neccessary
+  boolean  _monitor_safe;   // The monitors in this method have been determined
+                            // to be safe.
+
+  // Working Cell type state
+  int               _state_len;     // Size of states
+  CellTypeStateList _state;         // list of states
+  char[]            _state_vec_buf; // Buffer used to print a readable version of a state
+  int               _stack_top;
+  int               _monitor_top;
+
+  // Timing and statistics
+  //  static elapsedTimer _total_oopmap_time;   // Holds cumulative oopmap generation time
+  //  static long         _total_byte_count;    // Holds cumulative number of bytes inspected
+
+  // Monitor query logic
+  int _report_for_exit_bci;
+  int _matching_enter_bci;
+
+  // Cell type methods
+  void            initState() {
+    _state_len = _max_locals + _max_stack + _max_monitors;
+    _state     = new CellTypeStateList(_state_len);
+    _state_vec_buf = new char[Math.max(_max_locals, Math.max(_max_stack, Math.max(_max_monitors, 1)))];
+  }
+  void            makeContextUninitialized () {
+    CellTypeStateList vs = vars();
+
+    for (int i = 0; i < _max_locals; i++)
+      vs.get(i).set(CellTypeState.uninit);
+
+    _stack_top = 0;
+    _monitor_top = 0;
+  }
+
+  int             methodsigToEffect          (Symbol signature, boolean isStatic, CellTypeStateList effect) {
+    ComputeEntryStack ces = new ComputeEntryStack(signature);
+    return ces.computeForParameters(isStatic, effect);
+  }
+
+  boolean         mergeStateVectors          (CellTypeStateList cts, CellTypeStateList bbts) {
+    int i;
+    int len = _max_locals + _stack_top;
+    boolean change = false;
+
+    for (i = len - 1; i >= 0; i--) {
+      CellTypeState v = cts.get(i).merge(bbts.get(i), i);
+      change = change || !v.equal(bbts.get(i));
+      bbts.get(i).set(v);
+    }
+
+    if (_max_monitors > 0 && _monitor_top != bad_monitors) {
+      // If there are no monitors in the program, or there has been
+      // a monitor matching error before this point in the program,
+      // then we do not merge in the monitor state.
+
+      int base = _max_locals + _max_stack;
+      len = base + _monitor_top;
+      for (i = len - 1; i >= base; i--) {
+        CellTypeState v = cts.get(i).merge(bbts.get(i), i);
+
+        // Can we prove that, when there has been a change, it will already
+        // have been detected at this point?  That would make this equal
+        // check here unnecessary.
+        change = change || !v.equal(bbts.get(i));
+        bbts.get(i).set(v);
+      }
+    }
+
+    return change;
+  }
+
+  void            copyState                  (CellTypeStateList dst, CellTypeStateList src) {
+    int len = _max_locals + _stack_top;
+    for (int i = 0; i < len; i++) {
+      if (src.get(i).isNonlockReference()) {
+        dst.get(i).set(CellTypeState.makeSlotRef(i));
+      } else {
+        dst.get(i).set(src.get(i));
+      }
+    }
+    if (_max_monitors > 0 && _monitor_top != bad_monitors) {
+      int base = _max_locals + _max_stack;
+      len = base + _monitor_top;
+      for (int i = base; i < len; i++) {
+        dst.get(i).set(src.get(i));
+      }
+    }
+  }
+
+  void            mergeStateIntoBB           (BasicBlock bb) {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(bb.isAlive(), "merging state into a dead basicblock");
+    }
+
+    if (_stack_top == bb._stack_top) {
+      if (_monitor_top == bb._monitor_top) {
+        if (mergeStateVectors(_state, bb._state)) {
+          bb.setChanged(true);
+        }
+      } else {
+        if (TraceMonitorMismatch) {
+          reportMonitorMismatch("monitor stack height merge conflict");
+        }
+        // When the monitor stacks are not matched, we set _monitor_top to
+        // bad_monitors.  This signals that, from here on, the monitor stack cannot
+        // be trusted.  In particular, monitorexit bytecodes may throw
+        // exceptions.  We mark this block as changed so that the change
+        // propagates properly.
+        bb._monitor_top = bad_monitors;
+        bb.setChanged(true);
+        _monitor_safe = false;
+      }
+    } else if (!bb.isReachable()) {
+      // First time we look at this  BB
+      copyState(bb._state, _state);
+      bb._stack_top = _stack_top;
+      bb._monitor_top = _monitor_top;
+      bb.setChanged(true);
+    } else {
+      throw new RuntimeException("stack height conflict: " +
+                                 _stack_top + " vs. " + bb._stack_top);
+    }
+  }
+
+  void            mergeState                 (int bci, int[] data) {
+    mergeStateIntoBB(getBasicBlockAt(bci));
+  }
+
+  void            setVar                     (int localNo, CellTypeState cts) {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(cts.isReference() || cts.isValue() || cts.isAddress(),
+                  "wrong celltypestate");
+    }
+    if (localNo < 0 || localNo > _max_locals) {
+      throw new RuntimeException("variable write error: r" + localNo);
+    }
+    vars().get(localNo).set(cts);
+  }
+
+  CellTypeState   getVar                     (int localNo) {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(localNo < _max_locals + _nof_refval_conflicts, "variable read error");
+    }
+    if (localNo < 0 || localNo > _max_locals) {
+      throw new RuntimeException("variable read error: r" + localNo);
+    }
+    return vars().get(localNo).copy();
+  }
+
+  CellTypeState   pop                        () {
+    if ( _stack_top <= 0) {
+      throw new RuntimeException("stack underflow");
+    }
+    return  stack().get(--_stack_top).copy();
+  }
+
+  void            push                       (CellTypeState cts) {
+    if ( _stack_top >= _max_stack) {
+      if (DEBUG) {
+        System.err.println("Method: " + method().getName().asString() + method().getSignature().asString() +
+                           " _stack_top: " + _stack_top + " _max_stack: " + _max_stack);
+      }
+      throw new RuntimeException("stack overflow");
+    }
+    stack().get(_stack_top++).set(cts);
+    if (DEBUG) {
+      System.err.println("After push: _stack_top: " + _stack_top +
+                         " _max_stack: " + _max_stack +
+                         " just pushed: " + cts.toChar());
+    }
+  }
+
+  CellTypeState   monitorPop                 () {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(_monitor_top != bad_monitors, "monitorPop called on error monitor stack");
+    }
+    if (_monitor_top == 0) {
+      // We have detected a pop of an empty monitor stack.
+      _monitor_safe = false;
+      _monitor_top = bad_monitors;
+
+      if (TraceMonitorMismatch) {
+        reportMonitorMismatch("monitor stack underflow");
+      }
+      return CellTypeState.ref; // just to keep the analysis going.
+    }
+    return  monitors().get(--_monitor_top).copy();
+  }
+
+  void            monitorPush                (CellTypeState cts) {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(_monitor_top != bad_monitors, "monitorPush called on error monitor stack");
+    }
+    if (_monitor_top >= _max_monitors) {
+      // Some monitorenter is being executed more than once.
+      // This means that the monitor stack cannot be simulated.
+      _monitor_safe = false;
+      _monitor_top = bad_monitors;
+
+      if (TraceMonitorMismatch) {
+        reportMonitorMismatch("monitor stack overflow");
+      }
+      return;
+    }
+    monitors().get(_monitor_top++).set(cts);
+  }
+
+  CellTypeStateList vars    ()     { return _state; }
+  CellTypeStateList stack   ()     { return _state.subList(_max_locals, _state.size()); }
+  CellTypeStateList monitors()     { return _state.subList(_max_locals+_max_stack, _state.size()); }
+
+  void            replaceAllCTSMatches       (CellTypeState match,
+                                              CellTypeState replace) {
+    int i;
+    int len = _max_locals + _stack_top;
+    boolean change = false;
+
+    for (i = len - 1; i >= 0; i--) {
+      if (match.equal(_state.get(i))) {
+        _state.get(i).set(replace);
+      }
+    }
+
+    if (_monitor_top > 0) {
+      int base = _max_locals + _max_stack;
+      len = base + _monitor_top;
+      for (i = len - 1; i >= base; i--) {
+        if (match.equal(_state.get(i))) {
+          _state.get(i).set(replace);
+        }
+      }
+    }
+  }
+
+  void            printStates                (PrintStream tty, CellTypeStateList vector, int num) {
+    for (int i = 0; i < num; i++) {
+      vector.get(i).print(tty);
+    }
+  }
+
+  void            printCurrentState          (PrintStream tty,
+                                              BytecodeStream currentBC,
+                                              boolean        detailed) {
+    if (detailed) {
+      tty.print("     " + currentBC.bci() + " vars     = ");
+      printStates(tty, vars(), _max_locals);
+      tty.print("    " + Bytecodes.name(currentBC.code()));
+      switch(currentBC.code()) {
+      case Bytecodes._invokevirtual:
+      case Bytecodes._invokespecial:
+      case Bytecodes._invokestatic:
+      case Bytecodes._invokeinterface:
+        // FIXME: print signature of referenced method (need more
+        // accessors in ConstantPool and ConstantPoolCache)
+        int idx = currentBC.getIndexBig();
+        tty.print(" idx " + idx);
+        /*
+          int idx = currentBC.getIndexBig();
+          ConstantPool cp       = method().getConstants();
+          int nameAndTypeIdx    = cp.name_and_type_ref_index_at(idx);
+          int signatureIdx      = cp.signature_ref_index_at(nameAndTypeIdx);
+          symbolOop signature   = cp.symbol_at(signatureIdx);
+          tty.print("%s", signature.as_C_string());
+        */
+      }
+      tty.println();
+      tty.print("          stack    = ");
+      printStates(tty, stack(), _stack_top);
+      tty.println();
+      if (_monitor_top != bad_monitors) {
+        tty.print("          monitors = ");
+        printStates(tty, monitors(), _monitor_top);
+      } else {
+        tty.print("          [bad monitor stack]");
+      }
+      tty.println();
+    } else {
+      tty.print("    " + currentBC.bci() + "  vars = '" +
+                stateVecToString(vars(), _max_locals) + "' ");
+      tty.print("     stack = '" + stateVecToString(stack(), _stack_top) + "' ");
+      if (_monitor_top != bad_monitors) {
+        tty.print("  monitors = '" + stateVecToString(monitors(), _monitor_top) + "'  \t" +
+                  Bytecodes.name(currentBC.code()));
+      } else {
+        tty.print("  [bad monitor stack]");
+      }
+      switch(currentBC.code()) {
+      case Bytecodes._invokevirtual:
+      case Bytecodes._invokespecial:
+      case Bytecodes._invokestatic:
+      case Bytecodes._invokeinterface:
+        // FIXME: print signature of referenced method (need more
+        // accessors in ConstantPool and ConstantPoolCache)
+        int idx = currentBC.getIndexBig();
+        tty.print(" idx " + idx);
+        /*
+          int idx = currentBC.getIndexBig();
+          constantPoolOop cp    = method().constants();
+          int nameAndTypeIdx    = cp.name_and_type_ref_index_at(idx);
+          int signatureIdx      = cp.signature_ref_index_at(nameAndTypeIdx);
+          symbolOop signature   = cp.symbol_at(signatureIdx);
+          tty.print("%s", signature.as_C_string());
+        */
+      }
+      tty.println();
+    }
+  }
+
+  void            reportMonitorMismatch      (String msg) {
+    if (Assert.ASSERTS_ENABLED) {
+      System.err.print("    Monitor mismatch in method ");
+      method().printValueOn(System.err);
+      System.err.println(": " + msg);
+    }
+  }
+
+  // Basicblock info
+  BasicBlock[]    _basic_blocks;             // Array of basicblock info
+  int             _gc_points;
+  int             _bb_count;
+  BitMap          _bb_hdr_bits;
+
+  // Basicblocks methods
+  void          initializeBB               () {
+    _gc_points = 0;
+    _bb_count  = 0;
+    _bb_hdr_bits = new BitMap((int) _method.getCodeSize());
+  }
+
+  void          markBBHeadersAndCountGCPoints() {
+    initializeBB();
+
+    boolean fellThrough = false;  // False to get first BB marked.
+
+    // First mark all exception handlers as start of a basic-block
+    TypeArray excps = method().getExceptionTable();
+    for(int i = 0; i < excps.getLength(); i += 4) {
+      int handler_pc_idx = i+2;
+      markBB(excps.getIntAt(handler_pc_idx), null);
+    }
+
+    // Then iterate through the code
+    BytecodeStream bcs = new BytecodeStream(_method);
+    int bytecode;
+
+    while( (bytecode = bcs.next()) >= 0) {
+      int bci = bcs.bci();
+
+      if (!fellThrough)
+        markBB(bci, null);
+
+      fellThrough = jumpTargetsDo(bcs,
+                                  new JumpClosure() {
+                                      public void process(GenerateOopMap c, int bcpDelta, int[] data) {
+                                        c.markBB(bcpDelta, data);
+                                      }
+                                    },
+                                  null);
+
+      /* We will also mark successors of jsr's as basic block headers. */
+      switch (bytecode) {
+      case Bytecodes._jsr:
+        if (Assert.ASSERTS_ENABLED) {
+          Assert.that(!fellThrough, "should not happen");
+        }
+        markBB(bci + Bytecodes.lengthFor(bytecode), null);
+        break;
+      case Bytecodes._jsr_w:
+        if (Assert.ASSERTS_ENABLED) {
+          Assert.that(!fellThrough, "should not happen");
+        }
+        markBB(bci + Bytecodes.lengthFor(bytecode), null);
+        break;
+      }
+
+      if (possibleGCPoint(bcs))
+        _gc_points++;
+    }
+  }
+
+  boolean       isBBHeader                  (int bci) {
+    return _bb_hdr_bits.at(bci);
+  }
+
+  int           gcPoints                    () {
+    return _gc_points;
+  }
+
+  int           bbCount                     () {
+    return _bb_count;
+  }
+
+  void          setBBMarkBit                (int bci) {
+    _bb_hdr_bits.atPut(bci, true);
+  }
+
+  void          clear_bbmark_bit            (int bci) {
+    _bb_hdr_bits.atPut(bci, false);
+  }
+
+  BasicBlock    getBasicBlockAt             (int bci) {
+    BasicBlock bb = getBasicBlockContaining(bci);
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(bb._bci == bci, "should have found BB");
+    }
+    return bb;
+  }
+
+  BasicBlock    getBasicBlockContaining     (int bci) {
+    BasicBlock[] bbs = _basic_blocks;
+    int lo = 0, hi = _bb_count - 1;
+
+    while (lo <= hi) {
+      int m = (lo + hi) / 2;
+      int mbci = bbs[m]._bci;
+      int nbci;
+
+      if ( m == _bb_count-1) {
+        if (Assert.ASSERTS_ENABLED) {
+          Assert.that( bci >= mbci && bci < method().getCodeSize(), "sanity check failed");
+        }
+        return bbs[m];
+      } else {
+        nbci = bbs[m+1]._bci;
+      }
+
+      if ( mbci <= bci && bci < nbci) {
+        return bbs[m];
+      } else if (mbci < bci) {
+        lo = m + 1;
+      } else {
+        if (Assert.ASSERTS_ENABLED) {
+          Assert.that(mbci > bci, "sanity check");
+        }
+        hi = m - 1;
+      }
+    }
+
+    throw new RuntimeException("should have found BB");
+  }
+
+  void          interpBB                    (BasicBlock bb) {
+    // We do not want to do anything in case the basic-block has not been initialized. This
+    // will happen in the case where there is dead-code hang around in a method.
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(bb.isReachable(), "should be reachable or deadcode exist");
+    }
+    restoreState(bb);
+
+    BytecodeStream itr = new BytecodeStream(_method);
+
+    // Set iterator interval to be the current basicblock
+    int lim_bci = nextBBStartPC(bb);
+    itr.setInterval(bb._bci, lim_bci);
+
+    if (DEBUG) {
+      System.err.println("interpBB: method = " + method().getName().asString() +
+                         method().getSignature().asString() +
+                         ", BCI interval [" + bb._bci + ", " + lim_bci + ")");
+      {
+        System.err.print("Bytecodes:");
+        for (int i = bb._bci; i < lim_bci; i++) {
+          System.err.print(" 0x" + Long.toHexString(method().getBytecodeOrBPAt(i)));
+        }
+        System.err.println();
+      }
+    }
+
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(lim_bci != bb._bci, "must be at least one instruction in a basicblock");
+    }
+    itr.next(); // read first instruction
+
+    // Iterates through all bytecodes except the last in a basic block.
+    // We handle the last one special, since there is controlflow change.
+    while(itr.nextBCI() < lim_bci && !_got_error) {
+      if (_has_exceptions || (_monitor_top != 0)) {
+        // We do not need to interpret the results of exceptional
+        // continuation from this instruction when the method has no
+        // exception handlers and the monitor stack is currently
+        // empty.
+        doExceptionEdge(itr);
+      }
+      interp1(itr);
+      itr.next();
+    }
+
+    // Handle last instruction.
+    if (!_got_error) {
+      if (Assert.ASSERTS_ENABLED) {
+        Assert.that(itr.nextBCI() == lim_bci, "must point to end");
+      }
+      if (_has_exceptions || (_monitor_top != 0)) {
+        doExceptionEdge(itr);
+      }
+      interp1(itr);
+
+      boolean fall_through = jumpTargetsDo(itr, new JumpClosure() {
+          public void process(GenerateOopMap c, int bcpDelta, int[] data) {
+            c.mergeState(bcpDelta, data);
+          }
+        }, null);
+      if (_got_error)  return;
+
+      if (itr.code() == Bytecodes._ret) {
+        if (Assert.ASSERTS_ENABLED) {
+          Assert.that(!fall_through, "cannot be set if ret instruction");
+        }
+        // Automatically handles 'wide' ret indicies
+        retJumpTargetsDo(itr, new JumpClosure() {
+            public void process(GenerateOopMap c, int bcpDelta, int[] data) {
+              c.mergeState(bcpDelta, data);
+            }
+          }, itr.getIndex(), null);
+      } else if (fall_through) {
+        // Hit end of BB, but the instr. was a fall-through instruction,
+        // so perform transition as if the BB ended in a "jump".
+        if (Assert.ASSERTS_ENABLED) {
+          Assert.that(lim_bci == _basic_blocks[bbIndex(bb) + 1]._bci, "there must be another bb");
+        }
+        mergeStateIntoBB(_basic_blocks[bbIndex(bb) + 1]);
+      }
+    }
+  }
+
+  void          restoreState                (BasicBlock bb) {
+    for (int i = 0; i < _state_len; i++) {
+      _state.get(i).set(bb._state.get(i));
+    }
+    _stack_top   = bb._stack_top;
+    _monitor_top = bb._monitor_top;
+  }
+
+  int           nextBBStartPC               (BasicBlock bb) {
+    int bbNum = bbIndex(bb) + 1;
+    if (bbNum == _bb_count)
+      return (int) method().getCodeSize();
+
+    return _basic_blocks[bbNum]._bci;
+  }
+
+  void          updateBasicBlocks           (int bci, int delta) {
+    BitMap bbBits = new BitMap((int) (_method.getCodeSize() + delta));
+    for(int k = 0; k < _bb_count; k++) {
+      if (_basic_blocks[k]._bci > bci) {
+        _basic_blocks[k]._bci     += delta;
+        _basic_blocks[k]._end_bci += delta;
+      }
+      bbBits.atPut(_basic_blocks[k]._bci, true);
+    }
+    _bb_hdr_bits = bbBits;
+  }
+
+  void markBB(int bci, int[] data) {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(bci>= 0 && bci < method().getCodeSize(), "index out of bounds");
+    }
+    if (isBBHeader(bci))
+      return;
+
+    // FIXME: remove
+    //    if (TraceNewOopMapGeneration) {
+    //      tty.print_cr("Basicblock#%d begins at: %d", c._bb_count, bci);
+    //    }
+    setBBMarkBit(bci);
+    _bb_count++;
+  }
+
+  // Dead code detection
+  void          markReachableCode() {
+    final int[] change = new int[1];
+    change[0] = 1;
+
+    // Mark entry basic block as alive and all exception handlers
+    _basic_blocks[0].markAsAlive();
+    TypeArray excps = method().getExceptionTable();
+    for(int i = 0; i < excps.getLength(); i += 4) {
+      int handler_pc_idx = i+2;
+      BasicBlock bb = getBasicBlockAt(excps.getIntAt(handler_pc_idx));
+      // If block is not already alive (due to multiple exception handlers to same bb), then
+      // make it alive
+      if (bb.isDead())
+        bb.markAsAlive();
+    }
+
+    BytecodeStream bcs = new BytecodeStream(_method);
+
+    // Iterate through all basic blocks until we reach a fixpoint
+    while (change[0] != 0) {
+      change[0] = 0;
+
+      for (int i = 0; i < _bb_count; i++) {
+        BasicBlock bb = _basic_blocks[i];
+        if (bb.isAlive()) {
+          // Position bytecodestream at last bytecode in basicblock
+          bcs.setStart(bb._end_bci);
+          bcs.next();
+          int bytecode = bcs.code();
+          int bci = bcs.bci();
+          if (Assert.ASSERTS_ENABLED) {
+            Assert.that(bci == bb._end_bci, "wrong bci");
+          }
+
+          boolean fell_through = jumpTargetsDo(bcs, new JumpClosure() {
+              public void process(GenerateOopMap c, int bciDelta, int[] change) {
+                c.reachableBasicblock(bciDelta, change);
+              }
+            }, change);
+
+          // We will also mark successors of jsr's as alive.
+          switch (bytecode) {
+          case Bytecodes._jsr:
+          case Bytecodes._jsr_w:
+            if (Assert.ASSERTS_ENABLED) {
+              Assert.that(!fell_through, "should not happen");
+            }
+            reachableBasicblock(bci + Bytecodes.lengthFor(bytecode), change);
+            break;
+          }
+          if (fell_through) {
+            // Mark successor as alive
+            if (_basic_blocks[i+1].isDead()) {
+              _basic_blocks[i+1].markAsAlive();
+              change[0] = 1;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  void  reachableBasicblock        (int bci, int[] data) {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(bci>= 0 && bci < method().getCodeSize(), "index out of bounds");
+    }
+    BasicBlock bb = getBasicBlockAt(bci);
+    if (bb.isDead()) {
+      bb.markAsAlive();
+      data[0] = 1; // Mark basicblock as changed
+    }
+  }
+
+  // Interpretation methods (primary)
+  void  doInterpretation                    () {
+    // "i" is just for debugging, so we can detect cases where this loop is
+    // iterated more than once.
+    int i = 0;
+    do {
+      // FIXME: remove
+      //      if (TraceNewOopMapGeneration) {
+      //        tty.print("\n\nIteration #%d of do_interpretation loop, method:\n", i);
+      //        method().print_name(tty);
+      //        tty.print("\n\n");
+      //      }
+      _conflict = false;
+      _monitor_safe = true;
+      // init_state is now called from init_basic_blocks.  The length of a
+      // state vector cannot be determined until we have made a pass through
+      // the bytecodes counting the possible monitor entries.
+      if (!_got_error) initBasicBlocks();
+      if (!_got_error) setupMethodEntryState();
+      if (!_got_error) interpAll();
+      if (!_got_error) rewriteRefvalConflicts();
+      i++;
+    } while (_conflict && !_got_error);
+  }
+
+  void  initBasicBlocks                     () {
+    // Note: Could consider reserving only the needed space for each BB's state
+    // (entry stack may not be of maximal height for every basic block).
+    // But cumbersome since we don't know the stack heights yet.  (Nor the
+    // monitor stack heights...)
+
+    _basic_blocks = new BasicBlock[_bb_count];
+    for (int i = 0; i < _bb_count; i++) {
+      _basic_blocks[i] = new BasicBlock();
+    }
+
+    // Make a pass through the bytecodes.  Count the number of monitorenters.
+    // This can be used an upper bound on the monitor stack depth in programs
+    // which obey stack discipline with their monitor usage.  Initialize the
+    // known information about basic blocks.
+    BytecodeStream j = new BytecodeStream(_method);
+    int bytecode;
+
+    int bbNo = 0;
+    int monitor_count = 0;
+    int prev_bci = -1;
+    while( (bytecode = j.next()) >= 0) {
+      if (j.code() == Bytecodes._monitorenter) {
+        monitor_count++;
+      }
+
+      int bci = j.bci();
+      if (isBBHeader(bci)) {
+        // Initialize the basicblock structure
+        BasicBlock bb    = _basic_blocks[bbNo];
+        bb._bci          = bci;
+        bb._max_locals   = _max_locals;
+        bb._max_stack    = _max_stack;
+        bb.setChanged(false);
+        bb._stack_top    = BasicBlock._dead_basic_block; // Initialize all basicblocks are dead.
+        bb._monitor_top  = bad_monitors;
+
+        if (bbNo > 0) {
+          _basic_blocks[bbNo - 1]._end_bci = prev_bci;
+        }
+
+        bbNo++;
+      }
+      // Remember prevous bci.
+      prev_bci = bci;
+    }
+    // Set
+    _basic_blocks[bbNo-1]._end_bci = prev_bci;
+
+    _max_monitors = monitor_count;
+
+    // Now that we have a bound on the depth of the monitor stack, we can
+    // initialize the CellTypeState-related information.
+    initState();
+
+    // We allocate space for all state-vectors for all basicblocks in one huge chuck.
+    // Then in the next part of the code, we set a pointer in each _basic_block that
+    // points to each piece.
+    CellTypeStateList basicBlockState = new CellTypeStateList(bbNo * _state_len);
+
+    // Make a pass over the basicblocks and assign their state vectors.
+    for (int blockNum=0; blockNum < bbNo; blockNum++) {
+      BasicBlock bb = _basic_blocks[blockNum];
+      bb._state = basicBlockState.subList(blockNum * _state_len, (blockNum + 1) * _state_len);
+
+      if (Assert.ASSERTS_ENABLED) {
+        if (blockNum + 1 < bbNo) {
+          int bc_len = Bytecodes.javaLengthAt(_method, bb._end_bci);
+          Assert.that(bb._end_bci + bc_len == _basic_blocks[blockNum + 1]._bci,
+                      "unmatched bci info in basicblock");
+        }
+      }
+    }
+    if (Assert.ASSERTS_ENABLED) {
+      BasicBlock bb = _basic_blocks[bbNo-1];
+      int bc_len = Bytecodes.javaLengthAt(_method, bb._end_bci);
+      Assert.that(bb._end_bci + bc_len == _method.getCodeSize(), "wrong end bci");
+    }
+
+    // Check that the correct number of basicblocks was found
+    if (bbNo !=_bb_count) {
+      if (bbNo < _bb_count) {
+        throw new RuntimeException("jump into the middle of instruction?");
+      } else {
+        throw new RuntimeException("extra basic blocks - should not happen?");
+      }
+    }
+
+    // Mark all alive blocks
+    markReachableCode();
+  }
+
+  void  setupMethodEntryState               () {
+    // Initialize all locals to 'uninit' and set stack-height to 0
+    makeContextUninitialized();
+
+    // Initialize CellState type of arguments
+    methodsigToEffect(method().getSignature(), method().isStatic(), vars());
+
+    // If some references must be pre-assigned to null, then set that up
+    initializeVars();
+
+    // This is the start state
+    mergeStateIntoBB(_basic_blocks[0]);
+
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(_basic_blocks[0].changed(), "we are not getting off the ground");
+    }
+  }
+
+  void  interpAll                           () {
+    boolean change = true;
+
+    while (change && !_got_error) {
+      change = false;
+      for (int i = 0; i < _bb_count && !_got_error; i++) {
+        BasicBlock bb = _basic_blocks[i];
+        if (bb.changed()) {
+          if (_got_error) return;
+          change = true;
+          bb.setChanged(false);
+          interpBB(bb);
+        }
+      }
+    }
+  }
+
+  //
+  // Interpretation methods (secondary)
+  //
+
+  /** Sets the current state to be the state after executing the
+      current instruction, starting in the current state. */
+  void  interp1                             (BytecodeStream itr) {
+    if (DEBUG) {
+      System.err.println(" - bci " + itr.bci());
+    }
+
+    //    if (TraceNewOopMapGeneration) {
+    //      print_current_state(tty, itr, TraceNewOopMapGenerationDetailed);
+    //    }
+
+    // Should we report the results? Result is reported *before* the
+    // instruction at the current bci is executed.  However, not for
+    // calls. For calls we do not want to include the arguments, so we
+    // postpone the reporting until they have been popped (in method
+    // ppl).
+    if (_report_result == true) {
+      switch(itr.code()) {
+      case Bytecodes._invokevirtual:
+      case Bytecodes._invokespecial:
+      case Bytecodes._invokestatic:
+      case Bytecodes._invokeinterface:
+        _itr_send = itr;
+        _report_result_for_send = true;
+        break;
+      default:
+        fillStackmapForOpcodes(itr, vars(), stack(), _stack_top);
+        break;
+      }
+    }
+
+    // abstract interpretation of current opcode
+    switch(itr.code()) {
+    case Bytecodes._nop:               break;
+    case Bytecodes._goto:              break;
+    case Bytecodes._goto_w:            break;
+    case Bytecodes._iinc:              break;
+    case Bytecodes._return:            doReturnMonitorCheck();
+      break;
+
+    case Bytecodes._aconst_null:
+    case Bytecodes._new:               ppush1(CellTypeState.makeLineRef(itr.bci()));
+      break;
+
+    case Bytecodes._iconst_m1:
+    case Bytecodes._iconst_0:
+    case Bytecodes._iconst_1:
+    case Bytecodes._iconst_2:
+    case Bytecodes._iconst_3:
+    case Bytecodes._iconst_4:
+    case Bytecodes._iconst_5:
+    case Bytecodes._fconst_0:
+    case Bytecodes._fconst_1:
+    case Bytecodes._fconst_2:
+    case Bytecodes._bipush:
+    case Bytecodes._sipush:            ppush1(valCTS);             break;
+
+    case Bytecodes._lconst_0:
+    case Bytecodes._lconst_1:
+    case Bytecodes._dconst_0:
+    case Bytecodes._dconst_1:          ppush(vvCTS);               break;
+
+    case Bytecodes._ldc2_w:            ppush(vvCTS);               break;
+
+    case Bytecodes._ldc:               doLdc(itr.getIndex(), itr.bci());    break;
+    case Bytecodes._ldc_w:             doLdc(itr.getIndexBig(), itr.bci());break;
+
+    case Bytecodes._iload:
+    case Bytecodes._fload:             ppload(vCTS, itr.getIndex()); break;
+
+    case Bytecodes._lload:
+    case Bytecodes._dload:             ppload(vvCTS,itr.getIndex()); break;
+
+    case Bytecodes._aload:             ppload(rCTS, itr.getIndex()); break;
+
+    case Bytecodes._iload_0:
+    case Bytecodes._fload_0:           ppload(vCTS, 0);            break;
+    case Bytecodes._iload_1:
+    case Bytecodes._fload_1:           ppload(vCTS, 1);            break;
+    case Bytecodes._iload_2:
+    case Bytecodes._fload_2:           ppload(vCTS, 2);            break;
+    case Bytecodes._iload_3:
+    case Bytecodes._fload_3:           ppload(vCTS, 3);            break;
+
+    case Bytecodes._lload_0:
+    case Bytecodes._dload_0:           ppload(vvCTS, 0);           break;
+    case Bytecodes._lload_1:
+    case Bytecodes._dload_1:           ppload(vvCTS, 1);           break;
+    case Bytecodes._lload_2:
+    case Bytecodes._dload_2:           ppload(vvCTS, 2);           break;
+    case Bytecodes._lload_3:
+    case Bytecodes._dload_3:           ppload(vvCTS, 3);           break;
+
+    case Bytecodes._aload_0:           ppload(rCTS, 0);            break;
+    case Bytecodes._aload_1:           ppload(rCTS, 1);            break;
+    case Bytecodes._aload_2:           ppload(rCTS, 2);            break;
+    case Bytecodes._aload_3:           ppload(rCTS, 3);            break;
+
+    case Bytecodes._iaload:
+    case Bytecodes._faload:
+    case Bytecodes._baload:
+    case Bytecodes._caload:
+    case Bytecodes._saload:            pp(vrCTS, vCTS); break;
+
+    case Bytecodes._laload:            pp(vrCTS, vvCTS);  break;
+    case Bytecodes._daload:            pp(vrCTS, vvCTS); break;
+
+    case Bytecodes._aaload:            ppNewRef(vrCTS, itr.bci()); break;
+
+    case Bytecodes._istore:
+    case Bytecodes._fstore:            ppstore(vCTS, itr.getIndex()); break;
+
+    case Bytecodes._lstore:
+    case Bytecodes._dstore:            ppstore(vvCTS, itr.getIndex()); break;
+
+    case Bytecodes._astore:            doAstore(itr.getIndex());     break;
+
+    case Bytecodes._istore_0:
+    case Bytecodes._fstore_0:          ppstore(vCTS, 0);           break;
+    case Bytecodes._istore_1:
+    case Bytecodes._fstore_1:          ppstore(vCTS, 1);           break;
+    case Bytecodes._istore_2:
+    case Bytecodes._fstore_2:          ppstore(vCTS, 2);           break;
+    case Bytecodes._istore_3:
+    case Bytecodes._fstore_3:          ppstore(vCTS, 3);           break;
+
+    case Bytecodes._lstore_0:
+    case Bytecodes._dstore_0:          ppstore(vvCTS, 0);          break;
+    case Bytecodes._lstore_1:
+    case Bytecodes._dstore_1:          ppstore(vvCTS, 1);          break;
+    case Bytecodes._lstore_2:
+    case Bytecodes._dstore_2:          ppstore(vvCTS, 2);          break;
+    case Bytecodes._lstore_3:
+    case Bytecodes._dstore_3:          ppstore(vvCTS, 3);          break;
+
+    case Bytecodes._astore_0:          doAstore(0);                break;
+    case Bytecodes._astore_1:          doAstore(1);                break;
+    case Bytecodes._astore_2:          doAstore(2);                break;
+    case Bytecodes._astore_3:          doAstore(3);                break;
+
+    case Bytecodes._iastore:
+    case Bytecodes._fastore:
+    case Bytecodes._bastore:
+    case Bytecodes._castore:
+    case Bytecodes._sastore:           ppop(vvrCTS);               break;
+    case Bytecodes._lastore:
+    case Bytecodes._dastore:           ppop(vvvrCTS);              break;
+    case Bytecodes._aastore:           ppop(rvrCTS);               break;
+
+    case Bytecodes._pop:               ppopAny(1);                 break;
+    case Bytecodes._pop2:              ppopAny(2);                 break;
+
+    case Bytecodes._dup:               ppdupswap(1, "11");         break;
+    case Bytecodes._dup_x1:            ppdupswap(2, "121");        break;
+    case Bytecodes._dup_x2:            ppdupswap(3, "1321");       break;
+    case Bytecodes._dup2:              ppdupswap(2, "2121");       break;
+    case Bytecodes._dup2_x1:           ppdupswap(3, "21321");      break;
+    case Bytecodes._dup2_x2:           ppdupswap(4, "214321");     break;
+    case Bytecodes._swap:              ppdupswap(2, "12");         break;
+
+    case Bytecodes._iadd:
+    case Bytecodes._fadd:
+    case Bytecodes._isub:
+    case Bytecodes._fsub:
+    case Bytecodes._imul:
+    case Bytecodes._fmul:
+    case Bytecodes._idiv:
+    case Bytecodes._fdiv:
+    case Bytecodes._irem:
+    case Bytecodes._frem:
+    case Bytecodes._ishl:
+    case Bytecodes._ishr:
+    case Bytecodes._iushr:
+    case Bytecodes._iand:
+    case Bytecodes._ior:
+    case Bytecodes._ixor:
+    case Bytecodes._l2f:
+    case Bytecodes._l2i:
+    case Bytecodes._d2f:
+    case Bytecodes._d2i:
+    case Bytecodes._fcmpl:
+    case Bytecodes._fcmpg:             pp(vvCTS, vCTS); break;
+
+    case Bytecodes._ladd:
+    case Bytecodes._dadd:
+    case Bytecodes._lsub:
+    case Bytecodes._dsub:
+    case Bytecodes._lmul:
+    case Bytecodes._dmul:
+    case Bytecodes._ldiv:
+    case Bytecodes._ddiv:
+    case Bytecodes._lrem:
+    case Bytecodes._drem:
+    case Bytecodes._land:
+    case Bytecodes._lor:
+    case Bytecodes._lxor:              pp(vvvvCTS, vvCTS); break;
+
+    case Bytecodes._ineg:
+    case Bytecodes._fneg:
+    case Bytecodes._i2f:
+    case Bytecodes._f2i:
+    case Bytecodes._i2c:
+    case Bytecodes._i2s:
+    case Bytecodes._i2b:               pp(vCTS, vCTS); break;
+
+    case Bytecodes._lneg:
+    case Bytecodes._dneg:
+    case Bytecodes._l2d:
+    case Bytecodes._d2l:               pp(vvCTS, vvCTS); break;
+
+    case Bytecodes._lshl:
+    case Bytecodes._lshr:
+    case Bytecodes._lushr:             pp(vvvCTS, vvCTS); break;
+
+    case Bytecodes._i2l:
+    case Bytecodes._i2d:
+    case Bytecodes._f2l:
+    case Bytecodes._f2d:               pp(vCTS, vvCTS); break;
+
+    case Bytecodes._lcmp:              pp(vvvvCTS, vCTS); break;
+    case Bytecodes._dcmpl:
+    case Bytecodes._dcmpg:             pp(vvvvCTS, vCTS); break;
+
+    case Bytecodes._ifeq:
+    case Bytecodes._ifne:
+    case Bytecodes._iflt:
+    case Bytecodes._ifge:
+    case Bytecodes._ifgt:
+    case Bytecodes._ifle:
+    case Bytecodes._tableswitch:       ppop1(valCTS);
+      break;
+    case Bytecodes._ireturn:
+    case Bytecodes._freturn:           doReturnMonitorCheck();
+      ppop1(valCTS);
+      break;
+    case Bytecodes._if_icmpeq:
+    case Bytecodes._if_icmpne:
+    case Bytecodes._if_icmplt:
+    case Bytecodes._if_icmpge:
+    case Bytecodes._if_icmpgt:
+    case Bytecodes._if_icmple:         ppop(vvCTS);
+      break;
+
+    case Bytecodes._lreturn:           doReturnMonitorCheck();
+      ppop(vvCTS);
+      break;
+
+    case Bytecodes._dreturn:           doReturnMonitorCheck();
+      ppop(vvCTS);
+      break;
+
+    case Bytecodes._if_acmpeq:
+    case Bytecodes._if_acmpne:         ppop(rrCTS);                 break;
+
+    case Bytecodes._jsr:               doJsr(itr.dest());          break;
+    case Bytecodes._jsr_w:             doJsr(itr.dest_w());        break;
+
+    case Bytecodes._getstatic:         doField(true,  true,
+                                               itr.getIndexBig(),
+                                               itr.bci()); break;
+    case Bytecodes._putstatic:         doField(false, true,  itr.getIndexBig(), itr.bci()); break;
+    case Bytecodes._getfield:          doField(true,  false, itr.getIndexBig(), itr.bci()); break;
+    case Bytecodes._putfield:          doField(false, false, itr.getIndexBig(), itr.bci()); break;
+
+    case Bytecodes._invokevirtual:
+    case Bytecodes._invokespecial:     doMethod(false, false, itr.getIndexBig(), itr.bci()); break;
+    case Bytecodes._invokestatic:      doMethod(true,  false, itr.getIndexBig(), itr.bci()); break;
+    case Bytecodes._invokeinterface:   doMethod(false, true,  itr.getIndexBig(), itr.bci()); break;
+    case Bytecodes._newarray:
+    case Bytecodes._anewarray:         ppNewRef(vCTS, itr.bci()); break;
+    case Bytecodes._checkcast:         doCheckcast(); break;
+    case Bytecodes._arraylength:
+    case Bytecodes._instanceof:        pp(rCTS, vCTS); break;
+    case Bytecodes._monitorenter:      doMonitorenter(itr.bci()); break;
+    case Bytecodes._monitorexit:       doMonitorexit(itr.bci()); break;
+
+    case Bytecodes._athrow:            // handled by do_exception_edge() BUT ...
+      // vlh(apple): doExceptionEdge() does not get
+      // called if method has no exception handlers
+      if ((!_has_exceptions) && (_monitor_top > 0)) {
+        _monitor_safe = false;
+      }
+      break;
+
+    case Bytecodes._areturn:           doReturnMonitorCheck();
+      ppop1(refCTS);
+      break;
+    case Bytecodes._ifnull:
+    case Bytecodes._ifnonnull:         ppop1(refCTS); break;
+    case Bytecodes._multianewarray:    doMultianewarray(itr.codeAt(itr.bci() + 3), itr.bci()); break;
+
+    case Bytecodes._wide:              throw new RuntimeException("Iterator should skip this bytecode");
+    case Bytecodes._ret:                                           break;
+
+      // Java opcodes
+    case Bytecodes._fast_aaccess_0:     ppNewRef(rCTS, itr.bci()); break; // Pair bytecode for (aload_0, _fast_agetfield)
+
+    case Bytecodes._fast_iaccess_0:     ppush1(valCTS);            break; // Pair bytecode for (aload_0, _fast_igetfield)
+
+    case Bytecodes._fast_igetfield:     pp(rCTS, vCTS);            break;
+
+    case Bytecodes._fast_agetfield:     ppNewRef(rCTS, itr.bci()); break;
+
+    case Bytecodes._fast_aload_0:       ppload(rCTS,  0);          break;
+
+    case Bytecodes._lookupswitch:
+    case Bytecodes._fast_linearswitch:
+    case Bytecodes._fast_binaryswitch:  ppop1(valCTS);             break;
+
+    default:
+      throw new RuntimeException("unexpected opcode: " + itr.code());
+    }
+  }
+
+  void  doExceptionEdge                     (BytecodeStream itr) {
+    // Only check exception edge, if bytecode can trap
+    if (!Bytecodes.canTrap(itr.code())) return;
+    switch (itr.code()) {
+    case Bytecodes._aload_0:
+    case Bytecodes._fast_aload_0:
+      // These bytecodes can trap for rewriting.  We need to assume that
+      // they do not throw exceptions to make the monitor analysis work.
+      return;
+
+    case Bytecodes._ireturn:
+    case Bytecodes._lreturn:
+    case Bytecodes._freturn:
+    case Bytecodes._dreturn:
+    case Bytecodes._areturn:
+    case Bytecodes._return:
+      // If the monitor stack height is not zero when we leave the method,
+      // then we are either exiting with a non-empty stack or we have
+      // found monitor trouble earlier in our analysis.  In either case,
+      // assume an exception could be taken here.
+      if (_monitor_top == 0) {
+        return;
+      }
+      break;
+
+    case Bytecodes._monitorexit:
+      // If the monitor stack height is bad_monitors, then we have detected a
+      // monitor matching problem earlier in the analysis.  If the
+      // monitor stack height is 0, we are about to pop a monitor
+      // off of an empty stack.  In either case, the bytecode
+      // could throw an exception.
+      if (_monitor_top != bad_monitors && _monitor_top != 0) {
+        return;
+      }
+      break;
+    }
+
+    if (_has_exceptions) {
+      int bci = itr.bci();
+      TypeArray exct   = method().getExceptionTable();
+      for(int i = 0; i< exct.getLength(); i+=4) {
+        int start_pc   = exct.getIntAt(i);
+        int end_pc     = exct.getIntAt(i+1);
+        int handler_pc = exct.getIntAt(i+2);
+        int catch_type = exct.getIntAt(i+3);
+
+        if (start_pc <= bci && bci < end_pc) {
+          BasicBlock excBB = getBasicBlockAt(handler_pc);
+          CellTypeStateList excStk  = excBB.stack();
+          CellTypeStateList cOpStck = stack();
+          CellTypeState cOpStck_0 = cOpStck.get(0).copy();
+          int cOpStackTop = _stack_top;
+
+          // Exception stacks are always the same.
+          if (Assert.ASSERTS_ENABLED) {
+            Assert.that(method().getMaxStack() > 0, "sanity check");
+          }
+
+          // We remembered the size and first element of "cOpStck"
+          // above; now we temporarily set them to the appropriate
+          // values for an exception handler.
+          cOpStck.get(0).set(CellTypeState.makeSlotRef(_max_locals));
+          _stack_top = 1;
+
+          mergeStateIntoBB(excBB);
+
+          // Now undo the temporary change.
+          cOpStck.get(0).set(cOpStck_0);
+          _stack_top = cOpStackTop;
+
+          // If this is a "catch all" handler, then we do not need to
+          // consider any additional handlers.
+          if (catch_type == 0) {
+            return;
+          }
+        }
+      }
+    }
+
+    // It is possible that none of the exception handlers would have caught
+    // the exception.  In this case, we will exit the method.  We must
+    // ensure that the monitor stack is empty in this case.
+    if (_monitor_top == 0) {
+      return;
+    }
+
+    // We pessimistically assume that this exception can escape the
+    // method. (It is possible that it will always be caught, but
+    // we don't care to analyse the types of the catch clauses.)
+
+    // We don't set _monitor_top to bad_monitors because there are no successors
+    // to this exceptional exit.
+
+    if (TraceMonitorMismatch && _monitor_safe) {
+      // We check _monitor_safe so that we only report the first mismatched
+      // exceptional exit.
+      reportMonitorMismatch("non-empty monitor stack at exceptional exit");
+    }
+    _monitor_safe = false;
+  }
+
+  void  checkType                           (CellTypeState expected, CellTypeState actual) {
+    if (!expected.equalKind(actual)) {
+      throw new RuntimeException("wrong type on stack (found: " +
+                                 actual.toChar() + " expected: " +
+                                 expected.toChar() + ")");
+    }
+  }
+
+  void  ppstore                             (CellTypeState[] in,  int loc_no) {
+    for (int i = 0; i < in.length && !in[i].equal(CellTypeState.bottom); i++) {
+      CellTypeState expected = in[i];
+      CellTypeState actual   = pop();
+      checkType(expected, actual);
+      if (Assert.ASSERTS_ENABLED) {
+        Assert.that(loc_no >= 0, "sanity check");
+      }
+      setVar(loc_no++, actual);
+    }
+  }
+
+  void  ppload                              (CellTypeState[] out, int loc_no) {
+    for (int i = 0; i < out.length && !out[i].equal(CellTypeState.bottom); i++) {
+      CellTypeState out1 = out[i];
+      CellTypeState vcts = getVar(loc_no);
+      if (Assert.ASSERTS_ENABLED) {
+        Assert.that(out1.canBeReference() || out1.canBeValue(),
+                    "can only load refs. and values.");
+      }
+      if (out1.isReference()) {
+        if (Assert.ASSERTS_ENABLED) {
+          Assert.that(loc_no>=0, "sanity check");
+        }
+        if (!vcts.isReference()) {
+          // We were asked to push a reference, but the type of the
+          // variable can be something else
+          _conflict = true;
+          if (vcts.canBeUninit()) {
+            // It is a ref-uninit conflict (at least). If there are other
+            // problems, we'll get them in the next round
+            addToRefInitSet(loc_no);
+            vcts = out1;
+          } else {
+            // It wasn't a ref-uninit conflict. So must be a
+            // ref-val or ref-pc conflict. Split the variable.
+            recordRefvalConflict(loc_no);
+            vcts = out1;
+          }
+          push(out1); // recover...
+        } else {
+          push(vcts); // preserve reference.
+        }
+        // Otherwise it is a conflict, but one that verification would
+        // have caught if illegal. In particular, it can't be a topCTS
+        // resulting from mergeing two difference pcCTS's since the verifier
+        // would have rejected any use of such a merge.
+      } else {
+        push(out1); // handle val/init conflict
+      }
+      loc_no++;
+    }
+  }
+
+  void  ppush1                              (CellTypeState in) {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(in.isReference() | in.isValue(), "sanity check");
+    }
+    if (DEBUG) {
+      System.err.println("   - pushing " + in.toChar());
+    }
+    push(in);
+  }
+
+  void  ppush                               (CellTypeState[] in) {
+    for (int i = 0; i < in.length && !in[i].equal(CellTypeState.bottom); i++) {
+      ppush1(in[i]);
+    }
+  }
+
+  void  ppush                               (CellTypeStateList in) {
+    for (int i = 0; i < in.size() && !in.get(i).equal(CellTypeState.bottom); i++) {
+      ppush1(in.get(i));
+    }
+  }
+
+  void  ppop1                               (CellTypeState out) {
+    CellTypeState actual = pop();
+    if (DEBUG) {
+      System.err.println("   - popping " + actual.toChar() + ", expecting " + out.toChar());
+    }
+    checkType(out, actual);
+  }
+
+  void  ppop                                (CellTypeState[] out) {
+    for (int i = 0; i < out.length && !out[i].equal(CellTypeState.bottom); i++) {
+      ppop1(out[i]);
+    }
+  }
+
+  void  ppopAny                             (int poplen) {
+    if (_stack_top >= poplen) {
+      _stack_top -= poplen;
+    } else {
+      throw new RuntimeException("stack underflow");
+    }
+  }
+
+  void  pp                                  (CellTypeState[] in, CellTypeState[] out) {
+    ppop(in);
+    ppush(out);
+  }
+
+  void  ppNewRef                            (CellTypeState[] in, int bci) {
+    ppop(in);
+    ppush1(CellTypeState.makeLineRef(bci));
+  }
+
+  void  ppdupswap                           (int poplen, String out) {
+    CellTypeState[] actual = new CellTypeState[5];
+    Assert.that(poplen < 5, "this must be less than length of actual vector");
+
+    // pop all arguments
+    for(int i = 0; i < poplen; i++) actual[i] = pop();
+
+    // put them back
+    for (int i = 0; i < out.length(); i++) {
+      char push_ch = out.charAt(i);
+      int idx = push_ch - '1';
+      if (Assert.ASSERTS_ENABLED) {
+        Assert.that(idx >= 0 && idx < poplen, "wrong arguments");
+      }
+      push(actual[idx]);
+    }
+  }
+
+  void  doLdc                               (int idx, int bci) {
+    ConstantPool  cp  = method().getConstants();
+    ConstantTag   tag = cp.getTagAt(idx);
+    CellTypeState cts = (tag.isString() || tag.isUnresolvedString() ||
+                         tag.isKlass() || tag.isUnresolvedKlass())
+                          ? CellTypeState.makeLineRef(bci)
+                          : valCTS;
+    ppush1(cts);
+  }
+
+  void  doAstore                            (int idx) {
+    CellTypeState r_or_p = pop();
+    if (!r_or_p.isAddress() && !r_or_p.isReference()) {
+      // We actually expected ref or pc, but we only report that we expected a ref. It does not
+      // really matter (at least for now)
+      throw new RuntimeException("wrong type on stack (found: " +
+                                 r_or_p.toChar() + ", expected: {pr})");
+    }
+    setVar(idx, r_or_p);
+  }
+
+  void  doJsr                               (int targBCI) {
+    push(CellTypeState.makeAddr(targBCI));
+  }
+
+  void  doField                             (boolean is_get, boolean is_static, int idx, int bci) {
+    // Dig up signature for field in constant pool
+    ConstantPool cp        = method().getConstants();
+    int nameAndTypeIdx     = cp.getNameAndTypeRefIndexAt(idx);
+    int signatureIdx       = cp.getSignatureRefIndexAt(nameAndTypeIdx);
+    Symbol signature       = cp.getSymbolAt(signatureIdx);
+
+    if (DEBUG) {
+      System.err.println("doField: signature = " + signature.asString() + ", idx = " + idx +
+                         ", nameAndTypeIdx = " + nameAndTypeIdx + ", signatureIdx = " + signatureIdx + ", bci = " + bci);
+    }
+
+    // Parse signature (espcially simple for fields)
+    // The signature is UFT8 encoded, but the first char is always ASCII for signatures.
+    char sigch = (char) signature.getByteAt(0);
+    CellTypeState[] temp = new CellTypeState[4];
+    CellTypeState[] eff  = sigcharToEffect(sigch, bci, temp);
+
+    CellTypeState[] in = new CellTypeState[4];
+    CellTypeState[] out;
+    int i =  0;
+
+    if (is_get) {
+      out = eff;
+    } else {
+      out = epsilonCTS;
+      i   = copyCTS(in, eff);
+    }
+    if (!is_static) in[i++] = CellTypeState.ref;
+    in[i] = CellTypeState.bottom;
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(i<=3, "sanity check");
+    }
+    pp(in, out);
+  }
+
+  void  doMethod                            (boolean is_static, boolean is_interface, int idx, int bci) {
+    // Dig up signature for field in constant pool
+    ConstantPool cp       = _method.getConstants();
+    int nameAndTypeIdx    = cp.getNameAndTypeRefIndexAt(idx);
+    int signatureIdx      = cp.getSignatureRefIndexAt(nameAndTypeIdx);
+    Symbol signature      = cp.getSymbolAt(signatureIdx);
+
+    if (DEBUG) {
+      System.err.println("doMethod: signature = " + signature.asString() + ", idx = " + idx +
+                         ", nameAndTypeIdx = " + nameAndTypeIdx + ", signatureIdx = " + signatureIdx +
+                         ", bci = " + bci);
+    }
+
+    // Parse method signature
+    CellTypeStateList out = new CellTypeStateList(4);
+    CellTypeStateList in  = new CellTypeStateList(MAXARGSIZE+1);   // Includes result
+    ComputeCallStack cse  = new ComputeCallStack(signature);
+
+    // Compute return type
+    int res_length = cse.computeForReturntype(out);
+
+    // Temporary hack.
+    if (out.get(0).equal(CellTypeState.ref) && out.get(1).equal(CellTypeState.bottom)) {
+      out.get(0).set(CellTypeState.makeLineRef(bci));
+    }
+
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(res_length<=4, "max value should be vv");
+    }
+
+    // Compute arguments
+    int arg_length = cse.computeForParameters(is_static, in);
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(arg_length<=MAXARGSIZE, "too many locals");
+    }
+
+    // Pop arguments
+    for (int i = arg_length - 1; i >= 0; i--) ppop1(in.get(i));// Do args in reverse order.
+
+    // Report results
+    if (_report_result_for_send == true) {
+      fillStackmapForOpcodes(_itr_send, vars(), stack(), _stack_top);
+      _report_result_for_send = false;
+    }
+
+    // Push return address
+    ppush(out);
+  }
+
+  void  doMultianewarray                    (int dims, int bci) {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(dims >= 1, "sanity check");
+    }
+    for(int i = dims -1; i >=0; i--) {
+      ppop1(valCTS);
+    }
+    ppush1(CellTypeState.makeLineRef(bci));
+  }
+
+  void  doMonitorenter                      (int bci) {
+    CellTypeState actual = pop();
+    if (_monitor_top == bad_monitors) {
+      return;
+    }
+
+    // Bail out when we get repeated locks on an identical monitor.  This case
+    // isn't too hard to handle and can be made to work if supporting nested
+    // redundant synchronized statements becomes a priority.
+    //
+    // See also "Note" in do_monitorexit(), below.
+    if (actual.isLockReference()) {
+      _monitor_top = bad_monitors;
+      _monitor_safe = false;
+
+      if (TraceMonitorMismatch) {
+        reportMonitorMismatch("nested redundant lock -- bailout...");
+      }
+      return;
+    }
+
+    CellTypeState lock = CellTypeState.makeLockRef(bci);
+    checkType(refCTS, actual);
+    if (!actual.isInfoTop()) {
+      replaceAllCTSMatches(actual, lock);
+      monitorPush(lock);
+    }
+  }
+
+  void  doMonitorexit                       (int bci) {
+    CellTypeState actual = pop();
+    if (_monitor_top == bad_monitors) {
+      return;
+    }
+    checkType(refCTS, actual);
+    CellTypeState expected = monitorPop();
+    if (!actual.isLockReference() || !expected.equal(actual)) {
+      // The monitor we are exiting is not verifiably the one
+      // on the top of our monitor stack.  This causes a monitor
+      // mismatch.
+      _monitor_top = bad_monitors;
+      _monitor_safe = false;
+
+      // We need to mark this basic block as changed so that
+      // this monitorexit will be visited again.  We need to
+      // do this to ensure that we have accounted for the
+      // possibility that this bytecode will throw an
+      // exception.
+      BasicBlock bb = getBasicBlockContaining(bci);
+      bb.setChanged(true);
+      bb._monitor_top = bad_monitors;
+
+      if (TraceMonitorMismatch) {
+        reportMonitorMismatch("improper monitor pair");
+      }
+    } else {
+      // This code is a fix for the case where we have repeated
+      // locking of the same object in straightline code.  We clear
+      // out the lock when it is popped from the monitor stack
+      // and replace it with an unobtrusive reference value that can
+      // be locked again.
+      //
+      // Note: when generateOopMap is fixed to properly handle repeated,
+      //       nested, redundant locks on the same object, then this
+      //       fix will need to be removed at that time.
+      replaceAllCTSMatches(actual, CellTypeState.makeLineRef(bci));
+    }
+
+    if (_report_for_exit_bci == bci) {
+      _matching_enter_bci = expected.getMonitorSource();
+    }
+  }
+
+  void  doReturnMonitorCheck                () {
+    if (_monitor_top > 0) {
+      // The monitor stack must be empty when we leave the method
+      // for the monitors to be properly matched.
+      _monitor_safe = false;
+
+      // Since there are no successors to the *return bytecode, it
+      // isn't necessary to set _monitor_top to bad_monitors.
+
+      if (TraceMonitorMismatch) {
+        reportMonitorMismatch("non-empty monitor stack at return");
+      }
+    }
+  }
+
+  void  doCheckcast                         () {
+    CellTypeState actual = pop();
+    checkType(refCTS, actual);
+    push(actual);
+  }
+
+  CellTypeState[] sigcharToEffect           (char sigch, int bci, CellTypeState[] out) {
+    // Object and array
+    if (sigch=='L' || sigch=='[') {
+      out[0] = CellTypeState.makeLineRef(bci);
+      out[1] = CellTypeState.bottom;
+      return out;
+    }
+    if (sigch == 'J' || sigch == 'D' ) return vvCTS;  // Long and Double
+    if (sigch == 'V' ) return epsilonCTS;             // Void
+    return vCTS;                                      // Otherwise
+  }
+
+  // Copies (optionally bottom/zero terminated) CTS string from "src" into "dst".
+  //   Does NOT terminate with a bottom. Returns the number of cells copied.
+  int copyCTS                               (CellTypeState[] dst, CellTypeState[] src) {
+    int idx = 0;
+    for (; idx < src.length && !src[idx].isBottom(); idx++) {
+      dst[idx] = src[idx];
+    }
+    return idx;
+  }
+
+  // Create result set
+  boolean  _report_result;
+  boolean  _report_result_for_send;         // Unfortunatly, stackmaps for sends are special, so we need some extra
+  BytecodeStream _itr_send;                 // variables to handle them properly.
+
+  void  reportResult                        () {
+    //    if (TraceNewOopMapGeneration) tty.print_cr("Report result pass");
+
+    // We now want to report the result of the parse
+    _report_result = true;
+
+    // Prolog code
+    fillStackmapProlog(_gc_points);
+
+    // Mark everything changed, then do one interpretation pass.
+    for (int i = 0; i<_bb_count; i++) {
+      if (_basic_blocks[i].isReachable()) {
+        _basic_blocks[i].setChanged(true);
+        interpBB(_basic_blocks[i]);
+      }
+    }
+
+    // Note: Since we are skipping dead-code when we are reporting results, then
+    // the no. of encountered gc-points might be fewer than the previously number
+    // we have counted. (dead-code is a pain - it should be removed before we get here)
+    fillStackmapEpilog();
+
+    // Report initvars
+    fillInitVars(_init_vars);
+
+    _report_result = false;
+  }
+
+  // Initvars
+  List/*<Integer>*/ _init_vars;
+
+  void  initializeVars                      () {
+    for (int k = 0; k < _init_vars.size(); k++)
+      _state.get(((Integer) _init_vars.get(k)).intValue()).set(CellTypeState.makeSlotRef(k));
+  }
+
+  void  addToRefInitSet                     (int localNo) {
+    //    if (TraceNewOopMapGeneration)
+    //      tty.print_cr("Added init vars: %d", localNo);
+
+    Integer local = new Integer(localNo);
+
+    // Is it already in the set?
+    if (_init_vars.contains(local))
+      return;
+
+    _init_vars.add(local);
+  }
+
+  // Conflicts rewrite logic
+  boolean   _conflict;                      // True, if a conflict occured during interpretation
+  int       _nof_refval_conflicts;          // No. of conflicts that require rewrites
+  int[]     _new_var_map;
+
+  void recordRefvalConflict                 (int varNo) {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(varNo>=0 && varNo< _max_locals, "index out of range");
+    }
+
+    if (TraceOopMapRewrites) {
+      System.err.println("### Conflict detected (local no: " + varNo + ")");
+    }
+
+    if (_new_var_map == null) {
+      _new_var_map = new int[_max_locals];
+      for (int k = 0; k < _max_locals; k++)  _new_var_map[k] = k;
+    }
+
+    if ( _new_var_map[varNo] == varNo) {
+      // Check if max. number of locals has been reached
+      if (_max_locals + _nof_refval_conflicts >= MAX_LOCAL_VARS) {
+        throw new RuntimeException("Rewriting exceeded local variable limit");
+      }
+      _new_var_map[varNo] = _max_locals + _nof_refval_conflicts;
+      _nof_refval_conflicts++;
+    }
+  }
+
+  void rewriteRefvalConflicts               () {
+    if (_nof_refval_conflicts > 0) {
+      if (VM.getVM().isDebugging()) {
+        throw new RuntimeException("Should not reach here (method rewriting should have been done by the VM already)");
+      } else {
+        throw new RuntimeException("Method rewriting not yet implemented in Java");
+      }
+    }
+  }
+  // Rewriting-related routines are not needed here
+  //  void rewrite_refval_conflict              (int from, int to);
+  //  bool rewrite_refval_conflict_inst         (BytecodeStream *i, int from, int to);
+  //  bool rewrite_load_or_store                (BytecodeStream *i, Bytecodes.Code bc, Bytecodes.Code bc0, unsigned int varNo);
+
+  //  bool expand_current_instr                 (int bci, int ilen, int newIlen, u_char inst_buffer[]);
+  //  bool is_astore                            (BytecodeStream *itr, int *index);
+  //  bool is_aload                             (BytecodeStream *itr, int *index);
+
+  // List of bci's where a return address is on top of the stack
+  //  GrowableArray<intptr_t> *_ret_adr_tos;
+
+  //  bool stack_top_holds_ret_addr             (int bci);
+  //  void compute_ret_adr_at_TOS               ();
+  //  void update_ret_adr_at_TOS                (int bci, int delta);
+
+  String stateVecToString                   (CellTypeStateList vec, int len) {
+    for (int i = 0; i < len; i++) {
+      _state_vec_buf[i] = vec.get(i).toChar();
+    }
+    return new String(_state_vec_buf, 0, len);
+  }
+
+  // Helper method. Can be used in subclasses to fx. calculate gc_points. If the current instuction
+  // is a control transfer, then calls the jmpFct all possible destinations.
+  void  retJumpTargetsDo                    (BytecodeStream bcs, JumpClosure closure, int varNo, int[] data) {
+    CellTypeState ra = vars().get(varNo);
+    if (!ra.isGoodAddress()) {
+      throw new RuntimeException("ret returns from two jsr subroutines?");
+    }
+    int target = ra.getInfo();
+
+    RetTableEntry rtEnt = _rt.findJsrsForTarget(target);
+    int bci = bcs.bci();
+    for (int i = 0; i < rtEnt.nofJsrs(); i++) {
+      int target_bci = rtEnt.jsrs(i);
+      // Make sure a jrtRet does not set the changed bit for dead basicblock.
+      BasicBlock jsr_bb    = getBasicBlockContaining(target_bci - 1);
+      if (Assert.ASSERTS_ENABLED) {
+        BasicBlock target_bb = _basic_blocks[1 + bbIndex(jsr_bb)];
+        Assert.that(target_bb  == getBasicBlockAt(target_bci), "wrong calc. of successor basicblock");
+      }
+      boolean alive = jsr_bb.isAlive();
+      //      if (TraceNewOopMapGeneration) {
+      //        tty.print("pc = %d, ret . %d alive: %s\n", bci, target_bci, alive ? "true" : "false");
+      //      }
+      if (alive) {
+        closure.process(this, target_bci, data);
+      }
+    }
+  }
+
+  /** If the current instruction in "c" has no effect on control flow,
+      returns "true".  Otherwise, calls "closure.process()" one or
+      more times, with "c", an appropriate "pcDelta", and "data" as
+      arguments, then returns "false".  There is one exception: if the
+      current instruction is a "ret", returns "false" without calling
+      "jmpFct". Arrangements for tracking the control flow of a "ret"
+      must be made externally. */
+  boolean jumpTargetsDo                     (BytecodeStream bcs, JumpClosure closure, int[] data) {
+    int bci = bcs.bci();
+
+    switch (bcs.code()) {
+    case Bytecodes._ifeq:
+    case Bytecodes._ifne:
+    case Bytecodes._iflt:
+    case Bytecodes._ifge:
+    case Bytecodes._ifgt:
+    case Bytecodes._ifle:
+    case Bytecodes._if_icmpeq:
+    case Bytecodes._if_icmpne:
+    case Bytecodes._if_icmplt:
+    case Bytecodes._if_icmpge:
+    case Bytecodes._if_icmpgt:
+    case Bytecodes._if_icmple:
+    case Bytecodes._if_acmpeq:
+    case Bytecodes._if_acmpne:
+    case Bytecodes._ifnull:
+    case Bytecodes._ifnonnull:
+      closure.process(this, bcs.dest(), data);
+      closure.process(this, bci + 3, data);
+      break;
+
+    case Bytecodes._goto:
+      closure.process(this, bcs.dest(), data);
+      break;
+    case Bytecodes._goto_w:
+      closure.process(this, bcs.dest_w(), data);
+      break;
+    case Bytecodes._tableswitch:
+      {
+        BytecodeTableswitch tableswitch = BytecodeTableswitch.at(bcs);
+        int len = tableswitch.length();
+
+        closure.process(this, bci + tableswitch.defaultOffset(), data); /* Default. jump address */
+        while (--len >= 0) {
+          closure.process(this, bci + tableswitch.destOffsetAt(len), data);
+        }
+        break;
+      }
+
+    case Bytecodes._fast_linearswitch:     // Java opcodes
+    case Bytecodes._fast_binaryswitch:     // get_int_table handles conversions
+    case Bytecodes._lookupswitch:
+      {
+        BytecodeLookupswitch lookupswitch = BytecodeLookupswitch.at(bcs);
+        int npairs = lookupswitch.numberOfPairs();
+        closure.process(this, bci + lookupswitch.defaultOffset(), data); /* Default. */
+        while(--npairs >= 0) {
+          LookupswitchPair pair = lookupswitch.pairAt(npairs);
+          closure.process(this, bci + pair.offset(), data);
+        }
+        break;
+      }
+    case Bytecodes._jsr:
+      Assert.that(bcs.isWide()==false, "sanity check");
+      closure.process(this, bcs.dest(), data);
+      break;
+    case Bytecodes._jsr_w:
+      closure.process(this, bcs.dest_w(), data);
+      break;
+    case Bytecodes._wide:
+      throw new RuntimeException("Should not reach here");
+    case Bytecodes._athrow:
+    case Bytecodes._ireturn:
+    case Bytecodes._lreturn:
+    case Bytecodes._freturn:
+    case Bytecodes._dreturn:
+    case Bytecodes._areturn:
+    case Bytecodes._return:
+    case Bytecodes._ret:
+      break;
+    default:
+      return true;
+    }
+    return false;
+  }
+
+  // Monitor matching
+  //  int fill_out_arrays                       (int *enter, int *exit, int max);
+
+  //  friend class RelocCallback;
+
+  //----------------------------------------------------------------------
+  // Public routines for GenerateOopMap
+  //
+  public GenerateOopMap(Method method) {
+    // We have to initialize all variables here, that can be queried direcly
+    _method = method;
+    _max_locals=0;
+    _init_vars = null;
+    _rt = new RetTable();
+  }
+
+
+  // Compute the map.
+  public void computeMap() {
+    if (DEBUG) {
+      System.err.println("*** GenerateOopMap: computing for " +
+                         method().getMethodHolder().getName().asString() + "." +
+                         method().getName().asString() +
+                         method().getSignature().asString());
+    }
+
+    // Initialize values
+    _got_error      = false;
+    _conflict       = false;
+    _max_locals     = (int) method().getMaxLocals();
+    _max_stack      = (int) method().getMaxStack();
+    _has_exceptions = (method().getExceptionTable().getLength() > 0);
+    _nof_refval_conflicts = 0;
+    _init_vars      = new ArrayList(5);  // There are seldom more than 5 init_vars
+    _report_result  = false;
+    _report_result_for_send = false;
+    _report_for_exit_bci = -1;
+    _new_var_map    = null;
+    //    _ret_adr_tos    = new GrowableArray<intptr_t>(5);  // 5 seems like a good number;
+    //    _did_rewriting  = false;
+    //    _did_relocation = false;
+
+    // FIXME: remove
+    /*
+    if (TraceNewOopMapGeneration) {
+      tty.print("Method name: %s\n", method().name().as_C_string());
+      if (Verbose) {
+        _method.print_codes();
+        tty.print_cr("Exception table:");
+        typeArrayOop excps = method().exception_table();
+        for(int i = 0; i < excps.length(); i += 4) {
+          tty.print_cr("[%d - %d] . %d", excps.int_at(i + 0), excps.int_at(i + 1), excps.int_at(i + 2));
+        }
+      }
+    }
+    */
+
+    // if no code - do nothing
+    // compiler needs info
+    if (method().getCodeSize() == 0 || _max_locals + method().getMaxStack() == 0) {
+      fillStackmapProlog(0);
+      fillStackmapEpilog();
+      return;
+    }
+    // Step 1: Compute all jump targets and their return value
+    if (!_got_error)
+      _rt.computeRetTable(_method);
+
+    // Step 2: Find all basic blocks and count GC points
+    if (!_got_error)
+      markBBHeadersAndCountGCPoints();
+
+    // Step 3: Calculate stack maps
+    if (!_got_error)
+      doInterpretation();
+
+    // Step 4:Return results
+    if (!_got_error && reportResults())
+      reportResult();
+
+    if (_got_error) {
+      // We could expand this code to throw somekind of exception (e.g., VerifyException). However,
+      // an exception thrown in this part of the code is likly to mean that we are executing some
+      // illegal bytecodes (that the verifier should have caught if turned on), so we will just exit
+      // with a fatal.
+      throw new RuntimeException("Illegal bytecode sequence encountered while generating interpreter pointer maps - method should be rejected by verifier.");
+    }
+  }
+
+  // Do a callback on fill_stackmap_for_opcodes for basicblock containing bci
+  public void resultForBasicblock(int bci) {
+    // FIXME: remove
+    //    if (TraceNewOopMapGeneration) tty.print_cr("Report result pass for basicblock");
+
+    // We now want to report the result of the parse
+    _report_result = true;
+
+    // Find basicblock and report results
+    BasicBlock bb = getBasicBlockContaining(bci);
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(bb.isReachable(), "getting result from unreachable basicblock");
+    }
+    bb.setChanged(true);
+    interpBB(bb);
+  }
+
+  // Query
+  public int maxLocals()                                  { return _max_locals; }
+  public Method method()                                  { return _method; }
+
+  //  bool did_rewriting()                             { return _did_rewriting; }
+  //  bool did_relocation()                            { return _did_relocation; }
+
+  //  static void print_time();
+
+  // Monitor query
+  public boolean monitorSafe()                            { return _monitor_safe; }
+  // Takes as input the bci of a monitorexit bytecode.
+  // Returns the bci of the corresponding monitorenter.
+  // Can only be called safely after computeMap() is run.
+  public int  getMonitorMatch(int bci) {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(_monitor_safe, "Attempt to match monitor in broken code.");
+    }
+
+    //    if (TraceNewOopMapGeneration)
+    //      tty.print_cr("Report monitor match for bci : %d", bci);
+
+    // We want to report the line number of the monitorenter.
+    _report_for_exit_bci = bci;
+    _matching_enter_bci = -1;
+
+    // Find basicblock and report results
+    BasicBlock bb = getBasicBlockContaining(bci);
+    if (bb.isReachable()) {
+      bb.setChanged(true);
+      interpBB(bb);
+      _report_for_exit_bci = -1;
+      if (Assert.ASSERTS_ENABLED) {
+        Assert.that(_matching_enter_bci != -1, "monitor matching invariant");
+      }
+    }
+    return _matching_enter_bci;
+  }
+
+  // Returns a Arena allocated object that contains pairing info.
+  //  MonitorPairs* get_pairing(Arena *arena);
+
+  // copies monitor pairing info into area; area_count specifies maximum
+  // possible number of monitor pairs
+  //  int copy_pairing(int pair_count, MonitorPairs* pairs);
+
+  private int bbIndex(BasicBlock bb) {
+    for (int i = 0; i < _basic_blocks.length; i++) {
+      if (_basic_blocks[i] == bb) {
+        return i;
+      }
+    }
+    throw new RuntimeException("Should have found block");
+  }
+
+  //----------------------------------------------------------------------
+  // Specialization methods. Intended use:
+  // - possibleGCPoint must return true for every bci for which the
+  //   stackmaps must be returned
+  // - fillStackmapProlog is called just before the result is
+  //   reported. The arguments tells the estimated number of gc points
+  // - fillStackmapForOpcodes is called once for each bytecode index
+  //   in order (0...code_length-1)
+  // - fillStackmapEpilog is called after all results has been
+  //   reported. Note: Since the algorithm does not report stackmaps for
+  //   deadcode, fewer gc_points might have been encounted than assumed
+  //   during the epilog. It is the responsibility of the subclass to
+  //   count the correct number.
+  // - fillInitVars are called once with the result of the init_vars
+  //   computation
+  //
+  // All these methods are used during a call to computeMap. Note:
+  // None of the return results are valid after computeMap returns,
+  // since all values are allocated as resource objects.
+  //
+  // All virtual method must be implemented in subclasses
+  public boolean allowRewrites            ()                              { return false; }
+  public boolean reportResults            ()                              { return true;  }
+  public boolean reportInitVars           ()                              { return true;  }
+  public boolean possibleGCPoint          (BytecodeStream bcs)            { throw new RuntimeException("ShouldNotReachHere"); }
+  public void fillStackmapProlog          (int nofGCPoints)               { throw new RuntimeException("ShouldNotReachHere"); }
+  public void fillStackmapEpilog          ()                              { throw new RuntimeException("ShouldNotReachHere"); }
+  public void fillStackmapForOpcodes      (BytecodeStream bcs,
+                                           CellTypeStateList vars,
+                                           CellTypeStateList stack,
+                                           int stackTop)                  { throw new RuntimeException("ShouldNotReachHere"); }
+  public void fillInitVars                (List/*<Integer>*/ init_vars)   { throw new RuntimeException("ShouldNotReachHere"); }
+}