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