diff options
-rw-r--r-- | Readme.html | 2 | ||||
-rw-r--r-- | src/main/javassist/bytecode/stackmap/Tracer.java | 19 | ||||
-rw-r--r-- | src/main/javassist/bytecode/stackmap/TypeData.java | 57 | ||||
-rw-r--r-- | src/test/javassist/bytecode/StackMapTest.java | 45 |
4 files changed, 118 insertions, 5 deletions
diff --git a/Readme.html b/Readme.html index 33bf8894..4ae48994 100644 --- a/Readme.html +++ b/Readme.html @@ -284,7 +284,7 @@ see javassist.Dump. <p>-version 3.17 <ul> <li>OSGi bundle info is now included in the jar file. - <li>JIRA JASSIST-163, 166, 168, 170, 171 have been fixed. + <li>JIRA JASSIST-160, 163, 166, 168, 170, 171 have been fixed. </ul> <p>-version 3.16.1 on March 6, 2012 diff --git a/src/main/javassist/bytecode/stackmap/Tracer.java b/src/main/javassist/bytecode/stackmap/Tracer.java index d63fa75a..8a5aa97d 100644 --- a/src/main/javassist/bytecode/stackmap/Tracer.java +++ b/src/main/javassist/bytecode/stackmap/Tracer.java @@ -801,13 +801,30 @@ public abstract class Tracer implements TypeTag { checkParamTypes(desc, 1); if (notStatic) { String className = cpool.getMethodrefClassName(i); - stackTypes[--stackTop].setType(className, classPool); + TypeData target = stackTypes[--stackTop]; + if (target instanceof TypeData.UninitTypeVar && target.isUninit()) + constructorCalled((TypeData.UninitTypeVar)target); + + target.setType(className, classPool); } pushMemberType(desc); return 3; } + /* This is a constructor call on an uninitialized object. + * Sets flags of other references to that object. + */ + private void constructorCalled(TypeData.UninitTypeVar target) { + int offset = target.offset(); + target.constructorCalled(offset); + for (int i = 0; i < stackTop; i++) + stackTypes[i].constructorCalled(offset); + + for (int i = 0; i < localsTypes.length; i++) + localsTypes[i].constructorCalled(offset); + } + private int doInvokeIntfMethod(int pos, byte[] code) throws BadBytecode { int i = ByteArray.readU16bit(code, pos + 1); String desc = cpool.getInterfaceMethodrefType(i); diff --git a/src/main/javassist/bytecode/stackmap/TypeData.java b/src/main/javassist/bytecode/stackmap/TypeData.java index 2b11905f..d77f6a55 100644 --- a/src/main/javassist/bytecode/stackmap/TypeData.java +++ b/src/main/javassist/bytecode/stackmap/TypeData.java @@ -92,6 +92,9 @@ public abstract class TypeData { */ protected TypeVar toTypeVar() { return null; } + // see UninitTypeVar and UninitData + public void constructorCalled(int offset) {} + /** * Primitive types. */ @@ -147,7 +150,8 @@ public abstract class TypeData { public boolean eq(TypeData d) { return getName().equals(d.getName()); } } - // a type variable representing a class type. + /* a type variable representing a class type or a basic type. + */ public static class TypeVar extends AbsTypeVar { protected ArrayList lowers; // lower bounds of this type. ArrayList<TypeData> protected ArrayList usedBy; // reverse relations of lowers @@ -615,6 +619,42 @@ public abstract class TypeData { } } + public static class UninitTypeVar extends AbsTypeVar { + protected TypeData type; // UninitData or TOP + + public UninitTypeVar(UninitData t) { type = t; } + public int getTypeTag() { return type.getTypeTag(); } + public int getTypeData(ConstPool cp) { return type.getTypeData(cp); } + public BasicType isBasicType() { return type.isBasicType(); } + public boolean is2WordType() { return type.is2WordType(); } + public boolean isUninit() { return type.isUninit(); } + public boolean eq(TypeData d) { return type.eq(d); } + public String getName() { return type.getName(); } + + protected TypeVar toTypeVar() { return null; } + public TypeData join() { return type.join(); } + + public void setType(String s, ClassPool cp) throws BadBytecode { + type.setType(s, cp); + } + + public void merge(TypeData t) { + if (!t.eq(type)) + type = TypeTag.TOP; + } + + public void constructorCalled(int offset) { + type.constructorCalled(offset); + } + + public int offset() { + if (type instanceof UninitData) + return ((UninitData)type).offset; + else // if type == TypeTag.TOP + throw new RuntimeException("not available"); + } + } + /** * Type data for OBJECT. */ @@ -675,6 +715,8 @@ public abstract class TypeData { this.initialized = false; } + public UninitData copy() { return new UninitData(offset, getName()); } + public int getTypeTag() { return StackMapTable.UNINIT; } @@ -684,8 +726,10 @@ public abstract class TypeData { } public TypeData join() { - TypeData td = initialized ? new ClassName(getName()) : this; - return new TypeVar(td); + if (initialized) + return new TypeVar(new ClassName(getName())); + else + return new UninitTypeVar(copy()); } public boolean isUninit() { return true; } @@ -705,6 +749,11 @@ public abstract class TypeData { } public String toString() { return "uninit:" + getName() + "@" + offset; } + + public void constructorCalled(int offset) { + if (offset == this.offset) + initialized = true; + } } public static class UninitThis extends UninitData { @@ -712,6 +761,8 @@ public abstract class TypeData { super(-1, className); } + public UninitData copy() { return new UninitThis(getName()); } + public int getTypeTag() { return StackMapTable.THIS; } diff --git a/src/test/javassist/bytecode/StackMapTest.java b/src/test/javassist/bytecode/StackMapTest.java index bd21a899..3dba27d3 100644 --- a/src/test/javassist/bytecode/StackMapTest.java +++ b/src/test/javassist/bytecode/StackMapTest.java @@ -294,6 +294,51 @@ public class StackMapTest extends TestCase { } } + public void testRebuildConstructor() throws Exception { + CtClass cc = loader.get("javassist.bytecode.StackMapTest$T5"); + rebuildStackMaps2(cc); + cc.writeFile(); + Object t1 = make(cc.getName()); + assertEquals(122, invoke(t1, "test")); + } + + public static class T5 { + int count; + public T5() { count = 0; } + public T5(int k) { + if (k > 0) count = 10; + else count = 100; + count++; + } + public T5(double d) { + this(d > 0.0 ? 1 : -1); + if (d > 1.0) count += 10; + else count += 100; + count++; + } + public int test() { + return new T5(3).count + new T5(1.0).count; + } + } + + public void testRebuildConstructor2() throws Exception { + CtClass cc = loader.get("javassist.bytecode.StackMapTest$T6"); + rebuildStackMaps2(cc); + cc.writeFile(); + Object t1 = make(cc.getName()); + assertEquals(101, invoke(t1, "test2")); + } + + public static class T6 { + public int test2() { + T5 t0 = new T5(); + T5 t = new T5(t0.count > 0 ? (new T5(t0.count > 0 ? 1 : -1).count) : -1); + if (t0.count > 0) + t.count += 1000; + return t.count; + } + } + public void tstCtClassType() throws Exception { ClassPool cp = ClassPool.getDefault(); CtClass cc = cp.get("javassist.CtClassType"); |