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