diff options
Diffstat (limited to 'src/main/javassist/bytecode/stackmap/Tracer.java')
-rw-r--r-- | src/main/javassist/bytecode/stackmap/Tracer.java | 172 |
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); } } |