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