git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@665 30ef5769-5b8d-40dd-aea6-55b5d6557bb3tags/rel_3_17_1_ga
<p>-version 3.17 | <p>-version 3.17 | ||||
<ul> | <ul> | ||||
<li>OSGi bundle info is now included in the jar file. | <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> | </ul> | ||||
<p>-version 3.16.1 on March 6, 2012 | <p>-version 3.16.1 on March 6, 2012 |
checkParamTypes(desc, 1); | checkParamTypes(desc, 1); | ||||
if (notStatic) { | if (notStatic) { | ||||
String className = cpool.getMethodrefClassName(i); | 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); | pushMemberType(desc); | ||||
return 3; | 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 { | private int doInvokeIntfMethod(int pos, byte[] code) throws BadBytecode { | ||||
int i = ByteArray.readU16bit(code, pos + 1); | int i = ByteArray.readU16bit(code, pos + 1); | ||||
String desc = cpool.getInterfaceMethodrefType(i); | String desc = cpool.getInterfaceMethodrefType(i); |
*/ | */ | ||||
protected TypeVar toTypeVar() { return null; } | protected TypeVar toTypeVar() { return null; } | ||||
// see UninitTypeVar and UninitData | |||||
public void constructorCalled(int offset) {} | |||||
/** | /** | ||||
* Primitive types. | * Primitive types. | ||||
*/ | */ | ||||
public boolean eq(TypeData d) { return getName().equals(d.getName()); } | 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 { | public static class TypeVar extends AbsTypeVar { | ||||
protected ArrayList lowers; // lower bounds of this type. ArrayList<TypeData> | protected ArrayList lowers; // lower bounds of this type. ArrayList<TypeData> | ||||
protected ArrayList usedBy; // reverse relations of lowers | protected ArrayList usedBy; // reverse relations of lowers | ||||
} | } | ||||
} | } | ||||
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. | * Type data for OBJECT. | ||||
*/ | */ | ||||
this.initialized = false; | this.initialized = false; | ||||
} | } | ||||
public UninitData copy() { return new UninitData(offset, getName()); } | |||||
public int getTypeTag() { | public int getTypeTag() { | ||||
return StackMapTable.UNINIT; | return StackMapTable.UNINIT; | ||||
} | } | ||||
} | } | ||||
public TypeData join() { | 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; } | public boolean isUninit() { return true; } | ||||
} | } | ||||
public String toString() { return "uninit:" + getName() + "@" + offset; } | public String toString() { return "uninit:" + getName() + "@" + offset; } | ||||
public void constructorCalled(int offset) { | |||||
if (offset == this.offset) | |||||
initialized = true; | |||||
} | |||||
} | } | ||||
public static class UninitThis extends UninitData { | public static class UninitThis extends UninitData { | ||||
super(-1, className); | super(-1, className); | ||||
} | } | ||||
public UninitData copy() { return new UninitThis(getName()); } | |||||
public int getTypeTag() { | public int getTypeTag() { | ||||
return StackMapTable.THIS; | return StackMapTable.THIS; | ||||
} | } |
} | } | ||||
} | } | ||||
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 { | public void tstCtClassType() throws Exception { | ||||
ClassPool cp = ClassPool.getDefault(); | ClassPool cp = ClassPool.getDefault(); | ||||
CtClass cc = cp.get("javassist.CtClassType"); | CtClass cc = cp.get("javassist.CtClassType"); |