|
|
@@ -78,7 +78,17 @@ public abstract class TypeData { |
|
|
|
public abstract String getName(); |
|
|
|
public abstract void setType(String s, ClassPool cp) throws BadBytecode; |
|
|
|
|
|
|
|
// depth-first search |
|
|
|
/** |
|
|
|
* @param dim array dimension. It may be negative. |
|
|
|
*/ |
|
|
|
public abstract TypeData getArrayType(int dim) throws NotFoundException; |
|
|
|
|
|
|
|
/** |
|
|
|
* Depth-first search by Tarjan's algorithm |
|
|
|
* |
|
|
|
* @param order a node stack in the order in which nodes are visited. |
|
|
|
* @param index the index used by the algorithm. |
|
|
|
*/ |
|
|
|
public int dfs(ArrayList order, int index, ClassPool cp) |
|
|
|
throws NotFoundException |
|
|
|
{ |
|
|
@@ -89,32 +99,42 @@ public abstract class TypeData { |
|
|
|
* Returns this if it is a TypeVar or a TypeVar that this |
|
|
|
* type depends on. Otherwise, this method returns null. |
|
|
|
* It is used by dfs(). |
|
|
|
* |
|
|
|
* @param dim dimension |
|
|
|
*/ |
|
|
|
protected TypeVar toTypeVar() { return null; } |
|
|
|
protected TypeVar toTypeVar(int dim) { return null; } |
|
|
|
|
|
|
|
// see UninitTypeVar and UninitData |
|
|
|
public void constructorCalled(int offset) {} |
|
|
|
|
|
|
|
public String toString() { |
|
|
|
return super.toString() + "(" + toString2(new HashSet()) + ")"; |
|
|
|
} |
|
|
|
|
|
|
|
abstract String toString2(HashSet set); |
|
|
|
|
|
|
|
/** |
|
|
|
* Primitive types. |
|
|
|
*/ |
|
|
|
protected static class BasicType extends TypeData { |
|
|
|
private String name; |
|
|
|
private int typeTag; |
|
|
|
private char decodedName; |
|
|
|
|
|
|
|
public BasicType(String type, int tag) { |
|
|
|
public BasicType(String type, int tag, char decoded) { |
|
|
|
name = type; |
|
|
|
typeTag = tag; |
|
|
|
decodedName = decoded; |
|
|
|
} |
|
|
|
|
|
|
|
public int getTypeTag() { return typeTag; } |
|
|
|
public int getTypeData(ConstPool cp) { return 0; } |
|
|
|
|
|
|
|
public TypeData join() { |
|
|
|
if (this == TypeTag.TOP) |
|
|
|
return this; |
|
|
|
else |
|
|
|
return super.join(); |
|
|
|
if (this == TypeTag.TOP) |
|
|
|
return this; |
|
|
|
else |
|
|
|
return super.join(); |
|
|
|
} |
|
|
|
|
|
|
|
public BasicType isBasicType() { return this; } |
|
|
@@ -130,11 +150,33 @@ public abstract class TypeData { |
|
|
|
return name; |
|
|
|
} |
|
|
|
|
|
|
|
public char getDecodedName() { return decodedName; } |
|
|
|
|
|
|
|
public void setType(String s, ClassPool cp) throws BadBytecode { |
|
|
|
throw new BadBytecode("conflict: " + name + " and " + s); |
|
|
|
} |
|
|
|
|
|
|
|
public String toString() { return name; } |
|
|
|
/** |
|
|
|
* @param dim array dimension. It may be negative. |
|
|
|
*/ |
|
|
|
public TypeData getArrayType(int dim) throws NotFoundException { |
|
|
|
if (this == TypeTag.TOP) |
|
|
|
return this; |
|
|
|
else if (dim < 0) |
|
|
|
throw new NotFoundException("no element type: " + name); |
|
|
|
else if (dim == 0) |
|
|
|
return this; |
|
|
|
else { |
|
|
|
char[] name = new char[dim + 1]; |
|
|
|
for (int i = 0; i < dim; i++) |
|
|
|
name[i] = '['; |
|
|
|
|
|
|
|
name[dim] = decodedName; |
|
|
|
return new ClassName(new String(name)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
String toString2(HashSet set) { return name; } |
|
|
|
} |
|
|
|
|
|
|
|
// a type variable |
|
|
@@ -206,9 +248,9 @@ public abstract class TypeData { |
|
|
|
} |
|
|
|
|
|
|
|
public void merge(TypeData t) { |
|
|
|
lowers.add(t); |
|
|
|
if (t instanceof TypeVar) |
|
|
|
((TypeVar)t).usedBy.add(this); |
|
|
|
lowers.add(t); |
|
|
|
if (t instanceof TypeVar) |
|
|
|
((TypeVar)t).usedBy.add(this); |
|
|
|
} |
|
|
|
|
|
|
|
public int getTypeTag() { |
|
|
@@ -235,46 +277,68 @@ public abstract class TypeData { |
|
|
|
uppers.add(typeName); |
|
|
|
} |
|
|
|
|
|
|
|
protected TypeVar toTypeVar() { return this; } |
|
|
|
|
|
|
|
private int visited = 0; |
|
|
|
private int smallest = 0; |
|
|
|
private boolean inList = false; |
|
|
|
private int dimension = 0; |
|
|
|
|
|
|
|
protected TypeVar toTypeVar(int dim) { |
|
|
|
dimension = dim; |
|
|
|
return this; |
|
|
|
} |
|
|
|
|
|
|
|
/* When fixTypes() is called, getName() will return the correct |
|
|
|
* (i.e. fixed) type name. |
|
|
|
*/ |
|
|
|
public TypeData getArrayType(int dim) throws NotFoundException { |
|
|
|
if (dim == 0) |
|
|
|
return this; |
|
|
|
else { |
|
|
|
BasicType bt = isBasicType(); |
|
|
|
if (bt == null) |
|
|
|
if (isNullType()) |
|
|
|
return new NullType(); |
|
|
|
else |
|
|
|
return new ClassName(getName()).getArrayType(dim); |
|
|
|
else |
|
|
|
return bt.getArrayType(dim); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// depth-first serach |
|
|
|
public int dfs(ArrayList preOrder, int index, ClassPool cp) throws NotFoundException { |
|
|
|
if (visited > 0) |
|
|
|
return index; // MapMaker.make() may call an already visited node. |
|
|
|
|
|
|
|
visited = smallest = ++index; |
|
|
|
preOrder.add(this); |
|
|
|
inList = true; |
|
|
|
int n = lowers.size(); |
|
|
|
for (int i = 0; i < n; i++) { |
|
|
|
TypeVar child = ((TypeData)lowers.get(i)).toTypeVar(); |
|
|
|
if (child != null) |
|
|
|
if (child.visited == 0) { |
|
|
|
index = child.dfs(preOrder, index, cp); |
|
|
|
if (child.smallest < smallest) |
|
|
|
smallest = child.smallest; |
|
|
|
} |
|
|
|
else if (child.inList) |
|
|
|
if (child.visited < smallest) |
|
|
|
smallest = child.visited; |
|
|
|
} |
|
|
|
|
|
|
|
if (visited == smallest) { |
|
|
|
if (visited > 0) |
|
|
|
return index; // MapMaker.make() may call an already visited node. |
|
|
|
|
|
|
|
visited = smallest = ++index; |
|
|
|
preOrder.add(this); |
|
|
|
inList = true; |
|
|
|
int n = lowers.size(); |
|
|
|
for (int i = 0; i < n; i++) { |
|
|
|
TypeVar child = ((TypeData)lowers.get(i)).toTypeVar(dimension); |
|
|
|
if (child != null) |
|
|
|
if (child.visited == 0) { |
|
|
|
index = child.dfs(preOrder, index, cp); |
|
|
|
if (child.smallest < smallest) |
|
|
|
smallest = child.smallest; |
|
|
|
} |
|
|
|
else if (child.inList) |
|
|
|
if (child.visited < smallest) |
|
|
|
smallest = child.visited; |
|
|
|
} |
|
|
|
|
|
|
|
if (visited == smallest) { |
|
|
|
ArrayList scc = new ArrayList(); // strongly connected component |
|
|
|
TypeVar cv; |
|
|
|
do { |
|
|
|
cv = (TypeVar)preOrder.remove(preOrder.size() - 1); |
|
|
|
cv.inList = false; |
|
|
|
scc.add(cv); |
|
|
|
} while (cv != this); |
|
|
|
fixTypes(scc, cp); |
|
|
|
} |
|
|
|
TypeVar cv; |
|
|
|
do { |
|
|
|
cv = (TypeVar)preOrder.remove(preOrder.size() - 1); |
|
|
|
cv.inList = false; |
|
|
|
scc.add(cv); |
|
|
|
} while (cv != this); |
|
|
|
fixTypes(scc, cp); |
|
|
|
} |
|
|
|
|
|
|
|
return index; |
|
|
|
return index; |
|
|
|
} |
|
|
|
|
|
|
|
private void fixTypes(ArrayList scc, ClassPool cp) throws NotFoundException { |
|
|
@@ -283,10 +347,12 @@ public abstract class TypeData { |
|
|
|
TypeData kind = null; |
|
|
|
int size = scc.size(); |
|
|
|
for (int i = 0; i < size; i++) { |
|
|
|
ArrayList tds = ((TypeVar)scc.get(i)).lowers; |
|
|
|
TypeVar tvar = (TypeVar)scc.get(i); |
|
|
|
ArrayList tds = tvar.lowers; |
|
|
|
int size2 = tds.size(); |
|
|
|
for (int j = 0; j < size2; j++) { |
|
|
|
TypeData d = (TypeData)tds.get(j); |
|
|
|
TypeData td = (TypeData)tds.get(j); |
|
|
|
TypeData d = td.getArrayType(tvar.dimension); |
|
|
|
BasicType bt = d.isBasicType(); |
|
|
|
if (kind == null) { |
|
|
|
if (bt == null) { |
|
|
@@ -305,12 +371,11 @@ public abstract class TypeData { |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
if ((bt == null && isBasicType) |
|
|
|
|| (bt != null && kind != bt)) { |
|
|
|
if ((bt == null && isBasicType) || (bt != null && kind != bt)) { |
|
|
|
isBasicType = true; |
|
|
|
kind = TypeTag.TOP; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (bt == null && !d.isNullType()) |
|
|
@@ -319,19 +384,26 @@ public abstract class TypeData { |
|
|
|
} |
|
|
|
|
|
|
|
if (isBasicType) { |
|
|
|
is2WordType = kind.is2WordType(); |
|
|
|
for (int i = 0; i < size; i++) { |
|
|
|
TypeVar cv = (TypeVar)scc.get(i); |
|
|
|
cv.lowers.clear(); |
|
|
|
cv.lowers.add(kind); |
|
|
|
cv.is2WordType = kind.is2WordType(); |
|
|
|
} |
|
|
|
is2WordType = kind.is2WordType(); // necessary? |
|
|
|
fixTypes1(scc, kind); |
|
|
|
} |
|
|
|
else { |
|
|
|
String typeName = fixTypes2(scc, lowersSet, cp); |
|
|
|
for (int i = 0; i < size; i++) { |
|
|
|
TypeVar cv = (TypeVar)scc.get(i); |
|
|
|
cv.fixedType = typeName; |
|
|
|
fixTypes1(scc, new ClassName(typeName)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void fixTypes1(ArrayList scc, TypeData kind) throws NotFoundException { |
|
|
|
int size = scc.size(); |
|
|
|
for (int i = 0; i < size; i++) { |
|
|
|
TypeVar cv = (TypeVar)scc.get(i); |
|
|
|
TypeData kind2 = kind.getArrayType(-cv.dimension); |
|
|
|
if (kind2.isBasicType() == null) |
|
|
|
cv.fixedType = kind2.getName(); |
|
|
|
else { |
|
|
|
cv.lowers.clear(); |
|
|
|
cv.lowers.add(kind2); |
|
|
|
cv.is2WordType = kind2.is2WordType(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@@ -343,17 +415,17 @@ public abstract class TypeData { |
|
|
|
else if (lowersSet.size() == 1) |
|
|
|
return (String)it.next(); |
|
|
|
else { |
|
|
|
CtClass cc = cp.get((String)it.next()); |
|
|
|
while (it.hasNext()) |
|
|
|
cc = commonSuperClassEx(cc, cp.get((String)it.next())); |
|
|
|
CtClass cc = cp.get((String)it.next()); |
|
|
|
while (it.hasNext()) |
|
|
|
cc = commonSuperClassEx(cc, cp.get((String)it.next())); |
|
|
|
|
|
|
|
if (cc.getSuperclass() == null || isObjectArray(cc)) |
|
|
|
cc = fixByUppers(scc, cp, new HashSet(), cc); |
|
|
|
if (cc.getSuperclass() == null || isObjectArray(cc)) |
|
|
|
cc = fixByUppers(scc, cp, new HashSet(), cc); |
|
|
|
|
|
|
|
if (cc.isArray()) |
|
|
|
return Descriptor.toJvmName(cc); |
|
|
|
else |
|
|
|
return cc.getName(); |
|
|
|
if (cc.isArray()) |
|
|
|
return Descriptor.toJvmName(cc); |
|
|
|
else |
|
|
|
return cc.getName(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -387,6 +459,18 @@ public abstract class TypeData { |
|
|
|
|
|
|
|
return type; |
|
|
|
} |
|
|
|
|
|
|
|
String toString2(HashSet hash) { |
|
|
|
hash.add(this); |
|
|
|
if (lowers.size() > 0) { |
|
|
|
TypeData e = (TypeData)lowers.get(0); |
|
|
|
if (e != null && !hash.contains(e)) { |
|
|
|
return e.toString2(hash); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return "?"; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@@ -522,14 +606,14 @@ public abstract class TypeData { |
|
|
|
} |
|
|
|
|
|
|
|
public void merge(TypeData t) { |
|
|
|
try { |
|
|
|
if (!t.isNullType()) |
|
|
|
element.merge(ArrayElement.make(t)); |
|
|
|
} |
|
|
|
catch (BadBytecode e) { |
|
|
|
// never happens |
|
|
|
throw new RuntimeException("fatal: " + e); |
|
|
|
} |
|
|
|
try { |
|
|
|
if (!t.isNullType()) |
|
|
|
element.merge(ArrayElement.make(t)); |
|
|
|
} |
|
|
|
catch (BadBytecode e) { |
|
|
|
// never happens |
|
|
|
throw new RuntimeException("fatal: " + e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public String getName() { |
|
|
@@ -555,10 +639,18 @@ public abstract class TypeData { |
|
|
|
element.setType(ArrayElement.typeName(s), cp); |
|
|
|
} |
|
|
|
|
|
|
|
protected TypeVar toTypeVar() { return element.toTypeVar(); } |
|
|
|
protected TypeVar toTypeVar(int dim) { return element.toTypeVar(dim + 1); } |
|
|
|
|
|
|
|
public TypeData getArrayType(int dim) throws NotFoundException { |
|
|
|
return element.getArrayType(dim + 1); |
|
|
|
} |
|
|
|
|
|
|
|
public int dfs(ArrayList order, int index, ClassPool cp) throws NotFoundException { |
|
|
|
return element.dfs(order, index, cp); |
|
|
|
return element.dfs(order, index, cp); |
|
|
|
} |
|
|
|
|
|
|
|
String toString2(HashSet set) { |
|
|
|
return "[" + element.toString2(set); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -585,14 +677,14 @@ public abstract class TypeData { |
|
|
|
} |
|
|
|
|
|
|
|
public void merge(TypeData t) { |
|
|
|
try { |
|
|
|
if (!t.isNullType()) |
|
|
|
array.merge(ArrayType.make(t)); |
|
|
|
} |
|
|
|
catch (BadBytecode e) { |
|
|
|
// never happens |
|
|
|
throw new RuntimeException("fatal: " + e); |
|
|
|
} |
|
|
|
try { |
|
|
|
if (!t.isNullType()) |
|
|
|
array.merge(ArrayType.make(t)); |
|
|
|
} |
|
|
|
catch (BadBytecode e) { |
|
|
|
// never happens |
|
|
|
throw new RuntimeException("fatal: " + e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public String getName() { |
|
|
@@ -625,10 +717,18 @@ public abstract class TypeData { |
|
|
|
array.setType(ArrayType.typeName(s), cp); |
|
|
|
} |
|
|
|
|
|
|
|
protected TypeVar toTypeVar() { return array.toTypeVar(); } |
|
|
|
protected TypeVar toTypeVar(int dim) { return array.toTypeVar(dim - 1); } |
|
|
|
|
|
|
|
public TypeData getArrayType(int dim) throws NotFoundException { |
|
|
|
return array.getArrayType(dim - 1); |
|
|
|
} |
|
|
|
|
|
|
|
public int dfs(ArrayList order, int index, ClassPool cp) throws NotFoundException { |
|
|
|
return array.dfs(order, index, cp); |
|
|
|
return array.dfs(order, index, cp); |
|
|
|
} |
|
|
|
|
|
|
|
String toString2(HashSet set) { |
|
|
|
return "*" + array.toString2(set); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -644,7 +744,7 @@ public abstract class TypeData { |
|
|
|
public boolean eq(TypeData d) { return type.eq(d); } |
|
|
|
public String getName() { return type.getName(); } |
|
|
|
|
|
|
|
protected TypeVar toTypeVar() { return null; } |
|
|
|
protected TypeVar toTypeVar(int dim) { return null; } |
|
|
|
public TypeData join() { return type.join(); } |
|
|
|
|
|
|
|
public void setType(String s, ClassPool cp) throws BadBytecode { |
|
|
@@ -666,6 +766,12 @@ public abstract class TypeData { |
|
|
|
else // if type == TypeTag.TOP |
|
|
|
throw new RuntimeException("not available"); |
|
|
|
} |
|
|
|
|
|
|
|
public TypeData getArrayType(int dim) throws NotFoundException { |
|
|
|
return type.getArrayType(dim); |
|
|
|
} |
|
|
|
|
|
|
|
String toString2(HashSet set) { return ""; } |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@@ -695,6 +801,45 @@ public abstract class TypeData { |
|
|
|
public boolean eq(TypeData d) { return name.equals(d.getName()); } |
|
|
|
|
|
|
|
public void setType(String typeName, ClassPool cp) throws BadBytecode {} |
|
|
|
|
|
|
|
public TypeData getArrayType(int dim) throws NotFoundException { |
|
|
|
if (dim == 0) |
|
|
|
return this; |
|
|
|
else if (dim > 0) { |
|
|
|
char[] dimType = new char[dim]; |
|
|
|
for (int i = 0; i < dim; i++) |
|
|
|
dimType[i] = '['; |
|
|
|
|
|
|
|
String elementType = getName(); |
|
|
|
if (elementType.charAt(0) != '[') |
|
|
|
elementType = "L" + elementType.replace('.', '/') + ";"; |
|
|
|
|
|
|
|
return new ClassName(new String(dimType) + elementType); |
|
|
|
} |
|
|
|
else { |
|
|
|
for (int i = 0; i < -dim; i++) |
|
|
|
if (name.charAt(i) != '[') |
|
|
|
throw new NotFoundException("no " + dim + " dimensional array type: " + getName()); |
|
|
|
|
|
|
|
char type = name.charAt(-dim); |
|
|
|
if (type == '[') |
|
|
|
return new ClassName(name.substring(-dim)); |
|
|
|
else if (type == 'L') |
|
|
|
return new ClassName(name.substring(-dim + 1, name.length() - 1).replace('/', '.')); |
|
|
|
else if (type == TypeTag.DOUBLE.decodedName) |
|
|
|
return TypeTag.DOUBLE; |
|
|
|
else if (type == TypeTag.FLOAT.decodedName) |
|
|
|
return TypeTag.FLOAT; |
|
|
|
else if (type == TypeTag.LONG.decodedName) |
|
|
|
return TypeTag.LONG; |
|
|
|
else |
|
|
|
return TypeTag.INTEGER; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
String toString2(HashSet set) { |
|
|
|
return name; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@@ -713,6 +858,8 @@ public abstract class TypeData { |
|
|
|
|
|
|
|
public boolean isNullType() { return true; } |
|
|
|
public int getTypeData(ConstPool cp) { return 0; } |
|
|
|
|
|
|
|
public TypeData getArrayType(int dim) { return this; } |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@@ -756,14 +903,14 @@ public abstract class TypeData { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
public String toString() { return "uninit:" + getName() + "@" + offset; } |
|
|
|
|
|
|
|
public int offset() { return offset; } |
|
|
|
|
|
|
|
public void constructorCalled(int offset) { |
|
|
|
if (offset == this.offset) |
|
|
|
initialized = true; |
|
|
|
} |
|
|
|
|
|
|
|
String toString2(HashSet set) { return getName() + "," + offset; } |
|
|
|
} |
|
|
|
|
|
|
|
public static class UninitThis extends UninitData { |
|
|
@@ -781,6 +928,6 @@ public abstract class TypeData { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
public String toString() { return "uninit:this"; } |
|
|
|
String toString2(HashSet set) { return "uninit:this"; } |
|
|
|
} |
|
|
|
} |