[jboss-cvs] javassist/src/main/javassist/bytecode/stackmap ...
Shigeru Chiba
chiba at is.titech.ac.jp
Thu Apr 26 10:58:16 EDT 2007
User: chiba
Date: 07/04/26 10:58:16
Modified: src/main/javassist/bytecode/stackmap BasicBlock.java
MapMaker.java TypeData.java Tracer.java
Log:
snapshot. I am still working on stackmap support.
Revision Changes Path
1.4 +81 -15 javassist/src/main/javassist/bytecode/stackmap/BasicBlock.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: BasicBlock.java
===================================================================
RCS file: /cvsroot/jboss/javassist/src/main/javassist/bytecode/stackmap/BasicBlock.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- BasicBlock.java 10 Apr 2007 16:32:32 -0000 1.3
+++ BasicBlock.java 26 Apr 2007 14:58:16 -0000 1.4
@@ -24,6 +24,16 @@
public int stackTop, numLocals;
public TypeData[] stackTypes, localsTypes;
+ /* The version number of the values of numLocals and localsTypes.
+ * These values are repeatedly updated while MapMaker#make()
+ * is running. This field represents when the values are recorded.
+ */
+ public int version;
+
+ /* a flag used by MapMaker#recordUsage()
+ */
+ public int[] localsUsage;
+
/* The number of the basic blocks from which a thread of control
* may reach this basic block. The number excludes the preceding
* block. Thus, if it is zero, a thread of control reaches
@@ -32,6 +42,22 @@
*/
public int inbound;
+ public static class Branch {
+ public Branch next;
+ public int target;
+ public int typeIndex; // exception type
+ public Branch(Branch next, int target, int type) {
+ this.next = next;
+ this.target = target;
+ this.typeIndex = type;
+ }
+ }
+
+ /* A list of catch clauses that a thread may jump
+ * from this block to.
+ */
+ public Branch catchBlocks;
+
/* public static void main(String[] args) throws Exception {
BasicBlock b = new BasicBlock(0);
b.initFirstBlock(8, 1, args[0], args[1], args[2].equals("static"), args[2].equals("const"));
@@ -44,9 +70,13 @@
stackTop = numLocals = 0;
stackTypes = localsTypes = null;
inbound = 1;
+ localsUsage = null;
+ catchBlocks = null;
}
- public boolean alreadySet() { return stackTypes != null; }
+ public boolean alreadySet(int ver) {
+ return stackTypes != null && ver == version;
+ }
/*
* Computes the correct value of numLocals.
@@ -56,8 +86,15 @@
public void resetNumLocals() {
if (localsTypes != null) {
int nl = numLocals;
- while (nl > 0 && localsTypes[nl - 1] == TypeTag.TOP)
+ while (nl > 0 && localsTypes[nl - 1] == TypeTag.TOP) {
+ if (nl > 1) {
+ TypeData td = localsTypes[nl - 2];
+ if (td == TypeTag.LONG || td == TypeTag.DOUBLE)
+ break;
+ }
+
--nl;
+ }
numLocals = nl;
}
@@ -119,9 +156,14 @@
/**
* Divides the given code fragment into basic blocks.
+ * It returns null if the given MethodInfo does not include
+ * a CodeAttribute.
*/
public static BasicBlock[] makeBlocks(MethodInfo minfo) throws BadBytecode {
CodeAttribute ca = minfo.getCodeAttribute();
+ if (ca == null)
+ return null;
+
CodeIterator ci = ca.iterator();
ConstPool pool = minfo.getConstPool();
BasicBlock[] blocks = makeBlocks(ci, 0, ci.getCodeLength(), ca.getExceptionTable(), 0, pool);
@@ -148,7 +190,9 @@
ci.begin();
ci.move(begin);
ArrayList targets = new ArrayList();
- targets.add(new BasicBlock(begin));
+ BasicBlock bb0 = new BasicBlock(begin);
+ bb0.inbound = 0; // the first block is not a branch target.
+ targets.add(bb0);
while (ci.hasNext()) {
int index = ci.next();
if (index >= end)
@@ -203,7 +247,9 @@
}
}
- return trimArray(targets, end);
+ BasicBlock[] blocks = trimArray(targets, end);
+ markCatch(et, etOffset, blocks);
+ return blocks;
}
public int compareTo(Object obj) {
@@ -253,6 +299,28 @@
return results;
}
+ private static void markCatch(ExceptionTable et, int etOffset,
+ BasicBlock[] blocks)
+ {
+ if (et == null)
+ return;
+
+ int nblocks = blocks.length;
+ int n = et.size();
+ for (int i = 0; i < n; i++) {
+ int start = et.startPc(i) + etOffset;
+ int end = et.endPc(i) + etOffset;
+ int handler = et.handlerPc(i) + etOffset;
+ int type = et.catchType(i);
+ for (int k = 0; k < nblocks; k++) {
+ BasicBlock bb = blocks[k];
+ int p = bb.position;
+ if (start <= p && p < end)
+ bb.catchBlocks = new Branch(bb.catchBlocks, handler, type);
+ }
+ }
+ }
+
/**
* Initializes the first block by the given method descriptor.
*
@@ -280,20 +348,18 @@
int n = isStatic ? -1 : 0;
int i = 1;
- do {
try {
- i = descToTag(methodDesc, i, ++n, locals);
+ while ((i = descToTag(methodDesc, i, ++n, locals)) > 0)
+ if (locals[n].is2WordType())
+ locals[++n] = TOP;
}
catch (StringIndexOutOfBoundsException e) {
throw new BadBytecode("bad method descriptor: "
+ methodDesc);
}
- } while (i > 0);
numLocals = n;
localsTypes = locals;
- position = 0;
- inbound = 0;
}
private static int descToTag(String desc, int i,
1.2 +200 -69 javassist/src/main/javassist/bytecode/stackmap/MapMaker.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: MapMaker.java
===================================================================
RCS file: /cvsroot/jboss/javassist/src/main/javassist/bytecode/stackmap/MapMaker.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- MapMaker.java 10 Apr 2007 16:32:32 -0000 1.1
+++ MapMaker.java 26 Apr 2007 14:58:16 -0000 1.2
@@ -22,22 +22,33 @@
* Stack map maker.
*/
public class MapMaker extends Tracer {
- private boolean moveon;
+ private boolean moveon; // used for returning another value from doOpcode().
+ private boolean loopDetected;
+ private int iteration;
private BasicBlock[] blocks;
public static void main(String[] args) throws Exception {
- if (args.length > 1) {
+ boolean useMain2 = args[0].equals("0");
+ if (useMain2 && args.length > 1) {
main2(args);
return;
}
+ for (int i = 0; i < args.length; i++)
+ main1(args[i]);
+ }
+
+ public static void main1(String className) throws Exception {
ClassPool cp = ClassPool.getDefault();
- javassist.CtClass cc = cp.get(args[0]);
+ //javassist.CtClass cc = cp.get(className);
+ javassist.CtClass cc = cp.makeClass(new java.io.FileInputStream(className));
+ System.out.println(className);
ClassFile cf = cc.getClassFile();
java.util.List minfos = cf.getMethods();
for (int i = 0; i < minfos.size(); i++) {
MethodInfo minfo = (MethodInfo)minfos.get(i);
CodeAttribute ca = minfo.getCodeAttribute();
+ if (ca != null)
ca.setAttribute(MapMaker.getMap(cp, minfo));
}
@@ -46,19 +57,25 @@
public static void main2(String[] args) throws Exception {
ClassPool cp = ClassPool.getDefault();
- javassist.CtClass cc = cp.get(args[0]);
+ //javassist.CtClass cc = cp.get(args[1]);
+ javassist.CtClass cc = cp.makeClass(new java.io.FileInputStream(args[1]));
+ MethodInfo minfo;
MapMaker mm;
- if (args[1].equals("_init_"))
- mm = makeMapMaker(cp, cc.getDeclaredConstructors()[0].getMethodInfo());
+ if (args[2].equals("_init_"))
+ // minfo = cc.getDeclaredConstructors()[0].getMethodInfo();
+ minfo = cc.getClassInitializer().getMethodInfo();
else
- mm = makeMapMaker(cp, cc.getDeclaredMethod(args[1]).getMethodInfo());
+ minfo = cc.getDeclaredMethod(args[2]).getMethodInfo();
+ mm = makeMapMaker(cp, minfo);
if (mm == null)
System.out.println("single basic block");
else {
BasicBlock[] blocks = mm.getBlocks();
for (int i = 0; i < blocks.length; i++)
System.out.println(blocks[i]);
+
+ StackMapTable smt = mm.toStackMap();
}
}
@@ -77,20 +94,25 @@
return mm.toStackMap();
}
- /*
+ /**
* Makes basic blocks with stack maps. If the number of the basic blocks
- * is one, this method returns null.
+ * is one, this method returns null. If the given method info does not
+ * include a code attribute, this method also returns null.
*/
public static MapMaker makeMapMaker(ClassPool classes, MethodInfo minfo)
throws BadBytecode
{
CodeAttribute ca = minfo.getCodeAttribute();
+ if (ca == null)
+ return null;
+
CodeIterator ci = ca.iterator();
ConstPool pool = minfo.getConstPool();
ExceptionTable et = ca.getExceptionTable();
BasicBlock[] blocks = BasicBlock.makeBlocks(ci, 0, ci.getCodeLength(),
et, 0, pool);
if (blocks.length < 2)
+ if (blocks.length == 0 || blocks[0].inbound < 1)
return null;
boolean isStatic = (minfo.getAccessFlags() & AccessFlag.STATIC) != 0;
@@ -102,7 +124,7 @@
isStatic, minfo.isConstructor());
String retType = BasicBlock.getRetType(desc);
MapMaker mm = new MapMaker(classes, pool, maxStack, maxLocals,
- blocks, retType, blocks[0]);
+ blocks, retType, blocks[0], 0);
mm.make(ca.getCode(), et);
return mm;
}
@@ -112,18 +134,21 @@
*/
MapMaker(ClassPool classes, ConstPool cp,
int maxStack, int maxLocals, BasicBlock[] bb,
- String retType, BasicBlock init) {
- this(classes, cp, maxStack, maxLocals, bb, retType);
+ String retType, BasicBlock init, int iterate)
+ {
+ this(classes, cp, maxStack, maxLocals, bb, retType, iterate);
TypeData[] srcTypes = init.localsTypes;
copyFrom(srcTypes.length, srcTypes, this.localsTypes);
}
private MapMaker(ClassPool classes, ConstPool cp,
int maxStack, int maxLocals, BasicBlock[] bb,
- String retType)
+ String retType, int iterateNo)
{
super(classes, cp, maxStack, maxLocals, retType);
blocks = bb;
+ loopDetected = false;
+ iteration = iterateNo;
}
public BasicBlock[] getBlocks() { return blocks; }
@@ -132,41 +157,18 @@
* Runs an analyzer.
*/
void make(byte[] code, ExceptionTable et) throws BadBytecode {
+ blocks[0].version = iteration;
+ make(code, blocks[0]);
+ if (loopDetected) {
+ blocks[0].version = ++iteration;
make(code, blocks[0]);
- traceExceptions(code, et);
+ }
+
int n = blocks.length;
for (int i = 0; i < n; i++)
evalExpected(blocks[i]);
}
- private void traceExceptions(byte[] code, ExceptionTable et)
- throws BadBytecode
- {
- int n = et.size();
- for (int i = 0; i < n; i++) {
- int startPc = et.startPc(i);
- int handlerPc = et.handlerPc(i);
- BasicBlock handler = BasicBlock.find(blocks, handlerPc);
- if (handler.alreadySet())
- continue;
-
- BasicBlock thrower = BasicBlock.find(blocks, startPc);
- TypeData[] srcTypes = thrower.localsTypes;
- copyFrom(srcTypes.length, srcTypes, this.localsTypes);
- int typeIndex = et.catchType(i);
- String type;
- if (typeIndex == 0)
- type = "java.lang.Throwable";
- else
- type = cpool.getClassInfo(typeIndex);
-
- stackTop = 1;
- stackTypes[0] = new TypeData.ClassName(type);
- recordStackMap(handler);
- make(code, handler);
- }
- }
-
// Phase 1: Code Tracing
private void make(byte[] code, BasicBlock bb)
@@ -174,6 +176,7 @@
{
int pos = bb.position;
int end = pos + bb.length;
+ traceExceptions(code, bb.catchBlocks);
moveon = true;
while (moveon && pos < end)
pos += doOpcode(pos, code);
@@ -186,16 +189,55 @@
private void nextBlock(int pos, byte[] code, int offset) throws BadBytecode {
BasicBlock bb = BasicBlock.find(blocks, pos + offset);
- if (bb.alreadySet()) {
+ if (bb.alreadySet(iteration)) {
mergeMap(stackTypes, bb.stackTypes);
mergeMap(localsTypes, bb.localsTypes);
+ mergeUsage(bb);
}
else {
recordStackMap(bb);
+ bb.version = iteration;
MapMaker maker = new MapMaker(classPool, cpool, stackTypes.length,
- localsTypes.length, blocks, returnType);
+ localsTypes.length, blocks, returnType, iteration);
maker.copyFrom(this);
maker.make(code, bb);
+ recordUsage(bb, maker);
+ if (maker.loopDetected)
+ this.loopDetected = true;
+ }
+ }
+
+ private void traceExceptions(byte[] code, BasicBlock.Branch branches)
+ throws BadBytecode
+ {
+ while (branches != null) {
+ int pos = branches.target;
+ BasicBlock bb = BasicBlock.find(blocks, pos);
+ if (bb.alreadySet(iteration)) {
+ mergeMap(localsTypes, bb.localsTypes);
+ mergeUsage(bb);
+ }
+ else {
+ recordStackMap(bb, branches.typeIndex);
+ bb.version = iteration;
+ MapMaker maker = new MapMaker(classPool, cpool, stackTypes.length,
+ localsTypes.length, blocks, returnType, iteration);
+
+ /* the following code is equivalent to maker.copyFrom(this)
+ * except stackTypes are not copied.
+ */
+ maker.stackTypes[0] = bb.stackTypes[0].getSelf();
+ maker.stackTop = 1;
+ TypeData[] srcTypes = this.localsTypes;
+ copyFrom(srcTypes.length, srcTypes, maker.localsTypes);
+
+ maker.make(code, bb);
+ recordUsage(bb, maker);
+ if (maker.loopDetected)
+ this.loopDetected = true;
+ }
+
+ branches = branches.next;
}
}
@@ -234,6 +276,9 @@
TypeData t = srcTypes[i];
destTypes[i] = t == null ? null : t.getSelf();
if (t != TOP)
+ if (t.is2WordType())
+ k = i + 1;
+ else
k = i;
}
@@ -255,12 +300,64 @@
target.setStackMap(st, tStackTypes, k, tLocalsTypes);
}
+ private void recordStackMap(BasicBlock target, int exceptionType)
+ throws BadBytecode
+ {
+ int n = localsTypes.length;
+ TypeData[] tLocalsTypes = new TypeData[n];
+ int k = copyFrom(n, localsTypes, tLocalsTypes);
+
+ String type;
+ if (exceptionType == 0)
+ type = "java.lang.Throwable";
+ else
+ type = cpool.getClassInfo(exceptionType);
+
+ TypeData[] tStackTypes = new TypeData[stackTypes.length];
+ tStackTypes[0] = new TypeData.ClassName(type);
+
+ target.setStackMap(1, tStackTypes, k, tLocalsTypes);
+ }
+
+ private void recordUsage(BasicBlock target, MapMaker next) {
+ int[] nextUsage = next.localsUsage;
+ TypeData[] tData = target.localsTypes;
+ int n = tData.length;
+ for (int i = blocks[0].numLocals; i < n; i++)
+ if (nextUsage[i] == READ)
+ readLocal(i);
+ else
+ tData[i] = TOP;
+
+ int[] usage = new int[nextUsage.length];
+ n = usage.length;
+ for (int i = 0; i < n; i++)
+ usage[i] = nextUsage[i];
+
+ target.localsUsage = usage;
+ }
+
+ private void mergeUsage(BasicBlock target) {
+ int[] usage = target.localsUsage;
+ if (usage == null) {
+ // detected a loop.
+ loopDetected = true;
+ }
+ else {
+ int n = usage.length;
+ for (int i = 0; i < n; i++)
+ if (usage[i] == READ)
+ readLocal(i);
+ }
+ }
+
// Phase 2
void evalExpected(BasicBlock target) throws BadBytecode {
ClassPool cp = classPool;
evalExpected(cp, target.stackTop, target.stackTypes);
TypeData[] types = target.localsTypes;
+ if (types != null) // unless this block is dead code
evalExpected(cp, types.length, types);
}
@@ -282,13 +379,18 @@
int n = blocks.length;
BasicBlock prev = blocks[0];
int offsetDelta = prev.length;
+ if (prev.inbound > 0) { // the first instruction is a branch target.
+ writer.sameFrame(0);
+ offsetDelta--;
+ }
+
for (int i = 1; i < n; i++) {
BasicBlock bb = blocks[i];
if (bb.inbound > 0) {
bb.resetNumLocals();
int diffL = stackMapDiff(prev.numLocals, prev.localsTypes,
bb.numLocals, bb.localsTypes);
- toStackMapBody(writer, bb, diffL, offsetDelta);
+ toStackMapBody(writer, bb, diffL, offsetDelta, prev);
offsetDelta = bb.length - 1;
prev = bb;
}
@@ -301,7 +403,7 @@
}
private void toStackMapBody(StackMapTable.Writer writer, BasicBlock bb,
- int diffL, int offsetDelta) {
+ int diffL, int offsetDelta, BasicBlock prev) {
// if diffL is -100, two TypeData arrays do not share
// any elements.
@@ -316,17 +418,16 @@
return;
}
else if (0 < diffL && diffL <= 3) {
- int[] tags = new int[diffL];
int[] data = new int[diffL];
- fillStackMap(diffL, bb.numLocals - diffL, tags, data,
+ int[] tags = fillStackMap(bb.numLocals - prev.numLocals,
+ prev.numLocals, data,
bb.localsTypes);
writer.appendFrame(offsetDelta, tags, data);
return;
}
}
else if (stackTop == 1 && diffL == 0) {
- TypeData[] types = bb.stackTypes;
- TypeData td = types[0];
+ TypeData td = bb.stackTypes[0];
if (td == TOP)
writer.sameLocals(offsetDelta, StackMapTable.TOP, 0);
else
@@ -334,30 +435,45 @@
td.getTypeData(cpool));
return;
}
+ else if (stackTop == 2 && diffL == 0) {
+ TypeData td = bb.stackTypes[0];
+ if (td != TOP && td.is2WordType()) {
+ // bb.stackTypes[1] must be TOP.
+ writer.sameLocals(offsetDelta, td.getTypeTag(),
+ td.getTypeData(cpool));
+ return;
+ }
+ }
- int[] stags = new int[stackTop];
int[] sdata = new int[stackTop];
- int nl = bb.numLocals;
- int[] ltags = new int[nl];
- int[] ldata = new int[nl];
- fillStackMap(stackTop, 0, stags, sdata, bb.stackTypes);
- fillStackMap(nl, 0, ltags, ldata, bb.localsTypes);
+ int[] stags = fillStackMap(stackTop, 0, sdata, bb.stackTypes);
+ int[] ldata = new int[bb.numLocals];
+ int[] ltags = fillStackMap(bb.numLocals, 0, ldata, bb.localsTypes);
writer.fullFrame(offsetDelta, ltags, ldata, stags, sdata);
}
- private void fillStackMap(int num, int offset, int[] tags, int[] data, TypeData[] types) {
+ private int[] fillStackMap(int num, int offset, int[] data, TypeData[] types) {
+ int realNum = diffSize(types, offset, offset + num);
ConstPool cp = cpool;
+ int[] tags = new int[realNum];
+ int j = 0;
for (int i = 0; i < num; i++) {
TypeData td = types[offset + i];
if (td == TOP) {
- tags[i] = StackMapTable.TOP;
- data[i] = 0;
+ tags[j] = StackMapTable.TOP;
+ data[j] = 0;
}
else {
- tags[i] = td.getTypeTag();
- data[i] = td.getTypeData(cp);
+ tags[j] = td.getTypeTag();
+ data[j] = td.getTypeData(cp);
+ if (td.is2WordType())
+ i++;
}
+
+ j++;
}
+
+ return tags;
}
private static int stackMapDiff(int oldTdLen, TypeData[] oldTd,
@@ -371,7 +487,10 @@
len = newTdLen;
if (stackMapEq(oldTd, newTd, len))
- return diff;
+ if (diff > 0)
+ return diffSize(newTd, len, newTdLen);
+ else
+ return -diffSize(oldTd, len, oldTdLen);
else
return -100;
}
@@ -379,7 +498,7 @@
private static boolean stackMapEq(TypeData[] oldTd, TypeData[] newTd, int len) {
for (int i = 0; i < len; i++) {
TypeData td = oldTd[i];
- if (td == TOP) {
+ if (td == TOP) { // the next element to LONG/DOUBLE is TOP.
if (newTd[i] != TOP)
return false;
}
@@ -391,6 +510,18 @@
return true;
}
+ private static int diffSize(TypeData[] types, int offset, int len) {
+ int num = 0;
+ while (offset < len) {
+ TypeData td = types[offset++];
+ num++;
+ if (td != TOP && td.is2WordType())
+ offset++;
+ }
+
+ return num;
+ }
+
// Branch actions
protected void visitBranch(int pos, byte[] code, int offset) throws BadBytecode {
1.2 +54 -45 javassist/src/main/javassist/bytecode/stackmap/TypeData.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: TypeData.java
===================================================================
RCS file: /cvsroot/jboss/javassist/src/main/javassist/bytecode/stackmap/TypeData.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- TypeData.java 10 Apr 2007 16:32:32 -0000 1.1
+++ TypeData.java 26 Apr 2007 14:58:16 -0000 1.2
@@ -28,38 +28,9 @@
* array type is a subtype of Cloneable and Serializable
*/
- protected ArrayList equivalences;
-
- protected TypeData() {
- equivalences = new ArrayList();
- equivalences.add(this);
- }
-
- public void merge(TypeData neighbor) {
- if (this == neighbor)
- return;
+ protected TypeData() {}
- ArrayList list = equivalences;
- ArrayList list2 = neighbor.equivalences;
- if (list == list2)
- return;
-
- int n = list2.size();
- for (int i = 0; i < n; i++) {
- TypeData td = (TypeData)list2.get(i);
- add(list, td);
- td.equivalences = list;
- }
- }
-
- private static void add(ArrayList list, TypeData td) {
- int n = list.size();
- for (int i = 0; i < n; i++)
- if (list.get(i) == td)
- return;
-
- list.add(td);
- }
+ public abstract void merge(TypeData neighbor);
/**
* Sets the type name of this object type. If the given type name is
@@ -69,7 +40,7 @@
* @param className dot-separated name unless the type is an array type.
*/
static void setType(TypeData td, String className, ClassPool cp) throws BadBytecode {
- if (td == null)
+ if (td == TypeTag.TOP)
throw new BadBytecode("unset variable");
else
td.setType(className, cp);
@@ -90,14 +61,13 @@
*/
public abstract TypeData copy();
- public boolean isBasicType() { return false; }
- public boolean isObjectType() { return false; }
+ public abstract boolean isObjectType();
+ public boolean is2WordType() { return false; }
public boolean isNullType() { return false; }
public abstract String getName() throws BadBytecode;
protected abstract void setType(String s, ClassPool cp) throws BadBytecode;
public abstract void evalExpectedType(ClassPool cp) throws BadBytecode;
- protected abstract boolean hasExpectedType(); // only TypeName can return true.
public abstract String getExpected() throws BadBytecode;
/**
@@ -112,6 +82,8 @@
typeTag = tag;
}
+ public void merge(TypeData neighbor) {}
+
public boolean equals(Object obj) {
return this == obj;
}
@@ -119,7 +91,12 @@
public int getTypeTag() { return typeTag; }
public int getTypeData(ConstPool cp) { return 0; }
- public boolean isBasicType() { return true; }
+ public boolean isObjectType() { return false; }
+
+ public boolean is2WordType() {
+ return typeTag == StackMapTable.LONG
+ || typeTag == StackMapTable.DOUBLE;
+ }
public TypeData copy() {
return this;
@@ -135,10 +112,6 @@
return name;
}
- protected boolean hasExpectedType() {
- return false;
- }
-
protected void setType(String s, ClassPool cp) throws BadBytecode {
throw new BadBytecode("conflict:" + name + " and " + s);
}
@@ -147,16 +120,50 @@
}
protected static abstract class TypeName extends TypeData {
+ protected ArrayList equivalences;
+
private String expectedName;
private CtClass cache;
private boolean evalDone;
protected TypeName() {
+ equivalences = new ArrayList();
+ equivalences.add(this);
expectedName = null;
cache = null;
evalDone = false;
}
+ public void merge(TypeData neighbor) {
+ if (this == neighbor)
+ return;
+
+ if (!(neighbor instanceof TypeName))
+ return; // neighbor might be UninitData
+
+ TypeName neighbor2 = (TypeName)neighbor;
+ ArrayList list = equivalences;
+ ArrayList list2 = neighbor2.equivalences;
+ if (list == list2)
+ return;
+
+ int n = list2.size();
+ for (int i = 0; i < n; i++) {
+ TypeName tn = (TypeName)list2.get(i);
+ add(list, tn);
+ tn.equivalences = list;
+ }
+ }
+
+ private static void add(ArrayList list, TypeData td) {
+ int n = list.size();
+ for (int i = 0; i < n; i++)
+ if (list.get(i) == td)
+ return;
+
+ list.add(td);
+ }
+
/* NullType overrides this method.
*/
public int getTypeTag() { return StackMapTable.OBJECT; }
@@ -206,7 +213,7 @@
int n = equiv.size();
for (int i = 0; i < n; i++) {
TypeData td = (TypeData)equiv.get(i);
- if (td.hasExpectedType()) {
+ if (td instanceof TypeName) {
TypeName tn = (TypeName)td;
if (update(cp, name, tn.expectedName))
name = tn.expectedName;
@@ -218,7 +225,7 @@
for (int i = 0; i < n; i++) {
TypeData td = (TypeData)equiv.get(i);
- if (td.hasExpectedType()) {
+ if (td instanceof TypeName) {
TypeName tn = (TypeName)td;
tn.expectedName = name;
tn.cache = null;
@@ -241,7 +248,7 @@
return origName;
}
- protected boolean hasExpectedType() { return true; }
+ protected boolean isTypeName() { return true; }
private boolean update(ClassPool cp, String oldName, String typeName) throws BadBytecode {
if (typeName == null)
@@ -410,6 +417,8 @@
this.initialized = false;
}
+ public void merge(TypeData neighbor) {}
+
public int getTypeTag() { return StackMapTable.UNINIT; }
public int getTypeData(ConstPool cp) { return offset; }
@@ -433,14 +442,14 @@
return new ClassName(className);
}
+ public boolean isObjectType() { return true; }
+
protected void setType(String typeName, ClassPool cp) throws BadBytecode {
initialized = true;
}
public void evalExpectedType(ClassPool cp) throws BadBytecode {}
- protected boolean hasExpectedType() { return false; }
-
public String getName() {
return className;
}
1.2 +24 -7 javassist/src/main/javassist/bytecode/stackmap/Tracer.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: Tracer.java
===================================================================
RCS file: /cvsroot/jboss/javassist/src/main/javassist/bytecode/stackmap/Tracer.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- Tracer.java 10 Apr 2007 16:32:32 -0000 1.1
+++ Tracer.java 26 Apr 2007 14:58:16 -0000 1.2
@@ -36,6 +36,11 @@
protected TypeData[] stackTypes;
protected TypeData[] localsTypes;
+ static final int UNKNOWN = 0;
+ static final int READ = 1;
+ static final int UPDATED = 2;
+ protected int[] localsUsage;
+
public Tracer(ClassPool classes, ConstPool cp, int maxStack, int maxLocals,
String retType) {
classPool = classes;
@@ -44,15 +49,22 @@
stackTop = 0;
stackTypes = new TypeData[maxStack];
localsTypes = new TypeData[maxLocals];
+ localsUsage = new int[maxLocals];
}
/* If the type is LONG or DOUBLE,
* the next local variable is also read.
* IINC (or WIDE IINC) calls only readLocal() but it does not call writeLocal().
*/
- private void readLocal(int reg) {}
+ protected final void readLocal(int reg) {
+ if (localsUsage[reg] == UNKNOWN)
+ localsUsage[reg] = READ;
+ }
- private void writeLocal(int reg) {}
+ protected final void writeLocal(int reg) {
+ if (localsUsage[reg] == UNKNOWN)
+ localsUsage[reg] = UPDATED;
+ }
/**
* Does abstract interpretation on the given bytecode instruction.
@@ -230,7 +242,7 @@
case Opcode.AALOAD : {
int s = --stackTop - 1;
TypeData data = stackTypes[s];
- if (data == null || data.isBasicType())
+ if (data == null || !data.isObjectType())
throw new BadBytecode("bad AALOAD");
else
stackTypes[s] = new TypeData.ArrayElement(data);
@@ -278,7 +290,7 @@
private int doXLOAD(int localVar, TypeData type) {
stackTypes[stackTop++] = type;
- if (type == LONG || type == DOUBLE)
+ if (type.is2WordType())
stackTypes[stackTop++] = TOP;
readLocal(localVar);
@@ -414,7 +426,7 @@
stackTop--;
writeLocal(index);
localsTypes[index] = type;
- if (type == LONG || type == DOUBLE) {
+ if (type.is2WordType()) {
stackTop--;
localsTypes[index + 1] = TOP;
}
@@ -433,7 +445,7 @@
private void doDUP_XX(int delta, int len) {
TypeData types[] = stackTypes;
- int sp = stackTop;
+ int sp = stackTop - 1;
int end = sp - len;
while (sp > end) {
types[sp + delta] = types[sp];
@@ -614,8 +626,13 @@
case Opcode.ANEWARRAY : {
int i = ByteArray.readU16bit(code, pos + 1);
String type = cpool.getClassInfo(i).replace('.', '/');
+ if (type.charAt(0) == '[')
+ type = "[" + type;
+ else
+ type = "[L" + type + ";";
+
stackTypes[stackTop - 1]
- = new TypeData.ClassName("[L" + type + ";");
+ = new TypeData.ClassName(type);
return 3; }
case Opcode.ARRAYLENGTH :
stackTypes[stackTop - 1] = INTEGER;
More information about the jboss-cvs-commits
mailing list