1 /*
   2  * Copyright 2000-2006 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any questions.
  22  *  
  23  */
  24 
  25 package sun.jvm.hotspot.runtime;
  26 
  27 import java.io.*;
  28 import java.util.*;
  29 import sun.jvm.hotspot.*;
  30 import sun.jvm.hotspot.code.*;
  31 import sun.jvm.hotspot.compiler.*;
  32 import sun.jvm.hotspot.c1.*;
  33 import sun.jvm.hotspot.debugger.*;
  34 import sun.jvm.hotspot.interpreter.*;
  35 import sun.jvm.hotspot.oops.*;
  36 import sun.jvm.hotspot.types.*;
  37 import sun.jvm.hotspot.utilities.*;
  38 
  39 /** <P> A frame represents a physical stack frame (an activation).
  40     Frames can be C or Java frames, and the Java frames can be
  41     interpreted or compiled. In contrast, vframes represent
  42     source-level activations, so that one physical frame can
  43     correspond to multiple source level frames because of inlining.
  44     </P>
  45 
  46     <P> NOTE that this is not a VMObject and does not wrap an Address
  47     -- this is an actual port of the VM's Frame code to Java. </P>
  48 
  49     <P> NOTE also that this is incomplete -- just trying to get
  50     reading of interpreted frames working for now, so all non-core and
  51     setter methods are removed for now. (FIXME) </P> */
  52 
  53 public abstract class Frame implements Cloneable {
  54   /** A raw stack pointer. The accessor getSP() will return a real (usable)
  55       stack pointer (e.g. from Thread::last_Java_sp) */
  56   protected Address raw_sp; 
  57 
  58   /** Program counter (the next instruction after the call) */
  59   protected Address pc;
  60   protected boolean deoptimized;
  61 
  62   public Frame() {
  63     deoptimized = false;
  64   }
  65 
  66   static {
  67     VM.registerVMInitializedObserver(new Observer() {
  68         public void update(Observable o, Object data) {
  69           initialize(VM.getVM().getTypeDataBase());
  70         }
  71       });
  72   }
  73 
  74   /** Size of constMethodOopDesc for computing BCI from BCP (FIXME: hack) */
  75   private static long    constMethodOopDescSize;
  76 
  77   private static synchronized void initialize(TypeDataBase db) {
  78     Type constMethodOopType = db.lookupType("constMethodOopDesc");
  79     // FIXME: not sure whether alignment here is correct or how to
  80     // force it (round up to address size?)
  81     constMethodOopDescSize = constMethodOopType.getSize();
  82   }
  83 
  84   protected int bcpToBci(Address bcp, ConstMethod cm) {
  85     // bcp will be null for interpreter native methods
  86     // in addition depending on where we catch the system the value can
  87     // be a bcp or a bci.
  88     if (bcp == null) return 0;
  89     long bci = bcp.minus(null);
  90     if (bci >= 0 && bci < cm.getCodeSize()) return (int) bci;
  91     return (int) (bcp.minus(cm.getHandle()) - constMethodOopDescSize); 
  92   }
  93 
  94   protected int bcpToBci(Address bcp, Method m) {
  95     return bcpToBci(bcp, m.getConstMethod());
  96   }
  97 
  98   public abstract Object clone();
  99 
 100   // Accessors
 101 
 102   /** pc: Returns the pc at which this frame will continue normally.
 103       It must point at the beginning of the next instruction to
 104       execute. */
 105   public Address getPC()              { return pc; }
 106   public void    setPC(Address newpc) { pc = newpc; }
 107   public boolean isDeoptimized()      { return deoptimized; }
 108   
 109   public abstract Address getSP();
 110   public abstract Address getID();
 111   public abstract Address getFP();
 112 
 113   /** testers -- platform dependent */
 114   public abstract boolean equals(Object arg);
 115 
 116   /** type testers */
 117   public boolean isInterpretedFrame()           { return VM.getVM().getInterpreter().contains(getPC()); }
 118   public boolean isJavaFrame() {
 119     if (isInterpretedFrame()) return true;
 120     if (!VM.getVM().isCore()) {
 121       if (isCompiledFrame())    return true;
 122     }
 123     return false;
 124   }
 125 
 126   /** Java frame called from C? */
 127   public boolean isEntryFrame()                 { return VM.getVM().getStubRoutines().returnsToCallStub(getPC()); }
 128   public boolean isNativeFrame() {
 129     if (!VM.getVM().isCore()) {
 130       CodeBlob cb = VM.getVM().getCodeCache().findBlob(getPC());
 131       return (cb != null && cb.isNativeMethod());
 132     } else {
 133       return false;
 134     }
 135   }
 136 
 137   public boolean isCompiledFrame() {
 138     if (Assert.ASSERTS_ENABLED) {
 139       Assert.that(!VM.getVM().isCore(), "noncore builds only");
 140     }
 141     CodeBlob cb = VM.getVM().getCodeCache().findBlob(getPC());
 142     return (cb != null && cb.isJavaMethod());
 143   }
 144 
 145   public boolean isGlueFrame() {
 146     if (Assert.ASSERTS_ENABLED) {
 147       Assert.that(!VM.getVM().isCore(), "noncore builds only");
 148     }
 149     CodeBlob cb = VM.getVM().getCodeCache().findBlob(getPC());
 150     if (cb == null) {
 151       return false;
 152     }
 153     if (cb.isRuntimeStub()) return true;
 154     else return false;
 155   }
 156 
 157   /** oldest frame? (has no sender) FIXME: this is modified from the
 158       C++ code to handle the debugging situation where we try to
 159       traverse the stack for, for example, the signal thread, and
 160       don't find any valid Java frames. Would really like to put the
 161       second half of the conditional in some sort of debugging-only if
 162       statement. */
 163   // *** FIXME: THE CALL TO isJavaFrame() IS WAY TOO EXPENSIVE!!!!! ***
 164   public boolean isFirstFrame()                 { return ((isEntryFrame() && entryFrameIsFirst()) ||
 165                                                           (!isJavaFrame() && !hasSenderPD()));       }
 166   /** same for Java frame */
 167   public boolean isFirstJavaFrame()             { throw new RuntimeException("not yet implemented"); }
 168 
 169   /** This is an addition for debugging purposes on platforms which
 170       have the notion of signals. */
 171   public abstract boolean isSignalHandlerFrameDbg();
 172 
 173   /** If this is a signal handler frame (again, on a platform with a
 174       notion of signals), get the signal number. */
 175   public abstract int getSignalNumberDbg();
 176 
 177   /** If this is a signal handler frame (again, on a platform with a
 178       notion of signals), get the name of the signal. */
 179   public abstract String getSignalNameDbg();
 180 
 181   /** performs sanity checks on interpreted frames. */
 182   public abstract boolean isInterpretedFrameValid();
 183 
 184   /** tells whether this frame is marked for deoptimization */
 185   public boolean shouldBeDeoptimized()          { throw new RuntimeException("not yet implemented"); }
 186 
 187   /** tells whether this frame can be deoptimized */
 188   public boolean canBeDeoptimized()             { throw new RuntimeException("not yet implemented"); }
 189 
 190   /** returns the sending frame */
 191   public abstract Frame sender(RegisterMap map, CodeBlob nm);
 192 
 193   /** equivalent to sender(map, null) */
 194   public Frame sender(RegisterMap map)          { return sender(map, null); }
 195 
 196   /** returns the sender, but skips conversion frames */
 197   public Frame realSender(RegisterMap map) {
 198     if (!VM.getVM().isCore()) {
 199       Frame result = sender(map);
 200       while (result.isGlueFrame()) {
 201         result = result.sender(map);
 202       }
 203       return result;
 204     } else {
 205       return sender(map);
 206     }
 207   }
 208 
 209   /** Platform-dependent query indicating whether this frame has a
 210       sender. Should return true if it is possible to call sender() at
 211       all on this frame. (This is currently only needed for the
 212       debugging system, if a stack trace is attempted for a Java
 213       thread which has no Java frames, i.e., the signal thread; we
 214       have to know to stop traversal at the bottom frame.) */
 215   protected abstract boolean hasSenderPD();
 216 
 217   //--------------------------------------------------------------------------------
 218   // All frames:
 219   // A low-level interface for vframes:
 220 
 221   /** Returns the address of the requested "slot" on the stack. Slots
 222       are as wide as addresses, so are 32 bits wide on a 32-bit
 223       machine and 64 bits wide on a 64-bit machine. */
 224   public Address   addressOfStackSlot(int slot)              { return getFP().addOffsetTo(slot * VM.getVM().getAddressSize()); }
 225 
 226   /** Fetches the OopHandle at the requested slot */
 227   public OopHandle getOopHandleAt(int slot)                  { return addressOfStackSlot(slot).getOopHandleAt(0);              }
 228   /** Fetches the OopHandle at the slot, adjusted for compiler frames */
 229   // FIXME: looks like this is only used for compiled frames
 230   //  public OopHandle getOopHandleAtAdjusted(MethodOop method, int slot) { return addressOfStackSlot(slot).getOopHandleAt(0); }
 231   // FIXME: Not yet implementable
 232   //  public void  setOopHandleAt(int slot, OopHandle value) { addressOfStackSlot(slot).setOopHandleAt(0, value);              }
 233   
 234   /** Fetches the (Java) int at the requested slot */
 235   public int       getIntAt(int slot)                        { return addressOfStackSlot(slot).getJIntAt(0);                   }
 236   // FIXME: Not yet implementable
 237   // public void setIntAt(int slot, int value)               { addressOfStackSlot(slot).setJIntAt(0, value);                   }
 238                                                 
 239   /** returns the frame size in stack slots */
 240   public abstract long frameSize();
 241 
 242   /** Link (i.e., the pointer to the previous frame) */
 243   public abstract Address getLink();
 244   //  public abstract void    setLink(Address addr);
 245 
 246   /** Return address */
 247   public abstract Address getSenderPC();
 248   // FIXME: currently unimplementable
 249   //  public abstract void    setSenderPC(Address addr);
 250 
 251   /** The frame's original SP, before any extension by an interpreted
 252       callee; used for packing debug info into vframeArray objects and
 253       vframeArray lookup. */
 254   public abstract Address getUnextendedSP();
 255 
 256   /** Returns the stack pointer of the calling frame */
 257   public abstract Address getSenderSP();
 258 
 259   //--------------------------------------------------------------------------------
 260   // Interpreter frames:
 261   //
 262 
 263   public abstract Address addressOfInterpreterFrameLocals();
 264 
 265   public Address addressOfInterpreterFrameLocal(int slot) {
 266     return addressOfInterpreterFrameLocals().getAddressAt(0).addOffsetTo(-slot * VM.getVM().getAddressSize());
 267   }
 268 
 269   // FIXME: not yet implementable
 270   //  void interpreter_frame_set_locals(intptr_t* locs);
 271 
 272   // NOTE that the accessor "addressOfInterpreterFrameBCX" has
 273   // necessarily been eliminated. The byte code pointer is inherently
 274   // an interior pointer to a Method (the bytecodes follow the
 275   // methodOopDesc data structure) and therefore acquisition of it in
 276   // this system can not be allowed. All accesses to interpreter frame
 277   // byte codes are via the byte code index (BCI).
 278 
 279   /** Byte code index. In the underlying frame, what is actually
 280       stored is a byte code pointer (BCP), which is converted to a BCI
 281       and back by the GC when methods are moved. In this system,
 282       interior pointers are not allowed, so we must make the access to
 283       the interpreter frame's BCI atomic with respect to GC. This may
 284       mean implementation with an underlying call through native code
 285       into the VM or a magic sequence in the compiler. (FIXME) */
 286   public abstract int     getInterpreterFrameBCI();
 287   // FIXME: not yet implementable
 288   // public abstract void setInterpreterFrameBCI(int bci);
 289 
 290   // FIXME: elided for now
 291   //  public abstract Address addressOfInterpreterCalleeReceiver(Symbol signature);
 292 
 293   /** Find receiver for an invoke when arguments are just pushed on
 294       stack (i.e., callee stack-frame is not setup) */
 295   // FIXME: elided for now
 296   //  public OopHandle getInterpreterCalleeReceiver(SymbolOop signature) { return addressOfInterpreterCalleeReceiver(signature).getOopHandleAt(0); }
 297 
 298   //--------------------------------------------------------------------------------
 299   // Expression stack (may go up or down, direction == 1 or -1)
 300   //
 301 
 302   public abstract Address addressOfInterpreterFrameExpressionStack();
 303   public abstract int     getInterpreterFrameExpressionStackDirection();
 304   public Address addressOfInterpreterFrameExpressionStackSlot(int slot) {
 305     return addressOfInterpreterFrameExpressionStack().addOffsetTo(-slot * VM.getVM().getAddressSize());
 306   }
 307   
 308   /** Top of expression stack */
 309   public abstract Address addressOfInterpreterFrameTOS();
 310 
 311   /** Expression stack from top down */
 312   public abstract Address addressOfInterpreterFrameTOSAt(int slot);
 313 
 314   /** FIXME: is this portable? */
 315   public int getInterpreterFrameExpressionStackSize() {
 316     return (int) (1 + (getInterpreterFrameExpressionStackDirection() *
 317                        (addressOfInterpreterFrameTOS().minus(addressOfInterpreterFrameExpressionStack()))));
 318   }
 319 
 320   public abstract Address getInterpreterFrameSenderSP();
 321   // FIXME: not yet implementable
 322   //  public abstract void    setInterpreterFrameSenderSP(Address senderSP); 
 323   
 324   //--------------------------------------------------------------------------------
 325   // BasicObjectLocks:
 326   //
 327 
 328   public abstract BasicObjectLock interpreterFrameMonitorBegin();
 329   public abstract BasicObjectLock interpreterFrameMonitorEnd();
 330   /** NOTE: this returns a size in BYTES in this system! */
 331   public abstract int     interpreterFrameMonitorSize();
 332   public          BasicObjectLock nextMonitorInInterpreterFrame(BasicObjectLock cur) {
 333     return new BasicObjectLock(cur.address().addOffsetTo(interpreterFrameMonitorSize()));
 334   }
 335   public          BasicObjectLock previousMonitorInInterpreterFrame(BasicObjectLock cur) {
 336     return new BasicObjectLock(cur.address().addOffsetTo(-1 * interpreterFrameMonitorSize()));
 337   }
 338 
 339   // interpreter_frame_monitor_begin is higher in memory than interpreter_frame_monitor_end
 340   // Interpreter_frame_monitor_begin points to one element beyond the oldest one,
 341   // interpreter_frame_monitor_end   points to the youngest one, or if there are none,
 342   //                                 it points to one beyond where the first element will be.
 343   // interpreter_frame_monitor_size  reports the allocation size of a monitor in the interpreter stack.
 344   //                                 this value is >= BasicObjectLock::size(), and may be rounded up
 345   
 346   // FIXME: avoiding implementing this for now if possible
 347   //  public void interpreter_frame_set_monitor_end(BasicObjectLock* value);
 348   //  public void interpreter_frame_verify_monitor(BasicObjectLock* value) const;
 349   //
 350   // Tells whether the current interpreter_frame frame pointer
 351   // corresponds to the old compiled/deoptimized fp
 352   // The receiver used to be a top level frame
 353   // public boolean interpreter_frame_equals_unpacked_fp(intptr_t* fp);
 354 
 355   //--------------------------------------------------------------------------------
 356   // Method and constant pool cache:
 357   //
 358 
 359   /** Current method */
 360   public abstract Address  addressOfInterpreterFrameMethod();
 361 
 362   /** Current method */
 363   public Method            getInterpreterFrameMethod() {
 364     return (Method) VM.getVM().getObjectHeap().newOop(addressOfInterpreterFrameMethod().getOopHandleAt(0));
 365   }
 366 
 367   /** Current method */
 368   // FIXME: not yet implementable
 369   //  public void          setInterpreterFrameMethod(Method method);
 370 
 371   /** Constant pool cache */
 372   public abstract Address  addressOfInterpreterFrameCPCache();
 373   /** Constant pool cache */
 374   public ConstantPoolCache getInterpreterFrameCPCache() {
 375     return (ConstantPoolCache) VM.getVM().getObjectHeap().newOop(addressOfInterpreterFrameCPCache().getOopHandleAt(0));
 376   }
 377 
 378   //--------------------------------------------------------------------------------
 379   // Entry frames:
 380   //
 381 
 382   public abstract JavaCallWrapper getEntryFrameCallWrapper();
 383 
 384   // FIXME: add
 385   //  inline intptr_t* entry_frame_argument_at(int offset) const;
 386 
 387 
 388   /** Tells whether there is another chunk of Delta stack above */
 389   public boolean entryFrameIsFirst()            { return (getEntryFrameCallWrapper().getLastJavaSP() == null); }
 390 
 391   //--------------------------------------------------------------------------------
 392   // Safepoints:
 393   //
 394 
 395   protected abstract Address addressOfSavedOopResult();
 396   protected abstract Address addressOfSavedReceiver();
 397   
 398   public OopHandle getSavedOopResult() {
 399     return addressOfSavedOopResult().getOopHandleAt(0);
 400   }
 401 
 402   // FIXME: not yet implementable
 403   //  public void      setSavedOopResult(OopHandle obj);
 404 
 405   public OopHandle getSavedReceiver() {
 406     return addressOfSavedReceiver().getOopHandleAt(0);
 407   }
 408 
 409   // FIXME: not yet implementable
 410   //  public void      setSavedReceiver(OopHandle obj);
 411 
 412   //--------------------------------------------------------------------------------
 413   // Oop traversals:
 414   //
 415 
 416   public void oopsInterpretedArgumentsDo(Symbol signature, boolean isStatic, AddressVisitor f) {
 417     ArgumentOopFinder finder = new ArgumentOopFinder(signature, isStatic, this, f);
 418     finder.oopsDo();
 419   }
 420 
 421   /** Conversion from an VMReg::Name to physical stack location */
 422   public Address oopMapRegToLocation(VMReg reg, RegisterMap regMap) {
 423     VMReg stack0 = VM.getVM().getVMRegImplInfo().getStack0();
 424     if (reg.lessThan(stack0)) {
 425       // If it is passed in a register, it got spilled in the stub frame.  
 426       return regMap.getLocation(reg);
 427     } else {
 428       long spOffset = VM.getVM().getAddressSize() * reg.minus(stack0);
 429       return getUnextendedSP().addOffsetTo(spOffset);
 430     }
 431   }
 432 
 433   public void oopsDo(AddressVisitor oopVisitor, RegisterMap map) {
 434     if (isInterpretedFrame()) {
 435       oopsInterpretedDo(oopVisitor, map);
 436     } else if (isEntryFrame()) {
 437       oopsEntryDo(oopVisitor, map);
 438     } else if (VM.getVM().getCodeCache().contains(getPC())) {
 439       oopsCodeBlobDo(oopVisitor, map);
 440     } else {
 441       Assert.that(false, "should not reach here");
 442     }
 443   }
 444 
 445   //--------------------------------------------------------------------------------
 446   // Printing code
 447   //
 448 
 449   public void printValue() {
 450     printValueOn(System.out);
 451   }
 452 
 453   public void printValueOn(PrintStream tty) {
 454     //    FIXME;
 455   }
 456 
 457   public void print() {
 458     printOn(System.out);
 459   }
 460 
 461   public void printOn(PrintStream tty) {
 462     //    FIXME;
 463   }
 464 
 465   public void interpreterFramePrintOn(PrintStream tty) {
 466     //    FIXME;
 467   }
 468 
 469   //--------------------------------------------------------------------------------
 470   // Get/set typed locals from a frame.
 471   // Respects platform dependent word-ordering.
 472   //
 473   // FIXME: avoiding implementing this for now if possible
 474   //
 475   // Currently these work only for interpreted frames.
 476   // Todo: make these work for compiled frames.
 477   //
 478   //  oop     get_local_object(jint slot) const;
 479   //  jint    get_local_int   (jint slot) const;
 480   //  jlong   get_local_long  (jint slot) const;
 481   //  jfloat  get_local_float (jint slot) const;
 482   //  jdouble get_local_double(jint slot) const;
 483   //  
 484   //  void set_local_object(jint slot, oop     obj);
 485   //  void set_local_int   (jint slot, jint    i);
 486   //  void set_local_long  (jint slot, jlong   l);
 487   //  void set_local_float (jint slot, jfloat  f);
 488   //  void set_local_double(jint slot, jdouble d);
 489 
 490   // FIXME: add safepoint code, oops_do, etc.
 491   // FIXME: NOT FINISHED
 492   
 493 
 494 
 495 
 496 
 497   //--------------------------------------------------------------------------------
 498   // Internals only below this point
 499   //
 500 
 501   //   /** Helper method for better factored code in frame::sender */
 502   //   private frame sender_for_entry_frame(RegisterMap* map)        { throw new RuntimeException("not yet implemented"); }
 503   //   private frame sender_for_interpreter_frame(RegisterMap* map)  { throw new RuntimeException("not yet implemented"); }
 504 
 505   //
 506   // Oop iteration (FIXME: NOT FINISHED)
 507   //
 508 
 509   
 510   private static class InterpVisitor implements OopMapVisitor {
 511     private AddressVisitor addressVisitor;
 512 
 513     public InterpVisitor(AddressVisitor oopVisitor) {
 514       setAddressVisitor(oopVisitor);
 515     }
 516 
 517     public void setAddressVisitor(AddressVisitor addressVisitor) {
 518       this.addressVisitor = addressVisitor;
 519     }
 520 
 521     public void visitOopLocation(Address oopAddr) {
 522       addressVisitor.visitAddress(oopAddr);
 523     }
 524 
 525     public void visitDerivedOopLocation(Address baseOopAddr, Address derivedOopAddr) {
 526       if (VM.getVM().isClientCompiler()) {
 527         Assert.that(false, "should not reach here");
 528       } else if (VM.getVM().isServerCompiler() &&
 529                  VM.getVM().useDerivedPointerTable()) {
 530         Assert.that(false, "FIXME: add derived pointer table");
 531       }
 532     }
 533 
 534     public void visitValueLocation(Address valueAddr) {
 535     }
 536 
 537     public void visitDeadLocation(Address deadAddr) {
 538     }
 539   }
 540   
 541   private void oopsInterpretedDo(AddressVisitor oopVisitor, RegisterMap map) {
 542     if (Assert.ASSERTS_ENABLED) {
 543       Assert.that(map != null, "map must be set");
 544     }
 545     Method m = getInterpreterFrameMethod();
 546     int bci  = getInterpreterFrameBCI();
 547 
 548     // FIXME: Seeing this sometimes
 549     if (VM.getVM().isDebugging()) {
 550       if (bci < 0 || bci >= m.getCodeSize()) return;
 551     }
 552 
 553     if (Assert.ASSERTS_ENABLED) {
 554       //      Assert.that(VM.getVM().getUniverse().heap().isIn(m), "method must be valid oop");
 555       Assert.that((m.isNative() && (bci == 0)) || ((bci >= 0) && (bci < m.getCodeSize())), "invalid bci value");
 556     }
 557 
 558     // Handle the monitor elements in the activation
 559     // FIXME: monitor information not yet exposed
 560     //    for (
 561     //      BasicObjectLock* current = interpreter_frame_monitor_end();
 562     //      current < interpreter_frame_monitor_begin();
 563     //      current = next_monitor_in_interpreter_frame(current)
 564     //    ) {
 565     //#ifdef ASSERT
 566     //      interpreter_frame_verify_monitor(current);
 567     //#endif    
 568     //      current->oops_do(f);
 569     //    }
 570 
 571     // process fixed part
 572     oopVisitor.visitAddress(addressOfInterpreterFrameMethod());
 573     oopVisitor.visitAddress(addressOfInterpreterFrameCPCache());
 574 
 575     // FIXME: expose interpreterFrameMirrorOffset
 576     //    if (m.isNative() && m.isStatic()) {
 577     //      oopVisitor.visitAddress(getFP().addOffsetTo(interpreterFrameMirrorOffset));
 578     //    }
 579 
 580     int maxLocals = (int) (m.isNative() ? m.getSizeOfParameters() : m.getMaxLocals());
 581     InterpreterFrameClosure blk = new InterpreterFrameClosure(this, maxLocals, (int) m.getMaxStack(), oopVisitor);
 582     
 583     // process locals & expression stack
 584     OopMapCacheEntry mask = m.getMaskFor(bci);
 585     mask.iterateOop(blk);
 586 
 587     // process a callee's arguments if we are at a call site
 588     // (i.e., if we are at an invoke bytecode)  
 589     if (map.getIncludeArgumentOops() && !m.isNative()) {
 590       BytecodeInvoke call = BytecodeInvoke.atCheck(m, bci);
 591       if (call != null && getInterpreterFrameExpressionStackSize() > 0) {
 592         // we are at a call site & the expression stack is not empty
 593         // => process callee's arguments
 594         //
 595         // Note: The expression stack can be empty if an exception
 596         //       occured during method resolution/execution. In all
 597         //       cases we empty the expression stack completely be-
 598         //       fore handling the exception (the exception handling
 599         //       code in the interpreter calls a blocking runtime
 600         //       routine which can cause this code to be executed).
 601         //       (was bug gri 7/27/98)      
 602         oopsInterpretedArgumentsDo(call.signature(), call.isInvokestatic(), oopVisitor);
 603       }
 604     }
 605   }
 606 
 607   private void oopsEntryDo      (AddressVisitor oopVisitor, RegisterMap regMap) {}
 608   private void oopsCodeBlobDo   (AddressVisitor oopVisitor, RegisterMap regMap) {
 609     CodeBlob cb = VM.getVM().getCodeCache().findBlob(getPC());
 610     if (Assert.ASSERTS_ENABLED) {
 611       Assert.that(cb != null, "sanity check");
 612     }
 613     if (cb.getOopMaps() != null) {
 614       OopMapSet.oopsDo(this, cb, regMap, oopVisitor, VM.getVM().isDebugging());
 615 
 616       // FIXME: add in traversal of argument oops (skipping this for
 617       // now until we have the other stuff tested)
 618 
 619     }
 620 
 621     // FIXME: would add this in in non-debugging system
 622 
 623     // If we see an activation belonging to a non_entrant nmethod, we mark it.
 624     //    if (cb->is_nmethod() && ((nmethod *)cb)->is_not_entrant()) {
 625     //      ((nmethod*)cb)->mark_as_seen_on_stack();
 626     //    }
 627   }
 628 
 629   // FIXME: implement the above routines, plus add
 630   // oops_interpreted_arguments_do and oops_compiled_arguments_do
 631 }
 632 
 633 //
 634 // Only used internally, to iterate through oop slots in interpreted
 635 // frames
 636 //
 637 class InterpreterFrameClosure implements OffsetClosure {
 638   // Used for debugging this code
 639   private static final boolean DEBUG = false;
 640 
 641   private Frame fr;
 642   private AddressVisitor f;
 643   private int maxLocals;
 644   private int maxStack;
 645 
 646   InterpreterFrameClosure(Frame fr, int maxLocals, int maxStack, AddressVisitor f) {
 647     this.fr = fr;
 648     this.maxLocals = maxLocals;
 649     this.maxStack = maxStack;
 650     this.f = f;
 651   }
 652 
 653   public void offsetDo(int offset) {
 654     if (DEBUG) {
 655       System.err.println("Visiting offset " + offset + ", maxLocals = " + maxLocals +
 656                          " for frame " + fr + ", method " +
 657                          fr.getInterpreterFrameMethod().getMethodHolder().getName().asString() +
 658                          fr.getInterpreterFrameMethod().getName().asString());
 659     }
 660     Address addr;
 661     if (offset < maxLocals) {
 662       addr = fr.addressOfInterpreterFrameLocal(offset);
 663       if (Assert.ASSERTS_ENABLED) {
 664         Assert.that(AddressOps.gte(addr, fr.getSP()), "must be inside the frame");
 665       }
 666       if (DEBUG) {
 667         System.err.println("  Visiting local at addr " + addr);
 668       }
 669       f.visitAddress(addr);
 670     } else {
 671       addr = fr.addressOfInterpreterFrameExpressionStackSlot(offset - maxLocals);
 672       if (DEBUG) {
 673         System.err.println("  Address of expression stack slot: " + addr + ", TOS = " +
 674                            fr.addressOfInterpreterFrameTOS());
 675       }
 676       // In case of exceptions, the expression stack is invalid and the esp will be reset to express
 677       // this condition. Therefore, we call f only if addr is 'inside' the stack (i.e., addr >= esp for Intel).
 678       boolean inStack;
 679       if (fr.getInterpreterFrameExpressionStackDirection() > 0) {
 680         inStack = AddressOps.lte(addr, fr.addressOfInterpreterFrameTOS());
 681       } else {
 682         inStack = AddressOps.gte(addr, fr.addressOfInterpreterFrameTOS());
 683       }
 684       if (inStack) {
 685         if (DEBUG) {
 686           System.err.println("  In stack; visiting location.");
 687         }
 688         f.visitAddress(addr);
 689       } else if (DEBUG) {
 690         System.err.println("  *** WARNING: Address is out of bounds");
 691       }
 692     }
 693   }
 694 }
 695 
 696 // Only used internally, to find arguments in interpreted frames
 697 class ArgumentOopFinder extends SignatureInfo {
 698   private AddressVisitor f;
 699   private int            offset;
 700   private boolean        isStatic;
 701   private Frame          fr;
 702 
 703   protected void set(int size, int type) {
 704     offset -= size;
 705     if (type == BasicType.getTObject() || type == BasicType.getTArray()) oopOffsetDo();
 706   }
 707 
 708   private void oopOffsetDo() {
 709     f.visitAddress(fr.addressOfInterpreterFrameTOSAt(offset));
 710   }
 711 
 712   public ArgumentOopFinder(Symbol signature, boolean isStatic, Frame fr, AddressVisitor f) {
 713     super(signature);
 714 
 715     // compute size of arguments
 716     int argsSize = new ArgumentSizeComputer(signature).size() + (isStatic ? 0 : 1);
 717     if (Assert.ASSERTS_ENABLED) {
 718       Assert.that(!fr.isInterpretedFrame() ||     
 719                   argsSize <= fr.getInterpreterFrameExpressionStackSize(), "args cannot be on stack anymore");
 720     }
 721     // initialize ArgumentOopFinder
 722     this.f        = f;
 723     this.fr       = fr;    
 724     this.offset   = argsSize;
 725     this.isStatic = isStatic;
 726   }
 727   
 728   public void oopsDo() {
 729     if (!isStatic) {
 730       --offset;
 731       oopOffsetDo();
 732     }
 733     iterateParameters();
 734   }
 735 }