git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@375 30ef5769-5b8d-40dd-aea6-55b5d6557bb3tags/rel_3_17_1_ga
@@ -60,6 +60,7 @@ public class Liveness { | |||
private void computeLiveness1(TypedBlock tb) { | |||
if (tb.updating) { | |||
// a loop was detected. | |||
computeLiveness1u(tb); | |||
return; | |||
} | |||
@@ -193,12 +194,12 @@ public class Liveness { | |||
boolean changed = false; | |||
for (int i = 0; i < n; i++) { | |||
TypedBlock tb = blocks[i]; | |||
if (tb.status == DONE) | |||
tb.status = NOT_YET; | |||
else { | |||
if (tb.status == CHANGED_NOW) { | |||
tb.status = CHANGED_LAST; | |||
changed = true; | |||
} | |||
else | |||
tb.status = NOT_YET; | |||
} | |||
return changed; |
@@ -114,6 +114,7 @@ public class MapMaker extends Tracer { | |||
throws BadBytecode | |||
{ | |||
TypedBlock first = blocks[0]; | |||
fixParamTypes(first); | |||
TypeData[] srcTypes = first.localsTypes; | |||
copyFrom(srcTypes.length, srcTypes, this.localsTypes); | |||
make(code, first); | |||
@@ -123,6 +124,26 @@ public class MapMaker extends Tracer { | |||
evalExpected(blocks[i]); | |||
} | |||
/* | |||
* If a parameter type is String but it is used only as Object | |||
* within the method body, this MapMaker class will report its type | |||
* is Object. To avoid this, fixParamTypes calls TypeData.setType() | |||
* on each parameter type. | |||
*/ | |||
private void fixParamTypes(TypedBlock first) throws BadBytecode { | |||
TypeData[] types = first.localsTypes; | |||
int n = types.length; | |||
for (int i = 0; i < n; i++) { | |||
TypeData t = types[i]; | |||
if (t instanceof TypeData.ClassName) { | |||
/* Skip the following statement if t.isNullType() is true | |||
* although a parameter type is never null type. | |||
*/ | |||
TypeData.setType(t, t.getName(), classPool); | |||
} | |||
} | |||
} | |||
// Phase 1 | |||
private void make(byte[] code, TypedBlock tb) | |||
@@ -283,7 +304,6 @@ public class MapMaker extends Tracer { | |||
} | |||
else | |||
offsetDelta += bb.length; | |||
} | |||
return writer.toStackMapTable(cpool); |
@@ -307,7 +307,7 @@ public abstract class Tracer implements TypeTag { | |||
return 2; | |||
} | |||
private int doOpcode54_95(int pos, byte[] code, int op) { | |||
private int doOpcode54_95(int pos, byte[] code, int op) throws BadBytecode { | |||
TypeData[] localsTypes = this.localsTypes; | |||
TypeData[] stackTypes = this.stackTypes; | |||
switch (op) { | |||
@@ -366,11 +366,18 @@ public abstract class Tracer implements TypeTag { | |||
case Opcode.LASTORE : | |||
case Opcode.FASTORE : | |||
case Opcode.DASTORE : | |||
stackTop -= (op == Opcode.LASTORE || op == Opcode.DASTORE) ? 4 : 3; | |||
break; | |||
case Opcode.AASTORE : | |||
TypeData.setType(stackTypes[stackTop - 1], | |||
TypeData.ArrayElement.getElementType(stackTypes[stackTop - 3].getName()), | |||
classPool); | |||
stackTop -= 3; | |||
break; | |||
case Opcode.BASTORE : | |||
case Opcode.CASTORE : | |||
case Opcode.SASTORE : | |||
stackTop -= (op == Opcode.LASTORE || op == Opcode.DASTORE) ? 4 : 3; | |||
stackTop -= 3; | |||
break; | |||
case Opcode.POP : | |||
stackTop--; | |||
@@ -437,7 +444,6 @@ public abstract class Tracer implements TypeTag { | |||
stackTop--; | |||
// implicit upcast might be done. | |||
localsTypes[index] = stackTypes[stackTop].copy(); | |||
return 2; | |||
} | |||
@@ -632,6 +638,7 @@ public abstract class Tracer implements TypeTag { | |||
= new TypeData.ClassName(type); | |||
return 3; } | |||
case Opcode.ARRAYLENGTH : | |||
TypeData.setType(stackTypes[stackTop - 1], "[Ljava.lang.Object;", classPool); | |||
stackTypes[stackTop - 1] = INTEGER; | |||
break; | |||
case Opcode.ATHROW : | |||
@@ -639,17 +646,18 @@ public abstract class Tracer implements TypeTag { | |||
visitThrow(pos, code); | |||
break; | |||
case Opcode.CHECKCAST : { | |||
// TypeData.setType(stackData[stackTop - 1], "java.lang.Object", classPool); | |||
// TypeData.setType(stackTypes[stackTop - 1], "java.lang.Object", classPool); | |||
int i = ByteArray.readU16bit(code, pos + 1); | |||
stackTypes[stackTop - 1] = new TypeData.ClassName(cpool.getClassInfo(i)); | |||
return 3; } | |||
case Opcode.INSTANCEOF : | |||
// TypeData.setType(stackData[stackTop - 1], "java.lang.Object", classPool); | |||
// TypeData.setType(stackTypes[stackTop - 1], "java.lang.Object", classPool); | |||
stackTypes[stackTop - 1] = INTEGER; | |||
return 3; | |||
case Opcode.MONITORENTER : | |||
case Opcode.MONITOREXIT : | |||
stackTop--; | |||
// TypeData.setType(stackTypes[stackTop], "java.lang.Object", classPool); | |||
break; | |||
case Opcode.WIDE : | |||
return doWIDE(pos, code); |
@@ -209,20 +209,20 @@ public abstract class TypeData { | |||
return; | |||
ArrayList equiv = this.equivalences; | |||
String name = this.expectedName; | |||
int n = equiv.size(); | |||
for (int i = 0; i < n; i++) { | |||
TypeData td = (TypeData)equiv.get(i); | |||
if (td instanceof TypeName) { | |||
TypeName tn = (TypeName)td; | |||
if (update(cp, name, tn.expectedName)) | |||
name = tn.expectedName; | |||
String name = evalExpectedType2(equiv, n); | |||
if (name == null) { | |||
name = this.expectedName; | |||
for (int i = 0; i < n; i++) { | |||
TypeData td = (TypeData)equiv.get(i); | |||
if (td instanceof TypeName) { | |||
TypeName tn = (TypeName)td; | |||
if (update(cp, name, tn.expectedName)) | |||
name = tn.expectedName; | |||
} | |||
} | |||
} | |||
if (name == null) | |||
name = evalExpectedType2(equivalences, n); | |||
for (int i = 0; i < n; i++) { | |||
TypeData td = (TypeData)equiv.get(i); | |||
if (td instanceof TypeName) { | |||
@@ -257,6 +257,14 @@ public abstract class TypeData { | |||
return true; | |||
else if (oldName.equals(typeName)) | |||
return false; | |||
else if (typeName.charAt(0) == '[' | |||
&& oldName.equals("[Ljava.lang.Object;")) { | |||
/* this rule is not correct but Tracer class sets the type | |||
of the operand of arraylength to java.lang.Object[]. | |||
Thus, int[] etc. must be a subtype of java.lang.Object[]. | |||
*/ | |||
return true; | |||
} | |||
try { | |||
if (cache == null) | |||
@@ -365,10 +373,10 @@ public abstract class TypeData { | |||
public String getExpected() throws BadBytecode { | |||
String en = expectedName; | |||
if (en == null) { | |||
ArrayList equiv = equivalences; | |||
if (equiv.size() == 1) | |||
return getName(); | |||
else | |||
// ArrayList equiv = equivalences; | |||
// if (equiv.size() == 1) | |||
// return getName(); | |||
// else | |||
return "java.lang.Object"; | |||
} | |||
else | |||
@@ -416,6 +424,16 @@ public abstract class TypeData { | |||
else | |||
return "[L" + elementType.replace('.', '/') + ";"; | |||
} | |||
public static String getElementType(String arrayType) { | |||
char c = arrayType.charAt(1); | |||
if (c == 'L') | |||
return arrayType.substring(2, arrayType.length() - 1).replace('/', '.'); | |||
else if (c == '[') | |||
return arrayType.substring(1); | |||
else | |||
return arrayType; | |||
} | |||
} | |||
/** |
@@ -7,7 +7,10 @@ public class TypedBlock extends BasicBlock { | |||
public TypeData[] stackTypes, localsTypes; | |||
// set by a Liveness object. | |||
// inputs[i] is true if the i-th variable is used within this block. | |||
public boolean[] inputs; | |||
// working area for Liveness class. | |||
public boolean updating; | |||
public int status; | |||
public byte[] localsUsage; |