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