diff agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,397 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.oops;
+
+import java.io.*;
+import java.util.*;
+import sun.jvm.hotspot.code.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.interpreter.*;
+import sun.jvm.hotspot.memory.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.utilities.*;
+
+public class ConstMethod extends Oop {
+  static {
+    VM.registerVMInitializedObserver(new Observer() {
+        public void update(Observable o, Object data) {
+          initialize(VM.getVM().getTypeDataBase());
+        }
+      });
+  }
+
+  // anon-enum constants for _flags.
+  private static int HAS_LINENUMBER_TABLE;
+  private static int HAS_CHECKED_EXCEPTIONS;
+  private static int HAS_LOCALVARIABLE_TABLE;
+
+  private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
+    Type type                  = db.lookupType("constMethodOopDesc");
+    // Backpointer to non-const methodOop
+    method                     = new OopField(type.getOopField("_method"), 0);
+    // The exception handler table. 4-tuples of ints [start_pc, end_pc,
+    // handler_pc, catch_type index] For methods with no exceptions the
+    // table is pointing to Universe::the_empty_int_array
+    exceptionTable             = new OopField(type.getOopField("_exception_table"), 0);
+    constMethodSize            = new CIntField(type.getCIntegerField("_constMethod_size"), 0);
+    flags                      = new ByteField(type.getJByteField("_flags"), 0);
+
+    // enum constants for flags
+    HAS_LINENUMBER_TABLE      = db.lookupIntConstant("constMethodOopDesc::_has_linenumber_table").intValue();
+    HAS_CHECKED_EXCEPTIONS     = db.lookupIntConstant("constMethodOopDesc::_has_checked_exceptions").intValue();
+    HAS_LOCALVARIABLE_TABLE   = db.lookupIntConstant("constMethodOopDesc::_has_localvariable_table").intValue();
+
+    // Size of Java bytecodes allocated immediately after constMethodOop.
+    codeSize                   = new CIntField(type.getCIntegerField("_code_size"), 0);
+    nameIndex                  = new CIntField(type.getCIntegerField("_name_index"), 0);
+    signatureIndex             = new CIntField(type.getCIntegerField("_signature_index"), 0);
+    genericSignatureIndex      = new CIntField(type.getCIntegerField("_generic_signature_index"),0);
+
+    // start of byte code
+    bytecodeOffset = type.getSize();
+
+    type                       = db.lookupType("CheckedExceptionElement");
+    checkedExceptionElementSize = type.getSize();
+
+    type                       = db.lookupType("LocalVariableTableElement");
+    localVariableTableElementSize = type.getSize();
+  }
+
+  ConstMethod(OopHandle handle, ObjectHeap heap) {
+    super(handle, heap);
+  }
+
+  // Fields
+  private static OopField  method;
+  private static OopField  exceptionTable;
+  private static CIntField constMethodSize;
+  private static ByteField flags;
+  private static CIntField codeSize;
+  private static CIntField nameIndex;
+  private static CIntField signatureIndex;
+  private static CIntField genericSignatureIndex;
+
+  // start of bytecode
+  private static long bytecodeOffset;
+
+  private static long checkedExceptionElementSize;
+  private static long localVariableTableElementSize;
+
+  // Accessors for declared fields
+  public Method getMethod() {
+    return (Method) method.getValue(this);
+  }
+
+  public TypeArray getExceptionTable() {
+    return (TypeArray) exceptionTable.getValue(this);
+  }
+
+  public long getConstMethodSize() {
+    return constMethodSize.getValue(this);
+  }
+
+  public byte getFlags() {
+    return flags.getValue(this);
+  }
+
+  public long getCodeSize() {
+    return codeSize.getValue(this);
+  }
+
+  public long getNameIndex() {
+    return nameIndex.getValue(this);
+  }
+
+  public long getSignatureIndex() {
+    return signatureIndex.getValue(this);
+  }
+
+  public long getGenericSignatureIndex() {
+    return genericSignatureIndex.getValue(this);
+  }
+
+  public Symbol getName() {
+    return getMethod().getName();
+  }
+
+  public Symbol getSignature() {
+    return getMethod().getSignature();
+  }
+
+  public Symbol getGenericSignature() {
+    return getMethod().getGenericSignature();
+  }
+
+  // bytecode accessors
+
+  /** Get a bytecode or breakpoint at the given bci */
+  public int getBytecodeOrBPAt(int bci) {
+    return getHandle().getJByteAt(bytecodeOffset + bci) & 0xFF;
+  }
+
+  public byte getBytecodeByteArg(int bci) {
+    return (byte) getBytecodeOrBPAt(bci);
+  }
+
+  /** Fetches a 16-bit big-endian ("Java ordered") value from the
+      bytecode stream */
+  public short getBytecodeShortArg(int bci) {
+    int hi = getBytecodeOrBPAt(bci);
+    int lo = getBytecodeOrBPAt(bci + 1);
+    return (short) ((hi << 8) | lo);
+  }
+
+  /** Fetches a 32-bit big-endian ("Java ordered") value from the
+      bytecode stream */
+  public int getBytecodeIntArg(int bci) {
+    int b4 = getBytecodeOrBPAt(bci);
+    int b3 = getBytecodeOrBPAt(bci + 1);
+    int b2 = getBytecodeOrBPAt(bci + 2);
+    int b1 = getBytecodeOrBPAt(bci + 3);
+
+    return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
+  }
+
+  public byte[] getByteCode() {
+     byte[] bc = new byte[ (int) getCodeSize() ];
+     for( int i=0; i < bc.length; i++ )
+     {
+        long offs = bytecodeOffset + i;
+        bc[i] = getHandle().getJByteAt( offs );
+     }
+     return bc;
+  }
+
+  public long getObjectSize() {
+    return getConstMethodSize() * getHeap().getOopSize();
+  }
+
+  public void printValueOn(PrintStream tty) {
+    tty.print("ConstMethod " + getName().asString() + getSignature().asString() + "@" + getHandle());
+  }
+
+  public void iterateFields(OopVisitor visitor, boolean doVMFields) {
+    super.iterateFields(visitor, doVMFields);
+    if (doVMFields) {
+      visitor.doOop(method, true);
+      visitor.doOop(exceptionTable, true);
+      visitor.doCInt(constMethodSize, true);
+      visitor.doByte(flags, true);
+      visitor.doCInt(codeSize, true);
+      visitor.doCInt(nameIndex, true);
+      visitor.doCInt(signatureIndex, true);
+      visitor.doCInt(genericSignatureIndex, true);
+      visitor.doCInt(codeSize, true);
+    }
+  }
+
+  // Accessors
+
+  public boolean hasLineNumberTable() {
+    return (getFlags() & HAS_LINENUMBER_TABLE) != 0;
+  }
+
+  public int getLineNumberFromBCI(int bci) {
+    if (!VM.getVM().isCore()) {
+      if (bci == DebugInformationRecorder.SYNCHRONIZATION_ENTRY_BCI) bci = 0;
+    }
+
+    if (isNative()) {
+      return -1;
+    }
+
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(bci == 0 || 0 <= bci && bci < getCodeSize(), "illegal bci");
+    }
+    int bestBCI  =  0;
+    int bestLine = -1;
+    if (hasLineNumberTable()) {
+      // The line numbers are a short array of 2-tuples [start_pc, line_number].
+      // Not necessarily sorted and not necessarily one-to-one.
+      CompressedLineNumberReadStream stream =
+        new CompressedLineNumberReadStream(getHandle(), (int) offsetOfCompressedLineNumberTable());
+      while (stream.readPair()) {
+        if (stream.bci() == bci) {
+          // perfect match
+          return stream.line();
+        } else {
+          // update best_bci/line
+          if (stream.bci() < bci && stream.bci() >= bestBCI) {
+            bestBCI  = stream.bci();
+            bestLine = stream.line();
+          }
+        }
+      }
+    }
+    return bestLine;
+  }
+
+  public LineNumberTableElement[] getLineNumberTable() {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(hasLineNumberTable(),
+                  "should only be called if table is present");
+    }
+    int len = getLineNumberTableLength();
+    CompressedLineNumberReadStream stream =
+      new CompressedLineNumberReadStream(getHandle(), (int) offsetOfCompressedLineNumberTable());
+    LineNumberTableElement[] ret = new LineNumberTableElement[len];
+
+    for (int idx = 0; idx < len; idx++) {
+      stream.readPair();
+      ret[idx] = new LineNumberTableElement(stream.bci(), stream.line());
+    }
+    return ret;
+  }
+
+  public boolean hasLocalVariableTable() {
+    return (getFlags() & HAS_LOCALVARIABLE_TABLE) != 0;
+  }
+
+  public Symbol getLocalVariableName(int bci, int slot) {
+    return getMethod().getLocalVariableName(bci, slot);
+  }
+
+  /** Should only be called if table is present */
+  public LocalVariableTableElement[] getLocalVariableTable() {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(hasLocalVariableTable(), "should only be called if table is present");
+    }
+    LocalVariableTableElement[] ret = new LocalVariableTableElement[getLocalVariableTableLength()];
+    long offset = offsetOfLocalVariableTable();
+    for (int i = 0; i < ret.length; i++) {
+      ret[i] = new LocalVariableTableElement(getHandle(), offset);
+      offset += localVariableTableElementSize;
+    }
+    return ret;
+  }
+
+  public boolean hasCheckedExceptions() {
+    return (getFlags() & HAS_CHECKED_EXCEPTIONS) != 0;
+  }
+
+  public CheckedExceptionElement[] getCheckedExceptions() {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(hasCheckedExceptions(), "should only be called if table is present");
+    }
+    CheckedExceptionElement[] ret = new CheckedExceptionElement[getCheckedExceptionsLength()];
+    long offset = offsetOfCheckedExceptions();
+    for (int i = 0; i < ret.length; i++) {
+      ret[i] = new CheckedExceptionElement(getHandle(), offset);
+      offset += checkedExceptionElementSize;
+    }
+    return ret;
+  }
+
+
+  //---------------------------------------------------------------------------
+  // Internals only below this point
+  //
+
+  private boolean isNative() {
+    return getMethod().isNative();
+  }
+
+  // Offset of end of code
+  private long offsetOfCodeEnd() {
+    return bytecodeOffset + getCodeSize();
+  }
+
+  // Offset of start of compressed line number table (see methodOop.hpp)
+  private long offsetOfCompressedLineNumberTable() {
+    return offsetOfCodeEnd() + (isNative() ? 2 * VM.getVM().getAddressSize() : 0);
+  }
+
+  // Offset of last short in methodOop
+  private long offsetOfLastU2Element() {
+    return getObjectSize() - 2;
+  }
+
+  private long offsetOfCheckedExceptionsLength() {
+    return offsetOfLastU2Element();
+  }
+
+  private int getCheckedExceptionsLength() {
+    if (hasCheckedExceptions()) {
+      return (int) getHandle().getCIntegerAt(offsetOfCheckedExceptionsLength(), 2, true);
+    } else {
+      return 0;
+    }
+  }
+
+  // Offset of start of checked exceptions
+  private long offsetOfCheckedExceptions() {
+    long offset = offsetOfCheckedExceptionsLength();
+    long length = getCheckedExceptionsLength();
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(length > 0, "should only be called if table is present");
+    }
+    offset -= length * checkedExceptionElementSize;
+    return offset;
+  }
+
+  private int getLineNumberTableLength() {
+    int len = 0;
+    if (hasLineNumberTable()) {
+      CompressedLineNumberReadStream stream =
+        new CompressedLineNumberReadStream(getHandle(), (int) offsetOfCompressedLineNumberTable());
+      while (stream.readPair()) {
+        len += 1;
+      }
+    }
+    return len;
+  }
+
+  private int getLocalVariableTableLength() {
+    if (hasLocalVariableTable()) {
+      return (int) getHandle().getCIntegerAt(offsetOfLocalVariableTableLength(), 2, true);
+    } else {
+      return 0;
+    }
+  }
+
+  // Offset of local variable table length
+  private long offsetOfLocalVariableTableLength() {
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(hasLocalVariableTable(), "should only be called if table is present");
+    }
+    if (hasCheckedExceptions()) {
+      return offsetOfCheckedExceptions() - 2;
+    } else {
+      return offsetOfLastU2Element();
+    }
+  }
+
+  private long offsetOfLocalVariableTable() {
+    long offset = offsetOfLocalVariableTableLength();
+    long length = getLocalVariableTableLength();
+    if (Assert.ASSERTS_ENABLED) {
+      Assert.that(length > 0, "should only be called if table is present");
+    }
+    offset -= length * localVariableTableElementSize;
+    return offset;
+  }
+
+}