Переглянути джерело

snapshot. I am still working on stackmap support.


git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@360 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
tags/rel_3_17_1_ga
chiba 17 роки тому
джерело
коміт
1012230ca3

+ 1
- 1
src/main/javassist/bytecode/Opcode.java Переглянути файл

@@ -432,7 +432,7 @@ public interface Opcode {
0, // newarray, 188
0, // anewarray, 189
0, // arraylength, 190
0, // athrow, 191 stack is cleared
-1, // athrow, 191 stack is cleared
0, // checkcast, 192
0, // instanceof, 193
-1, // monitorenter, 194

+ 6
- 2
src/main/javassist/bytecode/StackMapTable.java Переглянути файл

@@ -509,9 +509,10 @@ public class StackMapTable extends AttributeInfo {
}

/**
* Writes a <code>append_frame</code>.
* Writes a <code>append_frame</code>. The number of the appended
* locals is specified by the length of <code>tags</code>.
*
* @param tag <code>locals[].tag</code>.
* @param tags <code>locals[].tag</code>.
* The length of this array must be
* either 1, 2, or 3.
* @param data <code>locals[].cpool_index</code>
@@ -531,6 +532,9 @@ public class StackMapTable extends AttributeInfo {

/**
* Writes a <code>full_frame</code>.
* <code>number_of_locals</code> and <code>number_of_stack_items</code>
* are specified by the the length of <code>localTags</code> and
* <code>stackTags</code>.
*
* @param localTags <code>locals[].tag</code>.
* @param localData <code>locals[].cpool_index</code>

+ 81
- 15
src/main/javassist/bytecode/stackmap/BasicBlock.java Переглянути файл

@@ -24,6 +24,16 @@ public class BasicBlock implements TypeTag, Comparable {
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 class BasicBlock implements TypeTag, Comparable {
*/
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 @@ public class BasicBlock implements TypeTag, Comparable {
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 class BasicBlock implements TypeTag, Comparable {
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 @@ public class BasicBlock implements TypeTag, Comparable {

/**
* 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 @@ public class BasicBlock implements TypeTag, Comparable {
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 @@ public class BasicBlock implements TypeTag, Comparable {
}
}

return trimArray(targets, end);
BasicBlock[] blocks = trimArray(targets, end);
markCatch(et, etOffset, blocks);
return blocks;
}

public int compareTo(Object obj) {
@@ -253,6 +299,28 @@ public class BasicBlock implements TypeTag, Comparable {
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 @@ public class BasicBlock implements TypeTag, Comparable {

int n = isStatic ? -1 : 0;
int i = 1;
do {
try {
i = descToTag(methodDesc, i, ++n, locals);
}
catch (StringIndexOutOfBoundsException e) {
throw new BadBytecode("bad method descriptor: "
+ methodDesc);
}
} while (i > 0);
try {
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);
}

numLocals = n;
localsTypes = locals;
position = 0;
inbound = 0;
}

private static int descToTag(String desc, int i,

+ 200
- 69
src/main/javassist/bytecode/stackmap/MapMaker.java Переглянути файл

@@ -22,23 +22,34 @@ import javassist.bytecode.*;
* 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();
ca.setAttribute(MapMaker.getMap(cp, minfo));
if (ca != null)
ca.setAttribute(MapMaker.getMap(cp, minfo));
}

cc.writeFile("tmp");
@@ -46,19 +57,25 @@ public class MapMaker extends Tracer {

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,21 +94,26 @@ public class MapMaker extends Tracer {
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)
return null;
if (blocks.length == 0 || blocks[0].inbound < 1)
return null;

boolean isStatic = (minfo.getAccessFlags() & AccessFlag.STATIC) != 0;
int maxStack = ca.getMaxStack();
@@ -102,7 +124,7 @@ public class MapMaker extends Tracer {
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;
}
@@ -111,19 +133,22 @@ public class MapMaker extends Tracer {
* Constructs a tracer.
*/
MapMaker(ClassPool classes, ConstPool cp,
int maxStack, int maxLocals, BasicBlock[] bb,
String retType, BasicBlock init) {
this(classes, cp, maxStack, maxLocals, bb, retType);
int maxStack, int maxLocals, BasicBlock[] bb,
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 @@ public class MapMaker extends Tracer {
* Runs an analyzer.
*/
void make(byte[] code, ExceptionTable et) throws BadBytecode {
blocks[0].version = iteration;
make(code, blocks[0]);
traceExceptions(code, et);
if (loopDetected) {
blocks[0].version = ++iteration;
make(code, blocks[0]);
}

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 @@ public class MapMaker extends Tracer {
{
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 @@ public class MapMaker extends Tracer {

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,7 +276,10 @@ public class MapMaker extends Tracer {
TypeData t = srcTypes[i];
destTypes[i] = t == null ? null : t.getSelf();
if (t != TOP)
k = i;
if (t.is2WordType())
k = i + 1;
else
k = i;
}

return k + 1;
@@ -255,13 +300,65 @@ public class MapMaker extends Tracer {
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;
evalExpected(cp, types.length, types);
if (types != null) // unless this block is dead code
evalExpected(cp, types.length, types);
}

private static void evalExpected(ClassPool cp, int n, TypeData[] types)
@@ -282,13 +379,18 @@ public class MapMaker extends Tracer {
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 @@ public class MapMaker extends Tracer {
}

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 @@ public class MapMaker extends Tracer {
return;
}
else if (0 < diffL && diffL <= 3) {
int[] tags = new int[diffL];
int[] data = new int[diffL];
fillStackMap(diffL, bb.numLocals - diffL, tags, data,
bb.localsTypes);
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 @@ public class MapMaker extends Tracer {
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 @@ public class MapMaker extends Tracer {
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 @@ public class MapMaker extends Tracer {
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 @@ public class MapMaker extends Tracer {
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 {

+ 24
- 7
src/main/javassist/bytecode/stackmap/Tracer.java Переглянути файл

@@ -36,6 +36,11 @@ public abstract class Tracer implements TypeTag {
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 @@ public abstract class Tracer implements TypeTag {
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 @@ public abstract class Tracer implements TypeTag {
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 @@ public abstract class Tracer implements TypeTag {

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 @@ public abstract class Tracer implements TypeTag {
stackTop--;
writeLocal(index);
localsTypes[index] = type;
if (type == LONG || type == DOUBLE) {
if (type.is2WordType()) {
stackTop--;
localsTypes[index + 1] = TOP;
}
@@ -433,7 +445,7 @@ public abstract class Tracer implements TypeTag {

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 @@ public abstract class Tracer implements TypeTag {
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;

+ 54
- 45
src/main/javassist/bytecode/stackmap/TypeData.java Переглянути файл

@@ -28,38 +28,9 @@ public abstract class TypeData {
* array type is a subtype of Cloneable and Serializable
*/

protected ArrayList equivalences;
protected TypeData() {}

protected TypeData() {
equivalences = new ArrayList();
equivalences.add(this);
}

public void merge(TypeData neighbor) {
if (this == neighbor)
return;

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 @@ public abstract class TypeData {
* @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 class TypeData {
*/
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 @@ public abstract class TypeData {
typeTag = tag;
}

public void merge(TypeData neighbor) {}

public boolean equals(Object obj) {
return this == obj;
}
@@ -119,7 +91,12 @@ public abstract class TypeData {
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 @@ public abstract class TypeData {
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 @@ public abstract class TypeData {
}

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 @@ public abstract class TypeData {
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 @@ public abstract class TypeData {

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 @@ public abstract class TypeData {
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 @@ public abstract class TypeData {
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 @@ public abstract class TypeData {
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;
}

Завантаження…
Відмінити
Зберегти