1 /* 2 * Copyright (c) 2000, 2010, 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 sun.jvm.hotspot.types.OopField 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 scopesDataOffsetField; 54 private static CIntegerField scopesPCsOffsetField; 55 private static CIntegerField dependenciesOffsetField; 56 private static CIntegerField handlerTableOffsetField; 57 private static CIntegerField nulChkTableOffsetField; 58 private static CIntegerField nmethodEndOffsetField; 59 60 /** Offsets for entry points */ 61 /** Entry point with class check */ 62 private static AddressField entryPointField; 63 /** Entry point without class check */ 64 private static AddressField verifiedEntryPointField; 65 /** Entry point for on stack replacement */ 66 private static AddressField osrEntryPointField; 67 68 // FIXME: add access to flags (how?) 69 70 /** NMethod Flushing lock (if non-zero, then the nmethod is not removed) */ 71 private static JIntField lockCountField; 72 73 /** not_entrant method removal. Each mark_sweep pass will update 74 this mark to current sweep invocation count if it is seen on the 75 stack. An not_entrant method can be removed when there is no 76 more activations, i.e., when the _stack_traversal_mark is less than 77 current sweep traversal index. */ 78 private static CIntegerField stackTraversalMarkField; 79 80 static { 81 VM.registerVMInitializedObserver(new Observer() { 82 public void update(Observable o, Object data) { 83 initialize(VM.getVM().getTypeDataBase()); 84 } 85 }); 86 } 87 88 private static void initialize(TypeDataBase db) { 89 Type type = db.lookupType("nmethod"); 90 91 methodField = type.getOopField("_method"); 92 entryBCIField = type.getCIntegerField("_entry_bci"); 93 osrLinkField = type.getAddressField("_osr_link"); 94 scavengeRootLinkField = type.getAddressField("_scavenge_root_link"); 95 scavengeRootStateField = type.getJByteField("_scavenge_root_state"); 96 97 exceptionOffsetField = type.getCIntegerField("_exception_offset"); 98 deoptOffsetField = type.getCIntegerField("_deoptimize_offset"); 99 deoptMhOffsetField = type.getCIntegerField("_deoptimize_mh_offset"); 100 origPCOffsetField = type.getCIntegerField("_orig_pc_offset"); 101 stubOffsetField = type.getCIntegerField("_stub_offset"); 102 oopsOffsetField = type.getCIntegerField("_oops_offset"); 103 scopesDataOffsetField = type.getCIntegerField("_scopes_data_offset"); 104 scopesPCsOffsetField = type.getCIntegerField("_scopes_pcs_offset"); 105 dependenciesOffsetField = type.getCIntegerField("_dependencies_offset"); 106 handlerTableOffsetField = type.getCIntegerField("_handler_table_offset"); 107 nulChkTableOffsetField = type.getCIntegerField("_nul_chk_table_offset"); 108 nmethodEndOffsetField = type.getCIntegerField("_nmethod_end_offset"); 109 entryPointField = type.getAddressField("_entry_point"); 110 verifiedEntryPointField = type.getAddressField("_verified_entry_point"); 111 osrEntryPointField = type.getAddressField("_osr_entry_point"); 112 lockCountField = type.getJIntField("_lock_count"); 113 stackTraversalMarkField = type.getCIntegerField("_stack_traversal_mark"); 114 115 pcDescSize = db.lookupType("PcDesc").getSize(); 116 } 117 118 public NMethod(Address addr) { 119 super(addr); 120 } 121 122 123 // Accessors 124 public Address getAddress() { 125 return addr; 126 } 127 128 public Method getMethod() { 129 return (Method) VM.getVM().getObjectHeap().newOop(methodField.getValue(addr)); 130 } 131 132 // Type info 133 public boolean isNMethod() { return true; } 134 public boolean isJavaMethod() { return !getMethod().isNative(); } 135 public boolean isNativeMethod() { return getMethod().isNative(); } 136 public boolean isOSRMethod() { return getEntryBCI() != VM.getVM().getInvocationEntryBCI(); } 137 138 /** Boundaries for different parts */ 139 public Address constantsBegin() { return contentBegin(); } 140 public Address constantsEnd() { return getEntryPoint(); } 141 public Address instsBegin() { return codeBegin(); } 142 public Address instsEnd() { return headerBegin().addOffsetTo(getStubOffset()); } 143 public Address exceptionBegin() { return headerBegin().addOffsetTo(getExceptionOffset()); } 144 public Address deoptHandlerBegin() { return headerBegin().addOffsetTo(getDeoptOffset()); } 145 public Address deoptMhHandlerBegin() { return headerBegin().addOffsetTo(getDeoptMhOffset()); } 146 public Address stubBegin() { return headerBegin().addOffsetTo(getStubOffset()); } 147 public Address stubEnd() { return headerBegin().addOffsetTo(getOopsOffset()); } 148 public Address oopsBegin() { return headerBegin().addOffsetTo(getOopsOffset()); } 149 public Address oopsEnd() { return headerBegin().addOffsetTo(getScopesDataOffset()); } 150 public Address scopesDataBegin() { return headerBegin().addOffsetTo(getScopesDataOffset()); } 151 public Address scopesDataEnd() { return headerBegin().addOffsetTo(getScopesPCsOffset()); } 152 public Address scopesPCsBegin() { return headerBegin().addOffsetTo(getScopesPCsOffset()); } 153 public Address scopesPCsEnd() { return headerBegin().addOffsetTo(getDependenciesOffset()); } 154 public Address dependenciesBegin() { return headerBegin().addOffsetTo(getDependenciesOffset()); } 155 public Address dependenciesEnd() { return headerBegin().addOffsetTo(getHandlerTableOffset()); } 156 public Address handlerTableBegin() { return headerBegin().addOffsetTo(getHandlerTableOffset()); } 157 public Address handlerTableEnd() { return headerBegin().addOffsetTo(getNulChkTableOffset()); } 158 public Address nulChkTableBegin() { return headerBegin().addOffsetTo(getNulChkTableOffset()); } 159 public Address nulChkTableEnd() { return headerBegin().addOffsetTo(getNMethodEndOffset()); } 160 161 public int constantsSize() { return (int) constantsEnd() .minus(constantsBegin()); } 162 public int instsSize() { return (int) instsEnd() .minus(instsBegin()); } 163 public int stubSize() { return (int) stubEnd() .minus(stubBegin()); } 164 public int oopsSize() { return (int) oopsEnd() .minus(oopsBegin()); } 165 public int scopesDataSize() { return (int) scopesDataEnd() .minus(scopesDataBegin()); } 166 public int scopesPCsSize() { return (int) scopesPCsEnd() .minus(scopesPCsBegin()); } 167 public int dependenciesSize() { return (int) dependenciesEnd().minus(dependenciesBegin()); } 168 public int handlerTableSize() { return (int) handlerTableEnd().minus(handlerTableBegin()); } 169 public int nulChkTableSize() { return (int) nulChkTableEnd() .minus(nulChkTableBegin()); } 170 public int origPCOffset() { return (int) origPCOffsetField.getValue(addr); } 171 172 public int totalSize() { 173 return 174 constantsSize() + 175 instsSize() + 176 stubSize() + 177 scopesDataSize() + 178 scopesPCsSize() + 179 dependenciesSize() + 180 handlerTableSize() + 181 nulChkTableSize(); 182 } 183 184 public boolean constantsContains (Address addr) { return constantsBegin() .lessThanOrEqual(addr) && constantsEnd() .greaterThan(addr); } 185 public boolean instsContains (Address addr) { return instsBegin() .lessThanOrEqual(addr) && instsEnd() .greaterThan(addr); } 186 public boolean stubContains (Address addr) { return stubBegin() .lessThanOrEqual(addr) && stubEnd() .greaterThan(addr); } 187 public boolean oopsContains (Address addr) { return oopsBegin() .lessThanOrEqual(addr) && oopsEnd() .greaterThan(addr); } 188 public boolean scopesDataContains (Address addr) { return scopesDataBegin() .lessThanOrEqual(addr) && scopesDataEnd() .greaterThan(addr); } 189 public boolean scopesPCsContains (Address addr) { return scopesPCsBegin() .lessThanOrEqual(addr) && scopesPCsEnd() .greaterThan(addr); } 190 public boolean handlerTableContains(Address addr) { return handlerTableBegin().lessThanOrEqual(addr) && handlerTableEnd().greaterThan(addr); } 191 public boolean nulChkTableContains (Address addr) { return nulChkTableBegin() .lessThanOrEqual(addr) && nulChkTableEnd() .greaterThan(addr); } 192 193 /** Entry points */ 194 public Address getEntryPoint() { return entryPointField.getValue(addr); } 195 public Address getVerifiedEntryPoint() { return verifiedEntryPointField.getValue(addr); } 196 197 /** Support for oops in scopes and relocs. Note: index 0 is reserved for null. */ 198 public OopHandle getOopAt(int index) { 199 if (index == 0) return null; 200 if (Assert.ASSERTS_ENABLED) { 201 Assert.that(index > 0 && index <= oopsSize(), "must be a valid non-zero index"); 202 } 203 return oopsBegin().getOopHandleAt((index - 1) * VM.getVM().getOopSize()); 204 } 205 206 // FIXME: add interpreter_entry_point() 207 // FIXME: add lazy_interpreter_entry_point() for C2 208 209 // ********** 210 // * FIXME: * ADD ACCESS TO FLAGS!!!! 211 // ********** 212 // public boolean isInUse(); 213 // public boolean isAlive(); 214 // public boolean isNotEntrant(); 215 // public boolean isZombie(); 216 217 // ******************************** 218 // * MAJOR FIXME: MAJOR HACK HERE * 219 // ******************************** 220 public boolean isZombie() { return false; } 221 222 // public boolean isUnloaded(); 223 // public boolean isYoung(); 224 // public boolean isOld(); 225 // public int age(); 226 // public boolean isMarkedForDeoptimization(); 227 // public boolean isMarkedForUnloading(); 228 // public boolean isMarkedForReclamation(); 229 // public int level(); 230 // public int version(); 231 232 // FIXME: add mutators for above 233 // FIXME: add exception cache access? 234 235 /** On-stack replacement support */ 236 // FIXME: add mutators 237 public int getOSREntryBCI() { 238 if (Assert.ASSERTS_ENABLED) { 239 Assert.that(getEntryBCI() != VM.getVM().getInvocationEntryBCI(), "wrong kind of nmethod"); 240 } 241 return getEntryBCI(); 242 } 243 244 public NMethod getOSRLink() { 245 return (NMethod) VMObjectFactory.newObject(NMethod.class, osrLinkField.getValue(addr)); 246 } 247 248 public NMethod getScavengeRootLink() { 249 return (NMethod) VMObjectFactory.newObject(NMethod.class, scavengeRootLinkField.getValue(addr)); 250 } 251 252 public int getScavengeRootState() { 253 return (int) scavengeRootStateField.getValue(addr); 254 } 255 256 // MethodHandle 257 public boolean isMethodHandleReturn(Address returnPc) { 258 // Hard to read a bit fields from Java and it's only there for performance 259 // so just go directly to the PCDesc 260 // if (!hasMethodHandleInvokes()) return false; 261 PCDesc pd = getPCDescAt(returnPc); 262 if (pd == null) 263 return false; 264 return pd.isMethodHandleInvoke(); 265 } 266 267 // Deopt 268 // Return true is the PC is one would expect if the frame is being deopted. 269 public boolean isDeoptPc (Address pc) { return isDeoptEntry(pc) || isDeoptMhEntry(pc); } 270 public boolean isDeoptEntry (Address pc) { return pc == deoptHandlerBegin(); } 271 public boolean isDeoptMhEntry (Address pc) { return pc == deoptMhHandlerBegin(); } 272 273 /** Tells whether frames described by this nmethod can be 274 deoptimized. Note: native wrappers cannot be deoptimized. */ 275 public boolean canBeDeoptimized() { return isJavaMethod(); } 276 277 // FIXME: add inline cache support 278 // FIXME: add flush() 279 280 public boolean isLockedByVM() { return lockCountField.getValue(addr) > 0; } 281 282 // FIXME: add mark_as_seen_on_stack 283 // FIXME: add can_not_entrant_be_converted 284 285 // FIXME: add GC support 286 // void follow_roots_or_mark_for_unloading(bool unloading_occurred, bool& marked_for_unloading); 287 // void follow_root_or_mark_for_unloading(oop* root, bool unloading_occurred, bool& marked_for_unloading); 288 // void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, void f(oop*)); 289 // void adjust_pointers(); 290 291 /** Finds a PCDesc with real-pc equal to "pc" */ 292 public PCDesc getPCDescAt(Address pc) { 293 // FIXME: consider adding cache like the one down in the VM 294 for (Address p = scopesPCsBegin(); p.lessThan(scopesPCsEnd()); p = p.addOffsetTo(pcDescSize)) { 295 PCDesc pcDesc = new PCDesc(p); 296 if (pcDesc.getRealPC(this).equals(pc)) { 297 return pcDesc; 298 } 299 } 300 return null; 301 } 302 303 /** ScopeDesc for an instruction */ 304 public ScopeDesc getScopeDescAt(Address pc) { 305 PCDesc pd = getPCDescAt(pc); 306 if (Assert.ASSERTS_ENABLED) { 307 Assert.that(pd != null, "scope must be present"); 308 } 309 return new ScopeDesc(this, pd.getScopeDecodeOffset(), pd.getObjDecodeOffset(), pd.getReexecute()); 310 } 311 312 /** This is only for use by the debugging system, and is only 313 intended for use in the topmost frame, where we are not 314 guaranteed to be at a PC for which we have a PCDesc. It finds 315 the PCDesc with realPC closest to the current PC. */ 316 public PCDesc getPCDescNearDbg(Address pc) { 317 PCDesc bestGuessPCDesc = null; 318 long bestDistance = 0; 319 for (Address p = scopesPCsBegin(); p.lessThan(scopesPCsEnd()); p = p.addOffsetTo(pcDescSize)) { 320 PCDesc pcDesc = new PCDesc(p); 321 // In case pc is null 322 long distance = -pcDesc.getRealPC(this).minus(pc); 323 if ((bestGuessPCDesc == null) || 324 ((distance >= 0) && (distance < bestDistance))) { 325 bestGuessPCDesc = pcDesc; 326 bestDistance = distance; 327 } 328 } 329 return bestGuessPCDesc; 330 } 331 332 /** This is only for use by the debugging system, and is only 333 intended for use in the topmost frame, where we are not 334 guaranteed to be at a PC for which we have a PCDesc. It finds 335 the ScopeDesc closest to the current PC. NOTE that this may 336 return NULL for compiled methods which don't have any 337 ScopeDescs! */ 338 public ScopeDesc getScopeDescNearDbg(Address pc) { 339 PCDesc pd = getPCDescNearDbg(pc); 340 if (pd == null) return null; 341 return new ScopeDesc(this, pd.getScopeDecodeOffset(), pd.getObjDecodeOffset(), pd.getReexecute()); 342 } 343 344 public Map/*<Address, PCDesc>*/ getSafepoints() { 345 Map safepoints = new HashMap(); // Map<Address, PCDesc> 346 sun.jvm.hotspot.debugger.Address p = null; 347 for (p = scopesPCsBegin(); p.lessThan(scopesPCsEnd()); 348 p = p.addOffsetTo(pcDescSize)) { 349 PCDesc pcDesc = new PCDesc(p); 350 sun.jvm.hotspot.debugger.Address pc = pcDesc.getRealPC(this); 351 safepoints.put(pc, pcDesc); 352 } 353 return safepoints; 354 } 355 356 // FIXME: add getPCOffsetForBCI() 357 // FIXME: add embeddedOopAt() 358 // FIXME: add isDependentOn() 359 // FIXME: add isPatchableAt() 360 361 /** Support for code generation. Only here for proof-of-concept. */ 362 public static int getEntryPointOffset() { return (int) entryPointField.getOffset(); } 363 public static int getVerifiedEntryPointOffset() { return (int) verifiedEntryPointField.getOffset(); } 364 public static int getOSREntryPointOffset() { return (int) osrEntryPointField.getOffset(); } 365 public static int getEntryBCIOffset() { return (int) entryBCIField.getOffset(); } 366 /** NOTE: renamed from "method_offset_in_bytes" */ 367 public static int getMethodOffset() { return (int) methodField.getOffset(); } 368 369 public void print() { 370 printOn(System.out); 371 } 372 373 protected void printComponentsOn(PrintStream tty) { 374 // FIXME: add relocation information 375 tty.println(" content: [" + contentBegin() + ", " + contentEnd() + "), " + 376 " code: [" + codeBegin() + ", " + codeEnd() + "), " + 377 " data: [" + dataBegin() + ", " + dataEnd() + "), " + 378 " oops: [" + oopsBegin() + ", " + oopsEnd() + "), " + 379 " frame size: " + getFrameSize()); 380 } 381 382 public String toString() { 383 Method method = getMethod(); 384 return "NMethod for " + 385 method.getMethodHolder().getName().asString() + "." + 386 method.getName().asString() + method.getSignature().asString() + "==>n" + 387 super.toString(); 388 } 389 390 public String flagsToString() { 391 // FIXME need access to flags... 392 return ""; 393 } 394 395 public String getName() { 396 Method method = getMethod(); 397 return "NMethod for " + 398 method.getMethodHolder().getName().asString() + "." + 399 method.getName().asString() + 400 method.getSignature().asString(); 401 } 402 403 //-------------------------------------------------------------------------------- 404 // Internals only below this point 405 // 406 407 private int getEntryBCI() { return (int) entryBCIField .getValue(addr); } 408 private int getExceptionOffset() { return (int) exceptionOffsetField .getValue(addr); } 409 private int getDeoptOffset() { return (int) deoptOffsetField .getValue(addr); } 410 private int getDeoptMhOffset() { return (int) deoptMhOffsetField .getValue(addr); } 411 private int getStubOffset() { return (int) stubOffsetField .getValue(addr); } 412 private int getOopsOffset() { return (int) oopsOffsetField .getValue(addr); } 413 private int getScopesDataOffset() { return (int) scopesDataOffsetField .getValue(addr); } 414 private int getScopesPCsOffset() { return (int) scopesPCsOffsetField .getValue(addr); } 415 private int getDependenciesOffset() { return (int) dependenciesOffsetField.getValue(addr); } 416 private int getHandlerTableOffset() { return (int) handlerTableOffsetField.getValue(addr); } 417 private int getNulChkTableOffset() { return (int) nulChkTableOffsetField .getValue(addr); } 418 private int getNMethodEndOffset() { return (int) nmethodEndOffsetField .getValue(addr); } 419 }