aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/javassist/bytecode/stackmap
diff options
context:
space:
mode:
authorShigeru Chiba <chibash@users.noreply.github.com>2016-07-30 23:04:07 +0900
committerGitHub <noreply@github.com>2016-07-30 23:04:07 +0900
commit65a8950b4f0718e273f42ca9832abd44ef731223 (patch)
treec01fd6094bbc2381fb3905efc343560deab0fd57 /src/main/javassist/bytecode/stackmap
parentd753903f73c547954bb9c11260f7a64ac3652633 (diff)
parentf795fcb1717fdde3e0c510b218b04abb55081202 (diff)
downloadjavassist-65a8950b4f0718e273f42ca9832abd44ef731223.tar.gz
javassist-65a8950b4f0718e273f42ca9832abd44ef731223.zip
Merge pull request #95 from jboss-javassist/master
merges bug fixes
Diffstat (limited to 'src/main/javassist/bytecode/stackmap')
-rw-r--r--src/main/javassist/bytecode/stackmap/TypeData.java329
-rw-r--r--src/main/javassist/bytecode/stackmap/TypeTag.java10
2 files changed, 243 insertions, 96 deletions
diff --git a/src/main/javassist/bytecode/stackmap/TypeData.java b/src/main/javassist/bytecode/stackmap/TypeData.java
index b83c9f69..206fd52a 100644
--- a/src/main/javassist/bytecode/stackmap/TypeData.java
+++ b/src/main/javassist/bytecode/stackmap/TypeData.java
@@ -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"; }
}
}
diff --git a/src/main/javassist/bytecode/stackmap/TypeTag.java b/src/main/javassist/bytecode/stackmap/TypeTag.java
index 2a90d147..6fcdb243 100644
--- a/src/main/javassist/bytecode/stackmap/TypeTag.java
+++ b/src/main/javassist/bytecode/stackmap/TypeTag.java
@@ -20,11 +20,11 @@ import javassist.bytecode.StackMapTable;
public interface TypeTag {
String TOP_TYPE = "*top*";
- TypeData TOP = new TypeData.BasicType(TOP_TYPE, StackMapTable.TOP);
- TypeData INTEGER = new TypeData.BasicType("int", StackMapTable.INTEGER);
- TypeData FLOAT = new TypeData.BasicType("float", StackMapTable.FLOAT);
- TypeData DOUBLE = new TypeData.BasicType("double", StackMapTable.DOUBLE);
- TypeData LONG = new TypeData.BasicType("long", StackMapTable.LONG);
+ TypeData.BasicType TOP = new TypeData.BasicType(TOP_TYPE, StackMapTable.TOP, ' ');
+ TypeData.BasicType INTEGER = new TypeData.BasicType("int", StackMapTable.INTEGER, 'I');
+ TypeData.BasicType FLOAT = new TypeData.BasicType("float", StackMapTable.FLOAT, 'F');
+ TypeData.BasicType DOUBLE = new TypeData.BasicType("double", StackMapTable.DOUBLE, 'D');
+ TypeData.BasicType LONG = new TypeData.BasicType("long", StackMapTable.LONG, 'J');
// and NULL, THIS, OBJECT, UNINIT
}