1 // ASM: a very small and fast Java bytecode manipulation framework 2 // Copyright (c) 2000-2011 INRIA, France Telecom 3 // All rights reserved. 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions 7 // are met: 8 // 1. Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // 2. Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // 3. Neither the name of the copyright holders nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 // THE POSSIBILITY OF SUCH DAMAGE. 28 package org.objectweb.asm.tree.analysis; 29 30 import java.util.List; 31 import org.objectweb.asm.ConstantDynamic; 32 import org.objectweb.asm.Handle; 33 import org.objectweb.asm.Opcodes; 34 import org.objectweb.asm.Type; 35 import org.objectweb.asm.tree.AbstractInsnNode; 36 import org.objectweb.asm.tree.FieldInsnNode; 37 import org.objectweb.asm.tree.IntInsnNode; 38 import org.objectweb.asm.tree.InvokeDynamicInsnNode; 39 import org.objectweb.asm.tree.LdcInsnNode; 40 import org.objectweb.asm.tree.MethodInsnNode; 41 import org.objectweb.asm.tree.MultiANewArrayInsnNode; 42 import org.objectweb.asm.tree.TypeInsnNode; 43 44 /** 45 * An {@link Interpreter} for {@link BasicValue} values. 46 * 47 * @author Eric Bruneton 48 * @author Bing Ran 49 */ 50 public class BasicInterpreter extends Interpreter<BasicValue> implements Opcodes { 51 52 /** 53 * Special type used for the {@literal null} literal. This is an object reference type with 54 * descriptor 'Lnull;'. 55 */ 56 public static final Type NULL_TYPE = Type.getObjectType("null"); 57 58 /** 59 * Constructs a new {@link BasicInterpreter} for the latest ASM API version. <i>Subclasses must 60 * not use this constructor</i>. Instead, they must use the {@link #BasicInterpreter(int)} 61 * version. 62 */ BasicInterpreter()63 public BasicInterpreter() { 64 super(/* latest api = */ ASM9); 65 if (getClass() != BasicInterpreter.class) { 66 throw new IllegalStateException(); 67 } 68 } 69 70 /** 71 * Constructs a new {@link BasicInterpreter}. 72 * 73 * @param api the ASM API version supported by this interpreter. Must be one of the {@code 74 * ASM}<i>x</i> values in {@link Opcodes}. 75 */ BasicInterpreter(final int api)76 protected BasicInterpreter(final int api) { 77 super(api); 78 } 79 80 @Override newValue(final Type type)81 public BasicValue newValue(final Type type) { 82 if (type == null) { 83 return BasicValue.UNINITIALIZED_VALUE; 84 } 85 switch (type.getSort()) { 86 case Type.VOID: 87 return null; 88 case Type.BOOLEAN: 89 case Type.CHAR: 90 case Type.BYTE: 91 case Type.SHORT: 92 case Type.INT: 93 return BasicValue.INT_VALUE; 94 case Type.FLOAT: 95 return BasicValue.FLOAT_VALUE; 96 case Type.LONG: 97 return BasicValue.LONG_VALUE; 98 case Type.DOUBLE: 99 return BasicValue.DOUBLE_VALUE; 100 case Type.ARRAY: 101 case Type.OBJECT: 102 return BasicValue.REFERENCE_VALUE; 103 default: 104 throw new AssertionError(); 105 } 106 } 107 108 @Override newOperation(final AbstractInsnNode insn)109 public BasicValue newOperation(final AbstractInsnNode insn) throws AnalyzerException { 110 switch (insn.getOpcode()) { 111 case ACONST_NULL: 112 return newValue(NULL_TYPE); 113 case ICONST_M1: 114 case ICONST_0: 115 case ICONST_1: 116 case ICONST_2: 117 case ICONST_3: 118 case ICONST_4: 119 case ICONST_5: 120 return BasicValue.INT_VALUE; 121 case LCONST_0: 122 case LCONST_1: 123 return BasicValue.LONG_VALUE; 124 case FCONST_0: 125 case FCONST_1: 126 case FCONST_2: 127 return BasicValue.FLOAT_VALUE; 128 case DCONST_0: 129 case DCONST_1: 130 return BasicValue.DOUBLE_VALUE; 131 case BIPUSH: 132 case SIPUSH: 133 return BasicValue.INT_VALUE; 134 case LDC: 135 Object value = ((LdcInsnNode) insn).cst; 136 if (value instanceof Integer) { 137 return BasicValue.INT_VALUE; 138 } else if (value instanceof Float) { 139 return BasicValue.FLOAT_VALUE; 140 } else if (value instanceof Long) { 141 return BasicValue.LONG_VALUE; 142 } else if (value instanceof Double) { 143 return BasicValue.DOUBLE_VALUE; 144 } else if (value instanceof String) { 145 return newValue(Type.getObjectType("java/lang/String")); 146 } else if (value instanceof Type) { 147 int sort = ((Type) value).getSort(); 148 if (sort == Type.OBJECT || sort == Type.ARRAY) { 149 return newValue(Type.getObjectType("java/lang/Class")); 150 } else if (sort == Type.METHOD) { 151 return newValue(Type.getObjectType("java/lang/invoke/MethodType")); 152 } else { 153 throw new AnalyzerException(insn, "Illegal LDC value " + value); 154 } 155 } else if (value instanceof Handle) { 156 return newValue(Type.getObjectType("java/lang/invoke/MethodHandle")); 157 } else if (value instanceof ConstantDynamic) { 158 return newValue(Type.getType(((ConstantDynamic) value).getDescriptor())); 159 } else { 160 throw new AnalyzerException(insn, "Illegal LDC value " + value); 161 } 162 case JSR: 163 return BasicValue.RETURNADDRESS_VALUE; 164 case GETSTATIC: 165 return newValue(Type.getType(((FieldInsnNode) insn).desc)); 166 case NEW: 167 return newValue(Type.getObjectType(((TypeInsnNode) insn).desc)); 168 default: 169 throw new AssertionError(); 170 } 171 } 172 173 @Override copyOperation(final AbstractInsnNode insn, final BasicValue value)174 public BasicValue copyOperation(final AbstractInsnNode insn, final BasicValue value) 175 throws AnalyzerException { 176 return value; 177 } 178 179 @Override unaryOperation(final AbstractInsnNode insn, final BasicValue value)180 public BasicValue unaryOperation(final AbstractInsnNode insn, final BasicValue value) 181 throws AnalyzerException { 182 switch (insn.getOpcode()) { 183 case INEG: 184 case IINC: 185 case L2I: 186 case F2I: 187 case D2I: 188 case I2B: 189 case I2C: 190 case I2S: 191 return BasicValue.INT_VALUE; 192 case FNEG: 193 case I2F: 194 case L2F: 195 case D2F: 196 return BasicValue.FLOAT_VALUE; 197 case LNEG: 198 case I2L: 199 case F2L: 200 case D2L: 201 return BasicValue.LONG_VALUE; 202 case DNEG: 203 case I2D: 204 case L2D: 205 case F2D: 206 return BasicValue.DOUBLE_VALUE; 207 case IFEQ: 208 case IFNE: 209 case IFLT: 210 case IFGE: 211 case IFGT: 212 case IFLE: 213 case TABLESWITCH: 214 case LOOKUPSWITCH: 215 case IRETURN: 216 case LRETURN: 217 case FRETURN: 218 case DRETURN: 219 case ARETURN: 220 case PUTSTATIC: 221 return null; 222 case GETFIELD: 223 return newValue(Type.getType(((FieldInsnNode) insn).desc)); 224 case NEWARRAY: 225 switch (((IntInsnNode) insn).operand) { 226 case T_BOOLEAN: 227 return newValue(Type.getType("[Z")); 228 case T_CHAR: 229 return newValue(Type.getType("[C")); 230 case T_BYTE: 231 return newValue(Type.getType("[B")); 232 case T_SHORT: 233 return newValue(Type.getType("[S")); 234 case T_INT: 235 return newValue(Type.getType("[I")); 236 case T_FLOAT: 237 return newValue(Type.getType("[F")); 238 case T_DOUBLE: 239 return newValue(Type.getType("[D")); 240 case T_LONG: 241 return newValue(Type.getType("[J")); 242 default: 243 break; 244 } 245 throw new AnalyzerException(insn, "Invalid array type"); 246 case ANEWARRAY: 247 return newValue(Type.getType("[" + Type.getObjectType(((TypeInsnNode) insn).desc))); 248 case ARRAYLENGTH: 249 return BasicValue.INT_VALUE; 250 case ATHROW: 251 return null; 252 case CHECKCAST: 253 return newValue(Type.getObjectType(((TypeInsnNode) insn).desc)); 254 case INSTANCEOF: 255 return BasicValue.INT_VALUE; 256 case MONITORENTER: 257 case MONITOREXIT: 258 case IFNULL: 259 case IFNONNULL: 260 return null; 261 default: 262 throw new AssertionError(); 263 } 264 } 265 266 @Override binaryOperation( final AbstractInsnNode insn, final BasicValue value1, final BasicValue value2)267 public BasicValue binaryOperation( 268 final AbstractInsnNode insn, final BasicValue value1, final BasicValue value2) 269 throws AnalyzerException { 270 switch (insn.getOpcode()) { 271 case IALOAD: 272 case BALOAD: 273 case CALOAD: 274 case SALOAD: 275 case IADD: 276 case ISUB: 277 case IMUL: 278 case IDIV: 279 case IREM: 280 case ISHL: 281 case ISHR: 282 case IUSHR: 283 case IAND: 284 case IOR: 285 case IXOR: 286 return BasicValue.INT_VALUE; 287 case FALOAD: 288 case FADD: 289 case FSUB: 290 case FMUL: 291 case FDIV: 292 case FREM: 293 return BasicValue.FLOAT_VALUE; 294 case LALOAD: 295 case LADD: 296 case LSUB: 297 case LMUL: 298 case LDIV: 299 case LREM: 300 case LSHL: 301 case LSHR: 302 case LUSHR: 303 case LAND: 304 case LOR: 305 case LXOR: 306 return BasicValue.LONG_VALUE; 307 case DALOAD: 308 case DADD: 309 case DSUB: 310 case DMUL: 311 case DDIV: 312 case DREM: 313 return BasicValue.DOUBLE_VALUE; 314 case AALOAD: 315 return BasicValue.REFERENCE_VALUE; 316 case LCMP: 317 case FCMPL: 318 case FCMPG: 319 case DCMPL: 320 case DCMPG: 321 return BasicValue.INT_VALUE; 322 case IF_ICMPEQ: 323 case IF_ICMPNE: 324 case IF_ICMPLT: 325 case IF_ICMPGE: 326 case IF_ICMPGT: 327 case IF_ICMPLE: 328 case IF_ACMPEQ: 329 case IF_ACMPNE: 330 case PUTFIELD: 331 return null; 332 default: 333 throw new AssertionError(); 334 } 335 } 336 337 @Override ternaryOperation( final AbstractInsnNode insn, final BasicValue value1, final BasicValue value2, final BasicValue value3)338 public BasicValue ternaryOperation( 339 final AbstractInsnNode insn, 340 final BasicValue value1, 341 final BasicValue value2, 342 final BasicValue value3) 343 throws AnalyzerException { 344 return null; 345 } 346 347 @Override naryOperation( final AbstractInsnNode insn, final List<? extends BasicValue> values)348 public BasicValue naryOperation( 349 final AbstractInsnNode insn, final List<? extends BasicValue> values) 350 throws AnalyzerException { 351 int opcode = insn.getOpcode(); 352 if (opcode == MULTIANEWARRAY) { 353 return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc)); 354 } else if (opcode == INVOKEDYNAMIC) { 355 return newValue(Type.getReturnType(((InvokeDynamicInsnNode) insn).desc)); 356 } else { 357 return newValue(Type.getReturnType(((MethodInsnNode) insn).desc)); 358 } 359 } 360 361 @Override returnOperation( final AbstractInsnNode insn, final BasicValue value, final BasicValue expected)362 public void returnOperation( 363 final AbstractInsnNode insn, final BasicValue value, final BasicValue expected) 364 throws AnalyzerException { 365 // Nothing to do. 366 } 367 368 @Override merge(final BasicValue value1, final BasicValue value2)369 public BasicValue merge(final BasicValue value1, final BasicValue value2) { 370 if (!value1.equals(value2)) { 371 return BasicValue.UNINITIALIZED_VALUE; 372 } 373 return value1; 374 } 375 } 376