1 /*
   2  * Copyright (c) 2001, 2006, 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.x86;
  26 
  27 import java.util.*;
  28 import sun.jvm.hotspot.code.*;
  29 import sun.jvm.hotspot.compiler.*;
  30 import sun.jvm.hotspot.debugger.*;
  31 import sun.jvm.hotspot.oops.*;
  32 import sun.jvm.hotspot.runtime.*;
  33 import sun.jvm.hotspot.types.*;
  34 import sun.jvm.hotspot.utilities.*;
  35 
  36 /** Specialization of and implementation of abstract methods of the
  37     Frame class for the x86 family of CPUs. */
  38 
  39 public class X86Frame extends Frame {
  40   private static final boolean DEBUG;
  41   static {
  42     DEBUG = System.getProperty("sun.jvm.hotspot.runtime.x86.X86Frame.DEBUG") != null;
  43   }
  44 
  45   // All frames
  46   private static final int LINK_OFFSET                =  0;
  47   private static final int RETURN_ADDR_OFFSET         =  1;
  48   private static final int SENDER_SP_OFFSET           =  2;
  49 
  50   // Interpreter frames
  51   private static final int INTERPRETER_FRAME_MIRROR_OFFSET    =  2; // for native calls only
  52   private static final int INTERPRETER_FRAME_SENDER_SP_OFFSET = -1;
  53   private static final int INTERPRETER_FRAME_LAST_SP_OFFSET   = INTERPRETER_FRAME_SENDER_SP_OFFSET - 1;
  54   private static final int INTERPRETER_FRAME_METHOD_OFFSET    = INTERPRETER_FRAME_LAST_SP_OFFSET - 1;
  55   private static       int INTERPRETER_FRAME_MDX_OFFSET;         // Non-core builds only
  56   private static       int INTERPRETER_FRAME_CACHE_OFFSET;
  57   private static       int INTERPRETER_FRAME_LOCALS_OFFSET;
  58   private static       int INTERPRETER_FRAME_BCX_OFFSET;
  59   private static       int INTERPRETER_FRAME_INITIAL_SP_OFFSET;
  60   private static       int INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET;
  61   private static       int INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET;
  62 
  63   // Entry frames
  64   private static       int ENTRY_FRAME_CALL_WRAPPER_OFFSET;
  65 
  66   // Native frames
  67   private static final int NATIVE_FRAME_INITIAL_PARAM_OFFSET =  2;
  68 
  69   private static VMReg rbp;
  70 
  71   static {
  72     VM.registerVMInitializedObserver(new Observer() {
  73         public void update(Observable o, Object data) {
  74           initialize(VM.getVM().getTypeDataBase());
  75         }
  76       });
  77   }
  78 
  79   private static synchronized void initialize(TypeDataBase db) {
  80     INTERPRETER_FRAME_MDX_OFFSET                  = INTERPRETER_FRAME_METHOD_OFFSET - 1;
  81     INTERPRETER_FRAME_CACHE_OFFSET                = INTERPRETER_FRAME_MDX_OFFSET - 1;
  82     INTERPRETER_FRAME_LOCALS_OFFSET               = INTERPRETER_FRAME_CACHE_OFFSET - 1;
  83     INTERPRETER_FRAME_BCX_OFFSET                  = INTERPRETER_FRAME_LOCALS_OFFSET - 1;
  84     INTERPRETER_FRAME_INITIAL_SP_OFFSET           = INTERPRETER_FRAME_BCX_OFFSET - 1;
  85     INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET    = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
  86     INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
  87 
  88     ENTRY_FRAME_CALL_WRAPPER_OFFSET = db.lookupIntConstant("frame::entry_frame_call_wrapper_offset");
  89     if (VM.getVM().getAddressSize() == 4) {
  90       rbp = new VMReg(5);
  91     } else {
  92       rbp = new VMReg(5 << 1);
  93     }
  94   }
  95 
  96 
  97   // an additional field beyond sp and pc:
  98   Address raw_fp; // frame pointer
  99   private Address raw_unextendedSP;
 100 
 101   private X86Frame() {
 102   }
 103 
 104   private void adjustForDeopt() {
 105     if ( pc != null) {
 106       // Look for a deopt pc and if it is deopted convert to original pc
 107       CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc);
 108       if (cb != null && cb.isJavaMethod()) {
 109         NMethod nm = (NMethod) cb;
 110         if (pc.equals(nm.deoptHandlerBegin())) {
 111           if (Assert.ASSERTS_ENABLED) {
 112             Assert.that(this.getUnextendedSP() != null, "null SP in Java frame");
 113           }
 114           // adjust pc if frame is deoptimized.
 115           pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset());
 116           deoptimized = true;
 117         }
 118       }
 119     }
 120   }
 121 
 122   public X86Frame(Address raw_sp, Address raw_fp, Address pc) {
 123     this.raw_sp = raw_sp;
 124     this.raw_unextendedSP = raw_sp;
 125     this.raw_fp = raw_fp;
 126     this.pc = pc;
 127     adjustUnextendedSP();
 128 
 129     // Frame must be fully constructed before this call
 130     adjustForDeopt();
 131 
 132     if (DEBUG) {
 133       System.out.println("X86Frame(sp, fp, pc): " + this);
 134       dumpStack();
 135     }
 136   }
 137 
 138   public X86Frame(Address raw_sp, Address raw_fp) {
 139     this.raw_sp = raw_sp;
 140     this.raw_unextendedSP = raw_sp;
 141     this.raw_fp = raw_fp;
 142     this.pc = raw_sp.getAddressAt(-1 * VM.getVM().getAddressSize());
 143     adjustUnextendedSP();
 144 
 145     // Frame must be fully constructed before this call
 146     adjustForDeopt();
 147 
 148     if (DEBUG) {
 149       System.out.println("X86Frame(sp, fp): " + this);
 150       dumpStack();
 151     }
 152   }
 153 
 154   public X86Frame(Address raw_sp, Address raw_unextendedSp, Address raw_fp, Address pc) {
 155     this.raw_sp = raw_sp;
 156     this.raw_unextendedSP = raw_unextendedSp;
 157     this.raw_fp = raw_fp;
 158     this.pc = pc;
 159     adjustUnextendedSP();
 160 
 161     // Frame must be fully constructed before this call
 162     adjustForDeopt();
 163 
 164     if (DEBUG) {
 165       System.out.println("X86Frame(sp, unextendedSP, fp, pc): " + this);
 166       dumpStack();
 167     }
 168 
 169   }
 170 
 171   public Object clone() {
 172     X86Frame frame = new X86Frame();
 173     frame.raw_sp = raw_sp;
 174     frame.raw_unextendedSP = raw_unextendedSP;
 175     frame.raw_fp = raw_fp;
 176     frame.pc = pc;
 177     frame.deoptimized = deoptimized;
 178     return frame;
 179   }
 180 
 181   public boolean equals(Object arg) {
 182     if (arg == null) {
 183       return false;
 184     }
 185 
 186     if (!(arg instanceof X86Frame)) {
 187       return false;
 188     }
 189 
 190     X86Frame other = (X86Frame) arg;
 191 
 192     return (AddressOps.equal(getSP(), other.getSP()) &&
 193             AddressOps.equal(getUnextendedSP(), other.getUnextendedSP()) &&
 194             AddressOps.equal(getFP(), other.getFP()) &&
 195             AddressOps.equal(getPC(), other.getPC()));
 196   }
 197 
 198   public int hashCode() {
 199     if (raw_sp == null) {
 200       return 0;
 201     }
 202 
 203     return raw_sp.hashCode();
 204   }
 205 
 206   public String toString() {
 207     return "sp: " + (getSP() == null? "null" : getSP().toString()) +
 208          ", unextendedSP: " + (getUnextendedSP() == null? "null" : getUnextendedSP().toString()) +
 209          ", fp: " + (getFP() == null? "null" : getFP().toString()) +
 210          ", pc: " + (pc == null? "null" : pc.toString());
 211   }
 212 
 213   // accessors for the instance variables
 214   public Address getFP() { return raw_fp; }
 215   public Address getSP() { return raw_sp; }
 216   public Address getID() { return raw_sp; }
 217 
 218   // FIXME: not implemented yet (should be done for Solaris/X86)
 219   public boolean isSignalHandlerFrameDbg() { return false; }
 220   public int     getSignalNumberDbg()      { return 0;     }
 221   public String  getSignalNameDbg()        { return null;  }
 222 
 223   public boolean isInterpretedFrameValid() {
 224     if (Assert.ASSERTS_ENABLED) {
 225       Assert.that(isInterpretedFrame(), "Not an interpreted frame");
 226     }
 227 
 228     // These are reasonable sanity checks
 229     if (getFP() == null || getFP().andWithMask(0x3) != null) {
 230       return false;
 231     }
 232 
 233     if (getSP() == null || getSP().andWithMask(0x3) != null) {
 234       return false;
 235     }
 236 
 237     if (getFP().addOffsetTo(INTERPRETER_FRAME_INITIAL_SP_OFFSET * VM.getVM().getAddressSize()).lessThan(getSP())) {
 238       return false;
 239     }
 240 
 241     // These are hacks to keep us out of trouble.
 242     // The problem with these is that they mask other problems
 243     if (getFP().lessThanOrEqual(getSP())) {
 244       // this attempts to deal with unsigned comparison above
 245       return false;
 246     }
 247 
 248     if (getFP().minus(getSP()) > 4096 * VM.getVM().getAddressSize()) {
 249       // stack frames shouldn't be large.
 250       return false;
 251     }
 252 
 253     return true;
 254   }
 255 
 256   // FIXME: not applicable in current system
 257   //  void    patch_pc(Thread* thread, address pc);
 258 
 259   public Frame sender(RegisterMap regMap, CodeBlob cb) {
 260     X86RegisterMap map = (X86RegisterMap) regMap;
 261 
 262     if (Assert.ASSERTS_ENABLED) {
 263       Assert.that(map != null, "map must be set");
 264     }
 265 
 266     // Default is we done have to follow them. The sender_for_xxx will
 267     // update it accordingly
 268     map.setIncludeArgumentOops(false);
 269 
 270     if (isEntryFrame())       return senderForEntryFrame(map);
 271     if (isInterpretedFrame()) return senderForInterpreterFrame(map);
 272     if (isRicochetFrame())    return senderForRicochetFrame(map);
 273 
 274     if(cb == null) {
 275       cb = VM.getVM().getCodeCache().findBlob(getPC());
 276     } else {
 277       if (Assert.ASSERTS_ENABLED) {
 278         Assert.that(cb.equals(VM.getVM().getCodeCache().findBlob(getPC())), "Must be the same");
 279       }
 280     }
 281 
 282     if (cb != null) {
 283       return senderForCompiledFrame(map, cb);
 284     }
 285 
 286     // Must be native-compiled frame, i.e. the marshaling code for native
 287     // methods that exists in the core system.
 288     return new X86Frame(getSenderSP(), getLink(), getSenderPC());
 289   }
 290 
 291   private Frame senderForRicochetFrame(X86RegisterMap map) {
 292     if (DEBUG) {
 293       System.out.println("senderForRicochetFrame");
 294     }
 295     X86RicochetFrame f = X86RicochetFrame.fromFrame(this);
 296     if (map.getUpdateMap())
 297       updateMapWithSavedLink(map, f.senderLinkAddress());
 298     return new X86Frame(f.extendedSenderSP(), f.exactSenderSP(), f.senderLink(), f.senderPC());
 299   }
 300 
 301   private Frame senderForEntryFrame(X86RegisterMap map) {
 302     if (DEBUG) {
 303       System.out.println("senderForEntryFrame");
 304     }
 305     if (Assert.ASSERTS_ENABLED) {
 306       Assert.that(map != null, "map must be set");
 307     }
 308     // Java frame called from C; skip all C frames and return top C
 309     // frame of that chunk as the sender
 310     X86JavaCallWrapper jcw = (X86JavaCallWrapper) getEntryFrameCallWrapper();
 311     if (Assert.ASSERTS_ENABLED) {
 312       Assert.that(!entryFrameIsFirst(), "next Java fp must be non zero");
 313       Assert.that(jcw.getLastJavaSP().greaterThan(getSP()), "must be above this frame on stack");
 314     }
 315     X86Frame fr;
 316     if (jcw.getLastJavaPC() != null) {
 317       fr = new X86Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP(), jcw.getLastJavaPC());
 318     } else {
 319       fr = new X86Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP());
 320     }
 321     map.clear();
 322     if (Assert.ASSERTS_ENABLED) {
 323       Assert.that(map.getIncludeArgumentOops(), "should be set by clear");
 324     }
 325     return fr;
 326   }
 327 
 328   //------------------------------------------------------------------------------
 329   // frame::adjust_unextended_sp
 330   private void adjustUnextendedSP() {
 331     // If we are returning to a compiled MethodHandle call site, the
 332     // saved_fp will in fact be a saved value of the unextended SP.  The
 333     // simplest way to tell whether we are returning to such a call site
 334     // is as follows:
 335 
 336     CodeBlob cb = cb();
 337     NMethod senderNm = (cb == null) ? null : cb.asNMethodOrNull();
 338     if (senderNm != null) {
 339       // If the sender PC is a deoptimization point, get the original
 340       // PC.  For MethodHandle call site the unextended_sp is stored in
 341       // saved_fp.
 342       if (senderNm.isDeoptMhEntry(getPC())) {
 343         // DEBUG_ONLY(verifyDeoptMhOriginalPc(senderNm, getFP()));
 344         raw_unextendedSP = getFP();
 345       }
 346       else if (senderNm.isDeoptEntry(getPC())) {
 347         // DEBUG_ONLY(verifyDeoptOriginalPc(senderNm, raw_unextendedSp));
 348       }
 349       else if (senderNm.isMethodHandleReturn(getPC())) {
 350         raw_unextendedSP = getFP();
 351       }
 352     }
 353   }
 354 
 355   private Frame senderForInterpreterFrame(X86RegisterMap map) {
 356     if (DEBUG) {
 357       System.out.println("senderForInterpreterFrame");
 358     }
 359     Address unextendedSP = addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0);
 360     Address sp = addressOfStackSlot(SENDER_SP_OFFSET);
 361     // We do not need to update the callee-save register mapping because above
 362     // us is either another interpreter frame or a converter-frame, but never
 363     // directly a compiled frame.
 364     // 11/24/04 SFG. With the removal of adapter frames this is no longer true.
 365     // However c2 no longer uses callee save register for java calls so there
 366     // are no callee register to find.
 367 
 368     if (map.getUpdateMap())
 369       updateMapWithSavedLink(map, addressOfStackSlot(LINK_OFFSET));
 370 
 371     return new X86Frame(sp, unextendedSP, getLink(), getSenderPC());
 372   }
 373 
 374   private void updateMapWithSavedLink(RegisterMap map, Address savedFPAddr) {
 375     map.setLocation(rbp, savedFPAddr);
 376   }
 377 
 378   private Frame senderForCompiledFrame(X86RegisterMap map, CodeBlob cb) {
 379     if (DEBUG) {
 380       System.out.println("senderForCompiledFrame");
 381     }
 382 
 383     //
 384     // NOTE: some of this code is (unfortunately) duplicated in X86CurrentFrameGuess
 385     //
 386 
 387     if (Assert.ASSERTS_ENABLED) {
 388       Assert.that(map != null, "map must be set");
 389     }
 390 
 391     // frame owned by optimizing compiler
 392     if (Assert.ASSERTS_ENABLED) {
 393         Assert.that(cb.getFrameSize() >= 0, "must have non-zero frame size");
 394     }
 395     Address senderSP = getUnextendedSP().addOffsetTo(cb.getFrameSize());
 396 
 397     // On Intel the return_address is always the word on the stack
 398     Address senderPC = senderSP.getAddressAt(-1 * VM.getVM().getAddressSize());
 399 
 400     // This is the saved value of EBP which may or may not really be an FP.
 401     // It is only an FP if the sender is an interpreter frame (or C1?).
 402     Address savedFPAddr = senderSP.addOffsetTo(- SENDER_SP_OFFSET * VM.getVM().getAddressSize());
 403 
 404     if (map.getUpdateMap()) {
 405       // Tell GC to use argument oopmaps for some runtime stubs that need it.
 406       // For C1, the runtime stub might not have oop maps, so set this flag
 407       // outside of update_register_map.
 408       map.setIncludeArgumentOops(cb.callerMustGCArguments());
 409 
 410       if (cb.getOopMaps() != null) {
 411         OopMapSet.updateRegisterMap(this, cb, map, true);
 412       }
 413 
 414       // Since the prolog does the save and restore of EBP there is no oopmap
 415       // for it so we must fill in its location as if there was an oopmap entry
 416       // since if our caller was compiled code there could be live jvm state in it.
 417       updateMapWithSavedLink(map, savedFPAddr);
 418     }
 419 
 420     return new X86Frame(senderSP, savedFPAddr.getAddressAt(0), senderPC);
 421   }
 422 
 423   protected boolean hasSenderPD() {
 424     // FIXME
 425     // Check for null ebp? Need to do some tests.
 426     return true;
 427   }
 428 
 429   public long frameSize() {
 430     return (getSenderSP().minus(getSP()) / VM.getVM().getAddressSize());
 431   }
 432 
 433   public Address getLink() {
 434     return addressOfStackSlot(LINK_OFFSET).getAddressAt(0);
 435   }
 436 
 437   // FIXME: not implementable yet
 438   //inline void      frame::set_link(intptr_t* addr)  { *(intptr_t **)addr_at(link_offset) = addr; }
 439 
 440   public Address getUnextendedSP() { return raw_unextendedSP; }
 441 
 442   // Return address:
 443   public Address getSenderPCAddr() { return addressOfStackSlot(RETURN_ADDR_OFFSET); }
 444   public Address getSenderPC()     { return getSenderPCAddr().getAddressAt(0);      }
 445 
 446   // return address of param, zero origin index.
 447   public Address getNativeParamAddr(int idx) {
 448     return addressOfStackSlot(NATIVE_FRAME_INITIAL_PARAM_OFFSET + idx);
 449   }
 450 
 451   public Address getSenderSP()     { return addressOfStackSlot(SENDER_SP_OFFSET); }
 452 
 453   public Address addressOfInterpreterFrameLocals() {
 454     return addressOfStackSlot(INTERPRETER_FRAME_LOCALS_OFFSET);
 455   }
 456 
 457   private Address addressOfInterpreterFrameBCX() {
 458     return addressOfStackSlot(INTERPRETER_FRAME_BCX_OFFSET);
 459   }
 460 
 461   public int getInterpreterFrameBCI() {
 462     // FIXME: this is not atomic with respect to GC and is unsuitable
 463     // for use in a non-debugging, or reflective, system. Need to
 464     // figure out how to express this.
 465     Address bcp = addressOfInterpreterFrameBCX().getAddressAt(0);
 466     OopHandle methodHandle = addressOfInterpreterFrameMethod().getOopHandleAt(0);
 467     Method method = (Method) VM.getVM().getObjectHeap().newOop(methodHandle);
 468     return bcpToBci(bcp, method);
 469   }
 470 
 471   public Address addressOfInterpreterFrameMDX() {
 472     return addressOfStackSlot(INTERPRETER_FRAME_MDX_OFFSET);
 473   }
 474 
 475   // FIXME
 476   //inline int frame::interpreter_frame_monitor_size() {
 477   //  return BasicObjectLock::size();
 478   //}
 479 
 480   // expression stack
 481   // (the max_stack arguments are used by the GC; see class FrameClosure)
 482 
 483   public Address addressOfInterpreterFrameExpressionStack() {
 484     Address monitorEnd = interpreterFrameMonitorEnd().address();
 485     return monitorEnd.addOffsetTo(-1 * VM.getVM().getAddressSize());
 486   }
 487 
 488   public int getInterpreterFrameExpressionStackDirection() { return -1; }
 489 
 490   // top of expression stack
 491   public Address addressOfInterpreterFrameTOS() {
 492     return getSP();
 493   }
 494 
 495   /** Expression stack from top down */
 496   public Address addressOfInterpreterFrameTOSAt(int slot) {
 497     return addressOfInterpreterFrameTOS().addOffsetTo(slot * VM.getVM().getAddressSize());
 498   }
 499 
 500   public Address getInterpreterFrameSenderSP() {
 501     if (Assert.ASSERTS_ENABLED) {
 502       Assert.that(isInterpretedFrame(), "interpreted frame expected");
 503     }
 504     return addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0);
 505   }
 506 
 507   // Monitors
 508   public BasicObjectLock interpreterFrameMonitorBegin() {
 509     return new BasicObjectLock(addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET));
 510   }
 511 
 512   public BasicObjectLock interpreterFrameMonitorEnd() {
 513     Address result = addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET).getAddressAt(0);
 514     if (Assert.ASSERTS_ENABLED) {
 515       // make sure the pointer points inside the frame
 516       Assert.that(AddressOps.gt(getFP(), result), "result must <  than frame pointer");
 517       Assert.that(AddressOps.lte(getSP(), result), "result must >= than stack pointer");
 518     }
 519     return new BasicObjectLock(result);
 520   }
 521 
 522   public int interpreterFrameMonitorSize() {
 523     return BasicObjectLock.size();
 524   }
 525 
 526   // Method
 527   public Address addressOfInterpreterFrameMethod() {
 528     return addressOfStackSlot(INTERPRETER_FRAME_METHOD_OFFSET);
 529   }
 530 
 531   // Constant pool cache
 532   public Address addressOfInterpreterFrameCPCache() {
 533     return addressOfStackSlot(INTERPRETER_FRAME_CACHE_OFFSET);
 534   }
 535 
 536   // Entry frames
 537   public JavaCallWrapper getEntryFrameCallWrapper() {
 538     return new X86JavaCallWrapper(addressOfStackSlot(ENTRY_FRAME_CALL_WRAPPER_OFFSET).getAddressAt(0));
 539   }
 540 
 541   protected Address addressOfSavedOopResult() {
 542     // offset is 2 for compiler2 and 3 for compiler1
 543     return getSP().addOffsetTo((VM.getVM().isClientCompiler() ? 2 : 3) *
 544                                VM.getVM().getAddressSize());
 545   }
 546 
 547   protected Address addressOfSavedReceiver() {
 548     return getSP().addOffsetTo(-4 * VM.getVM().getAddressSize());
 549   }
 550 
 551   private void dumpStack() {
 552     if (getFP() != null) {
 553       for (Address addr = getSP().addOffsetTo(-5 * VM.getVM().getAddressSize());
 554            AddressOps.lte(addr, getFP().addOffsetTo(5 * VM.getVM().getAddressSize()));
 555            addr = addr.addOffsetTo(VM.getVM().getAddressSize())) {
 556         System.out.println(addr + ": " + addr.getAddressAt(0));
 557       }
 558     } else {
 559       for (Address addr = getSP().addOffsetTo(-5 * VM.getVM().getAddressSize());
 560            AddressOps.lte(addr, getSP().addOffsetTo(20 * VM.getVM().getAddressSize()));
 561            addr = addr.addOffsetTo(VM.getVM().getAddressSize())) {
 562         System.out.println(addr + ": " + addr.getAddressAt(0));
 563       }
 564     }
 565   }
 566 }