diff options
Diffstat (limited to 'asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/BasicInterpreter.java')
-rw-r--r-- | asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/BasicInterpreter.java | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/BasicInterpreter.java b/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/BasicInterpreter.java new file mode 100644 index 00000000..01972b6a --- /dev/null +++ b/asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/BasicInterpreter.java @@ -0,0 +1,375 @@ +// ASM: a very small and fast Java bytecode manipulation framework +// Copyright (c) 2000-2011 INRIA, France Telecom +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +package org.objectweb.asm.tree.analysis; + +import java.util.List; +import org.objectweb.asm.ConstantDynamic; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MultiANewArrayInsnNode; +import org.objectweb.asm.tree.TypeInsnNode; + +/** + * An {@link Interpreter} for {@link BasicValue} values. + * + * @author Eric Bruneton + * @author Bing Ran + */ +public class BasicInterpreter extends Interpreter<BasicValue> implements Opcodes { + + /** + * Special type used for the {@literal null} literal. This is an object reference type with + * descriptor 'Lnull;'. + */ + public static final Type NULL_TYPE = Type.getObjectType("null"); + + /** + * Constructs a new {@link BasicInterpreter} for the latest ASM API version. <i>Subclasses must + * not use this constructor</i>. Instead, they must use the {@link #BasicInterpreter(int)} + * version. + */ + public BasicInterpreter() { + super(/* latest api = */ ASM9); + if (getClass() != BasicInterpreter.class) { + throw new IllegalStateException(); + } + } + + /** + * Constructs a new {@link BasicInterpreter}. + * + * @param api the ASM API version supported by this interpreter. Must be one of the {@code + * ASM}<i>x</i> values in {@link Opcodes}. + */ + 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; + } +} |