|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
package jdk.internal.org.objectweb.asm.tree.analysis; |
|
|
|
import java.util.List; |
|
import jdk.internal.org.objectweb.asm.ConstantDynamic; |
|
import jdk.internal.org.objectweb.asm.Handle; |
|
import jdk.internal.org.objectweb.asm.Opcodes; |
|
import jdk.internal.org.objectweb.asm.Type; |
|
import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode; |
|
import jdk.internal.org.objectweb.asm.tree.FieldInsnNode; |
|
import jdk.internal.org.objectweb.asm.tree.IntInsnNode; |
|
import jdk.internal.org.objectweb.asm.tree.InvokeDynamicInsnNode; |
|
import jdk.internal.org.objectweb.asm.tree.LdcInsnNode; |
|
import jdk.internal.org.objectweb.asm.tree.MethodInsnNode; |
|
import jdk.internal.org.objectweb.asm.tree.MultiANewArrayInsnNode; |
|
import jdk.internal.org.objectweb.asm.tree.TypeInsnNode; |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class BasicInterpreter extends Interpreter<BasicValue> implements Opcodes { |
|
|
|
|
|
|
|
|
|
*/ |
|
public static final Type NULL_TYPE = Type.getObjectType("null"); |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public BasicInterpreter() { |
|
super( ASM8); |
|
if (getClass() != BasicInterpreter.class) { |
|
throw new IllegalStateException(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected BasicInterpreter(final int api) { |
|
super(api); |
|
} |
|
|
|
@Override |
|
public BasicValue newValue(final Type type) { |
|
if (type == null) { |
|
return BasicValue.UNINITIALIZED_VALUE; |
|
} |
|
switch (type.getSort()) { |
|
case Type.VOID: |
|
return null; |
|
case Type.BOOLEAN: |
|
case Type.CHAR: |
|
case Type.BYTE: |
|
case Type.SHORT: |
|
case Type.INT: |
|
return BasicValue.INT_VALUE; |
|
case Type.FLOAT: |
|
return BasicValue.FLOAT_VALUE; |
|
case Type.LONG: |
|
return BasicValue.LONG_VALUE; |
|
case Type.DOUBLE: |
|
return BasicValue.DOUBLE_VALUE; |
|
case Type.ARRAY: |
|
case Type.OBJECT: |
|
return BasicValue.REFERENCE_VALUE; |
|
default: |
|
throw new AssertionError(); |
|
} |
|
} |
|
|
|
@Override |
|
public BasicValue newOperation(final AbstractInsnNode insn) throws AnalyzerException { |
|
switch (insn.getOpcode()) { |
|
case ACONST_NULL: |
|
return newValue(NULL_TYPE); |
|
case ICONST_M1: |
|
case ICONST_0: |
|
case ICONST_1: |
|
case ICONST_2: |
|
case ICONST_3: |
|
case ICONST_4: |
|
case ICONST_5: |
|
return BasicValue.INT_VALUE; |
|
case LCONST_0: |
|
case LCONST_1: |
|
return BasicValue.LONG_VALUE; |
|
case FCONST_0: |
|
case FCONST_1: |
|
case FCONST_2: |
|
return BasicValue.FLOAT_VALUE; |
|
case DCONST_0: |
|
case DCONST_1: |
|
return BasicValue.DOUBLE_VALUE; |
|
case BIPUSH: |
|
case SIPUSH: |
|
return BasicValue.INT_VALUE; |
|
case LDC: |
|
Object value = ((LdcInsnNode) insn).cst; |
|
if (value instanceof Integer) { |
|
return BasicValue.INT_VALUE; |
|
} else if (value instanceof Float) { |
|
return BasicValue.FLOAT_VALUE; |
|
} else if (value instanceof Long) { |
|
return BasicValue.LONG_VALUE; |
|
} else if (value instanceof Double) { |
|
return BasicValue.DOUBLE_VALUE; |
|
} else if (value instanceof String) { |
|
return newValue(Type.getObjectType("java/lang/String")); |
|
} else if (value instanceof Type) { |
|
int sort = ((Type) value).getSort(); |
|
if (sort == Type.OBJECT || sort == Type.ARRAY) { |
|
return newValue(Type.getObjectType("java/lang/Class")); |
|
} else if (sort == Type.METHOD) { |
|
return newValue(Type.getObjectType("java/lang/invoke/MethodType")); |
|
} else { |
|
throw new AnalyzerException(insn, "Illegal LDC value " + value); |
|
} |
|
} else if (value instanceof Handle) { |
|
return newValue(Type.getObjectType("java/lang/invoke/MethodHandle")); |
|
} else if (value instanceof ConstantDynamic) { |
|
return newValue(Type.getType(((ConstantDynamic) value).getDescriptor())); |
|
} else { |
|
throw new AnalyzerException(insn, "Illegal LDC value " + value); |
|
} |
|
case JSR: |
|
return BasicValue.RETURNADDRESS_VALUE; |
|
case GETSTATIC: |
|
return newValue(Type.getType(((FieldInsnNode) insn).desc)); |
|
case NEW: |
|
return newValue(Type.getObjectType(((TypeInsnNode) insn).desc)); |
|
default: |
|
throw new AssertionError(); |
|
} |
|
} |
|
|
|
@Override |
|
public BasicValue copyOperation(final AbstractInsnNode insn, final BasicValue value) |
|
throws AnalyzerException { |
|
return value; |
|
} |
|
|
|
@Override |
|
public BasicValue unaryOperation(final AbstractInsnNode insn, final BasicValue value) |
|
throws AnalyzerException { |
|
switch (insn.getOpcode()) { |
|
case INEG: |
|
case IINC: |
|
case L2I: |
|
case F2I: |
|
case D2I: |
|
case I2B: |
|
case I2C: |
|
case I2S: |
|
return BasicValue.INT_VALUE; |
|
case FNEG: |
|
case I2F: |
|
case L2F: |
|
case D2F: |
|
return BasicValue.FLOAT_VALUE; |
|
case LNEG: |
|
case I2L: |
|
case F2L: |
|
case D2L: |
|
return BasicValue.LONG_VALUE; |
|
case DNEG: |
|
case I2D: |
|
case L2D: |
|
case F2D: |
|
return BasicValue.DOUBLE_VALUE; |
|
case IFEQ: |
|
case IFNE: |
|
case IFLT: |
|
case IFGE: |
|
case IFGT: |
|
case IFLE: |
|
case TABLESWITCH: |
|
case LOOKUPSWITCH: |
|
case IRETURN: |
|
case LRETURN: |
|
case FRETURN: |
|
case DRETURN: |
|
case ARETURN: |
|
case PUTSTATIC: |
|
return null; |
|
case GETFIELD: |
|
return newValue(Type.getType(((FieldInsnNode) insn).desc)); |
|
case NEWARRAY: |
|
switch (((IntInsnNode) insn).operand) { |
|
case T_BOOLEAN: |
|
return newValue(Type.getType("[Z")); |
|
case T_CHAR: |
|
return newValue(Type.getType("[C")); |
|
case T_BYTE: |
|
return newValue(Type.getType("[B")); |
|
case T_SHORT: |
|
return newValue(Type.getType("[S")); |
|
case T_INT: |
|
return newValue(Type.getType("[I")); |
|
case T_FLOAT: |
|
return newValue(Type.getType("[F")); |
|
case T_DOUBLE: |
|
return newValue(Type.getType("[D")); |
|
case T_LONG: |
|
return newValue(Type.getType("[J")); |
|
default: |
|
break; |
|
} |
|
throw new AnalyzerException(insn, "Invalid array type"); |
|
case ANEWARRAY: |
|
return newValue(Type.getType("[" + Type.getObjectType(((TypeInsnNode) insn).desc))); |
|
case ARRAYLENGTH: |
|
return BasicValue.INT_VALUE; |
|
case ATHROW: |
|
return null; |
|
case CHECKCAST: |
|
return newValue(Type.getObjectType(((TypeInsnNode) insn).desc)); |
|
case INSTANCEOF: |
|
return BasicValue.INT_VALUE; |
|
case MONITORENTER: |
|
case MONITOREXIT: |
|
case IFNULL: |
|
case IFNONNULL: |
|
return null; |
|
default: |
|
throw new AssertionError(); |
|
} |
|
} |
|
|
|
@Override |
|
public BasicValue binaryOperation( |
|
final AbstractInsnNode insn, final BasicValue value1, final BasicValue value2) |
|
throws AnalyzerException { |
|
switch (insn.getOpcode()) { |
|
case IALOAD: |
|
case BALOAD: |
|
case CALOAD: |
|
case SALOAD: |
|
case IADD: |
|
case ISUB: |
|
case IMUL: |
|
case IDIV: |
|
case IREM: |
|
case ISHL: |
|
case ISHR: |
|
case IUSHR: |
|
case IAND: |
|
case IOR: |
|
case IXOR: |
|
return BasicValue.INT_VALUE; |
|
case FALOAD: |
|
case FADD: |
|
case FSUB: |
|
case FMUL: |
|
case FDIV: |
|
case FREM: |
|
return BasicValue.FLOAT_VALUE; |
|
case LALOAD: |
|
case LADD: |
|
case LSUB: |
|
case LMUL: |
|
case LDIV: |
|
case LREM: |
|
case LSHL: |
|
case LSHR: |
|
case LUSHR: |
|
case LAND: |
|
case LOR: |
|
case LXOR: |
|
return BasicValue.LONG_VALUE; |
|
case DALOAD: |
|
case DADD: |
|
case DSUB: |
|
case DMUL: |
|
case DDIV: |
|
case DREM: |
|
return BasicValue.DOUBLE_VALUE; |
|
case AALOAD: |
|
return BasicValue.REFERENCE_VALUE; |
|
case LCMP: |
|
case FCMPL: |
|
case FCMPG: |
|
case DCMPL: |
|
case DCMPG: |
|
return BasicValue.INT_VALUE; |
|
case IF_ICMPEQ: |
|
case IF_ICMPNE: |
|
case IF_ICMPLT: |
|
case IF_ICMPGE: |
|
case IF_ICMPGT: |
|
case IF_ICMPLE: |
|
case IF_ACMPEQ: |
|
case IF_ACMPNE: |
|
case PUTFIELD: |
|
return null; |
|
default: |
|
throw new AssertionError(); |
|
} |
|
} |
|
|
|
@Override |
|
public BasicValue ternaryOperation( |
|
final AbstractInsnNode insn, |
|
final BasicValue value1, |
|
final BasicValue value2, |
|
final BasicValue value3) |
|
throws AnalyzerException { |
|
return null; |
|
} |
|
|
|
@Override |
|
public BasicValue naryOperation( |
|
final AbstractInsnNode insn, final List<? extends BasicValue> values) |
|
throws AnalyzerException { |
|
int opcode = insn.getOpcode(); |
|
if (opcode == MULTIANEWARRAY) { |
|
return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc)); |
|
} else if (opcode == INVOKEDYNAMIC) { |
|
return newValue(Type.getReturnType(((InvokeDynamicInsnNode) insn).desc)); |
|
} else { |
|
return newValue(Type.getReturnType(((MethodInsnNode) insn).desc)); |
|
} |
|
} |
|
|
|
@Override |
|
public void returnOperation( |
|
final AbstractInsnNode insn, final BasicValue value, final BasicValue expected) |
|
throws AnalyzerException { |
|
// Nothing to do. |
|
} |
|
|
|
@Override |
|
public BasicValue merge(final BasicValue value1, final BasicValue value2) { |
|
if (!value1.equals(value2)) { |
|
return BasicValue.UNINITIALIZED_VALUE; |
|
} |
|
return value1; |
|
} |
|
} |