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