Browse Source

supported generic type signatures.


git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@348 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
tags/rel_3_17_1_ga
chiba 17 years ago
parent
commit
4752e2e80c

+ 9
- 0
src/main/javassist/CtBehavior.java View File

@@ -262,7 +262,16 @@ public abstract class CtBehavior extends CtMember {
* and the return type, <code>getSignature()</code> returns the
* same string (the return type of constructors is <code>void</code>).
*
* <p>Note that the returned string is not the type signature
* contained in the <code>SignatureAttirbute</code>. It is
* a descriptor. To obtain a type signature, call the following
* methods:
*
* <ul><pre>getMethodInfo().getAttribute(SignatureAttribute.tag)
* </pre></ul>
*
* @see javassist.bytecode.Descriptor
* @see javassist.bytecode.SignatureAttribute
*/
public String getSignature() {
return methodInfo.getDescriptor();

+ 11
- 0
src/main/javassist/CtField.java View File

@@ -285,6 +285,17 @@ public class CtField extends CtMember {
* Returns the character string representing the type of the field.
* If two fields have the same type,
* <code>getSignature()</code> returns the same string.
*
* <p>Note that the returned string is not the type signature
* contained in the <code>SignatureAttirbute</code>. It is
* a descriptor. To obtain a type signature, call the following
* methods:
*
* <ul><pre>getFieldInfo().getAttribute(SignatureAttribute.tag)
* </pre></ul>
*
* @see javassist.bytecode.Descriptor
* @see javassist.bytecode.SignatureAttribute
*/
public String getSignature() {
return fieldInfo.getDescriptor();

+ 9
- 7
src/main/javassist/bytecode/ClassFileWriter.java View File

@@ -68,7 +68,7 @@ public class ClassFileWriter {
out.println(Modifier.toString(AccessFlag.toModifier(acc))
+ " " + finfo.getName() + "\t"
+ finfo.getDescriptor());
printAttributes(finfo.getAttributes(), out, false);
printAttributes(finfo.getAttributes(), out, 'f');
}

out.println();
@@ -80,15 +80,15 @@ public class ClassFileWriter {
out.println(Modifier.toString(AccessFlag.toModifier(acc))
+ " " + minfo.getName() + "\t"
+ minfo.getDescriptor());
printAttributes(minfo.getAttributes(), out, false);
printAttributes(minfo.getAttributes(), out, 'm');
out.println();
}

out.println();
printAttributes(cf.getAttributes(), out, true);
printAttributes(cf.getAttributes(), out, 'c');
}

static void printAttributes(List list, PrintWriter out, boolean forClass) {
static void printAttributes(List list, PrintWriter out, char kind) {
if (list == null)
return;

@@ -104,7 +104,7 @@ public class ClassFileWriter {
+ ", " + ca.getExceptionTable().size()
+ " catch blocks");
out.println("<code attribute begin>");
printAttributes(ca.getAttributes(), out, forClass);
printAttributes(ca.getAttributes(), out, kind);
out.println("<code attribute end>");
}
else if (ai instanceof StackMapTable) {
@@ -118,10 +118,12 @@ public class ClassFileWriter {
out.println("signature: " + sig);
try {
String s;
if (forClass)
if (kind == 'c')
s = SignatureAttribute.toClassSignature(sig).toString();
else
else if (kind == 'm')
s = SignatureAttribute.toMethodSignature(sig).toString();
else
s = SignatureAttribute.toFieldSignature(sig).toString();

out.println(" " + s);
}

+ 22
- 0
src/main/javassist/bytecode/SignatureAttribute.java View File

@@ -489,6 +489,9 @@ public class SignatureAttribute extends AttributeInfo {
}
}

/**
* Type variables.
*/
public static class TypeVariable extends ObjectType {
String name;

@@ -516,6 +519,7 @@ public class SignatureAttribute extends AttributeInfo {
*
* @param sig the signature.
* @throws BadBytecode thrown when a syntactical error is found.
* @since 3.5
*/
public static ClassSignature toClassSignature(String sig) throws BadBytecode {
try {
@@ -531,6 +535,7 @@ public class SignatureAttribute extends AttributeInfo {
*
* @param sig the signature.
* @throws BadBytecode thrown when a syntactical error is found.
* @since 3.5
*/
public static MethodSignature toMethodSignature(String sig) throws BadBytecode {
try {
@@ -541,6 +546,23 @@ public class SignatureAttribute extends AttributeInfo {
}
}

/**
* Parses the given signature string as a field type signature.
*
* @param sig the signature string.
* @return the field type signature.
* @throws BadBytecode thrown when a syntactical error is found.
* @since 3.5
*/
public static ObjectType toFieldSignature(String sig) throws BadBytecode {
try {
return parseObjectType(sig, new Cursor(), false);
}
catch (IndexOutOfBoundsException e) {
throw error(sig);
}
}

private static ClassSignature parseSig(String sig)
throws BadBytecode, IndexOutOfBoundsException
{

+ 160
- 0
src/main/javassist/bytecode/stackmap/BasicBlock.java View File

@@ -0,0 +1,160 @@
package javassist.bytecode.stackmap;

import javassist.bytecode.*;

public class BasicBlock {
public int position;
public int stackTop;
public int[] stackTypes, localsTypes;
public Object[] stackData, localsData;

private BasicBlock(int pos) {
position = pos;
}

public void set(int st, int[] stypes, Object[] sdata, int[] ltypes, Object[] ldata)
throws BadBytecode
{
if (stackTypes == null) {
stackTop = st;
stackTypes = copy(stypes);
stackData = copy(sdata);
localsTypes = copy(ltypes);
localsData = copy(ldata);
}
else {
if (st != stackTop)
throw new BadBytecode("verification failure");

int n = ltypes.length;
for (int i = 0; i < n; i++)
if (ltypes[i] != localsTypes[i]) {
localsTypes[i] = StackAnalyzer.EMPTY;
localsData[i] = null;
}
else if (ltypes[i] == StackAnalyzer.OBJECT
&& !ldata[i].equals(localsData[i]))
; // localsData[i] = ??;
}
}

private static int[] copy(int[] a) {
int[] b = new int[a.length];
System.arraycopy(a, 0, b, 0, a.length);
return b;
}

private static Object[] copy(Object[] a) {
Object[] b = new Object[a.length];
System.arraycopy(a, 0, b, 0, a.length);
return b;
}

public static BasicBlock find(BasicBlock[] blocks, int pos) throws BadBytecode {
int n = blocks.length;
for (int i = 0; i < n; i++)
if (blocks[i].position == pos)
return blocks[i];

throw new BadBytecode("no basic block: " + pos);
}

public static BasicBlock[] makeBlocks(CodeIterator ci, ExceptionTable et)
throws BadBytecode
{
ci.begin();
int[] targets = new int[16];
int size = 0;
while (ci.hasNext()) {
int index = ci.next();
int op = ci.byteAt(index);
if ((Opcode.IFEQ <= op && op <= Opcode.IF_ACMPNE)
|| op == Opcode.IFNULL || op == Opcode.IFNONNULL)
targets = add(targets, size++, index + ci.s16bitAt(index + 1));
else if (Opcode.GOTO <= op && op <= Opcode.LOOKUPSWITCH)
switch (op) {
case Opcode.GOTO :
targets = add(targets, size++, index + ci.s16bitAt(index + 1));
break;
case Opcode.JSR :
case Opcode.RET :
throw new BadBytecode("jsr/ret at " + index);
case Opcode.TABLESWITCH : {
int pos = (index & ~3) + 4;
targets = add(targets, size++, index + ci.s32bitAt(pos)); // default offset
int low = ci.s32bitAt(pos + 4);
int high = ci.s32bitAt(pos + 8);
int p = pos + 12;
int n = p + (high - low + 1) * 4;
while (p < n) {
targets = add(targets, size++, index + ci.s32bitAt(p));
p += 4;
}
break; }
case Opcode.LOOKUPSWITCH : {
int pos = (index & ~3) + 4;
targets = add(targets, size++, index + ci.s32bitAt(pos)); // default offset
int p = pos + 8 + 4;
int n = p + ci.s32bitAt(pos + 4) * 8;
while (p < n) {
targets = add(targets, size++, index + ci.s32bitAt(p));
p += 8;
}
break; }
}
else if (op == Opcode.GOTO_W)
targets = add(targets, size++, index + ci.s32bitAt(index + 1));
else if (op == Opcode.JSR_W)
throw new BadBytecode("jsr_w at " + index);
}

if (et != null) {
int i = et.size();
while (--i >= 0) {
targets = add(targets, size++, et.startPc(i));
targets = add(targets, size++, et.handlerPc(i));
}
}

return trimArray(targets);
}

private static int[] add(int[] targets, int size, int value) {
if (targets.length >= size) {
int[] a = new int[size << 1];
System.arraycopy(targets, 0, a, 0, targets.length);
targets = a;
}

targets[size++] = value;
return targets;
}

private static BasicBlock[] trimArray(int[] targets) {
int size = targets.length;
java.util.Arrays.sort(targets);
int s = 0;
int t0 = 0;
for (int i = 0; i < size; i++) {
int t = targets[i];
if (t != t0) {
s++;
t0 = t;
}
}

BasicBlock[] results = new BasicBlock[s + 1];
results[0] = new BasicBlock(0);
t0 = 0;
for (int i = 0, j = 1; i < size; i++) {
int t = targets[i];
if (t != t0) {
BasicBlock b = new BasicBlock(t);
results[j++] = b;
t0 = t;
}
}

return results;
}
}

+ 846
- 0
src/main/javassist/bytecode/stackmap/StackAnalyzer.java View File

@@ -0,0 +1,846 @@
package javassist.bytecode.stackmap;

import javassist.bytecode.StackMapTable;
import javassist.bytecode.ByteArray;
import javassist.bytecode.Opcode;
import javassist.bytecode.ConstPool;
import javassist.bytecode.Descriptor;
import javassist.bytecode.BadBytecode;

public class StackAnalyzer {
private ConstPool cpool;
private int stackTop;
private int[] stackTypes;
private Object[] stackData; // String or Integer

private int[] localsTypes;
private boolean[] localsUpdated;
private Object[] localsData; // String or Integer

static final int EMPTY = -1;
static final int TOP = StackMapTable.TOP;
static final int INTEGER = StackMapTable.INTEGER;
static final int FLOAT = StackMapTable.FLOAT;
static final int DOUBLE = StackMapTable.DOUBLE;
static final int LONG = StackMapTable.LONG;
static final int NULL = StackMapTable.NULL;
static final int THIS = StackMapTable.THIS;
static final int OBJECT = StackMapTable.OBJECT;
static final int UNINIT = StackMapTable.UNINIT;

public StackAnalyzer(ConstPool cp, int maxStack, int maxLocals) {
cpool = cp;
stackTop = 0;
stackTypes = null;
localsTypes = null;
growStack(maxStack);
growLocals(maxLocals);
}

public void clearUpdatedFlags() {
boolean[] updated = localsUpdated;
for (int i = 0; i < updated.length; i++)
updated[i] = false;
}

public void growStack(int size) {
int oldSize;
int[] types = new int[size];
Object[] data = new Object[size];
if (stackTypes == null)
oldSize = 0;
else {
oldSize = stackTypes.length;
System.arraycopy(stackTypes, 0, types, 0, oldSize);
System.arraycopy(stackData, 0, data, 0, oldSize);
}

stackTypes = types;
stackData = data;
for (int i = oldSize; i < size; i++)
stackTypes[i] = EMPTY;
}

public void growLocals(int size) {
int oldSize;
int[] types = new int[size];
boolean[] updated = new boolean[size];
Object[] data = new Object[size];
if (localsTypes == null)
oldSize = 0;
else {
oldSize = localsTypes.length;
System.arraycopy(localsTypes, 0, types, 0, oldSize);
System.arraycopy(localsUpdated, 0, updated, 0, oldSize);
System.arraycopy(localsData, 0, data, 0, oldSize);
}

localsTypes = types;
localsUpdated = updated;
localsData = data;
for (int i = oldSize; i < size; i++)
localsTypes[i] = EMPTY;
}

public void pushType(int type, Object data) {
stackTypes[stackTop] = type;
stackData[stackTop++] = data;
}

/**
* @return the size of the instruction at POS.
*/
protected int doOpcode(int pos, byte[] code) throws BadBytecode {
int op = code[pos] & 0xff;
if (op < 96)
if (op < 54)
return doOpcode0_53(pos, code, op);
else
return doOpcode54_95(pos, code, op);
else
if (op < 148)
return doOpcode96_147(pos, code, op);
else
return doOpcode148_201(pos, code, op);
}

protected void visitBranch(int pos, byte[] code, int offset) {}
protected void visitGoto(int pos, byte[] code, int offset) {}
protected void visitTableSwitch(int pos, byte[] code, int n, int offsetPos, int defaultByte) {}
protected void visitLookupSwitch(int pos, byte[] code, int n, int pairsPos, int defaultByte) {}
protected void visitReturn(int pos, byte[] code) {}
protected void visitThrow(int pos, byte[] code) {}

/**
* Invoked when the visited instruction is jsr.
*/
protected void visitJSR(int pos, byte[] code) throws BadBytecode {
throwBadBytecode(pos, "jsr");
}

/**
* Invoked when the visited instruction is ret.
*/
protected void visitRET(int pos, byte[] code) throws BadBytecode {
throwBadBytecode(pos, "ret");
}

private void throwBadBytecode(int pos, String name) throws BadBytecode {
throw new BadBytecode(name + " at " + pos);
}

private int doOpcode0_53(int pos, byte[] code, int op) throws BadBytecode {
int[] stackTypes = this.stackTypes;
switch (op) {
case Opcode.NOP :
break;
case Opcode.ACONST_NULL :
stackTypes[stackTop++] = NULL;
break;
case Opcode.ICONST_M1 :
case Opcode.ICONST_0 :
case Opcode.ICONST_1 :
case Opcode.ICONST_2 :
case Opcode.ICONST_3 :
case Opcode.ICONST_4 :
case Opcode.ICONST_5 :
stackTypes[stackTop++] = INTEGER;
break;
case Opcode.LCONST_0 :
case Opcode.LCONST_1 :
stackTypes[stackTop++] = LONG;
stackTypes[stackTop++] = TOP;
break;
case Opcode.FCONST_0 :
case Opcode.FCONST_1 :
case Opcode.FCONST_2 :
stackTypes[stackTop++] = FLOAT;
break;
case Opcode.DCONST_0 :
case Opcode.DCONST_1 :
stackTypes[stackTop++] = DOUBLE;
stackTypes[stackTop++] = TOP;
break;
case Opcode.BIPUSH :
case Opcode.SIPUSH :
stackTypes[stackTop++] = INTEGER;
return op == Opcode.SIPUSH ? 3 : 2;
case Opcode.LDC :
doLDC(code[pos + 1] & 0xff);
return 2;
case Opcode.LDC_W :
case Opcode.LDC2_W :
doLDC(ByteArray.readU16bit(code, pos + 1));
return 3;
case Opcode.ILOAD :
return doXLOAD(INTEGER);
case Opcode.LLOAD :
return doXLOAD(LONG);
case Opcode.FLOAD :
return doXLOAD(FLOAT);
case Opcode.DLOAD :
return doXLOAD(DOUBLE);
case Opcode.ALOAD :
stackTypes[stackTop] = OBJECT;
stackData[stackTop++] = localsData[code[pos + 1] & 0xff];
return 2;
case Opcode.ILOAD_0 :
case Opcode.ILOAD_1 :
case Opcode.ILOAD_2 :
case Opcode.ILOAD_3 :
stackTypes[stackTop++] = INTEGER;
break;
case Opcode.LLOAD_0 :
case Opcode.LLOAD_1 :
case Opcode.LLOAD_2 :
case Opcode.LLOAD_3 :
stackTypes[stackTop++] = LONG;
stackTypes[stackTop++] = TOP;
break;
case Opcode.FLOAD_0 :
case Opcode.FLOAD_1 :
case Opcode.FLOAD_2 :
case Opcode.FLOAD_3 :
stackTypes[stackTop++] = FLOAT;
break;
case Opcode.DLOAD_0 :
case Opcode.DLOAD_1 :
case Opcode.DLOAD_2 :
case Opcode.DLOAD_3 :
stackTypes[stackTop++] = DOUBLE;
stackTypes[stackTop++] = TOP;
break;
case Opcode.ALOAD_0 :
case Opcode.ALOAD_1 :
case Opcode.ALOAD_2 :
case Opcode.ALOAD_3 :
stackTypes[stackTop] = OBJECT;
stackData[stackTop++] = localsData[op - Opcode.ALOAD_0];
break;
case Opcode.IALOAD :
stackTypes[--stackTop - 1] = INTEGER;
break;
case Opcode.LALOAD :
stackTypes[stackTop - 2] = LONG;
stackTypes[stackTop - 1] = TOP;
break;
case Opcode.FALOAD :
stackTypes[--stackTop - 1] = FLOAT;
break;
case Opcode.DALOAD :
stackTypes[stackTop - 2] = DOUBLE;
stackTypes[stackTop - 1] = TOP;
break;
case Opcode.AALOAD : {
int s = --stackTop - 1;
stackTypes[s] = OBJECT;
Object data = stackData[s];
if (data != null && data instanceof String)
stackData[s] = getDerefType((String)data);
else
throw new BadBytecode("bad AALOAD");

break; }
case Opcode.BALOAD :
case Opcode.CALOAD :
case Opcode.SALOAD :
stackTypes[--stackTop - 1] = INTEGER;
break;
default :
throw new RuntimeException("fatal");
}

return 1;
}

private void doLDC(int index) {
int[] stackTypes = this.stackTypes;
int tag = cpool.getTag(index);
if (tag == ConstPool.CONST_String) {
stackTypes[stackTop] = OBJECT;
stackData[stackTop++] = "java/lang/String";
}
else if (tag == ConstPool.CONST_Integer)
stackTypes[stackTop++] = INTEGER;
else if (tag == ConstPool.CONST_Float)
stackTypes[stackTop++] = FLOAT;
else if (tag == ConstPool.CONST_Long) {
stackTypes[stackTop++] = LONG;
stackTypes[stackTop++] = TOP;
}
else if (tag == ConstPool.CONST_Double) {
stackTypes[stackTop++] = DOUBLE;
stackTypes[stackTop++] = TOP;
}
else if (tag == ConstPool.CONST_Class) {
stackTypes[stackTop] = OBJECT;
stackData[stackTop++] = "java/lang/Class";
}
else
throw new RuntimeException("bad LDC: " + tag);
}

private int doXLOAD(int type) {
int[] stackTypes = this.stackTypes;
stackTypes[stackTop++] = type;
if (type == LONG || type == DOUBLE)
stackTypes[stackTop++] = TOP;

return 2;
}

private String getDerefType(String type) throws BadBytecode {
if (type.charAt(0) == '[') {
String type2 = type.substring(1);
if (type2.length() > 0) {
char c = type2.charAt(0);
if (c == '[')
return type2;
else if (c == 'L')
return type2.substring(1, type.length() - 2);
else
return type2;
}
}

throw new BadBytecode("bad array type for AALOAD: " + type);
}

private int doOpcode54_95(int pos, byte[] code, int op) {
int[] localsTypes = this.localsTypes;
int[] stackTypes = this.stackTypes;
switch (op) {
case Opcode.ISTORE :
return doXSTORE(pos, code, INTEGER);
case Opcode.LSTORE :
return doXSTORE(pos, code, LONG);
case Opcode.FSTORE :
return doXSTORE(pos, code, FLOAT);
case Opcode.DSTORE :
return doXSTORE(pos, code, DOUBLE);
case Opcode.ASTORE :
return doXSTORE(pos, code, OBJECT);
case Opcode.ISTORE_0 :
case Opcode.ISTORE_1 :
case Opcode.ISTORE_2 :
case Opcode.ISTORE_3 :
{ int var = op - Opcode.ISTORE_0;
localsTypes[var] = INTEGER;
localsUpdated[var] = true; }
stackTop--;
break;
case Opcode.LSTORE_0 :
case Opcode.LSTORE_1 :
case Opcode.LSTORE_2 :
case Opcode.LSTORE_3 :
{ int var = op - Opcode.LSTORE_0;
localsTypes[var] = LONG;
localsTypes[var + 1] = TOP;
localsUpdated[var] = true; }
stackTop -= 2;
break;
case Opcode.FSTORE_0 :
case Opcode.FSTORE_1 :
case Opcode.FSTORE_2 :
case Opcode.FSTORE_3 :
{ int var = op - Opcode.FSTORE_0;
localsTypes[var] = FLOAT;
localsUpdated[var] = true; }
stackTop--;
break;
case Opcode.DSTORE_0 :
case Opcode.DSTORE_1 :
case Opcode.DSTORE_2 :
case Opcode.DSTORE_3 :
{ int var = op - Opcode.DSTORE_0;
localsTypes[var] = DOUBLE;
localsTypes[var + 1] = TOP;
localsUpdated[var] = true; }
stackTop -= 2;
break;
case Opcode.ASTORE_0 :
case Opcode.ASTORE_1 :
case Opcode.ASTORE_2 :
case Opcode.ASTORE_3 :
{ int var = op - Opcode.ASTORE_0;
localsTypes[var] = OBJECT;
localsUpdated[var] = true;
localsData[var] = stackData[--stackTop]; }
break;
case Opcode.IASTORE :
case Opcode.LASTORE :
case Opcode.FASTORE :
case Opcode.DASTORE :
case Opcode.AASTORE :
case Opcode.BASTORE :
case Opcode.CASTORE :
case Opcode.SASTORE :
stackTop -= (op == Opcode.LASTORE || op == Opcode.DASTORE) ? 4 : 3;
break;
case Opcode.POP :
stackTop--;
break;
case Opcode.POP2 :
stackTop -= 2;
break;
case Opcode.DUP : {
int sp = stackTop;
stackTypes[sp] = stackTypes[sp - 1];
stackData[sp] = stackData[sp - 1];
stackTop = sp + 1;
break; }
case Opcode.DUP_X1 :
case Opcode.DUP_X2 : {
int len = op - Opcode.DUP_X1 + 2;
doDUP_XX(1, len);
int sp = stackTop;
stackTypes[sp - len] = stackTypes[sp];
stackData[sp - len] = stackData[sp];
stackTop = sp + 1;
break; }
case Opcode.DUP2 :
doDUP_XX(2, 2);
stackTop += 2;
break;
case Opcode.DUP2_X1 :
case Opcode.DUP2_X2 : {
int len = op - Opcode.DUP2_X1 + 3;
doDUP_XX(2, len);
Object[] stackData = this.stackData;
int sp = stackTop;
stackTypes[sp - len] = stackTypes[sp];
stackData[sp - len] = stackData[sp];
stackTypes[sp - len + 1] = stackTypes[sp + 1];
stackData[sp - len + 1] = stackData[sp + 1];
stackTop = sp + 2;
break; }
case Opcode.SWAP : {
Object[] stackData = this.stackData;
int sp = stackTop - 1;
int t = stackTypes[sp];
Object d = stackData[sp];
stackTypes[sp] = stackTypes[sp - 1];
stackData[sp] = stackData[sp - 1];
stackTypes[sp - 1] = t;
stackData[sp - 1] = d;
break; }
default :
throw new RuntimeException("fatal");
}

return 1;
}

private int doXSTORE(int pos, byte[] code, int type) {
int index = code[pos + 1] & 0xff;
return doXSTORE(index, type);
}

private int doXSTORE(int index, int type) {
stackTop--;
localsTypes[index] = type;
localsUpdated[index] = true;
if (type == LONG || type == DOUBLE) {
stackTop--;
localsTypes[index + 1] = TOP;
}
else if (type == OBJECT)
localsData[index] = stackData[stackTop];

return 2;
}

private void doDUP_XX(int delta, int len) {
int types[] = stackTypes;
Object data[] = stackData;
int sp = stackTop;
int end = sp - len;
while (sp > end) {
types[sp + delta] = types[sp];
data[sp + delta] = data[sp];
sp--;
}
}

private int doOpcode96_147(int pos, byte[] code, int op) {
if (op <= Opcode.LXOR) { // IADD...LXOR
stackTop -= Opcode.STACK_GROW[op];
return 1;
}

switch (op) {
case Opcode.IINC :
return 3;
case Opcode.I2L :
stackTypes[stackTop] = LONG;
stackTypes[stackTop - 1] = TOP;
stackTop++;
break;
case Opcode.I2F :
stackTypes[stackTop - 1] = FLOAT;
break;
case Opcode.I2D :
stackTypes[stackTop] = DOUBLE;
stackTypes[stackTop - 1] = TOP;
stackTop++;
break;
case Opcode.L2I :
stackTypes[--stackTop - 1] = INTEGER;
break;
case Opcode.L2F :
stackTypes[--stackTop - 1] = FLOAT;
break;
case Opcode.L2D :
stackTypes[stackTop - 1] = DOUBLE;
break;
case Opcode.F2I :
stackTypes[stackTop - 1] = INTEGER;
break;
case Opcode.F2L :
stackTypes[stackTop - 1] = TOP;
stackTypes[stackTop++] = LONG;
break;
case Opcode.F2D :
stackTypes[stackTop - 1] = TOP;
stackTypes[stackTop++] = DOUBLE;
break;
case Opcode.D2I :
stackTypes[--stackTop - 1] = INTEGER;
break;
case Opcode.D2L :
stackTypes[stackTop - 1] = LONG;
break;
case Opcode.D2F :
stackTypes[--stackTop - 1] = FLOAT;
break;
case Opcode.I2B :
case Opcode.I2C :
case Opcode.I2S :
break;
default :
throw new RuntimeException("fatal");
}

return 1;
}

private int doOpcode148_201(int pos, byte[] code, int op) throws BadBytecode {
switch (op) {
case Opcode.LCMP :
stackTypes[stackTop - 4] = INTEGER;
stackTop -= 3;
break;
case Opcode.FCMPL :
case Opcode.FCMPG :
stackTypes[--stackTop - 1] = INTEGER;
break;
case Opcode.DCMPL :
case Opcode.DCMPG :
stackTypes[stackTop - 4] = INTEGER;
stackTop -= 3;
break;
case Opcode.IFEQ :
case Opcode.IFNE :
case Opcode.IFLT :
case Opcode.IFGE :
case Opcode.IFGT :
case Opcode.IFLE :
stackTop--; // branch
visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
return 3;
case Opcode.IF_ICMPEQ :
case Opcode.IF_ICMPNE :
case Opcode.IF_ICMPLT :
case Opcode.IF_ICMPGE :
case Opcode.IF_ICMPGT :
case Opcode.IF_ICMPLE :
case Opcode.IF_ACMPEQ :
case Opcode.IF_ACMPNE :
stackTop -= 2; // branch
visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
return 3;
case Opcode.GOTO :
visitGoto(pos, code, ByteArray.readS16bit(code, pos + 1));
return 3; // branch
case Opcode.JSR :
stackTypes[stackTop++] = TOP; // not allowed?
visitJSR(pos, code);
return 3; // branch
case Opcode.RET :
visitRET(pos, code);
return 2; // not allowed?
case Opcode.TABLESWITCH : {
stackTop--; // branch
int pos2 = (pos & ~3) + 8;
int low = ByteArray.read32bit(code, pos2);
int high = ByteArray.read32bit(code, pos2 + 4);
int n = high - low + 1;
visitTableSwitch(pos, code, n, pos2 + 8, ByteArray.read32bit(code, pos2 - 4));
return n * 4 + 16 - (pos & 3); }
case Opcode.LOOKUPSWITCH : {
stackTop--; // branch
int pos2 = (pos & ~3) + 8;
int n = ByteArray.read32bit(code, pos2);
visitLookupSwitch(pos, code, n, pos2 + 4, ByteArray.read32bit(code, pos2 - 4));
return n * 8 + 12 - (pos & 3); }
case Opcode.IRETURN :
stackTop--;
visitReturn(pos, code);
break;
case Opcode.LRETURN :
stackTop -= 2;
visitReturn(pos, code);
break;
case Opcode.FRETURN :
stackTop--;
visitReturn(pos, code);
break;
case Opcode.DRETURN :
stackTop -= 2;
visitReturn(pos, code);
break;
case Opcode.ARETURN :
stackTop--;
visitReturn(pos, code);
break;
case Opcode.RETURN :
visitReturn(pos, code);
break;
case Opcode.GETSTATIC :
return doFieldAccess(pos, code, true);
case Opcode.PUTSTATIC :
return doFieldAccess(pos, code, false);
case Opcode.GETFIELD :
stackTop--;
return doFieldAccess(pos, code, true);
case Opcode.PUTFIELD :
stackTop--;
return doFieldAccess(pos, code, false);
case Opcode.INVOKEVIRTUAL :
case Opcode.INVOKESPECIAL :
return doInvokeMethod(pos, code, 1);
case Opcode.INVOKESTATIC :
return doInvokeMethod(pos, code, 0);
case Opcode.INVOKEINTERFACE :
return doInvokeIntfMethod(pos, code, 1);
case 186 :
throw new RuntimeException("bad opcode 186");
case Opcode.NEW : {
int i = ByteArray.readU16bit(code, pos + 1);
stackTypes[stackTop - 1] = UNINIT;
stackData[stackTop - 1] = new Integer(pos);
return 3; }
case Opcode.NEWARRAY :
return doNEWARRAY(pos, code);
case Opcode.ANEWARRAY : {
int i = ByteArray.readU16bit(code, pos + 1);
stackTypes[stackTop - 1] = OBJECT;
stackData[stackTop - 1]
= "[L" + cpool.getClassInfo(i).replace('.', '/') + ";";
return 3; }
case Opcode.ARRAYLENGTH :
stackTypes[stackTop - 1] = INTEGER;
break;
case Opcode.ATHROW :
stackTop--; // branch?
visitThrow(pos, code);
break;
case Opcode.CHECKCAST : {
int i = ByteArray.readU16bit(code, pos + 1);
stackData[stackTop - 1] = cpool.getClassInfo(i);
return 3; }
case Opcode.INSTANCEOF :
stackTypes[stackTop - 1] = INTEGER;
return 3;
case Opcode.MONITORENTER :
case Opcode.MONITOREXIT :
stackTop--;
break;
case Opcode.WIDE :
return doWIDE(pos, code);
case Opcode.MULTIANEWARRAY :
return doMultiANewArray(pos, code);
case Opcode.IFNULL :
case Opcode.IFNONNULL :
stackTop--; // branch
visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
return 3;
case Opcode.GOTO_W :
visitGoto(pos, code, ByteArray.read32bit(code, pos + 1));
return 5; // branch
case Opcode.JSR_W :
stackTypes[stackTop++] = TOP; // not allowed?
visitJSR(pos, code);
return 5;
}
return 1;
}

private int doWIDE(int pos, byte[] code) {
int op = code[pos + 1] & 0xff;
switch (op) {
case Opcode.ILOAD :
doXLOAD(INTEGER);
break;
case Opcode.LLOAD :
doXLOAD(LONG);
break;
case Opcode.FLOAD :
doXLOAD(FLOAT);
break;
case Opcode.DLOAD :
doXLOAD(DOUBLE);
break;
case Opcode.ALOAD :
stackTypes[stackTop] = OBJECT;
stackData[stackTop++] = localsData[ByteArray.readU16bit(code, pos)];
break;
case Opcode.ISTORE :
return doWIDE_STORE(pos, code, INTEGER);
case Opcode.LSTORE :
return doWIDE_STORE(pos, code, LONG);
case Opcode.FSTORE :
return doWIDE_STORE(pos, code, FLOAT);
case Opcode.DSTORE :
return doWIDE_STORE(pos, code, DOUBLE);
case Opcode.ASTORE :
return doWIDE_STORE(pos, code, OBJECT);
case Opcode.IINC :
return 6;
case Opcode.RET :
break;
default :
throw new RuntimeException("bad WIDE instruction: " + op);
}

return 4;
}

private int doWIDE_STORE(int pos, byte[] code, int type) {
int index = ByteArray.readU16bit(code, pos);
return doXSTORE(index, type);
}

private int doFieldAccess(int pos, byte[] code, boolean isGet) {
int index = ByteArray.readU16bit(code, pos + 1);
String desc = cpool.getFieldrefType(index);
if (isGet)
pushMemberType(desc);
else
stackTop -= Descriptor.dataSize(desc);

return 3;
}

private int doNEWARRAY(int pos, byte[] code) {
int s = stackTop - 1;
stackTypes[s] = OBJECT;
String type;
switch (code[pos + 1] & 0xff) {
case Opcode.T_BOOLEAN :
type = "[Z";
break;
case Opcode.T_CHAR :
type = "[C";
break;
case Opcode.T_FLOAT :
type = "[F";
break;
case Opcode.T_DOUBLE :
type = "[D";
break;
case Opcode.T_BYTE :
type = "[B";
break;
case Opcode.T_SHORT :
type = "[S";
break;
case Opcode.T_INT :
type = "[I";
break;
case Opcode.T_LONG :
type = "[J";
break;
default :
throw new RuntimeException("bad newarray");
}

stackData[s] = type;
return 2;
}

private int doMultiANewArray(int pos, byte[] code) {
int i = ByteArray.readU16bit(code, pos + 1);
int dim = code[pos + 3] & 0xff;
stackTop -= dim - 1;
String type = cpool.getClassInfo(i);
StringBuffer sbuf = new StringBuffer();
while (dim-- > 0)
sbuf.append('[');

sbuf.append('L').append(type.replace('.', '/')).append(';');
stackTypes[stackTop - 1] = OBJECT;
stackData[stackTop - 1] = sbuf.toString();
return 4;
}

private int doInvokeMethod(int pos, byte[] code, int targetSize) {
int i = ByteArray.readU16bit(code, pos + 1);
String desc = cpool.getMethodrefType(i);
stackTop -= Descriptor.paramSize(desc) + targetSize;
pushMemberType(desc);
return 3;
}

private int doInvokeIntfMethod(int pos, byte[] code, int targetSize) {
int i = ByteArray.readU16bit(code, pos + 1);
String desc = cpool.getInterfaceMethodrefType(i);
stackTop -= Descriptor.paramSize(desc) + targetSize;
pushMemberType(desc);
return 5;
}

private void pushMemberType(String descriptor) {
int top = 0;
if (descriptor.charAt(0) == '(') {
top = descriptor.indexOf(')') + 1;
if (top < 1)
throw new IndexOutOfBoundsException("bad descriptor: "
+ descriptor);
}

int[] types = stackTypes;
int index = stackTop;
switch (descriptor.charAt(top)) {
case '[' :
types[index] = OBJECT;
stackData[index] = descriptor.substring(top);
break;
case 'L' :
types[index] = OBJECT;
stackData[index] = descriptor.substring(top + 1,
descriptor.indexOf(';', top));
break;
case 'J' :
types[index] = LONG;
types[index + 1] = TOP;
stackTop += 2;
return;
case 'F' :
types[index] = FLOAT;
break;
case 'D' :
types[index] = DOUBLE;
types[index + 1] = TOP;
stackTop += 2;
return;
case 'V' :
return;
default : // C, B, S, I, Z
types[index] = INTEGER;
break;
}

stackTop++;
}
}

Loading…
Cancel
Save