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

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children ba764ed4b6f2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,735 @@
+/*
+ * Copyright 2000-2006 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.runtime;
+
+import java.io.*;
+import java.util.*;
+import sun.jvm.hotspot.*;
+import sun.jvm.hotspot.code.*;
+import sun.jvm.hotspot.compiler.*;
+import sun.jvm.hotspot.c1.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.interpreter.*;
+import sun.jvm.hotspot.oops.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.utilities.*;
+
+/** <P> A frame represents a physical stack frame (an activation).
+    Frames can be C or Java frames, and the Java frames can be
+    interpreted or compiled. In contrast, vframes represent
+    source-level activations, so that one physical frame can
+    correspond to multiple source level frames because of inlining.
+    </P>
+
+    <P> NOTE that this is not a VMObject and does not wrap an Address
+    -- this is an actual port of the VM's Frame code to Java. </P>
+
+    <P> NOTE also that this is incomplete -- just trying to get
+    reading of interpreted frames working for now, so all non-core and
+    setter methods are removed for now. (FIXME) </P> */
+
+public abstract class Frame implements Cloneable {
+  /** A raw stack pointer. The accessor getSP() will return a real (usable)
+      stack pointer (e.g. from Thread::last_Java_sp) */
+  protected Address raw_sp;
+
+  /** Program counter (the next instruction after the call) */
+  protected Address pc;
+  protected boolean deoptimized;
+
+  public Frame() {
+    deoptimized = false;
+  }
+
+  static {
+    VM.registerVMInitializedObserver(new Observer() {
+        public void update(Observable o, Object data) {
+          initialize(VM.getVM().getTypeDataBase());
+        }
+      });
+  }
+
+  /** Size of constMethodOopDesc for computing BCI from BCP (FIXME: hack) */
+  private static long    constMethodOopDescSize;
+
+  private static synchronized void initialize(TypeDataBase db) {
+    Type constMethodOopType = db.lookupType("constMethodOopDesc");
+    // FIXME: not sure whether alignment here is correct or how to
+    // force it (round up to address size?)
+    constMethodOopDescSize = constMethodOopType.getSize();
+  }
+
+  protected int bcpToBci(Address bcp, ConstMethod cm) {
+    // bcp will be null for interpreter native methods
+    // in addition depending on where we catch the system the value can
+    // be a bcp or a bci.
+    if (bcp == null) return 0;
+    long bci = bcp.minus(null);
+    if (bci >= 0 && bci < cm.getCodeSize()) return (int) bci;
+    return (int) (bcp.minus(cm.getHandle()) - constMethodOopDescSize);
+  }
+
+  protected int bcpToBci(Address bcp, Method m) {
+    return bcpToBci(bcp, m.getConstMethod());
+  }
+
+  public abstract Object clone();
+
+  // Accessors
+
+  /** pc: Returns the pc at which this frame will continue normally.
+      It must point at the beginning of the next instruction to
+      execute. */
+  public Address getPC()              { return pc; }
+  public void    setPC(Address newpc) { pc = newpc; }
+  public boolean isDeoptimized()      { return deoptimized; }
+
+  public abstract Address getSP();
+  public abstract Address getID();
+  public abstract Address getFP();
+
+  /** testers -- platform dependent */
+  public abstract boolean equals(Object arg);
+
+  /** type testers */
+  public boolean isInterpretedFrame()           { return VM.getVM().getInterpreter().contains(getPC()); }
+  public boolean isJavaFrame() {
+    if (isInterpretedFrame()) return true;
+    if (!VM.getVM().isCore()) {
+      if (isCompiledFrame())    return true;
+    }
+    return false;
+  }
+
+  /** Java frame called from C? */
+  public boolean isEntryFrame()                 { return VM.getVM().getStubRoutines().returnsToCallStub(getPC()); }
+  public boolean isNativeFrame() {
+    if (!VM.getVM().isCore()) {
+      CodeBlob cb = VM.getVM().getCodeCache().findBlob(getPC());
+      return (cb != null && cb.isNativeMethod());
+    } else {
+      return false;
+    }
+  }
+
+  public boolean isCompiledFrame() {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(!VM.getVM().isCore(), "noncore builds only");
+    }
+    CodeBlob cb = VM.getVM().getCodeCache().findBlob(getPC());
+    return (cb != null && cb.isJavaMethod());
+  }
+
+  public boolean isGlueFrame() {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(!VM.getVM().isCore(), "noncore builds only");
+    }
+    CodeBlob cb = VM.getVM().getCodeCache().findBlob(getPC());
+    if (cb == null) {
+      return false;
+    }
+    if (cb.isRuntimeStub()) return true;
+    else return false;
+  }
+
+  /** oldest frame? (has no sender) FIXME: this is modified from the
+      C++ code to handle the debugging situation where we try to
+      traverse the stack for, for example, the signal thread, and
+      don't find any valid Java frames. Would really like to put the
+      second half of the conditional in some sort of debugging-only if
+      statement. */
+  // *** FIXME: THE CALL TO isJavaFrame() IS WAY TOO EXPENSIVE!!!!! ***
+  public boolean isFirstFrame()                 { return ((isEntryFrame() && entryFrameIsFirst()) ||
+                                                          (!isJavaFrame() && !hasSenderPD()));       }
+  /** same for Java frame */
+  public boolean isFirstJavaFrame()             { throw new RuntimeException("not yet implemented"); }
+
+  /** This is an addition for debugging purposes on platforms which
+      have the notion of signals. */
+  public abstract boolean isSignalHandlerFrameDbg();
+
+  /** If this is a signal handler frame (again, on a platform with a
+      notion of signals), get the signal number. */
+  public abstract int getSignalNumberDbg();
+
+  /** If this is a signal handler frame (again, on a platform with a
+      notion of signals), get the name of the signal. */
+  public abstract String getSignalNameDbg();
+
+  /** performs sanity checks on interpreted frames. */
+  public abstract boolean isInterpretedFrameValid();
+
+  /** tells whether this frame is marked for deoptimization */
+  public boolean shouldBeDeoptimized()          { throw new RuntimeException("not yet implemented"); }
+
+  /** tells whether this frame can be deoptimized */
+  public boolean canBeDeoptimized()             { throw new RuntimeException("not yet implemented"); }
+
+  /** returns the sending frame */
+  public abstract Frame sender(RegisterMap map, CodeBlob nm);
+
+  /** equivalent to sender(map, null) */
+  public Frame sender(RegisterMap map)          { return sender(map, null); }
+
+  /** returns the sender, but skips conversion frames */
+  public Frame realSender(RegisterMap map) {
+    if (!VM.getVM().isCore()) {
+      Frame result = sender(map);
+      while (result.isGlueFrame()) {
+        result = result.sender(map);
+      }
+      return result;
+    } else {
+      return sender(map);
+    }
+  }
+
+  /** Platform-dependent query indicating whether this frame has a
+      sender. Should return true if it is possible to call sender() at
+      all on this frame. (This is currently only needed for the
+      debugging system, if a stack trace is attempted for a Java
+      thread which has no Java frames, i.e., the signal thread; we
+      have to know to stop traversal at the bottom frame.) */
+  protected abstract boolean hasSenderPD();
+
+  //--------------------------------------------------------------------------------
+  // All frames:
+  // A low-level interface for vframes:
+
+  /** Returns the address of the requested "slot" on the stack. Slots
+      are as wide as addresses, so are 32 bits wide on a 32-bit
+      machine and 64 bits wide on a 64-bit machine. */
+  public Address   addressOfStackSlot(int slot)              { return getFP().addOffsetTo(slot * VM.getVM().getAddressSize()); }
+
+  /** Fetches the OopHandle at the requested slot */
+  public OopHandle getOopHandleAt(int slot)                  { return addressOfStackSlot(slot).getOopHandleAt(0);              }
+  /** Fetches the OopHandle at the slot, adjusted for compiler frames */
+  // FIXME: looks like this is only used for compiled frames
+  //  public OopHandle getOopHandleAtAdjusted(MethodOop method, int slot) { return addressOfStackSlot(slot).getOopHandleAt(0); }
+  // FIXME: Not yet implementable
+  //  public void  setOopHandleAt(int slot, OopHandle value) { addressOfStackSlot(slot).setOopHandleAt(0, value);              }
+
+  /** Fetches the (Java) int at the requested slot */
+  public int       getIntAt(int slot)                        { return addressOfStackSlot(slot).getJIntAt(0);                   }
+  // FIXME: Not yet implementable
+  // public void setIntAt(int slot, int value)               { addressOfStackSlot(slot).setJIntAt(0, value);                   }
+
+  /** returns the frame size in stack slots */
+  public abstract long frameSize();
+
+  /** Link (i.e., the pointer to the previous frame) */
+  public abstract Address getLink();
+  //  public abstract void    setLink(Address addr);
+
+  /** Return address */
+  public abstract Address getSenderPC();
+  // FIXME: currently unimplementable
+  //  public abstract void    setSenderPC(Address addr);
+
+  /** The frame's original SP, before any extension by an interpreted
+      callee; used for packing debug info into vframeArray objects and
+      vframeArray lookup. */
+  public abstract Address getUnextendedSP();
+
+  /** Returns the stack pointer of the calling frame */
+  public abstract Address getSenderSP();
+
+  //--------------------------------------------------------------------------------
+  // Interpreter frames:
+  //
+
+  public abstract Address addressOfInterpreterFrameLocals();
+
+  public Address addressOfInterpreterFrameLocal(int slot) {
+    return addressOfInterpreterFrameLocals().getAddressAt(0).addOffsetTo(-slot * VM.getVM().getAddressSize());
+  }
+
+  // FIXME: not yet implementable
+  //  void interpreter_frame_set_locals(intptr_t* locs);
+
+  // NOTE that the accessor "addressOfInterpreterFrameBCX" has
+  // necessarily been eliminated. The byte code pointer is inherently
+  // an interior pointer to a Method (the bytecodes follow the
+  // methodOopDesc data structure) and therefore acquisition of it in
+  // this system can not be allowed. All accesses to interpreter frame
+  // byte codes are via the byte code index (BCI).
+
+  /** Byte code index. In the underlying frame, what is actually
+      stored is a byte code pointer (BCP), which is converted to a BCI
+      and back by the GC when methods are moved. In this system,
+      interior pointers are not allowed, so we must make the access to
+      the interpreter frame's BCI atomic with respect to GC. This may
+      mean implementation with an underlying call through native code
+      into the VM or a magic sequence in the compiler. (FIXME) */
+  public abstract int     getInterpreterFrameBCI();
+  // FIXME: not yet implementable
+  // public abstract void setInterpreterFrameBCI(int bci);
+
+  // FIXME: elided for now
+  //  public abstract Address addressOfInterpreterCalleeReceiver(Symbol signature);
+
+  /** Find receiver for an invoke when arguments are just pushed on
+      stack (i.e., callee stack-frame is not setup) */
+  // FIXME: elided for now
+  //  public OopHandle getInterpreterCalleeReceiver(SymbolOop signature) { return addressOfInterpreterCalleeReceiver(signature).getOopHandleAt(0); }
+
+  //--------------------------------------------------------------------------------
+  // Expression stack (may go up or down, direction == 1 or -1)
+  //
+
+  public abstract Address addressOfInterpreterFrameExpressionStack();
+  public abstract int     getInterpreterFrameExpressionStackDirection();
+  public Address addressOfInterpreterFrameExpressionStackSlot(int slot) {
+    return addressOfInterpreterFrameExpressionStack().addOffsetTo(-slot * VM.getVM().getAddressSize());
+  }
+
+  /** Top of expression stack */
+  public abstract Address addressOfInterpreterFrameTOS();
+
+  /** Expression stack from top down */
+  public abstract Address addressOfInterpreterFrameTOSAt(int slot);
+
+  /** FIXME: is this portable? */
+  public int getInterpreterFrameExpressionStackSize() {
+    return (int) (1 + (getInterpreterFrameExpressionStackDirection() *
+                       (addressOfInterpreterFrameTOS().minus(addressOfInterpreterFrameExpressionStack()))));
+  }
+
+  public abstract Address getInterpreterFrameSenderSP();
+  // FIXME: not yet implementable
+  //  public abstract void    setInterpreterFrameSenderSP(Address senderSP);
+
+  //--------------------------------------------------------------------------------
+  // BasicObjectLocks:
+  //
+
+  public abstract BasicObjectLock interpreterFrameMonitorBegin();
+  public abstract BasicObjectLock interpreterFrameMonitorEnd();
+  /** NOTE: this returns a size in BYTES in this system! */
+  public abstract int     interpreterFrameMonitorSize();
+  public          BasicObjectLock nextMonitorInInterpreterFrame(BasicObjectLock cur) {
+    return new BasicObjectLock(cur.address().addOffsetTo(interpreterFrameMonitorSize()));
+  }
+  public          BasicObjectLock previousMonitorInInterpreterFrame(BasicObjectLock cur) {
+    return new BasicObjectLock(cur.address().addOffsetTo(-1 * interpreterFrameMonitorSize()));
+  }
+
+  // interpreter_frame_monitor_begin is higher in memory than interpreter_frame_monitor_end
+  // Interpreter_frame_monitor_begin points to one element beyond the oldest one,
+  // interpreter_frame_monitor_end   points to the youngest one, or if there are none,
+  //                                 it points to one beyond where the first element will be.
+  // interpreter_frame_monitor_size  reports the allocation size of a monitor in the interpreter stack.
+  //                                 this value is >= BasicObjectLock::size(), and may be rounded up
+
+  // FIXME: avoiding implementing this for now if possible
+  //  public void interpreter_frame_set_monitor_end(BasicObjectLock* value);
+  //  public void interpreter_frame_verify_monitor(BasicObjectLock* value) const;
+  //
+  // Tells whether the current interpreter_frame frame pointer
+  // corresponds to the old compiled/deoptimized fp
+  // The receiver used to be a top level frame
+  // public boolean interpreter_frame_equals_unpacked_fp(intptr_t* fp);
+
+  //--------------------------------------------------------------------------------
+  // Method and constant pool cache:
+  //
+
+  /** Current method */
+  public abstract Address  addressOfInterpreterFrameMethod();
+
+  /** Current method */
+  public Method            getInterpreterFrameMethod() {
+    return (Method) VM.getVM().getObjectHeap().newOop(addressOfInterpreterFrameMethod().getOopHandleAt(0));
+  }
+
+  /** Current method */
+  // FIXME: not yet implementable
+  //  public void          setInterpreterFrameMethod(Method method);
+
+  /** Constant pool cache */
+  public abstract Address  addressOfInterpreterFrameCPCache();
+  /** Constant pool cache */
+  public ConstantPoolCache getInterpreterFrameCPCache() {
+    return (ConstantPoolCache) VM.getVM().getObjectHeap().newOop(addressOfInterpreterFrameCPCache().getOopHandleAt(0));
+  }
+
+  //--------------------------------------------------------------------------------
+  // Entry frames:
+  //
+
+  public abstract JavaCallWrapper getEntryFrameCallWrapper();
+
+  // FIXME: add
+  //  inline intptr_t* entry_frame_argument_at(int offset) const;
+
+
+  /** Tells whether there is another chunk of Delta stack above */
+  public boolean entryFrameIsFirst()            { return (getEntryFrameCallWrapper().getLastJavaSP() == null); }
+
+  //--------------------------------------------------------------------------------
+  // Safepoints:
+  //
+
+  protected abstract Address addressOfSavedOopResult();
+  protected abstract Address addressOfSavedReceiver();
+
+  public OopHandle getSavedOopResult() {
+    return addressOfSavedOopResult().getOopHandleAt(0);
+  }
+
+  // FIXME: not yet implementable
+  //  public void      setSavedOopResult(OopHandle obj);
+
+  public OopHandle getSavedReceiver() {
+    return addressOfSavedReceiver().getOopHandleAt(0);
+  }
+
+  // FIXME: not yet implementable
+  //  public void      setSavedReceiver(OopHandle obj);
+
+  //--------------------------------------------------------------------------------
+  // Oop traversals:
+  //
+
+  public void oopsInterpretedArgumentsDo(Symbol signature, boolean isStatic, AddressVisitor f) {
+    ArgumentOopFinder finder = new ArgumentOopFinder(signature, isStatic, this, f);
+    finder.oopsDo();
+  }
+
+  /** Conversion from an VMReg::Name to physical stack location */
+  public Address oopMapRegToLocation(VMReg reg, RegisterMap regMap) {
+    VMReg stack0 = VM.getVM().getVMRegImplInfo().getStack0();
+    if (reg.lessThan(stack0)) {
+      // If it is passed in a register, it got spilled in the stub frame.
+      return regMap.getLocation(reg);
+    } else {
+      long spOffset = VM.getVM().getAddressSize() * reg.minus(stack0);
+      return getUnextendedSP().addOffsetTo(spOffset);
+    }
+  }
+
+  public void oopsDo(AddressVisitor oopVisitor, RegisterMap map) {
+    if (isInterpretedFrame()) {
+      oopsInterpretedDo(oopVisitor, map);
+    } else if (isEntryFrame()) {
+      oopsEntryDo(oopVisitor, map);
+    } else if (VM.getVM().getCodeCache().contains(getPC())) {
+      oopsCodeBlobDo(oopVisitor, map);
+    } else {
+      Assert.that(false, "should not reach here");
+    }
+  }
+
+  //--------------------------------------------------------------------------------
+  // Printing code
+  //
+
+  public void printValue() {
+    printValueOn(System.out);
+  }
+
+  public void printValueOn(PrintStream tty) {
+    //    FIXME;
+  }
+
+  public void print() {
+    printOn(System.out);
+  }
+
+  public void printOn(PrintStream tty) {
+    //    FIXME;
+  }
+
+  public void interpreterFramePrintOn(PrintStream tty) {
+    //    FIXME;
+  }
+
+  //--------------------------------------------------------------------------------
+  // Get/set typed locals from a frame.
+  // Respects platform dependent word-ordering.
+  //
+  // FIXME: avoiding implementing this for now if possible
+  //
+  // Currently these work only for interpreted frames.
+  // Todo: make these work for compiled frames.
+  //
+  //  oop     get_local_object(jint slot) const;
+  //  jint    get_local_int   (jint slot) const;
+  //  jlong   get_local_long  (jint slot) const;
+  //  jfloat  get_local_float (jint slot) const;
+  //  jdouble get_local_double(jint slot) const;
+  //
+  //  void set_local_object(jint slot, oop     obj);
+  //  void set_local_int   (jint slot, jint    i);
+  //  void set_local_long  (jint slot, jlong   l);
+  //  void set_local_float (jint slot, jfloat  f);
+  //  void set_local_double(jint slot, jdouble d);
+
+  // FIXME: add safepoint code, oops_do, etc.
+  // FIXME: NOT FINISHED
+
+
+
+
+
+  //--------------------------------------------------------------------------------
+  // Internals only below this point
+  //
+
+  //   /** Helper method for better factored code in frame::sender */
+  //   private frame sender_for_entry_frame(RegisterMap* map)        { throw new RuntimeException("not yet implemented"); }
+  //   private frame sender_for_interpreter_frame(RegisterMap* map)  { throw new RuntimeException("not yet implemented"); }
+
+  //
+  // Oop iteration (FIXME: NOT FINISHED)
+  //
+
+
+  private static class InterpVisitor implements OopMapVisitor {
+    private AddressVisitor addressVisitor;
+
+    public InterpVisitor(AddressVisitor oopVisitor) {
+      setAddressVisitor(oopVisitor);
+    }
+
+    public void setAddressVisitor(AddressVisitor addressVisitor) {
+      this.addressVisitor = addressVisitor;
+    }
+
+    public void visitOopLocation(Address oopAddr) {
+      addressVisitor.visitAddress(oopAddr);
+    }
+
+    public void visitDerivedOopLocation(Address baseOopAddr, Address derivedOopAddr) {
+      if (VM.getVM().isClientCompiler()) {
+        Assert.that(false, "should not reach here");
+      } else if (VM.getVM().isServerCompiler() &&
+                 VM.getVM().useDerivedPointerTable()) {
+        Assert.that(false, "FIXME: add derived pointer table");
+      }
+    }
+
+    public void visitValueLocation(Address valueAddr) {
+    }
+
+    public void visitDeadLocation(Address deadAddr) {
+    }
+  }
+
+  private void oopsInterpretedDo(AddressVisitor oopVisitor, RegisterMap map) {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(map != null, "map must be set");
+    }
+    Method m = getInterpreterFrameMethod();
+    int bci  = getInterpreterFrameBCI();
+
+    // FIXME: Seeing this sometimes
+    if (VM.getVM().isDebugging()) {
+      if (bci < 0 || bci >= m.getCodeSize()) return;
+    }
+
+    if (Assert.ASSERTS_ENABLED) {
+      //      Assert.that(VM.getVM().getUniverse().heap().isIn(m), "method must be valid oop");
+      Assert.that((m.isNative() && (bci == 0)) || ((bci >= 0) && (bci < m.getCodeSize())), "invalid bci value");
+    }
+
+    // Handle the monitor elements in the activation
+    // FIXME: monitor information not yet exposed
+    //    for (
+    //      BasicObjectLock* current = interpreter_frame_monitor_end();
+    //      current < interpreter_frame_monitor_begin();
+    //      current = next_monitor_in_interpreter_frame(current)
+    //    ) {
+    //#ifdef ASSERT
+    //      interpreter_frame_verify_monitor(current);
+    //#endif
+    //      current->oops_do(f);
+    //    }
+
+    // process fixed part
+    oopVisitor.visitAddress(addressOfInterpreterFrameMethod());
+    oopVisitor.visitAddress(addressOfInterpreterFrameCPCache());
+
+    // FIXME: expose interpreterFrameMirrorOffset
+    //    if (m.isNative() && m.isStatic()) {
+    //      oopVisitor.visitAddress(getFP().addOffsetTo(interpreterFrameMirrorOffset));
+    //    }
+
+    int maxLocals = (int) (m.isNative() ? m.getSizeOfParameters() : m.getMaxLocals());
+    InterpreterFrameClosure blk = new InterpreterFrameClosure(this, maxLocals, (int) m.getMaxStack(), oopVisitor);
+
+    // process locals & expression stack
+    OopMapCacheEntry mask = m.getMaskFor(bci);
+    mask.iterateOop(blk);
+
+    // process a callee's arguments if we are at a call site
+    // (i.e., if we are at an invoke bytecode)
+    if (map.getIncludeArgumentOops() && !m.isNative()) {
+      BytecodeInvoke call = BytecodeInvoke.atCheck(m, bci);
+      if (call != null && getInterpreterFrameExpressionStackSize() > 0) {
+        // we are at a call site & the expression stack is not empty
+        // => process callee's arguments
+        //
+        // Note: The expression stack can be empty if an exception
+        //       occured during method resolution/execution. In all
+        //       cases we empty the expression stack completely be-
+        //       fore handling the exception (the exception handling
+        //       code in the interpreter calls a blocking runtime
+        //       routine which can cause this code to be executed).
+        //       (was bug gri 7/27/98)
+        oopsInterpretedArgumentsDo(call.signature(), call.isInvokestatic(), oopVisitor);
+      }
+    }
+  }
+
+  private void oopsEntryDo      (AddressVisitor oopVisitor, RegisterMap regMap) {}
+  private void oopsCodeBlobDo   (AddressVisitor oopVisitor, RegisterMap regMap) {
+    CodeBlob cb = VM.getVM().getCodeCache().findBlob(getPC());
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(cb != null, "sanity check");
+    }
+    if (cb.getOopMaps() != null) {
+      OopMapSet.oopsDo(this, cb, regMap, oopVisitor, VM.getVM().isDebugging());
+
+      // FIXME: add in traversal of argument oops (skipping this for
+      // now until we have the other stuff tested)
+
+    }
+
+    // FIXME: would add this in in non-debugging system
+
+    // If we see an activation belonging to a non_entrant nmethod, we mark it.
+    //    if (cb->is_nmethod() && ((nmethod *)cb)->is_not_entrant()) {
+    //      ((nmethod*)cb)->mark_as_seen_on_stack();
+    //    }
+  }
+
+  // FIXME: implement the above routines, plus add
+  // oops_interpreted_arguments_do and oops_compiled_arguments_do
+}
+
+//
+// Only used internally, to iterate through oop slots in interpreted
+// frames
+//
+class InterpreterFrameClosure implements OffsetClosure {
+  // Used for debugging this code
+  private static final boolean DEBUG = false;
+
+  private Frame fr;
+  private AddressVisitor f;
+  private int maxLocals;
+  private int maxStack;
+
+  InterpreterFrameClosure(Frame fr, int maxLocals, int maxStack, AddressVisitor f) {
+    this.fr = fr;
+    this.maxLocals = maxLocals;
+    this.maxStack = maxStack;
+    this.f = f;
+  }
+
+  public void offsetDo(int offset) {
+    if (DEBUG) {
+      System.err.println("Visiting offset " + offset + ", maxLocals = " + maxLocals +
+                         " for frame " + fr + ", method " +
+                         fr.getInterpreterFrameMethod().getMethodHolder().getName().asString() +
+                         fr.getInterpreterFrameMethod().getName().asString());
+    }
+    Address addr;
+    if (offset < maxLocals) {
+      addr = fr.addressOfInterpreterFrameLocal(offset);
+      if (Assert.ASSERTS_ENABLED) {
+        Assert.that(AddressOps.gte(addr, fr.getSP()), "must be inside the frame");
+      }
+      if (DEBUG) {
+        System.err.println("  Visiting local at addr " + addr);
+      }
+      f.visitAddress(addr);
+    } else {
+      addr = fr.addressOfInterpreterFrameExpressionStackSlot(offset - maxLocals);
+      if (DEBUG) {
+        System.err.println("  Address of expression stack slot: " + addr + ", TOS = " +
+                           fr.addressOfInterpreterFrameTOS());
+      }
+      // In case of exceptions, the expression stack is invalid and the esp will be reset to express
+      // this condition. Therefore, we call f only if addr is 'inside' the stack (i.e., addr >= esp for Intel).
+      boolean inStack;
+      if (fr.getInterpreterFrameExpressionStackDirection() > 0) {
+        inStack = AddressOps.lte(addr, fr.addressOfInterpreterFrameTOS());
+      } else {
+        inStack = AddressOps.gte(addr, fr.addressOfInterpreterFrameTOS());
+      }
+      if (inStack) {
+        if (DEBUG) {
+          System.err.println("  In stack; visiting location.");
+        }
+        f.visitAddress(addr);
+      } else if (DEBUG) {
+        System.err.println("  *** WARNING: Address is out of bounds");
+      }
+    }
+  }
+}
+
+// Only used internally, to find arguments in interpreted frames
+class ArgumentOopFinder extends SignatureInfo {
+  private AddressVisitor f;
+  private int            offset;
+  private boolean        isStatic;
+  private Frame          fr;
+
+  protected void set(int size, int type) {
+    offset -= size;
+    if (type == BasicType.getTObject() || type == BasicType.getTArray()) oopOffsetDo();
+  }
+
+  private void oopOffsetDo() {
+    f.visitAddress(fr.addressOfInterpreterFrameTOSAt(offset));
+  }
+
+  public ArgumentOopFinder(Symbol signature, boolean isStatic, Frame fr, AddressVisitor f) {
+    super(signature);
+
+    // compute size of arguments
+    int argsSize = new ArgumentSizeComputer(signature).size() + (isStatic ? 0 : 1);
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(!fr.isInterpretedFrame() ||
+                  argsSize <= fr.getInterpreterFrameExpressionStackSize(), "args cannot be on stack anymore");
+    }
+    // initialize ArgumentOopFinder
+    this.f        = f;
+    this.fr       = fr;
+    this.offset   = argsSize;
+    this.isStatic = isStatic;
+  }
+
+  public void oopsDo() {
+    if (!isStatic) {
+      --offset;
+      oopOffsetDo();
+    }
+    iterateParameters();
+  }
+}