1 /* 2 * Copyright (c) 2000, 2022, 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.oops; 26 27 import java.io.PrintStream; 28 import sun.jvm.hotspot.utilities.Observable; 29 import sun.jvm.hotspot.utilities.Observer; 30 31 import sun.jvm.hotspot.code.NMethod; 32 import sun.jvm.hotspot.debugger.Address; 33 import sun.jvm.hotspot.interpreter.OopMapCacheEntry; 34 import sun.jvm.hotspot.runtime.SignatureConverter; 35 import sun.jvm.hotspot.runtime.VM; 36 import sun.jvm.hotspot.runtime.VMObjectFactory; 37 import sun.jvm.hotspot.types.AddressField; 38 import sun.jvm.hotspot.types.Type; 39 import sun.jvm.hotspot.types.TypeDataBase; 40 import sun.jvm.hotspot.types.WrongTypeException; 41 import sun.jvm.hotspot.utilities.Assert; 42 43 // A Method represents a Java method 44 45 public class Method extends Metadata { 46 static { 47 VM.registerVMInitializedObserver(new Observer() { 48 public void update(Observable o, Object data) { 49 initialize(VM.getVM().getTypeDataBase()); 50 } 51 }); 52 } 53 54 private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { 55 type = db.lookupType("Method"); 56 constMethod = type.getAddressField("_constMethod"); 57 methodData = type.getAddressField("_method_data"); 58 methodCounters = type.getAddressField("_method_counters"); 59 accessFlags = new CIntField(type.getCIntegerField("_access_flags"), 0); 60 code = type.getAddressField("_code"); 61 vtableIndex = new CIntField(type.getCIntegerField("_vtable_index"), 0); 62 63 /* 64 fromCompiledCodeEntryPoint = type.getAddressField("_from_compiled_code_entry_point"); 65 interpreterEntry = type.getAddressField("_from_interpreted_entry"); 66 */ 67 68 objectInitializerName = null; 69 classInitializerName = null; 70 } 71 72 public Method(Address addr) { 73 super(addr); 74 } 75 76 public boolean isMethod() { return true; } 77 78 // Not a Method field, used to keep type. 79 private static Type type; 80 81 // Fields 82 private static AddressField constMethod; 83 private static AddressField methodData; 84 private static AddressField methodCounters; 85 private static CIntField accessFlags; 86 private static CIntField vtableIndex; 87 88 private static AddressField code; 89 /* 90 private static AddressCField fromCompiledCodeEntryPoint; 91 private static AddressField interpreterEntry; 92 */ 93 94 95 // constant method names - <init>, <clinit> 96 // Initialized lazily to avoid initialization ordering dependencies between ArrayKlass and String 97 private static String objectInitializerName; 98 private static String classInitializerName; 99 private static String objectInitializerName() { 100 if (objectInitializerName == null) { 101 objectInitializerName = "<init>"; 102 } 103 return objectInitializerName; 104 } 105 private static String classInitializerName() { 106 if (classInitializerName == null) { 107 classInitializerName = "<clinit>"; 108 } 109 return classInitializerName; 110 } 111 112 113 // Accessors for declared fields 114 public ConstMethod getConstMethod() { 115 Address addr = constMethod.getValue(getAddress()); 116 return VMObjectFactory.newObject(ConstMethod.class, addr); 117 } 118 public ConstantPool getConstants() { 119 return getConstMethod().getConstants(); 120 } 121 public MethodData getMethodData() { 122 Address addr = methodData.getValue(getAddress()); 123 return VMObjectFactory.newObject(MethodData.class, addr); 124 } 125 public MethodCounters getMethodCounters() { 126 Address addr = methodCounters.getValue(getAddress()); 127 return VMObjectFactory.newObject(MethodCounters.class, addr); 128 } 129 /** WARNING: this is in words, not useful in this system; use getObjectSize() instead */ 130 public long getMaxStack() { return getConstMethod().getMaxStack(); } 131 public long getMaxLocals() { return getConstMethod().getMaxLocals(); } 132 public long getSizeOfParameters() { return getConstMethod().getSizeOfParameters(); } 133 public long getNameIndex() { return getConstMethod().getNameIndex(); } 134 public long getSignatureIndex() { return getConstMethod().getSignatureIndex(); } 135 public long getGenericSignatureIndex() { return getConstMethod().getGenericSignatureIndex(); } 136 public long getAccessFlags() { return accessFlags.getValue(this); } 137 public long getCodeSize() { return getConstMethod().getCodeSize(); } 138 public long getVtableIndex() { return vtableIndex.getValue(this); } 139 public long getInvocationCount() { 140 MethodCounters mc = getMethodCounters(); 141 return mc == null ? 0 : mc.getInvocationCounter(); 142 } 143 public long getBackedgeCount() { 144 MethodCounters mc = getMethodCounters(); 145 return mc == null ? 0 : mc.getBackedgeCounter(); 146 } 147 148 // get associated compiled native method, if available, else return null. 149 public NMethod getNativeMethod() { 150 Address addr = code.getValue(getAddress()); 151 return VMObjectFactory.newObject(NMethod.class, addr); 152 } 153 154 // Convenience routine 155 public AccessFlags getAccessFlagsObj() { 156 return new AccessFlags(getAccessFlags()); 157 } 158 159 /** Get a bytecode or breakpoint at the given bci */ 160 public int getBytecodeOrBPAt(int bci) { 161 return getConstMethod().getBytecodeOrBPAt(bci); 162 } 163 164 /** Fetch the original non-breakpoint bytecode at the specified 165 bci. It is required that there is currently a bytecode at this 166 bci. */ 167 public int getOrigBytecodeAt(int bci) { 168 BreakpointInfo bp = getMethodHolder().getBreakpoints(); 169 for (; bp != null; bp = bp.getNext()) { 170 if (bp.match(this, bci)) { 171 return bp.getOrigBytecode(); 172 } 173 } 174 System.err.println("Requested bci " + bci); 175 for (; bp != null; bp = bp.getNext()) { 176 System.err.println("Breakpoint at bci " + bp.getBCI() + ", bytecode " + 177 bp.getOrigBytecode()); 178 } 179 Assert.that(false, "Should not reach here"); 180 return -1; // not reached 181 } 182 183 public byte getBytecodeByteArg(int bci) { 184 return getConstMethod().getBytecodeByteArg(bci); 185 } 186 187 /** Fetches a 16-bit big-endian ("Java ordered") value from the 188 bytecode stream */ 189 public short getBytecodeShortArg(int bci) { 190 return getConstMethod().getBytecodeShortArg(bci); 191 } 192 193 /** Fetches a 16-bit native ordered value from the 194 bytecode stream */ 195 public short getNativeShortArg(int bci) { 196 return getConstMethod().getNativeShortArg(bci); 197 } 198 199 /** Fetches a 32-bit big-endian ("Java ordered") value from the 200 bytecode stream */ 201 public int getBytecodeIntArg(int bci) { 202 return getConstMethod().getBytecodeIntArg(bci); 203 } 204 205 /** Fetches a 32-bit native ordered value from the 206 bytecode stream */ 207 public int getNativeIntArg(int bci) { 208 return getConstMethod().getNativeIntArg(bci); 209 } 210 211 public byte[] getByteCode() { 212 return getConstMethod().getByteCode(); 213 } 214 215 /* 216 public Address getCode() { return codeField.getValue(this); } 217 public Address getInterpreterEntry() { return interpreterEntryField.getValue(this); } 218 public Address getFromCompiledCodeEntryPoint() { return fromCompiledCodeEntryPointField.getValue(this); } 219 */ 220 // Accessors 221 public Symbol getName() { return getConstants().getSymbolAt(getNameIndex()); } 222 public Symbol getSignature() { return getConstants().getSymbolAt(getSignatureIndex()); } 223 public Symbol getGenericSignature() { 224 long index = getGenericSignatureIndex(); 225 return (index != 0L) ? getConstants().getSymbolAt(index) : null; 226 } 227 228 // Method holder (the Klass holding this method) 229 public InstanceKlass getMethodHolder() { return getConstants().getPoolHolder(); } 230 231 // Access flags 232 public boolean isPublic() { return getAccessFlagsObj().isPublic(); } 233 public boolean isPrivate() { return getAccessFlagsObj().isPrivate(); } 234 public boolean isProtected() { return getAccessFlagsObj().isProtected(); } 235 public boolean isPackagePrivate() { AccessFlags af = getAccessFlagsObj(); 236 return (!af.isPublic() && !af.isPrivate() && !af.isProtected()); } 237 public boolean isStatic() { return getAccessFlagsObj().isStatic(); } 238 public boolean isFinal() { return getAccessFlagsObj().isFinal(); } 239 public boolean isSynchronized() { return getAccessFlagsObj().isSynchronized(); } 240 public boolean isBridge() { return getAccessFlagsObj().isBridge(); } 241 public boolean isVarArgs() { return getAccessFlagsObj().isVarArgs(); } 242 public boolean isNative() { return getAccessFlagsObj().isNative(); } 243 public boolean isAbstract() { return getAccessFlagsObj().isAbstract(); } 244 public boolean isStrict() { return getAccessFlagsObj().isStrict(); } 245 public boolean isSynthetic() { return getAccessFlagsObj().isSynthetic(); } 246 247 public boolean isConstructor() { 248 return (!isStatic()) && getName().equals(objectInitializerName()); 249 } 250 251 public boolean isStaticInitializer() { 252 return isStatic() && getName().equals(classInitializerName()); 253 } 254 255 public boolean isObsolete() { 256 return getAccessFlagsObj().isObsolete(); 257 } 258 259 public OopMapCacheEntry getMaskFor(int bci) { 260 OopMapCacheEntry entry = new OopMapCacheEntry(); 261 entry.fill(this, bci); 262 return entry; 263 } 264 265 public long getSize() { 266 return type.getSize() + (isNative() ? 2: 0); 267 } 268 269 public void printValueOn(PrintStream tty) { 270 tty.print("Method " + getMethodHolder().getName().asString() + "." + 271 getName().asString() + getSignature().asString() + "@" + getAddress()); 272 } 273 274 public void iterateFields(MetadataVisitor visitor) { 275 visitor.doCInt(accessFlags, true); 276 } 277 278 public boolean hasLineNumberTable() { 279 return getConstMethod().hasLineNumberTable(); 280 } 281 282 public int getLineNumberFromBCI(int bci) { 283 return getConstMethod().getLineNumberFromBCI(bci); 284 } 285 286 public LineNumberTableElement[] getLineNumberTable() { 287 return getConstMethod().getLineNumberTable(); 288 } 289 290 public boolean hasLocalVariableTable() { 291 return getConstMethod().hasLocalVariableTable(); 292 } 293 294 /** Should only be called if table is present */ 295 public LocalVariableTableElement[] getLocalVariableTable() { 296 return getConstMethod().getLocalVariableTable(); 297 } 298 299 public Symbol getLocalVariableName(int bci, int slot) { 300 if (! hasLocalVariableTable()) { 301 return null; 302 } 303 304 LocalVariableTableElement[] locals = getLocalVariableTable(); 305 for (int l = 0; l < locals.length; l++) { 306 LocalVariableTableElement local = locals[l]; 307 if ((bci >= local.getStartBCI()) && 308 (bci < (local.getStartBCI() + local.getLength())) && 309 slot == local.getSlot()) { 310 return getConstants().getSymbolAt(local.getNameCPIndex()); 311 } 312 } 313 314 return null; 315 } 316 317 public boolean hasExceptionTable() { 318 return getConstMethod().hasExceptionTable(); 319 } 320 321 public ExceptionTableElement[] getExceptionTable() { 322 return getConstMethod().getExceptionTable(); 323 } 324 325 public boolean hasCheckedExceptions() { 326 return getConstMethod().hasCheckedExceptions(); 327 } 328 329 /** Should only be called if table is present */ 330 public CheckedExceptionElement[] getCheckedExceptions() { 331 return getConstMethod().getCheckedExceptions(); 332 } 333 334 /** Returns name and signature in external form for debugging 335 purposes */ 336 public String externalNameAndSignature() { 337 final StringBuffer buf = new StringBuffer(); 338 buf.append(getMethodHolder().getName().asString()); 339 buf.append("."); 340 buf.append(getName().asString()); 341 buf.append("("); 342 new SignatureConverter(getSignature(), buf).iterateParameters(); 343 buf.append(")"); 344 return buf.toString().replace('/', '.'); 345 } 346 347 public void dumpReplayData(PrintStream out) { 348 NMethod nm = getNativeMethod(); 349 int code_size = 0; 350 if (nm != null) { 351 code_size = (int)nm.codeEnd().minus(nm.getVerifiedEntryPoint()); 352 } 353 Klass holder = getMethodHolder(); 354 out.println("ciMethod " + 355 nameAsAscii() + " " + 356 getInvocationCount() + " " + 357 getBackedgeCount() + " " + 358 interpreterInvocationCount() + " " + 359 interpreterThrowoutCount() + " " + 360 code_size); 361 } 362 363 public int interpreterThrowoutCount() { 364 return getMethodCounters().interpreterThrowoutCount(); 365 } 366 367 public long interpreterInvocationCount() { 368 return getInvocationCount(); 369 } 370 371 public String nameAsAscii() { 372 return getMethodHolder().getName().asString() + " " + 373 OopUtilities.escapeString(getName().asString()) + " " + 374 getSignature().asString(); 375 } 376 }