0N/A/*
3790N/A * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
1472N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1472N/A * or visit www.oracle.com if you need additional information or have any
1472N/A * questions.
0N/A *
0N/A */
0N/A
0N/Apackage sun.jvm.hotspot.oops;
0N/A
0N/Aimport java.io.*;
0N/Aimport java.util.*;
0N/Aimport sun.jvm.hotspot.code.*;
0N/Aimport sun.jvm.hotspot.debugger.*;
0N/Aimport sun.jvm.hotspot.interpreter.*;
0N/Aimport sun.jvm.hotspot.memory.*;
0N/Aimport sun.jvm.hotspot.runtime.*;
0N/Aimport sun.jvm.hotspot.types.*;
0N/Aimport sun.jvm.hotspot.utilities.*;
0N/A
0N/Apublic class ConstMethod extends Oop {
0N/A static {
0N/A VM.registerVMInitializedObserver(new Observer() {
0N/A public void update(Observable o, Object data) {
0N/A initialize(VM.getVM().getTypeDataBase());
0N/A }
0N/A });
0N/A }
0N/A
0N/A // anon-enum constants for _flags.
0N/A private static int HAS_LINENUMBER_TABLE;
0N/A private static int HAS_CHECKED_EXCEPTIONS;
0N/A private static int HAS_LOCALVARIABLE_TABLE;
3879N/A private static int HAS_EXCEPTION_TABLE;
0N/A
0N/A private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
0N/A Type type = db.lookupType("constMethodOopDesc");
3790N/A constants = new OopField(type.getOopField("_constants"), 0);
0N/A constMethodSize = new CIntField(type.getCIntegerField("_constMethod_size"), 0);
0N/A flags = new ByteField(type.getJByteField("_flags"), 0);
0N/A
0N/A // enum constants for flags
0N/A HAS_LINENUMBER_TABLE = db.lookupIntConstant("constMethodOopDesc::_has_linenumber_table").intValue();
0N/A HAS_CHECKED_EXCEPTIONS = db.lookupIntConstant("constMethodOopDesc::_has_checked_exceptions").intValue();
0N/A HAS_LOCALVARIABLE_TABLE = db.lookupIntConstant("constMethodOopDesc::_has_localvariable_table").intValue();
3879N/A HAS_EXCEPTION_TABLE = db.lookupIntConstant("constMethodOopDesc::_has_exception_table").intValue();
0N/A
0N/A // Size of Java bytecodes allocated immediately after constMethodOop.
0N/A codeSize = new CIntField(type.getCIntegerField("_code_size"), 0);
0N/A nameIndex = new CIntField(type.getCIntegerField("_name_index"), 0);
0N/A signatureIndex = new CIntField(type.getCIntegerField("_signature_index"), 0);
0N/A genericSignatureIndex = new CIntField(type.getCIntegerField("_generic_signature_index"),0);
3790N/A idnum = new CIntField(type.getCIntegerField("_method_idnum"), 0);
0N/A
0N/A // start of byte code
0N/A bytecodeOffset = type.getSize();
0N/A
0N/A type = db.lookupType("CheckedExceptionElement");
0N/A checkedExceptionElementSize = type.getSize();
0N/A
0N/A type = db.lookupType("LocalVariableTableElement");
0N/A localVariableTableElementSize = type.getSize();
3879N/A
3879N/A type = db.lookupType("ExceptionTableElement");
3879N/A exceptionTableElementSize = type.getSize();
0N/A }
0N/A
0N/A ConstMethod(OopHandle handle, ObjectHeap heap) {
0N/A super(handle, heap);
0N/A }
0N/A
0N/A // Fields
3790N/A private static OopField constants;
0N/A private static CIntField constMethodSize;
0N/A private static ByteField flags;
0N/A private static CIntField codeSize;
0N/A private static CIntField nameIndex;
0N/A private static CIntField signatureIndex;
0N/A private static CIntField genericSignatureIndex;
3790N/A private static CIntField idnum;
0N/A
0N/A // start of bytecode
0N/A private static long bytecodeOffset;
0N/A
0N/A private static long checkedExceptionElementSize;
0N/A private static long localVariableTableElementSize;
3879N/A private static long exceptionTableElementSize;
0N/A
3790N/A public Method getMethod() {
3790N/A InstanceKlass ik = (InstanceKlass)getConstants().getPoolHolder();
3790N/A ObjArray methods = ik.getMethods();
3790N/A return (Method)methods.getObjAt(getIdNum());
3790N/A }
3790N/A
0N/A // Accessors for declared fields
3790N/A public ConstantPool getConstants() {
3790N/A return (ConstantPool) constants.getValue(this);
0N/A }
0N/A
0N/A public long getConstMethodSize() {
0N/A return constMethodSize.getValue(this);
0N/A }
0N/A
0N/A public byte getFlags() {
0N/A return flags.getValue(this);
0N/A }
0N/A
0N/A public long getCodeSize() {
0N/A return codeSize.getValue(this);
0N/A }
0N/A
0N/A public long getNameIndex() {
0N/A return nameIndex.getValue(this);
0N/A }
0N/A
0N/A public long getSignatureIndex() {
0N/A return signatureIndex.getValue(this);
0N/A }
0N/A
0N/A public long getGenericSignatureIndex() {
0N/A return genericSignatureIndex.getValue(this);
0N/A }
0N/A
3790N/A public long getIdNum() {
3790N/A return idnum.getValue(this);
3790N/A }
3790N/A
0N/A public Symbol getName() {
0N/A return getMethod().getName();
0N/A }
0N/A
0N/A public Symbol getSignature() {
0N/A return getMethod().getSignature();
0N/A }
0N/A
0N/A public Symbol getGenericSignature() {
0N/A return getMethod().getGenericSignature();
0N/A }
0N/A
0N/A // bytecode accessors
0N/A
0N/A /** Get a bytecode or breakpoint at the given bci */
0N/A public int getBytecodeOrBPAt(int bci) {
0N/A return getHandle().getJByteAt(bytecodeOffset + bci) & 0xFF;
0N/A }
0N/A
0N/A public byte getBytecodeByteArg(int bci) {
0N/A return (byte) getBytecodeOrBPAt(bci);
0N/A }
0N/A
0N/A /** Fetches a 16-bit big-endian ("Java ordered") value from the
0N/A bytecode stream */
0N/A public short getBytecodeShortArg(int bci) {
0N/A int hi = getBytecodeOrBPAt(bci);
0N/A int lo = getBytecodeOrBPAt(bci + 1);
0N/A return (short) ((hi << 8) | lo);
0N/A }
0N/A
2663N/A /** Fetches a 16-bit native ordered value from the
2663N/A bytecode stream */
2663N/A public short getNativeShortArg(int bci) {
2663N/A int hi = getBytecodeOrBPAt(bci);
2663N/A int lo = getBytecodeOrBPAt(bci + 1);
2663N/A if (VM.getVM().isBigEndian()) {
2663N/A return (short) ((hi << 8) | lo);
2663N/A } else {
2663N/A return (short) ((lo << 8) | hi);
2663N/A }
2663N/A }
2663N/A
0N/A /** Fetches a 32-bit big-endian ("Java ordered") value from the
0N/A bytecode stream */
0N/A public int getBytecodeIntArg(int bci) {
0N/A int b4 = getBytecodeOrBPAt(bci);
0N/A int b3 = getBytecodeOrBPAt(bci + 1);
0N/A int b2 = getBytecodeOrBPAt(bci + 2);
0N/A int b1 = getBytecodeOrBPAt(bci + 3);
0N/A
0N/A return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
0N/A }
0N/A
2663N/A /** Fetches a 32-bit native ordered value from the
2663N/A bytecode stream */
2663N/A public int getNativeIntArg(int bci) {
2663N/A int b4 = getBytecodeOrBPAt(bci);
2663N/A int b3 = getBytecodeOrBPAt(bci + 1);
2663N/A int b2 = getBytecodeOrBPAt(bci + 2);
2663N/A int b1 = getBytecodeOrBPAt(bci + 3);
2663N/A
2663N/A if (VM.getVM().isBigEndian()) {
2663N/A return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
2663N/A } else {
2663N/A return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
2663N/A }
2663N/A }
2663N/A
0N/A public byte[] getByteCode() {
0N/A byte[] bc = new byte[ (int) getCodeSize() ];
0N/A for( int i=0; i < bc.length; i++ )
0N/A {
0N/A long offs = bytecodeOffset + i;
0N/A bc[i] = getHandle().getJByteAt( offs );
0N/A }
0N/A return bc;
0N/A }
0N/A
0N/A public long getObjectSize() {
0N/A return getConstMethodSize() * getHeap().getOopSize();
0N/A }
0N/A
0N/A public void printValueOn(PrintStream tty) {
0N/A tty.print("ConstMethod " + getName().asString() + getSignature().asString() + "@" + getHandle());
0N/A }
0N/A
0N/A public void iterateFields(OopVisitor visitor, boolean doVMFields) {
0N/A super.iterateFields(visitor, doVMFields);
0N/A if (doVMFields) {
3790N/A visitor.doOop(constants, true);
0N/A visitor.doCInt(constMethodSize, true);
0N/A visitor.doByte(flags, true);
0N/A visitor.doCInt(codeSize, true);
0N/A visitor.doCInt(nameIndex, true);
0N/A visitor.doCInt(signatureIndex, true);
0N/A visitor.doCInt(genericSignatureIndex, true);
0N/A visitor.doCInt(codeSize, true);
0N/A }
0N/A }
0N/A
0N/A // Accessors
0N/A
0N/A public boolean hasLineNumberTable() {
0N/A return (getFlags() & HAS_LINENUMBER_TABLE) != 0;
0N/A }
0N/A
0N/A public int getLineNumberFromBCI(int bci) {
0N/A if (!VM.getVM().isCore()) {
0N/A if (bci == DebugInformationRecorder.SYNCHRONIZATION_ENTRY_BCI) bci = 0;
0N/A }
0N/A
0N/A if (isNative()) {
0N/A return -1;
0N/A }
0N/A
0N/A if (Assert.ASSERTS_ENABLED) {
0N/A Assert.that(bci == 0 || 0 <= bci && bci < getCodeSize(), "illegal bci");
0N/A }
0N/A int bestBCI = 0;
0N/A int bestLine = -1;
0N/A if (hasLineNumberTable()) {
0N/A // The line numbers are a short array of 2-tuples [start_pc, line_number].
0N/A // Not necessarily sorted and not necessarily one-to-one.
0N/A CompressedLineNumberReadStream stream =
0N/A new CompressedLineNumberReadStream(getHandle(), (int) offsetOfCompressedLineNumberTable());
0N/A while (stream.readPair()) {
0N/A if (stream.bci() == bci) {
0N/A // perfect match
0N/A return stream.line();
0N/A } else {
0N/A // update best_bci/line
0N/A if (stream.bci() < bci && stream.bci() >= bestBCI) {
0N/A bestBCI = stream.bci();
0N/A bestLine = stream.line();
0N/A }
0N/A }
0N/A }
0N/A }
0N/A return bestLine;
0N/A }
0N/A
0N/A public LineNumberTableElement[] getLineNumberTable() {
0N/A if (Assert.ASSERTS_ENABLED) {
0N/A Assert.that(hasLineNumberTable(),
0N/A "should only be called if table is present");
0N/A }
0N/A int len = getLineNumberTableLength();
0N/A CompressedLineNumberReadStream stream =
0N/A new CompressedLineNumberReadStream(getHandle(), (int) offsetOfCompressedLineNumberTable());
0N/A LineNumberTableElement[] ret = new LineNumberTableElement[len];
0N/A
0N/A for (int idx = 0; idx < len; idx++) {
0N/A stream.readPair();
0N/A ret[idx] = new LineNumberTableElement(stream.bci(), stream.line());
0N/A }
0N/A return ret;
0N/A }
0N/A
0N/A public boolean hasLocalVariableTable() {
0N/A return (getFlags() & HAS_LOCALVARIABLE_TABLE) != 0;
0N/A }
0N/A
0N/A public Symbol getLocalVariableName(int bci, int slot) {
0N/A return getMethod().getLocalVariableName(bci, slot);
0N/A }
0N/A
0N/A /** Should only be called if table is present */
0N/A public LocalVariableTableElement[] getLocalVariableTable() {
0N/A if (Assert.ASSERTS_ENABLED) {
0N/A Assert.that(hasLocalVariableTable(), "should only be called if table is present");
0N/A }
0N/A LocalVariableTableElement[] ret = new LocalVariableTableElement[getLocalVariableTableLength()];
0N/A long offset = offsetOfLocalVariableTable();
0N/A for (int i = 0; i < ret.length; i++) {
0N/A ret[i] = new LocalVariableTableElement(getHandle(), offset);
0N/A offset += localVariableTableElementSize;
0N/A }
0N/A return ret;
0N/A }
0N/A
3879N/A public boolean hasExceptionTable() {
3879N/A return (getFlags() & HAS_EXCEPTION_TABLE) != 0;
3879N/A }
3879N/A
3879N/A public ExceptionTableElement[] getExceptionTable() {
3879N/A if (Assert.ASSERTS_ENABLED) {
3879N/A Assert.that(hasExceptionTable(), "should only be called if table is present");
3879N/A }
3879N/A ExceptionTableElement[] ret = new ExceptionTableElement[getExceptionTableLength()];
3879N/A long offset = offsetOfExceptionTable();
3879N/A for (int i = 0; i < ret.length; i++) {
3879N/A ret[i] = new ExceptionTableElement(getHandle(), offset);
3879N/A offset += exceptionTableElementSize;
3879N/A }
3879N/A return ret;
3879N/A }
3879N/A
0N/A public boolean hasCheckedExceptions() {
0N/A return (getFlags() & HAS_CHECKED_EXCEPTIONS) != 0;
0N/A }
0N/A
0N/A public CheckedExceptionElement[] getCheckedExceptions() {
0N/A if (Assert.ASSERTS_ENABLED) {
0N/A Assert.that(hasCheckedExceptions(), "should only be called if table is present");
0N/A }
0N/A CheckedExceptionElement[] ret = new CheckedExceptionElement[getCheckedExceptionsLength()];
0N/A long offset = offsetOfCheckedExceptions();
0N/A for (int i = 0; i < ret.length; i++) {
0N/A ret[i] = new CheckedExceptionElement(getHandle(), offset);
0N/A offset += checkedExceptionElementSize;
0N/A }
0N/A return ret;
0N/A }
0N/A
0N/A
0N/A //---------------------------------------------------------------------------
0N/A // Internals only below this point
0N/A //
0N/A
0N/A private boolean isNative() {
0N/A return getMethod().isNative();
0N/A }
0N/A
0N/A // Offset of end of code
0N/A private long offsetOfCodeEnd() {
0N/A return bytecodeOffset + getCodeSize();
0N/A }
0N/A
0N/A // Offset of start of compressed line number table (see methodOop.hpp)
0N/A private long offsetOfCompressedLineNumberTable() {
0N/A return offsetOfCodeEnd() + (isNative() ? 2 * VM.getVM().getAddressSize() : 0);
0N/A }
0N/A
0N/A // Offset of last short in methodOop
0N/A private long offsetOfLastU2Element() {
0N/A return getObjectSize() - 2;
0N/A }
0N/A
0N/A private long offsetOfCheckedExceptionsLength() {
0N/A return offsetOfLastU2Element();
0N/A }
0N/A
0N/A private int getCheckedExceptionsLength() {
0N/A if (hasCheckedExceptions()) {
0N/A return (int) getHandle().getCIntegerAt(offsetOfCheckedExceptionsLength(), 2, true);
0N/A } else {
0N/A return 0;
0N/A }
0N/A }
0N/A
0N/A // Offset of start of checked exceptions
0N/A private long offsetOfCheckedExceptions() {
0N/A long offset = offsetOfCheckedExceptionsLength();
0N/A long length = getCheckedExceptionsLength();
0N/A if (Assert.ASSERTS_ENABLED) {
0N/A Assert.that(length > 0, "should only be called if table is present");
0N/A }
0N/A offset -= length * checkedExceptionElementSize;
0N/A return offset;
0N/A }
0N/A
0N/A private int getLineNumberTableLength() {
0N/A int len = 0;
0N/A if (hasLineNumberTable()) {
0N/A CompressedLineNumberReadStream stream =
0N/A new CompressedLineNumberReadStream(getHandle(), (int) offsetOfCompressedLineNumberTable());
0N/A while (stream.readPair()) {
0N/A len += 1;
0N/A }
0N/A }
0N/A return len;
0N/A }
0N/A
0N/A private int getLocalVariableTableLength() {
0N/A if (hasLocalVariableTable()) {
0N/A return (int) getHandle().getCIntegerAt(offsetOfLocalVariableTableLength(), 2, true);
0N/A } else {
0N/A return 0;
0N/A }
0N/A }
0N/A
0N/A // Offset of local variable table length
0N/A private long offsetOfLocalVariableTableLength() {
0N/A if (Assert.ASSERTS_ENABLED) {
0N/A Assert.that(hasLocalVariableTable(), "should only be called if table is present");
0N/A }
3879N/A
3879N/A if (hasExceptionTable()) {
3879N/A return offsetOfExceptionTable() - 2;
3879N/A } else if (hasCheckedExceptions()) {
0N/A return offsetOfCheckedExceptions() - 2;
0N/A } else {
0N/A return offsetOfLastU2Element();
0N/A }
0N/A }
0N/A
0N/A private long offsetOfLocalVariableTable() {
0N/A long offset = offsetOfLocalVariableTableLength();
0N/A long length = getLocalVariableTableLength();
0N/A if (Assert.ASSERTS_ENABLED) {
0N/A Assert.that(length > 0, "should only be called if table is present");
0N/A }
0N/A offset -= length * localVariableTableElementSize;
0N/A return offset;
0N/A }
0N/A
3879N/A private int getExceptionTableLength() {
3879N/A if (hasExceptionTable()) {
3879N/A return (int) getHandle().getCIntegerAt(offsetOfExceptionTableLength(), 2, true);
3879N/A } else {
3879N/A return 0;
3879N/A }
3879N/A }
3879N/A
3879N/A private long offsetOfExceptionTableLength() {
3879N/A if (Assert.ASSERTS_ENABLED) {
3879N/A Assert.that(hasExceptionTable(), "should only be called if table is present");
3879N/A }
3879N/A if (hasCheckedExceptions()) {
3879N/A return offsetOfCheckedExceptions() - 2;
3879N/A } else {
3879N/A return offsetOfLastU2Element();
3879N/A }
3879N/A }
3879N/A
3879N/A private long offsetOfExceptionTable() {
3879N/A long offset = offsetOfExceptionTableLength();
3879N/A long length = getExceptionTableLength();
3879N/A if (Assert.ASSERTS_ENABLED) {
3879N/A Assert.that(length > 0, "should only be called if table is present");
3879N/A }
3879N/A offset -= length * exceptionTableElementSize;
3879N/A return offset;
3879N/A }
3879N/A
0N/A}