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