com.feilong.lib.javassist.bytecode.stackmap.Tracer Maven / Gradle / Ivy
/*
* Javassist, a Java-bytecode translator toolkit.
* 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,
* 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
* for the specific language governing rights and limitations under the
* License.
*/
package com.feilong.lib.javassist.bytecode.stackmap;
import com.feilong.lib.javassist.ClassPool;
import com.feilong.lib.javassist.bytecode.BadBytecode;
import com.feilong.lib.javassist.bytecode.ByteArray;
import com.feilong.lib.javassist.bytecode.ConstPool;
import com.feilong.lib.javassist.bytecode.Descriptor;
import com.feilong.lib.javassist.bytecode.Opcode;
/*
* A class for performing abstract interpretation.
* See also MapMaker class.
*/
public abstract class Tracer implements TypeTag{
protected ClassPool classPool;
protected ConstPool cpool;
protected String returnType; // used as the type of ARETURN
protected int stackTop;
protected TypeData[] stackTypes;
protected TypeData[] localsTypes;
public Tracer(ClassPool classes, ConstPool cp, int maxStack, int maxLocals, String retType){
classPool = classes;
cpool = cp;
returnType = retType;
stackTop = 0;
stackTypes = TypeData.make(maxStack);
localsTypes = TypeData.make(maxLocals);
}
public Tracer(Tracer t){
classPool = t.classPool;
cpool = t.cpool;
returnType = t.returnType;
stackTop = t.stackTop;
stackTypes = TypeData.make(t.stackTypes.length);
localsTypes = TypeData.make(t.localsTypes.length);
}
/**
* Does abstract interpretation on the given bytecode instruction.
* It records whether or not a local variable (i.e. register) is accessed.
* If the instruction requires that a local variable or
* a stack element has a more specific type, this method updates the
* type of it.
*
* @param pos
* the position of the instruction.
* @return the size of the instruction at POS.
*/
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){
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(), e);
}
}
protected void visitBranch(int pos,byte[] code,int offset) throws BadBytecode{
}
protected void visitGoto(int pos,byte[] code,int offset) throws BadBytecode{
}
protected void visitReturn(int pos,byte[] code) throws BadBytecode{
}
protected void visitThrow(int pos,byte[] code) throws BadBytecode{
}
/**
* @param pos
* the position of TABLESWITCH
* @param code
* bytecode
* @param n
* the number of case labels
* @param offsetPos
* the position of the branch-target table.
* @param defaultOffset
* the offset to the default branch target.
*/
protected void visitTableSwitch(int pos,byte[] code,int n,int offsetPos,int defaultOffset) throws BadBytecode{
}
/**
* @param pos
* the position of LOOKUPSWITCH
* @param code
* bytecode
* @param n
* the number of case labels
* @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,int pairsPos,int defaultOffset) throws BadBytecode{
}
/**
* Invoked when the visited instruction is jsr.
* Java6 or later does not allow using RET.
*/
protected void visitJSR(int pos,byte[] code) throws BadBytecode{
/*
* Since JSR pushes a return address onto the operand stack,
* the stack map at the entry point of a subroutine is
* stackTypes resulting after executing the following code:
*
* stackTypes[stackTop++] = TOP;
*/
}
/**
* Invoked when the visited instruction is ret or wide ret.
* Java6 or later does not allow using RET.
*/
protected void visitRET(int pos,byte[] code) throws BadBytecode{
}
private int doOpcode0_53(int pos,byte[] code,int op) throws BadBytecode{
int reg;
TypeData[] stackTypes = this.stackTypes;
switch (op) {
case Opcode.NOP:
break;
case Opcode.ACONST_NULL:
stackTypes[stackTop++] = new TypeData.NullType();
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, code, pos);
case Opcode.LLOAD:
return doXLOAD(LONG, code, pos);
case Opcode.FLOAD:
return doXLOAD(FLOAT, code, pos);
case Opcode.DLOAD:
return doXLOAD(DOUBLE, code, pos);
case Opcode.ALOAD:
return doALOAD(code[pos + 1] & 0xff);
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:
reg = op - Opcode.ALOAD_0;
stackTypes[stackTop++] = localsTypes[reg];
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;
TypeData data = stackTypes[s];
stackTypes[s] = TypeData.ArrayElement.make(data);
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){
TypeData[] stackTypes = this.stackTypes;
int tag = cpool.getTag(index);
if (tag == ConstPool.CONST_String){
stackTypes[stackTop++] = new TypeData.ClassName("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++] = new TypeData.ClassName("java.lang.Class");
}else{
throw new RuntimeException("bad LDC: " + tag);
}
}
private int doXLOAD(TypeData type,byte[] code,int pos){
int localVar = code[pos + 1] & 0xff;
return doXLOAD(localVar, type);
}
private int doXLOAD(int localVar,TypeData type){
stackTypes[stackTop++] = type;
if (type.is2WordType()){
stackTypes[stackTop++] = TOP;
}
return 2;
}
private int doALOAD(int localVar){
stackTypes[stackTop++] = localsTypes[localVar];
return 2;
}
private int doOpcode54_95(int pos,byte[] code,int op) throws BadBytecode{
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 doASTORE(code[pos + 1] & 0xff);
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;
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;
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;
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;
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;
doASTORE(var);
break;
}
case Opcode.IASTORE:
case Opcode.LASTORE:
case Opcode.FASTORE:
case Opcode.DASTORE:
stackTop -= (op == Opcode.LASTORE || op == Opcode.DASTORE) ? 4 : 3;
break;
case Opcode.AASTORE:
TypeData.aastore(stackTypes[stackTop - 3], stackTypes[stackTop - 1], classPool);
stackTop -= 3;
break;
case Opcode.BASTORE:
case Opcode.CASTORE:
case Opcode.SASTORE:
stackTop -= 3;
break;
case Opcode.POP:
stackTop--;
break;
case Opcode.POP2:
stackTop -= 2;
break;
case Opcode.DUP:{
int sp = stackTop;
stackTypes[sp] = stackTypes[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];
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);
int sp = stackTop;
stackTypes[sp - len] = stackTypes[sp];
stackTypes[sp - len + 1] = stackTypes[sp + 1];
stackTop = sp + 2;
break;
}
case Opcode.SWAP:{
int sp = stackTop - 1;
TypeData t = stackTypes[sp];
stackTypes[sp] = stackTypes[sp - 1];
stackTypes[sp - 1] = t;
break;
}
default:
throw new RuntimeException("fatal");
}
return 1;
}
private int doXSTORE(int pos,byte[] code,TypeData type){
int index = code[pos + 1] & 0xff;
return doXSTORE(index, type);
}
private int doXSTORE(int index,TypeData type){
stackTop--;
localsTypes[index] = type;
if (type.is2WordType()){
stackTop--;
localsTypes[index + 1] = TOP;
}
return 2;
}
private int doASTORE(int index){
stackTop--;
// implicit upcast might be done.
localsTypes[index] = stackTypes[stackTop];
return 2;
}
private void doDUP_XX(int delta,int len){
TypeData types[] = stackTypes;
int sp = stackTop - 1;
int end = sp - len;
while (sp > end){
types[sp + delta] = types[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:
// this does not call writeLocal().
return 3;
case Opcode.I2L:
stackTypes[stackTop - 1] = LONG;
stackTypes[stackTop] = TOP;
stackTop++;
break;
case Opcode.I2F:
stackTypes[stackTop - 1] = FLOAT;
break;
case Opcode.I2D:
stackTypes[stackTop - 1] = DOUBLE;
stackTypes[stackTop] = TOP;
stackTop++;
break;
case Opcode.L2I:
stackTypes[--stackTop - 1] = INTEGER;
break;
case Opcode.L2F:
stackTypes[--stackTop - 1] = FLOAT;
break;
case Opcode.L2D:
stackTypes[stackTop - 2] = DOUBLE;
break;
case Opcode.F2I:
stackTypes[stackTop - 1] = INTEGER;
break;
case Opcode.F2L:
stackTypes[stackTop - 1] = LONG;
stackTypes[stackTop] = TOP;
stackTop++;
break;
case Opcode.F2D:
stackTypes[stackTop - 1] = DOUBLE;
stackTypes[stackTop] = TOP;
stackTop++;
break;
case Opcode.D2I:
stackTypes[--stackTop - 1] = INTEGER;
break;
case Opcode.D2L:
stackTypes[stackTop - 2] = 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:
visitJSR(pos, code);
return 3; // branch
case Opcode.RET:
visitRET(pos, code);
return 2;
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:
stackTypes[--stackTop].setType(returnType, classPool);
visitReturn(pos, code);
break;
case Opcode.RETURN:
visitReturn(pos, code);
break;
case Opcode.GETSTATIC:
return doGetField(pos, code, false);
case Opcode.PUTSTATIC:
return doPutField(pos, code, false);
case Opcode.GETFIELD:
return doGetField(pos, code, true);
case Opcode.PUTFIELD:
return doPutField(pos, code, true);
case Opcode.INVOKEVIRTUAL:
case Opcode.INVOKESPECIAL:
return doInvokeMethod(pos, code, true);
case Opcode.INVOKESTATIC:
return doInvokeMethod(pos, code, false);
case Opcode.INVOKEINTERFACE:
return doInvokeIntfMethod(pos, code);
case Opcode.INVOKEDYNAMIC:
return doInvokeDynamic(pos, code);
case Opcode.NEW:{
int i = ByteArray.readU16bit(code, pos + 1);
stackTypes[stackTop++] = new TypeData.UninitData(pos, cpool.getClassInfo(i));
return 3;
}
case Opcode.NEWARRAY:
return doNEWARRAY(pos, code);
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(type);
return 3;
}
case Opcode.ARRAYLENGTH:
stackTypes[stackTop - 1].setType("[Ljava.lang.Object;", classPool);
stackTypes[stackTop - 1] = INTEGER;
break;
case Opcode.ATHROW:
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);
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);
stackTypes[stackTop - 1] = INTEGER;
return 3;
case Opcode.MONITORENTER:
case Opcode.MONITOREXIT:
stackTop--;
// TypeData.setType(stackTypes[stackTop], "java.lang.Object", classPool);
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:
visitJSR(pos, code);
return 5;
}
return 1;
}
private int doWIDE(int pos,byte[] code) throws BadBytecode{
int op = code[pos + 1] & 0xff;
switch (op) {
case Opcode.ILOAD:
doWIDE_XLOAD(pos, code, INTEGER);
break;
case Opcode.LLOAD:
doWIDE_XLOAD(pos, code, LONG);
break;
case Opcode.FLOAD:
doWIDE_XLOAD(pos, code, FLOAT);
break;
case Opcode.DLOAD:
doWIDE_XLOAD(pos, code, DOUBLE);
break;
case Opcode.ALOAD:{
int index = ByteArray.readU16bit(code, pos + 2);
doALOAD(index);
break;
}
case Opcode.ISTORE:
doWIDE_STORE(pos, code, INTEGER);
break;
case Opcode.LSTORE:
doWIDE_STORE(pos, code, LONG);
break;
case Opcode.FSTORE:
doWIDE_STORE(pos, code, FLOAT);
break;
case Opcode.DSTORE:
doWIDE_STORE(pos, code, DOUBLE);
break;
case Opcode.ASTORE:{
int index = ByteArray.readU16bit(code, pos + 2);
doASTORE(index);
break;
}
case Opcode.IINC:
// this does not call writeLocal().
return 6;
case Opcode.RET:
visitRET(pos, code);
break;
default:
throw new RuntimeException("bad WIDE instruction: " + op);
}
return 4;
}
private void doWIDE_XLOAD(int pos,byte[] code,TypeData type){
int index = ByteArray.readU16bit(code, pos + 2);
doXLOAD(index, type);
}
private void doWIDE_STORE(int pos,byte[] code,TypeData type){
int index = ByteArray.readU16bit(code, pos + 2);
doXSTORE(index, type);
}
private int doPutField(int pos,byte[] code,boolean notStatic) throws BadBytecode{
int index = ByteArray.readU16bit(code, pos + 1);
String desc = cpool.getFieldrefType(index);
stackTop -= Descriptor.dataSize(desc);
char c = desc.charAt(0);
if (c == 'L'){
stackTypes[stackTop].setType(getFieldClassName(desc, 0), classPool);
}else if (c == '['){
stackTypes[stackTop].setType(desc, classPool);
}
setFieldTarget(notStatic, index);
return 3;
}
private int doGetField(int pos,byte[] code,boolean notStatic) throws BadBytecode{
int index = ByteArray.readU16bit(code, pos + 1);
setFieldTarget(notStatic, index);
String desc = cpool.getFieldrefType(index);
pushMemberType(desc);
return 3;
}
private void setFieldTarget(boolean notStatic,int index) throws BadBytecode{
if (notStatic){
String className = cpool.getFieldrefClassName(index);
stackTypes[--stackTop].setType(className, classPool);
}
}
private int doNEWARRAY(int pos,byte[] code){
int s = stackTop - 1;
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");
}
stackTypes[s] = new TypeData.ClassName(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).replace('.', '/');
stackTypes[stackTop - 1] = new TypeData.ClassName(type);
return 4;
}
private int doInvokeMethod(int pos,byte[] code,boolean notStatic) throws BadBytecode{
int i = ByteArray.readU16bit(code, pos + 1);
String desc = cpool.getMethodrefType(i);
checkParamTypes(desc, 1);
if (notStatic){
String className = cpool.getMethodrefClassName(i);
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 (TypeData localsType : localsTypes){
localsType.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);
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;
}
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);
}
}
TypeData[] types = stackTypes;
int index = stackTop;
switch (descriptor.charAt(top)) {
case '[':
types[index] = new TypeData.ClassName(descriptor.substring(top));
break;
case 'L':
types[index] = new TypeData.ClassName(getFieldClassName(descriptor, 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++;
}
private static String getFieldClassName(String desc,int index){
return desc.substring(index + 1, desc.length() - 1).replace('/', '.');
}
private void checkParamTypes(String desc,int i) throws BadBytecode{
char c = desc.charAt(i);
if (c == ')'){
return;
}
int k = i;
boolean array = false;
while (c == '['){
array = true;
c = desc.charAt(++k);
}
if (c == 'L'){
k = desc.indexOf(';', k) + 1;
if (k <= 0){
throw new IndexOutOfBoundsException("bad descriptor");
}
}else{
k++;
}
checkParamTypes(desc, k);
if (!array && (c == 'J' || c == 'D')){
stackTop -= 2;
}else{
stackTop--;
}
if (array){
stackTypes[stackTop].setType(desc.substring(i, k), classPool);
}else if (c == 'L'){
stackTypes[stackTop].setType(desc.substring(i + 1, k - 1).replace('/', '.'), classPool);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy