1/* 2 * Copyright (c) 2000, 2015, 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 25package sun.jvm.hotspot.oops; 26 27import java.io.PrintStream; 28import java.util.Observable; 29import java.util.Observer; 30 31import sun.jvm.hotspot.code.NMethod; 32import sun.jvm.hotspot.debugger.Address; 33import sun.jvm.hotspot.interpreter.OopMapCacheEntry; 34import sun.jvm.hotspot.runtime.SignatureConverter; 35import sun.jvm.hotspot.runtime.VM; 36import sun.jvm.hotspot.runtime.VMObjectFactory; 37import sun.jvm.hotspot.types.AddressField; 38import sun.jvm.hotspot.types.Type; 39import sun.jvm.hotspot.types.TypeDataBase; 40import sun.jvm.hotspot.types.WrongTypeException; 41import sun.jvm.hotspot.utilities.Assert; 42 43// A Method represents a Java method 44 45public 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 Method and SymbolTable 97 private static Symbol objectInitializerName; 98 private static Symbol classInitializerName; 99 private static Symbol objectInitializerName() { 100 if (objectInitializerName == null) { 101 objectInitializerName = VM.getVM().getSymbolTable().probe("<init>"); 102 } 103 return objectInitializerName; 104 } 105 private static Symbol classInitializerName() { 106 if (classInitializerName == null) { 107 classInitializerName = VM.getVM().getSymbolTable().probe("<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 (ConstMethod) 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 (MethodData) VMObjectFactory.newObject(MethodData.class, addr); 124 } 125 public MethodCounters getMethodCounters() { 126 Address addr = methodCounters.getValue(getAddress()); 127 return (MethodCounters) 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 (NMethod) 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 " + getName().asString() + getSignature().asString() + "@" + getAddress()); 271 } 272 273 public void iterateFields(MetadataVisitor visitor) { 274 visitor.doCInt(accessFlags, true); 275 } 276 277 public boolean hasLineNumberTable() { 278 return getConstMethod().hasLineNumberTable(); 279 } 280 281 public int getLineNumberFromBCI(int bci) { 282 return getConstMethod().getLineNumberFromBCI(bci); 283 } 284 285 public LineNumberTableElement[] getLineNumberTable() { 286 return getConstMethod().getLineNumberTable(); 287 } 288 289 public boolean hasLocalVariableTable() { 290 return getConstMethod().hasLocalVariableTable(); 291 } 292 293 /** Should only be called if table is present */ 294 public LocalVariableTableElement[] getLocalVariableTable() { 295 return getConstMethod().getLocalVariableTable(); 296 } 297 298 public Symbol getLocalVariableName(int bci, int slot) { 299 if (! hasLocalVariableTable()) { 300 return null; 301 } 302 303 LocalVariableTableElement[] locals = getLocalVariableTable(); 304 for (int l = 0; l < locals.length; l++) { 305 LocalVariableTableElement local = locals[l]; 306 if ((bci >= local.getStartBCI()) && 307 (bci < (local.getStartBCI() + local.getLength())) && 308 slot == local.getSlot()) { 309 return getConstants().getSymbolAt(local.getNameCPIndex()); 310 } 311 } 312 313 return null; 314 } 315 316 public boolean hasExceptionTable() { 317 return getConstMethod().hasExceptionTable(); 318 } 319 320 public ExceptionTableElement[] getExceptionTable() { 321 return getConstMethod().getExceptionTable(); 322 } 323 324 public boolean hasCheckedExceptions() { 325 return getConstMethod().hasCheckedExceptions(); 326 } 327 328 /** Should only be called if table is present */ 329 public CheckedExceptionElement[] getCheckedExceptions() { 330 return getConstMethod().getCheckedExceptions(); 331 } 332 333 /** Returns name and signature in external form for debugging 334 purposes */ 335 public String externalNameAndSignature() { 336 final StringBuffer buf = new StringBuffer(); 337 buf.append(getMethodHolder().getName().asString()); 338 buf.append("."); 339 buf.append(getName().asString()); 340 buf.append("("); 341 new SignatureConverter(getSignature(), buf).iterateParameters(); 342 buf.append(")"); 343 return buf.toString().replace('/', '.'); 344 } 345 346 public void dumpReplayData(PrintStream out) { 347 NMethod nm = getNativeMethod(); 348 int code_size = 0; 349 if (nm != null) { 350 code_size = (int)nm.codeEnd().minus(nm.getVerifiedEntryPoint()); 351 } 352 Klass holder = getMethodHolder(); 353 out.println("ciMethod " + 354 nameAsAscii() + " " + 355 getInvocationCount() + " " + 356 getBackedgeCount() + " " + 357 interpreterInvocationCount() + " " + 358 interpreterThrowoutCount() + " " + 359 code_size); 360 } 361 362 public int interpreterThrowoutCount() { 363 return getMethodCounters().interpreterThrowoutCount(); 364 } 365 366 public int interpreterInvocationCount() { 367 return getMethodCounters().interpreterInvocationCount(); 368 } 369 370 public String nameAsAscii() { 371 return getMethodHolder().getName().asString() + " " + 372 OopUtilities.escapeString(getName().asString()) + " " + 373 getSignature().asString(); 374 } 375} 376