1 /*
   2  * Copyright (c) 2000, 2013, 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.code;
  26 
  27 import java.io.*;
  28 import java.util.*;
  29 import sun.jvm.hotspot.debugger.*;
  30 import sun.jvm.hotspot.memory.*;
  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 public class NMethod extends CodeBlob {
  37   private static long          pcDescSize;
  38   private static AddressField  methodField;
  39   /** != InvocationEntryBci if this nmethod is an on-stack replacement method */
  40   private static CIntegerField entryBCIField;
  41   /** To support simple linked-list chaining of nmethods */
  42   private static AddressField  osrLinkField;
  43   private static AddressField  scavengeRootLinkField;
  44   private static JByteField    scavengeRootStateField;
  45 
  46   /** Offsets for different nmethod parts */
  47   private static CIntegerField exceptionOffsetField;
  48   private static CIntegerField deoptOffsetField;
  49   private static CIntegerField deoptMhOffsetField;
  50   private static CIntegerField origPCOffsetField;
  51   private static CIntegerField stubOffsetField;
  52   private static CIntegerField oopsOffsetField;
  53   private static CIntegerField metadataOffsetField;
  54   private static CIntegerField scopesDataOffsetField;
  55   private static CIntegerField scopesPCsOffsetField;
  56   private static CIntegerField dependenciesOffsetField;
  57   private static CIntegerField handlerTableOffsetField;
  58   private static CIntegerField nulChkTableOffsetField;
  59   private static CIntegerField nmethodEndOffsetField;
  60 
  61   /** Offsets for entry points */
  62   /** Entry point with class check */
  63   private static AddressField  entryPointField;
  64   /** Entry point without class check */
  65   private static AddressField  verifiedEntryPointField;
  66   /** Entry point for on stack replacement */
  67   private static AddressField  osrEntryPointField;
  68 
  69   // FIXME: add access to flags (how?)
  70 
  71   /** NMethod Flushing lock (if non-zero, then the nmethod is not removed) */
  72   private static JIntField     lockCountField;
  73 
  74   /** not_entrant method removal. Each mark_sweep pass will update
  75       this mark to current sweep invocation count if it is seen on the
  76       stack.  An not_entrant method can be removed when there is no
  77       more activations, i.e., when the _stack_traversal_mark is less than
  78       current sweep traversal index. */
  79   private static CIntegerField stackTraversalMarkField;
  80 
  81   private static CIntegerField compLevelField;
  82 
  83   static {
  84     VM.registerVMInitializedObserver(new Observer() {
  85         public void update(Observable o, Object data) {
  86           initialize(VM.getVM().getTypeDataBase());
  87         }
  88       });
  89   }
  90 
  91   private static void initialize(TypeDataBase db) {
  92     Type type = db.lookupType("nmethod");
  93 
  94     methodField                 = type.getAddressField("_method");
  95     entryBCIField               = type.getCIntegerField("_entry_bci");
  96     osrLinkField                = type.getAddressField("_osr_link");
  97     scavengeRootLinkField       = type.getAddressField("_scavenge_root_link");
  98     scavengeRootStateField      = type.getJByteField("_scavenge_root_state");
  99 
 100     exceptionOffsetField        = type.getCIntegerField("_exception_offset");
 101     deoptOffsetField            = type.getCIntegerField("_deoptimize_offset");
 102     deoptMhOffsetField          = type.getCIntegerField("_deoptimize_mh_offset");
 103     origPCOffsetField           = type.getCIntegerField("_orig_pc_offset");
 104     stubOffsetField             = type.getCIntegerField("_stub_offset");
 105     oopsOffsetField             = type.getCIntegerField("_oops_offset");
 106     metadataOffsetField         = type.getCIntegerField("_metadata_offset");
 107     scopesDataOffsetField       = type.getCIntegerField("_scopes_data_offset");
 108     scopesPCsOffsetField        = type.getCIntegerField("_scopes_pcs_offset");
 109     dependenciesOffsetField     = type.getCIntegerField("_dependencies_offset");
 110     handlerTableOffsetField     = type.getCIntegerField("_handler_table_offset");
 111     nulChkTableOffsetField      = type.getCIntegerField("_nul_chk_table_offset");
 112     nmethodEndOffsetField       = type.getCIntegerField("_nmethod_end_offset");
 113     entryPointField             = type.getAddressField("_entry_point");
 114     verifiedEntryPointField     = type.getAddressField("_verified_entry_point");
 115     osrEntryPointField          = type.getAddressField("_osr_entry_point");
 116     lockCountField              = type.getJIntField("_lock_count");
 117     stackTraversalMarkField     = type.getCIntegerField("_stack_traversal_mark");
 118     compLevelField              = type.getCIntegerField("_comp_level");
 119     pcDescSize = db.lookupType("PcDesc").getSize();
 120   }
 121 
 122   public NMethod(Address addr) {
 123     super(addr);
 124   }
 125 
 126 
 127   // Accessors
 128   public Address getAddress() {
 129     return addr;
 130   }
 131 
 132   public Method getMethod() {
 133     return (Method)Metadata.instantiateWrapperFor(methodField.getValue(addr));
 134   }
 135 
 136   // Type info
 137   public boolean isNMethod()      { return true;                    }
 138   public boolean isJavaMethod()   { return !getMethod().isNative(); }
 139   public boolean isNativeMethod() { return getMethod().isNative();  }
 140   public boolean isOSRMethod()    { return getEntryBCI() != VM.getVM().getInvocationEntryBCI(); }
 141 
 142   /** Boundaries for different parts */
 143   public Address constantsBegin()       { return contentBegin();                                     }
 144   public Address constantsEnd()         { return getEntryPoint();                                    }
 145   public Address instsBegin()           { return codeBegin();                                        }
 146   public Address instsEnd()             { return headerBegin().addOffsetTo(getStubOffset());         }
 147   public Address exceptionBegin()       { return headerBegin().addOffsetTo(getExceptionOffset());    }
 148   public Address deoptHandlerBegin()    { return headerBegin().addOffsetTo(getDeoptOffset());        }
 149   public Address deoptMhHandlerBegin()  { return headerBegin().addOffsetTo(getDeoptMhOffset());      }
 150   public Address stubBegin()            { return headerBegin().addOffsetTo(getStubOffset());         }
 151   public Address stubEnd()              { return headerBegin().addOffsetTo(getOopsOffset());         }
 152   public Address oopsBegin()            { return headerBegin().addOffsetTo(getOopsOffset());         }
 153   public Address oopsEnd()              { return headerBegin().addOffsetTo(getMetadataOffset());     }
 154   public Address metadataBegin()        { return headerBegin().addOffsetTo(getMetadataOffset());     }
 155   public Address metadataEnd()          { return headerBegin().addOffsetTo(getScopesDataOffset());   }
 156   public Address scopesDataBegin()      { return headerBegin().addOffsetTo(getScopesDataOffset());   }
 157   public Address scopesDataEnd()        { return headerBegin().addOffsetTo(getScopesPCsOffset());    }
 158   public Address scopesPCsBegin()       { return headerBegin().addOffsetTo(getScopesPCsOffset());    }
 159   public Address scopesPCsEnd()         { return headerBegin().addOffsetTo(getDependenciesOffset()); }
 160   public Address dependenciesBegin()    { return headerBegin().addOffsetTo(getDependenciesOffset()); }
 161   public Address dependenciesEnd()      { return headerBegin().addOffsetTo(getHandlerTableOffset()); }
 162   public Address handlerTableBegin()    { return headerBegin().addOffsetTo(getHandlerTableOffset()); }
 163   public Address handlerTableEnd()      { return headerBegin().addOffsetTo(getNulChkTableOffset());  }
 164   public Address nulChkTableBegin()     { return headerBegin().addOffsetTo(getNulChkTableOffset());  }
 165   public Address nulChkTableEnd()       { return headerBegin().addOffsetTo(getNMethodEndOffset());   }
 166 
 167   public int constantsSize()            { return (int) constantsEnd()   .minus(constantsBegin());    }
 168   public int instsSize()                { return (int) instsEnd()       .minus(instsBegin());        }
 169   public int stubSize()                 { return (int) stubEnd()        .minus(stubBegin());         }
 170   public int oopsSize()                 { return (int) oopsEnd()        .minus(oopsBegin());         }
 171   public int metadataSize()             { return (int) metadataEnd()    .minus(metadataBegin());     }
 172   public int scopesDataSize()           { return (int) scopesDataEnd()  .minus(scopesDataBegin());   }
 173   public int scopesPCsSize()            { return (int) scopesPCsEnd()   .minus(scopesPCsBegin());    }
 174   public int dependenciesSize()         { return (int) dependenciesEnd().minus(dependenciesBegin()); }
 175   public int handlerTableSize()         { return (int) handlerTableEnd().minus(handlerTableBegin()); }
 176   public int nulChkTableSize()          { return (int) nulChkTableEnd() .minus(nulChkTableBegin());  }
 177   public int origPCOffset()             { return (int) origPCOffsetField.getValue(addr);             }
 178 
 179   public int totalSize() {
 180     return
 181       constantsSize()    +
 182       instsSize()        +
 183       stubSize()         +
 184       scopesDataSize()   +
 185       scopesPCsSize()    +
 186       dependenciesSize() +
 187       handlerTableSize() +
 188       nulChkTableSize();
 189   }
 190 
 191   public boolean constantsContains   (Address addr) { return constantsBegin()   .lessThanOrEqual(addr) && constantsEnd()   .greaterThan(addr); }
 192   public boolean instsContains       (Address addr) { return instsBegin()       .lessThanOrEqual(addr) && instsEnd()       .greaterThan(addr); }
 193   public boolean stubContains        (Address addr) { return stubBegin()        .lessThanOrEqual(addr) && stubEnd()        .greaterThan(addr); }
 194   public boolean oopsContains        (Address addr) { return oopsBegin()        .lessThanOrEqual(addr) && oopsEnd()        .greaterThan(addr); }
 195   public boolean metadataContains    (Address addr) { return metadataBegin()    .lessThanOrEqual(addr) && metadataEnd()    .greaterThan(addr); }
 196   public boolean scopesDataContains  (Address addr) { return scopesDataBegin()  .lessThanOrEqual(addr) && scopesDataEnd()  .greaterThan(addr); }
 197   public boolean scopesPCsContains   (Address addr) { return scopesPCsBegin()   .lessThanOrEqual(addr) && scopesPCsEnd()   .greaterThan(addr); }
 198   public boolean handlerTableContains(Address addr) { return handlerTableBegin().lessThanOrEqual(addr) && handlerTableEnd().greaterThan(addr); }
 199   public boolean nulChkTableContains (Address addr) { return nulChkTableBegin() .lessThanOrEqual(addr) && nulChkTableEnd() .greaterThan(addr); }
 200 
 201   public int getOopsLength() { return (int) (oopsSize() / VM.getVM().getOopSize()); }
 202   public int getMetadataLength() { return (int) (metadataSize() / VM.getVM().getOopSize()); }
 203 
 204   /** Entry points */
 205   public Address getEntryPoint()         { return entryPointField.getValue(addr);         }
 206   public Address getVerifiedEntryPoint() { return verifiedEntryPointField.getValue(addr); }
 207 
 208   /** Support for oops in scopes and relocs. Note: index 0 is reserved for null. */
 209   public OopHandle getOopAt(int index) {
 210     if (index == 0) return null;
 211     if (Assert.ASSERTS_ENABLED) {
 212       Assert.that(index > 0 && index <= getOopsLength(), "must be a valid non-zero index");
 213     }
 214     return oopsBegin().getOopHandleAt((index - 1) * VM.getVM().getOopSize());
 215   }
 216 
 217   /** Support for metadata in scopes and relocs. Note: index 0 is reserved for null. */
 218   public Address getMetadataAt(int index) {
 219     if (index == 0) return null;
 220     if (Assert.ASSERTS_ENABLED) {
 221       Assert.that(index > 0 && index <= getMetadataLength(), "must be a valid non-zero index");
 222     }
 223     return metadataBegin().getAddressAt((index - 1) * VM.getVM().getOopSize());
 224   }
 225 
 226   public Method getMethodAt(int index) {
 227     return (Method)Metadata.instantiateWrapperFor(getMetadataAt(index));
 228   }
 229 
 230   // FIXME: add interpreter_entry_point()
 231   // FIXME: add lazy_interpreter_entry_point() for C2
 232 
 233   // **********
 234   // * FIXME: * ADD ACCESS TO FLAGS!!!!
 235   // **********
 236   // public boolean isInUse();
 237   // public boolean isAlive();
 238   // public boolean isNotEntrant();
 239   // public boolean isZombie();
 240 
 241   // ********************************
 242   // * MAJOR FIXME: MAJOR HACK HERE *
 243   // ********************************
 244   public boolean isZombie() { return false; }
 245 
 246   // public boolean isUnloaded();
 247   // public boolean isYoung();
 248   // public boolean isOld();
 249   // public int     age();
 250   // public boolean isMarkedForDeoptimization();
 251   // public boolean isMarkedForUnloading();
 252   // public int     level();
 253   // public int     version();
 254 
 255   // FIXME: add mutators for above
 256   // FIXME: add exception cache access?
 257 
 258   /** On-stack replacement support */
 259   // FIXME: add mutators
 260   public int getOSREntryBCI() {
 261     if (Assert.ASSERTS_ENABLED) {
 262       Assert.that(getEntryBCI() != VM.getVM().getInvocationEntryBCI(), "wrong kind of nmethod");
 263     }
 264     return getEntryBCI();
 265   }
 266 
 267   public NMethod getOSRLink() {
 268     return (NMethod) VMObjectFactory.newObject(NMethod.class, osrLinkField.getValue(addr));
 269   }
 270 
 271   public NMethod getScavengeRootLink() {
 272     return (NMethod) VMObjectFactory.newObject(NMethod.class, scavengeRootLinkField.getValue(addr));
 273   }
 274 
 275   public int getScavengeRootState() {
 276     return (int) scavengeRootStateField.getValue(addr);
 277   }
 278 
 279   // MethodHandle
 280   public boolean isMethodHandleReturn(Address returnPc) {
 281     // Hard to read a bit fields from Java and it's only there for performance
 282     // so just go directly to the PCDesc
 283     // if (!hasMethodHandleInvokes())  return false;
 284     PCDesc pd = getPCDescAt(returnPc);
 285     if (pd == null)
 286       return false;
 287     return pd.isMethodHandleInvoke();
 288   }
 289 
 290   // Deopt
 291   // Return true is the PC is one would expect if the frame is being deopted.
 292   public boolean isDeoptPc      (Address pc) { return isDeoptEntry(pc) || isDeoptMhEntry(pc); }
 293   public boolean isDeoptEntry   (Address pc) { return pc == deoptHandlerBegin(); }
 294   public boolean isDeoptMhEntry (Address pc) { return pc == deoptMhHandlerBegin(); }
 295 
 296   /** Tells whether frames described by this nmethod can be
 297       deoptimized. Note: native wrappers cannot be deoptimized. */
 298   public boolean canBeDeoptimized() { return isJavaMethod(); }
 299 
 300   // FIXME: add inline cache support
 301   // FIXME: add flush()
 302 
 303   public boolean isLockedByVM() { return lockCountField.getValue(addr) > 0; }
 304 
 305   // FIXME: add mark_as_seen_on_stack
 306   // FIXME: add can_not_entrant_be_converted
 307 
 308   // FIXME: add GC support
 309   //  void follow_roots_or_mark_for_unloading(bool unloading_occurred, bool& marked_for_unloading);
 310   //  void follow_root_or_mark_for_unloading(oop* root, bool unloading_occurred, bool& marked_for_unloading);
 311   //  void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, void f(oop*));
 312   //  void adjust_pointers();
 313 
 314   /** Finds a PCDesc with real-pc equal to "pc" */
 315   public PCDesc getPCDescAt(Address pc) {
 316     // FIXME: consider adding cache like the one down in the VM
 317     for (Address p = scopesPCsBegin(); p.lessThan(scopesPCsEnd()); p = p.addOffsetTo(pcDescSize)) {
 318       PCDesc pcDesc = new PCDesc(p);
 319       if (pcDesc.getRealPC(this).equals(pc)) {
 320         return pcDesc;
 321       }
 322     }
 323     return null;
 324   }
 325 
 326   /** ScopeDesc for an instruction */
 327   public ScopeDesc getScopeDescAt(Address pc) {
 328     PCDesc pd = getPCDescAt(pc);
 329     if (Assert.ASSERTS_ENABLED) {
 330       Assert.that(pd != null, "scope must be present");
 331     }
 332     return new ScopeDesc(this, pd.getScopeDecodeOffset(), pd.getObjDecodeOffset(), pd.getReexecute());
 333   }
 334 
 335   /** This is only for use by the debugging system, and is only
 336       intended for use in the topmost frame, where we are not
 337       guaranteed to be at a PC for which we have a PCDesc. It finds
 338       the PCDesc with realPC closest to the current PC. */
 339   public PCDesc getPCDescNearDbg(Address pc) {
 340     PCDesc bestGuessPCDesc = null;
 341     long bestDistance = 0;
 342     for (Address p = scopesPCsBegin(); p.lessThan(scopesPCsEnd()); p = p.addOffsetTo(pcDescSize)) {
 343       PCDesc pcDesc = new PCDesc(p);
 344       // In case pc is null
 345       long distance = -pcDesc.getRealPC(this).minus(pc);
 346       if ((bestGuessPCDesc == null) ||
 347           ((distance >= 0) && (distance < bestDistance))) {
 348         bestGuessPCDesc = pcDesc;
 349         bestDistance    = distance;
 350       }
 351     }
 352     return bestGuessPCDesc;
 353   }
 354 
 355   PCDesc find_pc_desc(long pc, boolean approximate) {
 356     return find_pc_desc_internal(pc, approximate);
 357   }
 358 
 359   // Finds a PcDesc with real-pc equal to "pc"
 360   PCDesc find_pc_desc_internal(long pc, boolean approximate) {
 361     long base_address = VM.getAddressValue(codeBegin());
 362     int pc_offset = (int) (pc - base_address);
 363 
 364     // Fallback algorithm: quasi-linear search for the PcDesc
 365     // Find the last pc_offset less than the given offset.
 366     // The successor must be the required match, if there is a match at all.
 367     // (Use a fixed radix to avoid expensive affine pointer arithmetic.)
 368     Address lower = scopesPCsBegin();
 369     Address upper = scopesPCsEnd();
 370     upper = upper.addOffsetTo(-pcDescSize); // exclude final sentinel
 371     if (lower.greaterThan(upper))  return null;  // native method; no PcDescs at all
 372 
 373     // Take giant steps at first (4096, then 256, then 16, then 1)
 374     int LOG2_RADIX = 4;
 375     int RADIX = (1 << LOG2_RADIX);
 376     Address mid;
 377     for (int step = (1 << (LOG2_RADIX*3)); step > 1; step >>= LOG2_RADIX) {
 378       while ((mid = lower.addOffsetTo(step * pcDescSize)).lessThan(upper)) {
 379         PCDesc m = new PCDesc(mid);
 380         if (m.getPCOffset() < pc_offset) {
 381           lower = mid;
 382         } else {
 383           upper = mid;
 384           break;
 385         }
 386       }
 387     }
 388     // Sneak up on the value with a linear search of length ~16.
 389     while (true) {
 390       mid = lower.addOffsetTo(pcDescSize);
 391       PCDesc m = new PCDesc(mid);
 392       if (m.getPCOffset() < pc_offset) {
 393         lower = mid;
 394       } else {
 395         upper = mid;
 396         break;
 397       }
 398     }
 399 
 400     PCDesc u = new PCDesc(upper);
 401     if (match_desc(u, pc_offset, approximate)) {
 402       return u;
 403     } else {
 404       return null;
 405     }
 406   }
 407 
 408   // ScopeDesc retrieval operation
 409   PCDesc pc_desc_at(long pc)   { return find_pc_desc(pc, false); }
 410   // pc_desc_near returns the first PCDesc at or after the givne pc.
 411   PCDesc pc_desc_near(long pc) { return find_pc_desc(pc, true); }
 412 
 413   // Return a the last scope in (begin..end]
 414   public ScopeDesc scope_desc_in(long begin, long end) {
 415     PCDesc p = pc_desc_near(begin+1);
 416     if (p != null && VM.getAddressValue(p.getRealPC(this)) <= end) {
 417       return new ScopeDesc(this, p.getScopeDecodeOffset(), p.getObjDecodeOffset(), p.getReexecute());
 418     }
 419     return null;
 420   }
 421 
 422   static boolean match_desc(PCDesc pc, int pc_offset, boolean approximate) {
 423     if (!approximate) {
 424       return pc.getPCOffset() == pc_offset;
 425     } else {
 426       PCDesc prev = new PCDesc(pc.getAddress().addOffsetTo(-pcDescSize));
 427        return prev.getPCOffset() < pc_offset && pc_offset <= pc.getPCOffset();
 428     }
 429   }
 430 
 431   /** This is only for use by the debugging system, and is only
 432       intended for use in the topmost frame, where we are not
 433       guaranteed to be at a PC for which we have a PCDesc. It finds
 434       the ScopeDesc closest to the current PC. NOTE that this may
 435       return NULL for compiled methods which don't have any
 436       ScopeDescs! */
 437   public ScopeDesc getScopeDescNearDbg(Address pc) {
 438     PCDesc pd = getPCDescNearDbg(pc);
 439     if (pd == null) return null;
 440     return new ScopeDesc(this, pd.getScopeDecodeOffset(), pd.getObjDecodeOffset(), pd.getReexecute());
 441   }
 442 
 443   public Map/*<Address, PCDesc>*/ getSafepoints() {
 444     Map safepoints = new HashMap(); // Map<Address, PCDesc>
 445     sun.jvm.hotspot.debugger.Address p = null;
 446     for (p = scopesPCsBegin(); p.lessThan(scopesPCsEnd());
 447          p = p.addOffsetTo(pcDescSize)) {
 448        PCDesc pcDesc = new PCDesc(p);
 449        sun.jvm.hotspot.debugger.Address pc = pcDesc.getRealPC(this);
 450        safepoints.put(pc, pcDesc);
 451     }
 452     return safepoints;
 453   }
 454 
 455   // FIXME: add getPCOffsetForBCI()
 456   // FIXME: add embeddedOopAt()
 457   // FIXME: add isDependentOn()
 458   // FIXME: add isPatchableAt()
 459 
 460   /** Support for code generation. Only here for proof-of-concept. */
 461   public static int getEntryPointOffset()            { return (int) entryPointField.getOffset();            }
 462   public static int getVerifiedEntryPointOffset()    { return (int) verifiedEntryPointField.getOffset();    }
 463   public static int getOSREntryPointOffset()         { return (int) osrEntryPointField.getOffset();         }
 464   public static int getEntryBCIOffset()              { return (int) entryBCIField.getOffset();              }
 465   /** NOTE: renamed from "method_offset_in_bytes" */
 466   public static int getMethodOffset()                { return (int) methodField.getOffset();                }
 467 
 468   public void print() {
 469     printOn(System.out);
 470   }
 471 
 472   protected void printComponentsOn(PrintStream tty) {
 473     // FIXME: add relocation information
 474     tty.println(" content: [" + contentBegin() + ", " + contentEnd() + "), " +
 475                 " code: [" + codeBegin() + ", " + codeEnd() + "), " +
 476                 " data: [" + dataBegin() + ", " + dataEnd() + "), " +
 477                 " oops: [" + oopsBegin() + ", " + oopsEnd() + "), " +
 478                 " frame size: " + getFrameSize());
 479   }
 480 
 481   public String toString() {
 482     Method method = getMethod();
 483     return "NMethod for " +
 484             method.getMethodHolder().getName().asString() + "." +
 485             method.getName().asString() + method.getSignature().asString() + "==>n" +
 486             super.toString();
 487   }
 488 
 489   public String flagsToString() {
 490     // FIXME need access to flags...
 491     return "";
 492   }
 493 
 494   public String getName() {
 495     Method method = getMethod();
 496     return "NMethod for " +
 497            method.getMethodHolder().getName().asString() + "." +
 498            method.getName().asString() +
 499            method.getSignature().asString();
 500   }
 501 
 502   public void dumpReplayData(PrintStream out) {
 503     HashMap h = new HashMap();
 504     for (int i = 1; i < getMetadataLength(); i++) {
 505       Metadata meta = Metadata.instantiateWrapperFor(getMetadataAt(i));
 506       System.err.println(meta);
 507       if (h.get(meta) != null) continue;
 508       h.put(meta, meta);
 509       if (meta instanceof InstanceKlass) {
 510         ((InstanceKlass)meta).dumpReplayData(out);
 511       } else if (meta instanceof Method) {
 512         ((Method)meta).dumpReplayData(out);
 513         MethodData mdo = ((Method)meta).getMethodData();
 514         if (mdo != null) {
 515           mdo.dumpReplayData(out);
 516         }
 517       }
 518     }
 519     Method method = getMethod();
 520     if (h.get(method) == null) {
 521       method.dumpReplayData(out);
 522       MethodData mdo = method.getMethodData();
 523       if (mdo != null) {
 524         mdo.dumpReplayData(out);
 525       }
 526     }
 527     if (h.get(method.getMethodHolder()) == null) {
 528       ((InstanceKlass)method.getMethodHolder()).dumpReplayData(out);
 529     }
 530     Klass holder = method.getMethodHolder();
 531     out.println("compile " + holder.getName().asString() + " " +
 532                 OopUtilities.escapeString(method.getName().asString()) + " " +
 533                 method.getSignature().asString() + " " +
 534                 getEntryBCI() + " " + getCompLevel());
 535 
 536   }
 537 
 538   //--------------------------------------------------------------------------------
 539   // Internals only below this point
 540   //
 541 
 542   private int getEntryBCI()           { return (int) entryBCIField          .getValue(addr); }
 543   private int getExceptionOffset()    { return (int) exceptionOffsetField   .getValue(addr); }
 544   private int getDeoptOffset()        { return (int) deoptOffsetField       .getValue(addr); }
 545   private int getDeoptMhOffset()      { return (int) deoptMhOffsetField     .getValue(addr); }
 546   private int getStubOffset()         { return (int) stubOffsetField        .getValue(addr); }
 547   private int getOopsOffset()         { return (int) oopsOffsetField        .getValue(addr); }
 548   private int getMetadataOffset()     { return (int) metadataOffsetField    .getValue(addr); }
 549   private int getScopesDataOffset()   { return (int) scopesDataOffsetField  .getValue(addr); }
 550   private int getScopesPCsOffset()    { return (int) scopesPCsOffsetField   .getValue(addr); }
 551   private int getDependenciesOffset() { return (int) dependenciesOffsetField.getValue(addr); }
 552   private int getHandlerTableOffset() { return (int) handlerTableOffsetField.getValue(addr); }
 553   private int getNulChkTableOffset()  { return (int) nulChkTableOffsetField .getValue(addr); }
 554   private int getNMethodEndOffset()   { return (int) nmethodEndOffsetField  .getValue(addr); }
 555   private int getCompLevel()          { return (int) compLevelField         .getValue(addr); }
 556 }