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