aboutsummaryrefslogtreecommitdiff
path: root/src/main/javassist/bytecode/stackmap/Tracer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/javassist/bytecode/stackmap/Tracer.java')
-rw-r--r--src/main/javassist/bytecode/stackmap/Tracer.java172
1 files changed, 91 insertions, 81 deletions
diff --git a/src/main/javassist/bytecode/stackmap/Tracer.java b/src/main/javassist/bytecode/stackmap/Tracer.java
index 89e788d..6f99e5f 100644
--- a/src/main/javassist/bytecode/stackmap/Tracer.java
+++ b/src/main/javassist/bytecode/stackmap/Tracer.java
@@ -1,11 +1,12 @@
/*
* Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
+ * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ * the terms of the GNU Lesser General Public License Version 2.1 or later,
+ * or the Apache License Version 2.0.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
@@ -15,12 +16,12 @@
package javassist.bytecode.stackmap;
+import javassist.ClassPool;
+import javassist.bytecode.BadBytecode;
import javassist.bytecode.ByteArray;
-import javassist.bytecode.Opcode;
import javassist.bytecode.ConstPool;
import javassist.bytecode.Descriptor;
-import javassist.bytecode.BadBytecode;
-import javassist.ClassPool;
+import javassist.bytecode.Opcode;
/*
* A class for performing abstract interpretation.
@@ -30,7 +31,7 @@ import javassist.ClassPool;
public abstract class Tracer implements TypeTag {
protected ClassPool classPool;
protected ConstPool cpool;
- protected String returnType;
+ protected String returnType; // used as the type of ARETURN
protected int stackTop;
protected TypeData[] stackTypes;
@@ -42,39 +43,17 @@ public abstract class Tracer implements TypeTag {
cpool = cp;
returnType = retType;
stackTop = 0;
- stackTypes = new TypeData[maxStack];
- localsTypes = new TypeData[maxLocals];
+ stackTypes = TypeData.make(maxStack);
+ localsTypes = TypeData.make(maxLocals);
}
- public Tracer(Tracer t, boolean copyStack) {
+ public Tracer(Tracer t) {
classPool = t.classPool;
cpool = t.cpool;
returnType = t.returnType;
-
stackTop = t.stackTop;
- int size = t.stackTypes.length;
- stackTypes = new TypeData[size];
- if (copyStack)
- copyFrom(t.stackTop, t.stackTypes, stackTypes);
-
- int size2 = t.localsTypes.length;
- localsTypes = new TypeData[size2];
- copyFrom(size2, t.localsTypes, localsTypes);
- }
-
- protected static int copyFrom(int n, TypeData[] srcTypes, TypeData[] destTypes) {
- int k = -1;
- for (int i = 0; i < n; i++) {
- TypeData t = srcTypes[i];
- destTypes[i] = t == TOP ? TOP : t.getSelf();
- if (t != TOP)
- if (t.is2WordType())
- k = i + 1;
- else
- k = i;
- }
-
- return k + 1;
+ stackTypes = TypeData.make(t.stackTypes.length);
+ localsTypes = TypeData.make(t.localsTypes.length);
}
/**
@@ -90,19 +69,16 @@ public abstract class Tracer implements TypeTag {
protected int doOpcode(int pos, byte[] code) throws BadBytecode {
try {
int op = code[pos] & 0xff;
+ if (op < 54)
+ return doOpcode0_53(pos, code, op);
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);
+ return doOpcode54_95(pos, code, op);
+ if (op < 148)
+ return doOpcode96_147(pos, code, op);
+ return doOpcode148_201(pos, code, op);
}
catch (ArrayIndexOutOfBoundsException e) {
- throw new BadBytecode("inconsistent stack height " + e.getMessage());
+ throw new BadBytecode("inconsistent stack height " + e.getMessage(), e);
}
}
@@ -125,7 +101,7 @@ public abstract class Tracer implements TypeTag {
* @param pos the position of LOOKUPSWITCH
* @param code bytecode
* @param n the number of case labels
- * @param offsetPos the position of the table of pairs of a value and a branch target.
+ * @param pairsPos the position of the table of pairs of a value and a branch target.
* @param defaultOffset the offset to the default branch target.
*/
protected void visitLookupSwitch(int pos, byte[] code, int n,
@@ -254,11 +230,7 @@ public abstract class Tracer implements TypeTag {
case Opcode.AALOAD : {
int s = --stackTop - 1;
TypeData data = stackTypes[s];
- if (data == null || !data.isObjectType())
- throw new BadBytecode("bad AALOAD");
- else
- stackTypes[s] = new TypeData.ArrayElement(data);
-
+ stackTypes[s] = TypeData.ArrayElement.make(data);
break; }
case Opcode.BALOAD :
case Opcode.CALOAD :
@@ -308,14 +280,12 @@ public abstract class Tracer implements TypeTag {
return 2;
}
- private int doALOAD(int localVar) { // int localVar, TypeData type) {
+ private int doALOAD(int localVar) {
stackTypes[stackTop++] = localsTypes[localVar];
return 2;
}
private int doOpcode54_95(int pos, byte[] code, int op) throws BadBytecode {
- TypeData[] localsTypes = this.localsTypes;
- TypeData[] stackTypes = this.stackTypes;
switch (op) {
case Opcode.ISTORE :
return doXSTORE(pos, code, INTEGER);
@@ -375,9 +345,9 @@ public abstract class Tracer implements TypeTag {
stackTop -= (op == Opcode.LASTORE || op == Opcode.DASTORE) ? 4 : 3;
break;
case Opcode.AASTORE :
- TypeData.setType(stackTypes[stackTop - 1],
- TypeData.ArrayElement.getElementType(stackTypes[stackTop - 3].getName()),
- classPool);
+ TypeData.ArrayElement.aastore(stackTypes[stackTop - 3],
+ stackTypes[stackTop - 1],
+ classPool);
stackTop -= 3;
break;
case Opcode.BASTORE :
@@ -449,7 +419,7 @@ public abstract class Tracer implements TypeTag {
private int doASTORE(int index) {
stackTop--;
// implicit upcast might be done.
- localsTypes[index] = stackTypes[stackTop].copy();
+ localsTypes[index] = stackTypes[stackTop];
return 2;
}
@@ -474,16 +444,16 @@ public abstract class Tracer implements TypeTag {
// this does not call writeLocal().
return 3;
case Opcode.I2L :
- stackTypes[stackTop] = LONG;
- stackTypes[stackTop - 1] = TOP;
+ stackTypes[stackTop - 1] = LONG;
+ stackTypes[stackTop] = TOP;
stackTop++;
break;
case Opcode.I2F :
stackTypes[stackTop - 1] = FLOAT;
break;
case Opcode.I2D :
- stackTypes[stackTop] = DOUBLE;
- stackTypes[stackTop - 1] = TOP;
+ stackTypes[stackTop - 1] = DOUBLE;
+ stackTypes[stackTop] = TOP;
stackTop++;
break;
case Opcode.L2I :
@@ -493,24 +463,26 @@ public abstract class Tracer implements TypeTag {
stackTypes[--stackTop - 1] = FLOAT;
break;
case Opcode.L2D :
- stackTypes[stackTop - 1] = DOUBLE;
+ stackTypes[stackTop - 2] = DOUBLE;
break;
case Opcode.F2I :
stackTypes[stackTop - 1] = INTEGER;
break;
case Opcode.F2L :
- stackTypes[stackTop - 1] = TOP;
- stackTypes[stackTop++] = LONG;
+ stackTypes[stackTop - 1] = LONG;
+ stackTypes[stackTop] = TOP;
+ stackTop++;
break;
case Opcode.F2D :
- stackTypes[stackTop - 1] = TOP;
- stackTypes[stackTop++] = DOUBLE;
+ stackTypes[stackTop - 1] = DOUBLE;
+ stackTypes[stackTop] = TOP;
+ stackTop++;
break;
case Opcode.D2I :
stackTypes[--stackTop - 1] = INTEGER;
break;
case Opcode.D2L :
- stackTypes[stackTop - 1] = LONG;
+ stackTypes[stackTop - 2] = LONG;
break;
case Opcode.D2F :
stackTypes[--stackTop - 1] = FLOAT;
@@ -601,7 +573,7 @@ public abstract class Tracer implements TypeTag {
visitReturn(pos, code);
break;
case Opcode.ARETURN :
- TypeData.setType(stackTypes[--stackTop], returnType, classPool);
+ stackTypes[--stackTop].setType(returnType, classPool);
visitReturn(pos, code);
break;
case Opcode.RETURN :
@@ -622,8 +594,8 @@ public abstract class Tracer implements TypeTag {
return doInvokeMethod(pos, code, false);
case Opcode.INVOKEINTERFACE :
return doInvokeIntfMethod(pos, code);
- case 186 :
- throw new RuntimeException("bad opcode 186");
+ case Opcode.INVOKEDYNAMIC :
+ return doInvokeDynamic(pos, code);
case Opcode.NEW : {
int i = ByteArray.readU16bit(code, pos + 1);
stackTypes[stackTop++]
@@ -643,17 +615,21 @@ public abstract class Tracer implements TypeTag {
= new TypeData.ClassName(type);
return 3; }
case Opcode.ARRAYLENGTH :
- TypeData.setType(stackTypes[stackTop - 1], "[Ljava.lang.Object;", classPool);
+ stackTypes[stackTop - 1].setType("[Ljava.lang.Object;", classPool);
stackTypes[stackTop - 1] = INTEGER;
break;
case Opcode.ATHROW :
- TypeData.setType(stackTypes[--stackTop], "java.lang.Throwable", classPool);
+ stackTypes[--stackTop].setType("java.lang.Throwable", classPool);
visitThrow(pos, code);
break;
case Opcode.CHECKCAST : {
// TypeData.setType(stackTypes[stackTop - 1], "java.lang.Object", classPool);
int i = ByteArray.readU16bit(code, pos + 1);
- stackTypes[stackTop - 1] = new TypeData.ClassName(cpool.getClassInfo(i));
+ String type = cpool.getClassInfo(i);
+ if (type.charAt(0) == '[')
+ type = type.replace('.', '/'); // getClassInfo() may return "[java.lang.Object;".
+
+ stackTypes[stackTop - 1] = new TypeData.ClassName(type);
return 3; }
case Opcode.INSTANCEOF :
// TypeData.setType(stackTypes[stackTop - 1], "java.lang.Object", classPool);
@@ -747,9 +723,9 @@ public abstract class Tracer implements TypeTag {
stackTop -= Descriptor.dataSize(desc);
char c = desc.charAt(0);
if (c == 'L')
- TypeData.setType(stackTypes[stackTop], getFieldClassName(desc, 0), classPool);
+ stackTypes[stackTop].setType(getFieldClassName(desc, 0), classPool);
else if (c == '[')
- TypeData.setType(stackTypes[stackTop], desc, classPool);
+ stackTypes[stackTop].setType(desc, classPool);
setFieldTarget(notStatic, index);
return 3;
@@ -766,7 +742,7 @@ public abstract class Tracer implements TypeTag {
private void setFieldTarget(boolean notStatic, int index) throws BadBytecode {
if (notStatic) {
String className = cpool.getFieldrefClassName(index);
- TypeData.setType(stackTypes[--stackTop], className, classPool);
+ stackTypes[--stackTop].setType(className, classPool);
}
}
@@ -822,19 +798,54 @@ public abstract class Tracer implements TypeTag {
checkParamTypes(desc, 1);
if (notStatic) {
String className = cpool.getMethodrefClassName(i);
- TypeData.setType(stackTypes[--stackTop], className, classPool);
+ TypeData target = stackTypes[--stackTop];
+ if (target instanceof TypeData.UninitTypeVar && target.isUninit())
+ constructorCalled(target, ((TypeData.UninitTypeVar)target).offset());
+ else if (target instanceof TypeData.UninitData)
+ constructorCalled(target, ((TypeData.UninitData)target).offset());
+
+ target.setType(className, classPool);
}
pushMemberType(desc);
return 3;
}
+ /* This is a constructor call on an uninitialized object.
+ * Sets flags of other references to that object.
+ *
+ * @param offset the offset where the object has been created.
+ */
+ private void constructorCalled(TypeData target, int offset) {
+ target.constructorCalled(offset);
+ for (int i = 0; i < stackTop; i++)
+ stackTypes[i].constructorCalled(offset);
+
+ for (int i = 0; i < localsTypes.length; i++)
+ localsTypes[i].constructorCalled(offset);
+ }
+
private int doInvokeIntfMethod(int pos, byte[] code) throws BadBytecode {
int i = ByteArray.readU16bit(code, pos + 1);
String desc = cpool.getInterfaceMethodrefType(i);
checkParamTypes(desc, 1);
String className = cpool.getInterfaceMethodrefClassName(i);
- TypeData.setType(stackTypes[--stackTop], className, classPool);
+ stackTypes[--stackTop].setType(className, classPool);
+ pushMemberType(desc);
+ return 5;
+ }
+
+ private int doInvokeDynamic(int pos, byte[] code) throws BadBytecode {
+ int i = ByteArray.readU16bit(code, pos + 1);
+ String desc = cpool.getInvokeDynamicType(i);
+ checkParamTypes(desc, 1);
+
+ // assume CosntPool#REF_invokeStatic
+ /* TypeData target = stackTypes[--stackTop];
+ if (target instanceof TypeData.UninitTypeVar && target.isUninit())
+ constructorCalled((TypeData.UninitTypeVar)target);
+ */
+
pushMemberType(desc);
return 5;
}
@@ -911,10 +922,9 @@ public abstract class Tracer implements TypeTag {
stackTop--;
if (array)
- TypeData.setType(stackTypes[stackTop],
- desc.substring(i, k), classPool);
+ stackTypes[stackTop].setType(desc.substring(i, k), classPool);
else if (c == 'L')
- TypeData.setType(stackTypes[stackTop],
- desc.substring(i + 1, k - 1).replace('/', '.'), classPool);
+ stackTypes[stackTop].setType(desc.substring(i + 1, k - 1).replace('/', '.'),
+ classPool);
}
}