--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,481 @@
+/*
+ * Copyright 2000-2005 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.debugger.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.utilities.*;
+
+// A ConstantPool is an array containing class constants
+// as described in the class file
+
+public class ConstantPool extends Array implements ClassConstants {
+ // Used for debugging this code
+ private static final boolean DEBUG = false;
+
+ protected void debugMessage(String message) {
+ System.out.println(message);
+ }
+
+ static {
+ VM.registerVMInitializedObserver(new Observer() {
+ public void update(Observable o, Object data) {
+ initialize(VM.getVM().getTypeDataBase());
+ }
+ });
+ }
+
+ private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
+ Type type = db.lookupType("constantPoolOopDesc");
+ tags = new OopField(type.getOopField("_tags"), 0);
+ cache = new OopField(type.getOopField("_cache"), 0);
+ poolHolder = new OopField(type.getOopField("_pool_holder"), 0);
+ headerSize = type.getSize();
+ elementSize = db.getOopSize();
+ }
+
+ ConstantPool(OopHandle handle, ObjectHeap heap) {
+ super(handle, heap);
+ }
+
+ public boolean isConstantPool() { return true; }
+
+ private static OopField tags;
+ private static OopField cache;
+ private static OopField poolHolder;
+
+
+ private static long headerSize;
+ private static long elementSize;
+
+ public TypeArray getTags() { return (TypeArray) tags.getValue(this); }
+ public ConstantPoolCache getCache() { return (ConstantPoolCache) cache.getValue(this); }
+ public Klass getPoolHolder() { return (Klass) poolHolder.getValue(this); }
+
+ private long indexOffset(long index) {
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(index > 0 && index < getLength(), "invalid cp index");
+ }
+ return (index * elementSize) + headerSize;
+ }
+
+ public ConstantTag getTagAt(long index) {
+ return new ConstantTag(getTags().getByteAt((int) index));
+ }
+
+ public Oop getObjAt(long index){
+ return getHeap().newOop(getHandle().getOopHandleAt(indexOffset(index)));
+ }
+
+ public Symbol getSymbolAt(long index) {
+ return (Symbol) getObjAt(index);
+ }
+
+ public int getIntAt(long index){
+ return getHandle().getJIntAt(indexOffset(index));
+ }
+
+ public float getFloatAt(long index){
+ return getHandle().getJFloatAt(indexOffset(index));
+ }
+
+ public long getLongAt(long index) {
+ int oneHalf = getHandle().getJIntAt(indexOffset(index + 1));
+ int otherHalf = getHandle().getJIntAt(indexOffset(index));
+ // buildLongFromIntsPD accepts higher address value, lower address value
+ // in that order.
+ return VM.getVM().buildLongFromIntsPD(oneHalf, otherHalf);
+ }
+
+ public double getDoubleAt(long index) {
+ return Double.longBitsToDouble(getLongAt(index));
+ }
+
+ public int getFieldOrMethodAt(int which) {
+ if (DEBUG) {
+ System.err.print("ConstantPool.getFieldOrMethodAt(" + which + "): new index = ");
+ }
+ int i = -1;
+ ConstantPoolCache cache = getCache();
+ if (cache == null) {
+ i = which;
+ } else {
+ // change byte-ordering and go via cache
+ i = cache.getEntryAt(0xFFFF & VM.getVM().getBytes().swapShort((short) which)).getConstantPoolIndex();
+ }
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(getTagAt(i).isFieldOrMethod(), "Corrupted constant pool");
+ }
+ if (DEBUG) {
+ System.err.println(i);
+ }
+ int res = getIntAt(i);
+ if (DEBUG) {
+ System.err.println("ConstantPool.getFieldOrMethodAt(" + i + "): result = " + res);
+ }
+ return res;
+ }
+
+ public int getNameAndTypeAt(int which) {
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(getTagAt(which).isNameAndType(), "Corrupted constant pool");
+ }
+ int i = getIntAt(which);
+ if (DEBUG) {
+ System.err.println("ConstantPool.getNameAndTypeAt(" + which + "): result = " + i);
+ }
+ return i;
+ }
+
+ public Symbol getNameRefAt(int which) {
+ int refIndex = getNameAndTypeAt(getNameAndTypeRefIndexAt(which));
+ int nameIndex = extractLowShortFromInt(refIndex);
+ return getSymbolAt(nameIndex);
+ }
+
+ public Symbol getSignatureRefAt(int which) {
+ int refIndex = getNameAndTypeAt(getNameAndTypeRefIndexAt(which));
+ int sigIndex = extractHighShortFromInt(refIndex);
+ return getSymbolAt(sigIndex);
+ }
+
+ // returns null, if not resolved.
+ public Klass getKlassRefAt(int which) {
+ if( ! getTagAt(which).isKlass()) return null;
+ return (Klass) getObjAt(which);
+ }
+
+ // returns null, if not resolved.
+ public InstanceKlass getFieldOrMethodKlassRefAt(int which) {
+ int refIndex = getFieldOrMethodAt(which);
+ int klassIndex = extractLowShortFromInt(refIndex);
+ return (InstanceKlass) getKlassRefAt(klassIndex);
+ }
+
+ // returns null, if not resolved.
+ public Method getMethodRefAt(int which) {
+ InstanceKlass klass = getFieldOrMethodKlassRefAt(which);
+ if (klass == null) return null;
+ Symbol name = getNameRefAt(which);
+ Symbol sig = getSignatureRefAt(which);
+ return klass.findMethod(name, sig);
+ }
+
+ // returns null, if not resolved.
+ public Field getFieldRefAt(int which) {
+ InstanceKlass klass = getFieldOrMethodKlassRefAt(which);
+ if (klass == null) return null;
+ Symbol name = getNameRefAt(which);
+ Symbol sig = getSignatureRefAt(which);
+ return klass.findField(name, sig);
+ }
+
+ public int getNameAndTypeRefIndexAt(int index) {
+ int refIndex = getFieldOrMethodAt(index);
+ if (DEBUG) {
+ System.err.println("ConstantPool.getNameAndTypeRefIndexAt(" + index + "): refIndex = " + refIndex);
+ }
+ int i = extractHighShortFromInt(refIndex);
+ if (DEBUG) {
+ System.err.println("ConstantPool.getNameAndTypeRefIndexAt(" + index + "): result = " + i);
+ }
+ return i;
+ }
+
+ /** Lookup for entries consisting of (name_index, signature_index) */
+ public int getNameRefIndexAt(int index) {
+ int refIndex = getNameAndTypeAt(index);
+ if (DEBUG) {
+ System.err.println("ConstantPool.getNameRefIndexAt(" + index + "): refIndex = " + refIndex);
+ }
+ int i = extractLowShortFromInt(refIndex);
+ if (DEBUG) {
+ System.err.println("ConstantPool.getNameRefIndexAt(" + index + "): result = " + i);
+ }
+ return i;
+ }
+
+ /** Lookup for entries consisting of (name_index, signature_index) */
+ public int getSignatureRefIndexAt(int index) {
+ int refIndex = getNameAndTypeAt(index);
+ if (DEBUG) {
+ System.err.println("ConstantPool.getSignatureRefIndexAt(" + index + "): refIndex = " + refIndex);
+ }
+ int i = extractHighShortFromInt(refIndex);
+ if (DEBUG) {
+ System.err.println("ConstantPool.getSignatureRefIndexAt(" + index + "): result = " + i);
+ }
+ return i;
+ }
+
+ final private static String[] nameForTag = new String[] {
+ };
+
+ private String nameForTag(int tag) {
+ switch (tag) {
+ case JVM_CONSTANT_Utf8: return "JVM_CONSTANT_Utf8";
+ case JVM_CONSTANT_Unicode: return "JVM_CONSTANT_Unicode";
+ case JVM_CONSTANT_Integer: return "JVM_CONSTANT_Integer";
+ case JVM_CONSTANT_Float: return "JVM_CONSTANT_Float";
+ case JVM_CONSTANT_Long: return "JVM_CONSTANT_Long";
+ case JVM_CONSTANT_Double: return "JVM_CONSTANT_Double";
+ case JVM_CONSTANT_Class: return "JVM_CONSTANT_Class";
+ case JVM_CONSTANT_String: return "JVM_CONSTANT_String";
+ case JVM_CONSTANT_Fieldref: return "JVM_CONSTANT_Fieldref";
+ case JVM_CONSTANT_Methodref: return "JVM_CONSTANT_Methodref";
+ case JVM_CONSTANT_InterfaceMethodref: return "JVM_CONSTANT_InterfaceMethodref";
+ case JVM_CONSTANT_NameAndType: return "JVM_CONSTANT_NameAndType";
+ case JVM_CONSTANT_Invalid: return "JVM_CONSTANT_Invalid";
+ case JVM_CONSTANT_UnresolvedClass: return "JVM_CONSTANT_UnresolvedClass";
+ case JVM_CONSTANT_ClassIndex: return "JVM_CONSTANT_ClassIndex";
+ case JVM_CONSTANT_UnresolvedString: return "JVM_CONSTANT_UnresolvedString";
+ case JVM_CONSTANT_StringIndex: return "JVM_CONSTANT_StringIndex";
+ }
+ throw new InternalError("unknown tag");
+ }
+
+ public void iterateFields(OopVisitor visitor, boolean doVMFields) {
+ super.iterateFields(visitor, doVMFields);
+ if (doVMFields) {
+ visitor.doOop(tags, true);
+ visitor.doOop(cache, true);
+ visitor.doOop(poolHolder, true);
+
+ final int length = (int) getLength();
+ // zero'th pool entry is always invalid. ignore it.
+ for (int index = 1; index < length; index++) {
+ int ctag = (int) getTags().getByteAt((int) index);
+ switch (ctag) {
+ case JVM_CONSTANT_ClassIndex:
+ case JVM_CONSTANT_StringIndex:
+ case JVM_CONSTANT_Integer:
+ visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
+ break;
+
+ case JVM_CONSTANT_Float:
+ visitor.doFloat(new FloatField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
+ break;
+
+ case JVM_CONSTANT_Long:
+ visitor.doLong(new LongField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
+ // long entries occupy two slots
+ index++;
+ break;
+
+ case JVM_CONSTANT_Double:
+ visitor.doDouble(new DoubleField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
+ // double entries occupy two slots
+ index++;
+ break;
+
+ case JVM_CONSTANT_UnresolvedClass:
+ case JVM_CONSTANT_Class:
+ case JVM_CONSTANT_UnresolvedString:
+ case JVM_CONSTANT_Utf8:
+ visitor.doOop(new OopField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
+ break;
+
+ case JVM_CONSTANT_Fieldref:
+ case JVM_CONSTANT_Methodref:
+ case JVM_CONSTANT_InterfaceMethodref:
+ case JVM_CONSTANT_NameAndType:
+ visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
+ break;
+ }
+ }
+ }
+ /*
+ int length = getLength();
+ for (int index = 0; index < length; index++) {
+ long offset = baseOffset + (index + typeDataBase.getOopSize());
+ visitor.doOop(new IndexableField(index, offset, false), getObjAt(index));
+ }
+ */
+ }
+
+ public void writeBytes(OutputStream os) throws IOException {
+ // Map between any modified UTF-8 and it's constant pool index.
+ Map utf8ToIndex = new HashMap();
+ DataOutputStream dos = new DataOutputStream(os);
+ TypeArray tags = getTags();
+ int len = (int)getLength();
+ int ci = 0; // constant pool index
+
+ // collect all modified UTF-8 Strings from Constant Pool
+
+ for (ci = 1; ci < len; ci++) {
+ byte cpConstType = tags.getByteAt(ci);
+ if(cpConstType == JVM_CONSTANT_Utf8) {
+ Symbol sym = getSymbolAt(ci);
+ utf8ToIndex.put(sym.asString(), new Short((short) ci));
+ }
+ else if(cpConstType == JVM_CONSTANT_Long ||
+ cpConstType == JVM_CONSTANT_Double) {
+ ci++;
+ }
+ }
+
+
+ for(ci = 1; ci < len; ci++) {
+ int cpConstType = (int)tags.getByteAt(ci);
+ // write cp_info
+ // write constant type
+ switch(cpConstType) {
+ case JVM_CONSTANT_Utf8: {
+ dos.writeByte(cpConstType);
+ Symbol sym = getSymbolAt(ci);
+ dos.writeShort((short)sym.getLength());
+ dos.write(sym.asByteArray());
+ if (DEBUG) debugMessage("CP[" + ci + "] = modified UTF-8 " + sym.asString());
+ break;
+ }
+
+ case JVM_CONSTANT_Unicode:
+ throw new IllegalArgumentException("Unicode constant!");
+
+ case JVM_CONSTANT_Integer:
+ dos.writeByte(cpConstType);
+ dos.writeInt(getIntAt(ci));
+ if (DEBUG) debugMessage("CP[" + ci + "] = int " + getIntAt(ci));
+ break;
+
+ case JVM_CONSTANT_Float:
+ dos.writeByte(cpConstType);
+ dos.writeFloat(getFloatAt(ci));
+ if (DEBUG) debugMessage("CP[" + ci + "] = float " + getFloatAt(ci));
+ break;
+
+ case JVM_CONSTANT_Long: {
+ dos.writeByte(cpConstType);
+ long l = getLongAt(ci);
+ // long entries occupy two pool entries
+ ci++;
+ dos.writeLong(l);
+ break;
+ }
+
+ case JVM_CONSTANT_Double:
+ dos.writeByte(cpConstType);
+ dos.writeDouble(getDoubleAt(ci));
+ // double entries occupy two pool entries
+ ci++;
+ break;
+
+ case JVM_CONSTANT_Class: {
+ dos.writeByte(cpConstType);
+ // Klass already resolved. ConstantPool constains klassOop.
+ Klass refKls = (Klass) getObjAt(ci);
+ String klassName = refKls.getName().asString();
+ Short s = (Short) utf8ToIndex.get(klassName);
+ dos.writeShort(s.shortValue());
+ if (DEBUG) debugMessage("CP[" + ci + "] = class " + s);
+ break;
+ }
+
+ // case JVM_CONSTANT_ClassIndex:
+ case JVM_CONSTANT_UnresolvedClass: {
+ dos.writeByte(JVM_CONSTANT_Class);
+ String klassName = getSymbolAt(ci).asString();
+ Short s = (Short) utf8ToIndex.get(klassName);
+ dos.writeShort(s.shortValue());
+ if (DEBUG) debugMessage("CP[" + ci + "] = class " + s);
+ break;
+ }
+
+ case JVM_CONSTANT_String: {
+ dos.writeByte(cpConstType);
+ String str = OopUtilities.stringOopToString(getObjAt(ci));
+ Short s = (Short) utf8ToIndex.get(str);
+ dos.writeShort(s.shortValue());
+ if (DEBUG) debugMessage("CP[" + ci + "] = string " + s);
+ break;
+ }
+
+ // case JVM_CONSTANT_StringIndex:
+ case JVM_CONSTANT_UnresolvedString: {
+ dos.writeByte(JVM_CONSTANT_String);
+ String val = getSymbolAt(ci).asString();
+
+ Short s = (Short) utf8ToIndex.get(val);
+ dos.writeShort(s.shortValue());
+ if (DEBUG) debugMessage("CP[" + ci + "] = string " + s);
+ break;
+ }
+
+ // all external, internal method/field references
+ case JVM_CONSTANT_Fieldref:
+ case JVM_CONSTANT_Methodref:
+ case JVM_CONSTANT_InterfaceMethodref: {
+ dos.writeByte(cpConstType);
+ int value = getIntAt(ci);
+ short klassIndex = (short) extractLowShortFromInt(value);
+ short nameAndTypeIndex = (short) extractHighShortFromInt(value);
+ dos.writeShort(klassIndex);
+ dos.writeShort(nameAndTypeIndex);
+ if (DEBUG) debugMessage("CP[" + ci + "] = ref klass = " +
+ klassIndex + ", N&T = " + nameAndTypeIndex);
+ break;
+ }
+
+ case JVM_CONSTANT_NameAndType: {
+ dos.writeByte(cpConstType);
+ int value = getIntAt(ci);
+ short nameIndex = (short) extractLowShortFromInt(value);
+ short signatureIndex = (short) extractHighShortFromInt(value);
+ dos.writeShort(nameIndex);
+ dos.writeShort(signatureIndex);
+ if (DEBUG) debugMessage("CP[" + ci + "] = N&T name = " + nameIndex
+ + ", type = " + signatureIndex);
+ break;
+ }
+ } // switch
+ }
+ dos.flush();
+ return;
+ }
+
+ public void printValueOn(PrintStream tty) {
+ tty.print("ConstantPool for " + getPoolHolder().getName().asString());
+ }
+
+ public long getObjectSize() {
+ return alignObjectSize(headerSize + (getLength() * elementSize));
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private static int extractHighShortFromInt(int val) {
+ return (val >> 16) & 0xFFFF;
+ }
+
+ private static int extractLowShortFromInt(int val) {
+ return val & 0xFFFF;
+ }
+}