From 716fb49d201cf5d8628c7217edb6c0f4f255e218 Mon Sep 17 00:00:00 2001 From: chiba Date: Fri, 4 Nov 2011 14:01:56 +0000 Subject: [PATCH] fixed JASSIST-146 git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@595 30ef5769-5b8d-40dd-aea6-55b5d6557bb3 --- src/main/javassist/bytecode/ConstPool.java | 438 ++++++++++-------- src/test/javassist/JvstTest2.java | 2 + src/test/javassist/JvstTest4.java | 3 +- src/test/javassist/bytecode/BytecodeTest.java | 197 +++++++- src/test/test4/Rename.java | 8 +- 5 files changed, 445 insertions(+), 203 deletions(-) diff --git a/src/main/javassist/bytecode/ConstPool.java b/src/main/javassist/bytecode/ConstPool.java index a04ba128..0a01f9a2 100644 --- a/src/main/javassist/bytecode/ConstPool.java +++ b/src/main/javassist/bytecode/ConstPool.java @@ -34,27 +34,8 @@ import javassist.CtClass; public final class ConstPool { LongVector items; int numOfItems; - HashMap classes; - HashMap strings; - ConstInfo[] constInfoCache; - int[] constInfoIndexCache; int thisClassInfo; - - private static final int CACHE_SIZE = 32; - - /** - * A hash function for CACHE_SIZE - */ - private static int hashFunc(int a, int b) { - int h = -2128831035; - final int prime = 16777619; - h = (h ^ (a & 0xff)) * prime; - h = (h ^ (b & 0xff)) * prime; - - // changing the hash key size from 32bit to 5bit - h = (h >> 5) ^ (h & 0x1f); - return h & 0x1f; // 0..31 - } + HashMap itemsCache; /** * CONSTANT_Class @@ -125,12 +106,9 @@ public final class ConstPool { */ public ConstPool(String thisclass) { items = new LongVector(); + itemsCache = null; numOfItems = 0; - addItem(null); // index 0 is reserved by the JVM. - classes = new HashMap(); - strings = new HashMap(); - constInfoCache = new ConstInfo[CACHE_SIZE]; - constInfoIndexCache = new int[CACHE_SIZE]; + addItem0(null); // index 0 is reserved by the JVM. thisClassInfo = addClassInfo(thisclass); } @@ -140,10 +118,7 @@ public final class ConstPool { * @param in byte stream. */ public ConstPool(DataInputStream in) throws IOException { - classes = new HashMap(); - strings = new HashMap(); - constInfoCache = new ConstInfo[CACHE_SIZE]; - constInfoIndexCache = new int[CACHE_SIZE]; + itemsCache = null; thisClassInfo = 0; /* read() initializes items and numOfItems, and do addItem(null). */ @@ -151,10 +126,7 @@ public final class ConstPool { } void prune() { - classes = new HashMap(); - strings = new HashMap(); - constInfoCache = new ConstInfo[CACHE_SIZE]; - constInfoIndexCache = new int[CACHE_SIZE]; + itemsCache = null; } /** @@ -686,11 +658,25 @@ public final class ConstPool { return null; // false } - private int addItem(ConstInfo info) { + private int addItem0(ConstInfo info) { items.addElement(info); return numOfItems++; } + private int addItem(ConstInfo info) { + if (itemsCache == null) + itemsCache = makeItemsCache(items); + + ConstInfo found = (ConstInfo)itemsCache.get(info); + if (found != null) + return found.index; + else { + items.addElement(info); + itemsCache.put(info, info); + return numOfItems++; + } + } + /** * Copies the n-th item in this ConstPool object into the destination * ConstPool object. @@ -711,7 +697,7 @@ public final class ConstPool { } int addConstInfoPadding() { - return addItem(new ConstInfoPadding()); + return addItem0(new ConstInfoPadding(numOfItems)); } /** @@ -748,15 +734,8 @@ public final class ConstPool { * @return the index of the added entry. */ public int addClassInfo(String qname) { - ClassInfo info = (ClassInfo)classes.get(qname); - if (info != null) - return info.index; - else { - int utf8 = addUtf8Info(Descriptor.toJvmName(qname)); - info = new ClassInfo(utf8, numOfItems); - classes.put(qname, info); - return addItem(info); - } + int utf8 = addUtf8Info(Descriptor.toJvmName(qname)); + return addItem(new ClassInfo(utf8, numOfItems)); } /** @@ -780,17 +759,7 @@ public final class ConstPool { * @return the index of the added entry. */ public int addNameAndTypeInfo(int name, int type) { - int h = hashFunc(name, type); - ConstInfo ci = constInfoCache[h]; - if (ci != null && ci instanceof NameAndTypeInfo && ci.hashCheck(name, type)) - return constInfoIndexCache[h]; - else { - NameAndTypeInfo item = new NameAndTypeInfo(name, type); - constInfoCache[h] = item; - int i = addItem(item); - constInfoIndexCache[h] = i; - return i; - } + return addItem(new NameAndTypeInfo(name, type, numOfItems)); } /** @@ -819,17 +788,7 @@ public final class ConstPool { * @return the index of the added entry. */ public int addFieldrefInfo(int classInfo, int nameAndTypeInfo) { - int h = hashFunc(classInfo, nameAndTypeInfo); - ConstInfo ci = constInfoCache[h]; - if (ci != null && ci instanceof FieldrefInfo && ci.hashCheck(classInfo, nameAndTypeInfo)) - return constInfoIndexCache[h]; - else { - FieldrefInfo item = new FieldrefInfo(classInfo, nameAndTypeInfo); - constInfoCache[h] = item; - int i = addItem(item); - constInfoIndexCache[h] = i; - return i; - } + return addItem(new FieldrefInfo(classInfo, nameAndTypeInfo, numOfItems)); } /** @@ -858,17 +817,7 @@ public final class ConstPool { * @return the index of the added entry. */ public int addMethodrefInfo(int classInfo, int nameAndTypeInfo) { - int h = hashFunc(classInfo, nameAndTypeInfo); - ConstInfo ci = constInfoCache[h]; - if (ci != null && ci instanceof MethodrefInfo && ci.hashCheck(classInfo, nameAndTypeInfo)) - return constInfoIndexCache[h]; - else { - MethodrefInfo item = new MethodrefInfo(classInfo, nameAndTypeInfo); - constInfoCache[h] = item; - int i = addItem(item); - constInfoIndexCache[h] = i; - return i; - } + return addItem(new MethodrefInfo(classInfo, nameAndTypeInfo, numOfItems)); } /** @@ -901,17 +850,8 @@ public final class ConstPool { */ public int addInterfaceMethodrefInfo(int classInfo, int nameAndTypeInfo) { - int h = hashFunc(classInfo, nameAndTypeInfo); - ConstInfo ci = constInfoCache[h]; - if (ci != null && ci instanceof InterfaceMethodrefInfo && ci.hashCheck(classInfo, nameAndTypeInfo)) - return constInfoIndexCache[h]; - else { - InterfaceMethodrefInfo item =new InterfaceMethodrefInfo(classInfo, nameAndTypeInfo); - constInfoCache[h] = item; - int i = addItem(item); - constInfoIndexCache[h] = i; - return i; - } + return addItem(new InterfaceMethodrefInfo(classInfo, nameAndTypeInfo, + numOfItems)); } /** @@ -924,7 +864,8 @@ public final class ConstPool { * @return the index of the added entry. */ public int addStringInfo(String str) { - return addItem(new StringInfo(addUtf8Info(str))); + int utf = addUtf8Info(str); + return addItem(new StringInfo(utf, numOfItems)); } /** @@ -934,7 +875,7 @@ public final class ConstPool { * @return the index of the added entry. */ public int addIntegerInfo(int i) { - return addItem(new IntegerInfo(i)); + return addItem(new IntegerInfo(i, numOfItems)); } /** @@ -944,7 +885,7 @@ public final class ConstPool { * @return the index of the added entry. */ public int addFloatInfo(float f) { - return addItem(new FloatInfo(f)); + return addItem(new FloatInfo(f, numOfItems)); } /** @@ -954,8 +895,10 @@ public final class ConstPool { * @return the index of the added entry. */ public int addLongInfo(long l) { - int i = addItem(new LongInfo(l)); - addItem(new ConstInfoPadding()); + int i = addItem(new LongInfo(l, numOfItems)); + if (i == numOfItems - 1) // if not existing + addConstInfoPadding(); + return i; } @@ -966,8 +909,10 @@ public final class ConstPool { * @return the index of the added entry. */ public int addDoubleInfo(double d) { - int i = addItem(new DoubleInfo(d)); - addItem(new ConstInfoPadding()); + int i = addItem(new DoubleInfo(d, numOfItems)); + if (i == numOfItems - 1) // if not existing + addConstInfoPadding(); + return i; } @@ -975,31 +920,18 @@ public final class ConstPool { * Adds a new CONSTANT_Utf8_info * structure. * - *

If the given utf8 string has been already recorded in the - * table, then this method does not add a new entry to avoid adding - * a duplicated entry. - * Instead, it returns the index of the entry already recorded. - * * @return the index of the added entry. */ public int addUtf8Info(String utf8) { - Utf8Info info = (Utf8Info)strings.get(utf8); - if (info != null) - return info.index; - else { - info = new Utf8Info(utf8, numOfItems); - strings.put(utf8, info); - return addItem(info); - } + return addItem(new Utf8Info(utf8, numOfItems)); } /** * Get all the class names. * - * @return a set of class names + * @return a set of class names (String objects). */ - public Set getClassNames() - { + public Set getClassNames() { HashSet result = new HashSet(); LongVector v = items; int size = numOfItems; @@ -1020,11 +952,9 @@ public final class ConstPool { public void renameClass(String oldName, String newName) { LongVector v = items; int size = numOfItems; - classes = new HashMap(classes.size() * 2); for (int i = 1; i < size; ++i) { ConstInfo ci = v.elementAt(i); - ci.renameClass(this, oldName, newName); - ci.makeHashtable(this); + ci.renameClass(this, oldName, newName, itemsCache); } } @@ -1037,11 +967,9 @@ public final class ConstPool { public void renameClass(Map classnames) { LongVector v = items; int size = numOfItems; - classes = new HashMap(classes.size() * 2); for (int i = 1; i < size; ++i) { ConstInfo ci = v.elementAt(i); - ci.renameClass(this, classnames); - ci.makeHashtable(this); + ci.renameClass(this, classnames, itemsCache); } } @@ -1050,24 +978,29 @@ public final class ConstPool { items = new LongVector(n); numOfItems = 0; - addItem(null); // index 0 is reserved by the JVM. + addItem0(null); // index 0 is reserved by the JVM. while (--n > 0) { // index 0 is reserved by JVM int tag = readOne(in); if ((tag == LongInfo.tag) || (tag == DoubleInfo.tag)) { - addItem(new ConstInfoPadding()); + addConstInfoPadding(); --n; } } + } + private static HashMap makeItemsCache(LongVector items) { + HashMap cache = new HashMap(); int i = 1; while (true) { ConstInfo info = items.elementAt(i++); if (info == null) break; else - info.makeHashtable(this); + cache.put(info, info); } + + return cache; } private int readOne(DataInputStream in) throws IOException { @@ -1076,44 +1009,43 @@ public final class ConstPool { switch (tag) { case Utf8Info.tag : // 1 info = new Utf8Info(in, numOfItems); - strings.put(((Utf8Info)info).string, info); break; case IntegerInfo.tag : // 3 - info = new IntegerInfo(in); + info = new IntegerInfo(in, numOfItems); break; case FloatInfo.tag : // 4 - info = new FloatInfo(in); + info = new FloatInfo(in, numOfItems); break; case LongInfo.tag : // 5 - info = new LongInfo(in); + info = new LongInfo(in, numOfItems); break; case DoubleInfo.tag : // 6 - info = new DoubleInfo(in); + info = new DoubleInfo(in, numOfItems); break; case ClassInfo.tag : // 7 info = new ClassInfo(in, numOfItems); // classes.put(, info); break; case StringInfo.tag : // 8 - info = new StringInfo(in); + info = new StringInfo(in, numOfItems); break; case FieldrefInfo.tag : // 9 - info = new FieldrefInfo(in); + info = new FieldrefInfo(in, numOfItems); break; case MethodrefInfo.tag : // 10 - info = new MethodrefInfo(in); + info = new MethodrefInfo(in, numOfItems); break; case InterfaceMethodrefInfo.tag : // 11 - info = new InterfaceMethodrefInfo(in); + info = new InterfaceMethodrefInfo(in, numOfItems); break; case NameAndTypeInfo.tag : // 12 - info = new NameAndTypeInfo(in); + info = new NameAndTypeInfo(in, numOfItems); break; default : - throw new IOException("invalid constant type: " + tag); + throw new IOException("invalid constant type: " + tag + " at " + numOfItems); } - addItem(info); + addItem0(info); return tag; } @@ -1149,21 +1081,21 @@ public final class ConstPool { } abstract class ConstInfo { + int index; + + public ConstInfo(int i) { index = i; } + public abstract int getTag(); public String getClassName(ConstPool cp) { return null; } - public void renameClass(ConstPool cp, String oldName, String newName) {} - public void renameClass(ConstPool cp, Map classnames) {} + public void renameClass(ConstPool cp, String oldName, String newName, HashMap cache) {} + public void renameClass(ConstPool cp, Map classnames, HashMap cache) {} public abstract int copy(ConstPool src, ConstPool dest, Map classnames); // ** classnames is a mapping between JVM names. public abstract void write(DataOutputStream out) throws IOException; public abstract void print(PrintWriter out); - void makeHashtable(ConstPool cp) {} // called after read() finishes in ConstPool. - - boolean hashCheck(int a, int b) { return false; } - public String toString() { ByteArrayOutputStream bout = new ByteArrayOutputStream(); PrintWriter out = new PrintWriter(bout); @@ -1175,6 +1107,8 @@ abstract class ConstInfo { /* padding following DoubleInfo or LongInfo. */ class ConstInfoPadding extends ConstInfo { + public ConstInfoPadding(int i) { super(i); } + public int getTag() { return 0; } public int copy(ConstPool src, ConstPool dest, Map map) { @@ -1191,46 +1125,72 @@ class ConstInfoPadding extends ConstInfo { class ClassInfo extends ConstInfo { static final int tag = 7; int name; - int index; - public ClassInfo(int className, int i) { + public ClassInfo(int className, int index) { + super(index); name = className; - index = i; } - public ClassInfo(DataInputStream in, int i) throws IOException { + public ClassInfo(DataInputStream in, int index) throws IOException { + super(index); name = in.readUnsignedShort(); - index = i; + } + + public int hashCode() { return name; } + + public boolean equals(Object obj) { + return obj instanceof ClassInfo && ((ClassInfo)obj).name == name; } public int getTag() { return tag; } public String getClassName(ConstPool cp) { return cp.getUtf8Info(name); - }; + } - public void renameClass(ConstPool cp, String oldName, String newName) { + public void renameClass(ConstPool cp, String oldName, String newName, HashMap cache) { String nameStr = cp.getUtf8Info(name); + String newNameStr = null; if (nameStr.equals(oldName)) - name = cp.addUtf8Info(newName); + newNameStr = newName; else if (nameStr.charAt(0) == '[') { - String nameStr2 = Descriptor.rename(nameStr, oldName, newName); - if (nameStr != nameStr2) - name = cp.addUtf8Info(nameStr2); + String s = Descriptor.rename(nameStr, oldName, newName); + if (nameStr != s) + newNameStr = s; } + + if (newNameStr != null) + if (cache == null) + name = cp.addUtf8Info(newNameStr); + else { + cache.remove(this); + name = cp.addUtf8Info(newNameStr); + cache.put(this, this); + } } - public void renameClass(ConstPool cp, Map map) { + public void renameClass(ConstPool cp, Map map, HashMap cache) { String oldName = cp.getUtf8Info(name); + String newName = null; if (oldName.charAt(0) == '[') { - String newName = Descriptor.rename(oldName, map); - if (oldName != newName) - name = cp.addUtf8Info(newName); + String s = Descriptor.rename(oldName, map); + if (oldName != s) + newName = s; } else { - String newName = (String)map.get(oldName); - if (newName != null && !newName.equals(oldName)) + String s = (String)map.get(oldName); + if (s != null && !s.equals(oldName)) + newName = s; + } + + if (newName != null) { + if (cache == null) + name = cp.addUtf8Info(newName); + else { + cache.remove(this); name = cp.addUtf8Info(newName); + cache.put(this, this); + } } } @@ -1254,11 +1214,6 @@ class ClassInfo extends ConstInfo { out.print("Class #"); out.println(name); } - - void makeHashtable(ConstPool cp) { - String name = Descriptor.toJavaName(getClassName(cp)); - cp.classes.put(name, this); - } } class NameAndTypeInfo extends ConstInfo { @@ -1266,32 +1221,55 @@ class NameAndTypeInfo extends ConstInfo { int memberName; int typeDescriptor; - public NameAndTypeInfo(int name, int type) { + public NameAndTypeInfo(int name, int type, int index) { + super(index); memberName = name; typeDescriptor = type; } - public NameAndTypeInfo(DataInputStream in) throws IOException { + public NameAndTypeInfo(DataInputStream in, int index) throws IOException { + super(index); memberName = in.readUnsignedShort(); typeDescriptor = in.readUnsignedShort(); } - boolean hashCheck(int a, int b) { return a == memberName && b == typeDescriptor; } + public int hashCode() { return (memberName << 16) ^ typeDescriptor; } + + public boolean equals(Object obj) { + if (obj instanceof NameAndTypeInfo) { + NameAndTypeInfo nti = (NameAndTypeInfo)obj; + return nti.memberName == memberName && nti.typeDescriptor == typeDescriptor; + } + else + return false; + } public int getTag() { return tag; } - public void renameClass(ConstPool cp, String oldName, String newName) { + public void renameClass(ConstPool cp, String oldName, String newName, HashMap cache) { String type = cp.getUtf8Info(typeDescriptor); String type2 = Descriptor.rename(type, oldName, newName); if (type != type2) - typeDescriptor = cp.addUtf8Info(type2); + if (cache == null) + typeDescriptor = cp.addUtf8Info(type2); + else { + cache.remove(this); + typeDescriptor = cp.addUtf8Info(type2); + cache.put(this, this); + } } - public void renameClass(ConstPool cp, Map map) { + public void renameClass(ConstPool cp, Map map, HashMap cache) { String type = cp.getUtf8Info(typeDescriptor); String type2 = Descriptor.rename(type, map); if (type != type2) - typeDescriptor = cp.addUtf8Info(type2); + if (cache == null) + typeDescriptor = cp.addUtf8Info(type2); + else { + cache.remove(this); + typeDescriptor = cp.addUtf8Info(type2); + cache.put(this, this); + } } public int copy(ConstPool src, ConstPool dest, Map map) { @@ -1320,24 +1298,36 @@ abstract class MemberrefInfo extends ConstInfo { int classIndex; int nameAndTypeIndex; - public MemberrefInfo(int cindex, int ntindex) { + public MemberrefInfo(int cindex, int ntindex, int thisIndex) { + super(thisIndex); classIndex = cindex; nameAndTypeIndex = ntindex; } - public MemberrefInfo(DataInputStream in) throws IOException { + public MemberrefInfo(DataInputStream in, int thisIndex) throws IOException { + super(thisIndex); classIndex = in.readUnsignedShort(); nameAndTypeIndex = in.readUnsignedShort(); } + public int hashCode() { return (classIndex << 16) ^ nameAndTypeIndex; } + + public boolean equals(Object obj) { + if (obj instanceof MemberrefInfo) { + MemberrefInfo mri = (MemberrefInfo)obj; + return mri.classIndex == classIndex && mri.nameAndTypeIndex == nameAndTypeIndex + && mri.getClass() == this.getClass(); + } + else + return false; + } + public int copy(ConstPool src, ConstPool dest, Map map) { int classIndex2 = src.getItem(classIndex).copy(src, dest, map); int ntIndex2 = src.getItem(nameAndTypeIndex).copy(src, dest, map); return copy2(dest, classIndex2, ntIndex2); } - boolean hashCheck(int a, int b) { return a == classIndex && b == nameAndTypeIndex; } - abstract protected int copy2(ConstPool dest, int cindex, int ntindex); public void write(DataOutputStream out) throws IOException { @@ -1359,12 +1349,12 @@ abstract class MemberrefInfo extends ConstInfo { class FieldrefInfo extends MemberrefInfo { static final int tag = 9; - public FieldrefInfo(int cindex, int ntindex) { - super(cindex, ntindex); + public FieldrefInfo(int cindex, int ntindex, int thisIndex) { + super(cindex, ntindex, thisIndex); } - public FieldrefInfo(DataInputStream in) throws IOException { - super(in); + public FieldrefInfo(DataInputStream in, int thisIndex) throws IOException { + super(in, thisIndex); } public int getTag() { return tag; } @@ -1379,12 +1369,12 @@ class FieldrefInfo extends MemberrefInfo { class MethodrefInfo extends MemberrefInfo { static final int tag = 10; - public MethodrefInfo(int cindex, int ntindex) { - super(cindex, ntindex); + public MethodrefInfo(int cindex, int ntindex, int thisIndex) { + super(cindex, ntindex, thisIndex); } - public MethodrefInfo(DataInputStream in) throws IOException { - super(in); + public MethodrefInfo(DataInputStream in, int thisIndex) throws IOException { + super(in, thisIndex); } public int getTag() { return tag; } @@ -1399,12 +1389,12 @@ class MethodrefInfo extends MemberrefInfo { class InterfaceMethodrefInfo extends MemberrefInfo { static final int tag = 11; - public InterfaceMethodrefInfo(int cindex, int ntindex) { - super(cindex, ntindex); + public InterfaceMethodrefInfo(int cindex, int ntindex, int thisIndex) { + super(cindex, ntindex, thisIndex); } - public InterfaceMethodrefInfo(DataInputStream in) throws IOException { - super(in); + public InterfaceMethodrefInfo(DataInputStream in, int thisIndex) throws IOException { + super(in, thisIndex); } public int getTag() { return tag; } @@ -1420,14 +1410,22 @@ class StringInfo extends ConstInfo { static final int tag = 8; int string; - public StringInfo(int str) { + public StringInfo(int str, int index) { + super(index); string = str; } - public StringInfo(DataInputStream in) throws IOException { + public StringInfo(DataInputStream in, int index) throws IOException { + super(index); string = in.readUnsignedShort(); } + public int hashCode() { return string; } + + public boolean equals(Object obj) { + return obj instanceof StringInfo && ((StringInfo)obj).string == string; + } + public int getTag() { return tag; } public int copy(ConstPool src, ConstPool dest, Map map) { @@ -1449,14 +1447,22 @@ class IntegerInfo extends ConstInfo { static final int tag = 3; int value; - public IntegerInfo(int i) { - value = i; + public IntegerInfo(int v, int index) { + super(index); + value = v; } - public IntegerInfo(DataInputStream in) throws IOException { + public IntegerInfo(DataInputStream in, int index) throws IOException { + super(index); value = in.readInt(); } + public int hashCode() { return value; } + + public boolean equals(Object obj) { + return obj instanceof IntegerInfo && ((IntegerInfo)obj).value == value; + } + public int getTag() { return tag; } public int copy(ConstPool src, ConstPool dest, Map map) { @@ -1478,14 +1484,22 @@ class FloatInfo extends ConstInfo { static final int tag = 4; float value; - public FloatInfo(float f) { + public FloatInfo(float f, int index) { + super(index); value = f; } - public FloatInfo(DataInputStream in) throws IOException { + public FloatInfo(DataInputStream in, int index) throws IOException { + super(index); value = in.readFloat(); } + public int hashCode() { return Float.floatToIntBits(value); } + + public boolean equals(Object obj) { + return obj instanceof FloatInfo && ((FloatInfo)obj).value == value; + } + public int getTag() { return tag; } public int copy(ConstPool src, ConstPool dest, Map map) { @@ -1507,14 +1521,22 @@ class LongInfo extends ConstInfo { static final int tag = 5; long value; - public LongInfo(long l) { + public LongInfo(long l, int index) { + super(index); value = l; } - public LongInfo(DataInputStream in) throws IOException { + public LongInfo(DataInputStream in, int index) throws IOException { + super(index); value = in.readLong(); } + public int hashCode() { return (int)(value ^ (value >>> 32)); } + + public boolean equals(Object obj) { + return obj instanceof LongInfo && ((LongInfo)obj).value == value; + } + public int getTag() { return tag; } public int copy(ConstPool src, ConstPool dest, Map map) { @@ -1536,14 +1558,25 @@ class DoubleInfo extends ConstInfo { static final int tag = 6; double value; - public DoubleInfo(double d) { + public DoubleInfo(double d, int index) { + super(index); value = d; } - public DoubleInfo(DataInputStream in) throws IOException { + public DoubleInfo(DataInputStream in, int index) throws IOException { + super(index); value = in.readDouble(); } + public int hashCode() { + long v = Double.doubleToLongBits(value); + return (int)(v ^ (v >>> 32)); + } + + public boolean equals(Object obj) { + return obj instanceof DoubleInfo && ((DoubleInfo)obj).value == value; + } + public int getTag() { return tag; } public int copy(ConstPool src, ConstPool dest, Map map) { @@ -1564,16 +1597,23 @@ class DoubleInfo extends ConstInfo { class Utf8Info extends ConstInfo { static final int tag = 1; String string; - int index; - public Utf8Info(String utf8, int i) { + public Utf8Info(String utf8, int index) { + super(index); string = utf8; - index = i; } - public Utf8Info(DataInputStream in, int i) throws IOException { + public Utf8Info(DataInputStream in, int index) throws IOException { + super(index); string = in.readUTF(); - index = i; + } + + public int hashCode() { + return string.hashCode(); + } + + public boolean equals(Object obj) { + return obj instanceof Utf8Info && ((Utf8Info)obj).string.equals(string); } public int getTag() { return tag; } diff --git a/src/test/javassist/JvstTest2.java b/src/test/javassist/JvstTest2.java index 7a9d398a..71704e08 100644 --- a/src/test/javassist/JvstTest2.java +++ b/src/test/javassist/JvstTest2.java @@ -3,6 +3,8 @@ package javassist; import java.io.*; import java.net.URL; import java.lang.reflect.Method; + +import javassist.bytecode.ClassFile; import javassist.expr.*; public class JvstTest2 extends JvstTestRoot { diff --git a/src/test/javassist/JvstTest4.java b/src/test/javassist/JvstTest4.java index 67c229fa..93177f6e 100644 --- a/src/test/javassist/JvstTest4.java +++ b/src/test/javassist/JvstTest4.java @@ -122,7 +122,8 @@ public class JvstTest4 extends JvstTestRoot { cc2.rebuildClassFile(); cc2.writeFile(); Object obj = make(cc.getName()); - assertEquals(4, invoke(obj, "run")); + assertEquals("test4.Rename2", obj.getClass().getName()); + assertEquals(14, invoke(obj, "run")); } public void testRename2() throws Exception { diff --git a/src/test/javassist/bytecode/BytecodeTest.java b/src/test/javassist/bytecode/BytecodeTest.java index 27fa0b5a..4b88852b 100644 --- a/src/test/javassist/bytecode/BytecodeTest.java +++ b/src/test/javassist/bytecode/BytecodeTest.java @@ -66,7 +66,7 @@ public class BytecodeTest extends TestCase { assertEquals(LongVector.ASIZE * LongVector.VSIZE, vec.capacity()); int size = LongVector.ASIZE * LongVector.VSIZE * 3; for (int i = 0; i < size; i++) { - vec.addElement(new IntegerInfo(i)); + vec.addElement(new IntegerInfo(i, i)); assertEquals(i, ((IntegerInfo)vec.elementAt(i)).value); assertEquals(i + 1, vec.size()); } @@ -75,7 +75,7 @@ public class BytecodeTest extends TestCase { vec = new LongVector(size - 5); assertEquals(size, vec.capacity()); for (int i = 0; i < size; i++) { - vec.addElement(new IntegerInfo(i)); + vec.addElement(new IntegerInfo(i, i)); assertEquals(i, ((IntegerInfo)vec.elementAt(i)).value); assertEquals(i + 1, vec.size()); } @@ -558,6 +558,199 @@ public class BytecodeTest extends TestCase { assertEquals(bs2[i], bos2[i]); } + public void testConstInfos() throws Exception { + int n = 1; + Utf8Info ui1 = new Utf8Info("test", n++); + Utf8Info ui2 = new Utf8Info("te" + "st", n++); + Utf8Info ui3 = new Utf8Info("test2", n++); + assertTrue(ui1.hashCode() == ui2.hashCode()); + assertTrue(ui1.equals(ui1)); + assertTrue(ui1.equals(ui2)); + assertFalse(ui1.equals(ui3)); + assertFalse(ui1.equals(null)); + + ClassInfo ci1 = new ClassInfo(ui1.index, n++); + ClassInfo ci2 = new ClassInfo(ui1.index, n++); + ClassInfo ci3 = new ClassInfo(ui2.index, n++); + ClassInfo ci4 = new ClassInfo(ui3.index, n++); + assertTrue(ci1.hashCode() == ci2.hashCode()); + assertTrue(ci1.equals(ci1)); + assertTrue(ci1.equals(ci2)); + assertFalse(ci1.equals(ci3)); + assertFalse(ci1.equals(ci4)); + assertFalse(ci1.equals(ui1)); + assertFalse(ci1.equals(null)); + + NameAndTypeInfo ni1 = new NameAndTypeInfo(ui1.index, ui3.index, n++); + NameAndTypeInfo ni2 = new NameAndTypeInfo(ui1.index, ui3.index, n++); + NameAndTypeInfo ni3 = new NameAndTypeInfo(ui1.index, ui1.index, n++); + NameAndTypeInfo ni4 = new NameAndTypeInfo(ui3.index, ui3.index, n++); + assertTrue(ni1.hashCode() == ni2.hashCode()); + assertTrue(ni1.equals(ni1)); + assertTrue(ni1.equals(ni2)); + assertFalse(ni1.equals(ni3)); + assertFalse(ni1.equals(ni4)); + assertFalse(ni1.equals(ci1)); + assertFalse(ni1.equals(null)); + + MethodrefInfo mi1 = new MethodrefInfo(ui1.index, ui3.index, n++); + MethodrefInfo mi2 = new MethodrefInfo(ui1.index, ui3.index, n++); + MethodrefInfo mi3 = new MethodrefInfo(ui1.index, ui1.index, n++); + MethodrefInfo mi4 = new MethodrefInfo(ui2.index, ui3.index, n++); + assertTrue(mi1.hashCode() == mi2.hashCode()); + assertTrue(mi1.equals(mi1)); + assertTrue(mi1.equals(mi2)); + assertFalse(mi1.equals(mi3)); + assertFalse(mi1.equals(mi4)); + assertFalse(mi1.equals(ci1)); + assertFalse(mi1.equals(null)); + + FieldrefInfo field1 = new FieldrefInfo(ui1.index, ui3.index, n++); + FieldrefInfo field2 = new FieldrefInfo(ui1.index, ui1.index, n++); + FieldrefInfo field3 = new FieldrefInfo(ui1.index, ui1.index, n++); + InterfaceMethodrefInfo intf1 = new InterfaceMethodrefInfo(ui1.index, ui3.index, n++); + InterfaceMethodrefInfo intf2 = new InterfaceMethodrefInfo(ui1.index, ui3.index, n++); + assertFalse(mi1.equals(field1)); + assertFalse(field1.equals(mi1)); + assertTrue(field2.equals(field3)); + assertFalse(mi1.equals(field2)); + assertFalse(mi1.equals(intf1)); + assertFalse(intf1.equals(mi1)); + assertTrue(intf1.equals(intf2)); + + StringInfo si1 = new StringInfo(ui1.index, n++); + StringInfo si2 = new StringInfo(ui1.index, n++); + StringInfo si3 = new StringInfo(ui2.index, n++); + assertTrue(si1.hashCode() == si2.hashCode()); + assertTrue(si1.equals(si1)); + assertTrue(si1.equals(si2)); + assertFalse(si1.equals(si3)); + assertFalse(si1.equals(ci1)); + assertFalse(si1.equals(null)); + + IntegerInfo ii1 = new IntegerInfo(12345, n++); + IntegerInfo ii2 = new IntegerInfo(12345, n++); + IntegerInfo ii3 = new IntegerInfo(-12345, n++); + assertTrue(ii1.hashCode() == ii2.hashCode()); + assertTrue(ii1.equals(ii1)); + assertTrue(ii1.equals(ii2)); + assertFalse(ii1.equals(ii3)); + assertFalse(ii1.equals(ci1)); + assertFalse(ii1.equals(null)); + + FloatInfo fi1 = new FloatInfo(12345.0F, n++); + FloatInfo fi2 = new FloatInfo(12345.0F, n++); + FloatInfo fi3 = new FloatInfo(-12345.0F, n++); + assertTrue(fi1.hashCode() == fi2.hashCode()); + assertTrue(fi1.equals(fi1)); + assertTrue(fi1.equals(fi2)); + assertFalse(fi1.equals(fi3)); + assertFalse(fi1.equals(ci1)); + assertFalse(fi1.equals(null)); + + LongInfo li1 = new LongInfo(12345L, n++); + LongInfo li2 = new LongInfo(12345L, n++); + LongInfo li3 = new LongInfo(-12345L, n++); + assertTrue(li1.hashCode() == li2.hashCode()); + assertTrue(li1.equals(li1)); + assertTrue(li1.equals(li2)); + assertFalse(li1.equals(li3)); + assertFalse(li1.equals(ci1)); + assertFalse(li1.equals(null)); + + DoubleInfo di1 = new DoubleInfo(12345.0, n++); + DoubleInfo di2 = new DoubleInfo(12345.0, n++); + DoubleInfo di3 = new DoubleInfo(-12345.0, n++); + assertTrue(di1.hashCode() == di2.hashCode()); + assertTrue(di1.equals(di1)); + assertTrue(di1.equals(di2)); + assertFalse(di1.equals(di3)); + assertFalse(di1.equals(ci1)); + assertFalse(di1.equals(null)); + } + + public void testConstInfoAdd() { + ConstPool cp = new ConstPool("test.Tester"); + assertEquals("test.Tester", cp.getClassName()); + int n0 = cp.addClassInfo("test.Foo"); + assertEquals(n0, cp.addClassInfo("test.Foo")); + int n1 = cp.addUtf8Info("test.Bar"); + assertEquals(n1, cp.addUtf8Info("test.Bar")); + int n2 = cp.addUtf8Info("()V"); + assertEquals(n2, cp.addUtf8Info("()V")); + assertTrue(n1 != n2); + int n3 = cp.addNameAndTypeInfo(n1, n2); + assertEquals(n3, cp.addNameAndTypeInfo(n1, n2)); + assertEquals(n3, cp.addNameAndTypeInfo("test.Bar", "()V")); + int n4 = cp.addNameAndTypeInfo("test.Baz", "()V"); + assertTrue(n3 != n4); + assertTrue(n3 != cp.addNameAndTypeInfo(cp.addUtf8Info("test.Baz"), n2)); + int n5 = cp.addFieldrefInfo(n0, n3); + assertEquals(n5, cp.addFieldrefInfo(n0, n3)); + assertTrue(n5 != cp.addFieldrefInfo(n0, n4)); + assertTrue(cp.addMethodrefInfo(n0, n3) == cp.addMethodrefInfo(n0, n3)); + assertTrue(cp.addMethodrefInfo(n0, "test", "()B") == cp.addMethodrefInfo(n0, "test", "()B")); + assertTrue(cp.addMethodrefInfo(n0, "test", "()B") != cp.addMethodrefInfo(n0, "test", "()I")); + assertTrue(n5 != cp.addInterfaceMethodrefInfo(n0, n3)); + assertTrue(cp.addInterfaceMethodrefInfo(n0, "test", "()B") + == cp.addInterfaceMethodrefInfo(n0, "test", "()B")); + assertTrue(cp.addInterfaceMethodrefInfo(n0, "test", "()B") + != cp.addInterfaceMethodrefInfo(n0, "test", "()I")); + int n6 = cp.addStringInfo("foobar"); + assertEquals(n6, cp.addStringInfo("foobar")); + assertTrue(n6 != cp.addStringInfo("foobar2")); + int n7 = cp.addIntegerInfo(123); + assertEquals(n7, cp.addIntegerInfo(123)); + assertTrue(n7 != cp.addIntegerInfo(-123)); + int n8 = cp.addFloatInfo(123); + assertEquals(n8, cp.addFloatInfo(123.0F)); + assertTrue(n8 != cp.addFloatInfo(-123.0F)); + int n9 = cp.addLongInfo(1234L); + assertEquals(n9, cp.addLongInfo(1234L)); + assertTrue(n9 != cp.addLongInfo(-1234L)); + int n10 = cp.addDoubleInfo(1234.0); + assertEquals(n10, cp.addDoubleInfo(1234.0)); + assertTrue(n10 != cp.addDoubleInfo(-1234.0)); + + cp.prune(); + assertEquals(n1, cp.addUtf8Info("test.Bar")); + assertEquals(n0, cp.addClassInfo("test.Foo")); + assertEquals(n10, cp.addDoubleInfo(1234.0)); + } + + public void testRenameInConstPool() { + ConstPool cp = new ConstPool("test.Tester"); + int n1 = cp.addClassInfo("test.Foo"); + int n2 = cp.addClassInfo("test.Bar"); + int n3 = cp.addClassInfo("test.Baz"); + int n4 = cp.addNameAndTypeInfo("foo", "(Ltest/Foo;)V"); + int n5 = cp.addNameAndTypeInfo("bar", "(Ltest/Bar;)V"); + int n6 = cp.addNameAndTypeInfo("baz", "(Ltest/Baz;)V"); + int n7 = cp.addClassInfo("[Ltest/Foo;"); + int n8 = cp.addClassInfo("[Ltest/Bar;"); + + cp.renameClass("test/Foo", "test/Foo2"); + assertEquals("test.Foo2", cp.getClassInfo(n1)); + assertEquals("(Ltest/Foo2;)V", cp.getUtf8Info(cp.getNameAndTypeDescriptor(n4))); + assertTrue(cp.addClassInfo("test.Foo2") == n1); + assertTrue(cp.addClassInfo("test.Foo") != n1); + assertTrue(cp.addNameAndTypeInfo("foo", "(Ltest/Foo2;)V") == n4); + assertTrue(cp.addNameAndTypeInfo("foo", "(Ltest/Foo;)V") != n4); + assertEquals("[Ltest.Foo2;", cp.getClassInfo(n7)); + + ClassMap map = new ClassMap(); + map.put("test.Bar", "test.Bar2"); + map.put("test.Baz", "test.Baz2"); + cp.renameClass(map); + assertEquals("test.Bar2", cp.getClassInfo(n2)); + assertEquals("(Ltest/Bar2;)V", cp.getUtf8Info(cp.getNameAndTypeDescriptor(n5))); + assertTrue(cp.addClassInfo("test.Bar2") == n2); + assertTrue(cp.addClassInfo("test.Bar") != n2); + assertTrue(cp.addNameAndTypeInfo("bar", "(Ltest/Bar2;)V") == n5); + assertTrue(cp.addNameAndTypeInfo("bar", "(Ltest/Bar;)V") != n5); + assertEquals("[Ltest.Bar2;", cp.getClassInfo(n8)); + } + public static void main(String[] args) { // junit.textui.TestRunner.run(suite()); junit.awtui.TestRunner.main(new String[] { diff --git a/src/test/test4/Rename.java b/src/test/test4/Rename.java index 1ded1f69..b2ff794e 100644 --- a/src/test/test4/Rename.java +++ b/src/test/test4/Rename.java @@ -4,6 +4,10 @@ interface IRename { Rename foo(Rename r); } +class RenameB { + int foo() { return 10; } +} + public class Rename implements IRename { int value = 3; Rename next = null; @@ -19,6 +23,8 @@ public class Rename implements IRename { public int run() { next = new Rename(); next.value = 4; - return foo(this).value; + RenameB rb = new RenameB(); + return foo(this).value + rb.foo(); } } + -- 2.39.5