001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.nabla.forward.analysis; 018 019 import java.util.Iterator; 020 import java.util.List; 021 022 import org.apache.commons.nabla.DifferentiationException; 023 import org.apache.commons.nabla.NablaMessages; 024 import org.objectweb.asm.Handle; 025 import org.objectweb.asm.Opcodes; 026 import org.objectweb.asm.Type; 027 import org.objectweb.asm.tree.AbstractInsnNode; 028 import org.objectweb.asm.tree.FieldInsnNode; 029 import org.objectweb.asm.tree.IntInsnNode; 030 import org.objectweb.asm.tree.InvokeDynamicInsnNode; 031 import org.objectweb.asm.tree.LdcInsnNode; 032 import org.objectweb.asm.tree.MethodInsnNode; 033 import org.objectweb.asm.tree.MultiANewArrayInsnNode; 034 import org.objectweb.asm.tree.TypeInsnNode; 035 import org.objectweb.asm.tree.analysis.AnalyzerException; 036 import org.objectweb.asm.tree.analysis.Interpreter; 037 038 /** An interpreter tracking which instructions use which values. 039 * <p> 040 * The implementation of this class is largely copied from the original BasicInterpreter from asm, 041 * which is distributed under the following terms: 042 * </p> 043 * <p> 044 * ASM: a very small and fast Java bytecode manipulation framework 045 * Copyright (c) 2000-2011 INRIA, France Telecom 046 * All rights reserved. 047 * 048 * Redistribution and use in source and binary forms, with or without 049 * modification, are permitted provided that the following conditions 050 * are met: 051 * 1. Redistributions of source code must retain the above copyright 052 * notice, this list of conditions and the following disclaimer. 053 * 2. Redistributions in binary form must reproduce the above copyright 054 * notice, this list of conditions and the following disclaimer in the 055 * documentation and/or other materials provided with the distribution. 056 * 3. Neither the name of the copyright holders nor the names of its 057 * contributors may be used to endorse or promote products derived from 058 * this software without specific prior written permission. 059 * 060 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 061 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 062 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 063 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 064 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 065 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 066 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 067 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 068 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 069 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 070 * THE POSSIBILITY OF SUCH DAMAGE. 071 * </p> 072 * @see TrackingValue 073 * @version $Id$ 074 */ 075 public class TrackingInterpreter extends Interpreter<TrackingValue> { 076 077 /** Build an interpreter. 078 */ 079 public TrackingInterpreter() { 080 super(Opcodes.ASM4); 081 } 082 083 /** {@inheritDoc} */ 084 @Override 085 public TrackingValue newValue(final Type type) { 086 return (type == null) ? TrackingValue.UNINITIALIZED_VALUE : new TrackingValue(type); 087 } 088 089 /** {@inheritDoc} */ 090 @Override 091 public TrackingValue newOperation(final AbstractInsnNode insn) throws AnalyzerException { 092 switch (insn.getOpcode()) { 093 case Opcodes.ACONST_NULL: 094 return new TrackingValue(Type.getObjectType("null"), insn); 095 case Opcodes.ICONST_M1: 096 case Opcodes.ICONST_0: 097 case Opcodes.ICONST_1: 098 case Opcodes.ICONST_2: 099 case Opcodes.ICONST_3: 100 case Opcodes.ICONST_4: 101 case Opcodes.ICONST_5: 102 return new TrackingValue(Type.INT_TYPE, insn); 103 case Opcodes.LCONST_0: 104 case Opcodes.LCONST_1: 105 return new TrackingValue(Type.LONG_TYPE, insn); 106 case Opcodes.FCONST_0: 107 case Opcodes.FCONST_1: 108 case Opcodes.FCONST_2: 109 return new TrackingValue(Type.FLOAT_TYPE, insn); 110 case Opcodes.DCONST_0: 111 case Opcodes.DCONST_1: 112 return new TrackingValue(Type.DOUBLE_TYPE, insn); 113 case Opcodes.BIPUSH: 114 case Opcodes.SIPUSH: 115 return new TrackingValue(Type.INT_TYPE, insn); 116 case Opcodes.LDC: 117 final Object cst = ((LdcInsnNode) insn).cst; 118 if (cst instanceof Integer) { 119 return new TrackingValue(Type.INT_TYPE, insn); 120 } else if (cst instanceof Float) { 121 return new TrackingValue(Type.FLOAT_TYPE, insn); 122 } else if (cst instanceof Long) { 123 return new TrackingValue(Type.LONG_TYPE, insn); 124 } else if (cst instanceof Double) { 125 return new TrackingValue(Type.DOUBLE_TYPE, insn); 126 } else if (cst instanceof String) { 127 return new TrackingValue(Type.getType(String.class), insn); 128 } else if (cst instanceof Type) { 129 final int sort = ((Type) cst).getSort(); 130 if (sort == Type.OBJECT || sort == Type.ARRAY) { 131 return new TrackingValue(Type.getType(Class.class), insn); 132 } else if (sort == Type.METHOD) { 133 return new TrackingValue(Type.getObjectType("java/lang/invoke/MethodType"), insn); 134 } else { 135 throw DifferentiationException.createIllegalArgumentException(NablaMessages.ILLEGAL_LDC_CONSTANT, 136 cst); 137 } 138 } else if (cst instanceof Handle) { 139 return new TrackingValue(Type.getObjectType("java/lang/invoke/MethodHandle"), insn); 140 } else { 141 throw DifferentiationException.createIllegalArgumentException(NablaMessages.ILLEGAL_LDC_CONSTANT, 142 cst); 143 } 144 case Opcodes.JSR: 145 return new TrackingValue(Type.VOID_TYPE, insn); // return address value 146 case Opcodes.GETSTATIC: 147 return new TrackingValue(Type.getType(((FieldInsnNode) insn).desc), insn); 148 case Opcodes.NEW: 149 return new TrackingValue(Type.getObjectType(((TypeInsnNode) insn).desc), insn); 150 default: 151 throw DifferentiationException.createInternalError(null); 152 } 153 } 154 155 /** {@inheritDoc} */ 156 public TrackingValue unaryOperation(final AbstractInsnNode insn, final TrackingValue value) 157 throws AnalyzerException { 158 ((TrackingValue) value).addConsumer(insn); 159 switch (insn.getOpcode()) { 160 case Opcodes.INEG: 161 case Opcodes.IINC: 162 case Opcodes.L2I: 163 case Opcodes.F2I: 164 case Opcodes.D2I: 165 case Opcodes.I2B: 166 case Opcodes.I2C: 167 case Opcodes.I2S: 168 return new TrackingValue(Type.INT_TYPE, insn); 169 case Opcodes.FNEG: 170 case Opcodes.I2F: 171 case Opcodes.L2F: 172 case Opcodes.D2F: 173 return new TrackingValue(Type.FLOAT_TYPE, insn); 174 case Opcodes.LNEG: 175 case Opcodes.I2L: 176 case Opcodes.F2L: 177 case Opcodes.D2L: 178 return new TrackingValue(Type.LONG_TYPE, insn); 179 case Opcodes.DNEG: 180 case Opcodes.I2D: 181 case Opcodes.L2D: 182 case Opcodes.F2D: 183 return new TrackingValue(Type.DOUBLE_TYPE, insn); 184 case Opcodes.IFEQ: 185 case Opcodes.IFNE: 186 case Opcodes.IFLT: 187 case Opcodes.IFGE: 188 case Opcodes.IFGT: 189 case Opcodes.IFLE: 190 case Opcodes.TABLESWITCH: 191 case Opcodes.LOOKUPSWITCH: 192 case Opcodes.IRETURN: 193 case Opcodes.LRETURN: 194 case Opcodes.FRETURN: 195 case Opcodes.DRETURN: 196 case Opcodes.ARETURN: 197 case Opcodes.PUTSTATIC: 198 return null; 199 case Opcodes.GETFIELD: 200 return new TrackingValue(Type.getType(((FieldInsnNode) insn).desc), insn); 201 case Opcodes.NEWARRAY: 202 switch (((IntInsnNode) insn).operand) { 203 case Opcodes.T_BOOLEAN: 204 return new TrackingValue(Type.getType("[Z"), insn); 205 case Opcodes.T_CHAR: 206 return new TrackingValue(Type.getType("[C"), insn); 207 case Opcodes.T_BYTE: 208 return new TrackingValue(Type.getType("[B"), insn); 209 case Opcodes.T_SHORT: 210 return new TrackingValue(Type.getType("[S"), insn); 211 case Opcodes.T_INT: 212 return new TrackingValue(Type.getType("[I"), insn); 213 case Opcodes.T_FLOAT: 214 return new TrackingValue(Type.getType("[F"), insn); 215 case Opcodes.T_DOUBLE: 216 return new TrackingValue(Type.getType("[D"), insn); 217 case Opcodes.T_LONG: 218 return new TrackingValue(Type.getType("[J"), insn); 219 default: 220 throw new AnalyzerException(insn, "Invalid array type"); 221 } 222 case Opcodes.ANEWARRAY: { 223 final String desc = ((TypeInsnNode) insn).desc; 224 return new TrackingValue(Type.getType("[" + Type.getObjectType(desc)), insn); 225 } 226 case Opcodes.ARRAYLENGTH: 227 return new TrackingValue(Type.INT_TYPE, insn); 228 case Opcodes.ATHROW: 229 return null; 230 case Opcodes.CHECKCAST: { 231 final String desc = ((TypeInsnNode) insn).desc; 232 return new TrackingValue(Type.getObjectType(desc), insn); 233 } 234 case Opcodes.INSTANCEOF: 235 return new TrackingValue(Type.INT_TYPE, insn); 236 case Opcodes.MONITORENTER: 237 case Opcodes.MONITOREXIT: 238 case Opcodes.IFNULL: 239 case Opcodes.IFNONNULL: 240 return null; 241 default: 242 throw DifferentiationException.createInternalError(null); 243 } 244 } 245 246 /** {@inheritDoc} */ 247 public TrackingValue binaryOperation(final AbstractInsnNode insn, 248 final TrackingValue value1, final TrackingValue value2) 249 throws AnalyzerException { 250 ((TrackingValue) value1).addConsumer(insn); 251 ((TrackingValue) value2).addConsumer(insn); 252 switch (insn.getOpcode()) { 253 case Opcodes.IALOAD: 254 case Opcodes.BALOAD: 255 case Opcodes.CALOAD: 256 case Opcodes.SALOAD: 257 case Opcodes.IADD: 258 case Opcodes.ISUB: 259 case Opcodes.IMUL: 260 case Opcodes.IDIV: 261 case Opcodes.IREM: 262 case Opcodes.ISHL: 263 case Opcodes.ISHR: 264 case Opcodes.IUSHR: 265 case Opcodes.IAND: 266 case Opcodes.IOR: 267 case Opcodes.IXOR: 268 return new TrackingValue(Type.INT_TYPE, insn); 269 case Opcodes.FALOAD: 270 case Opcodes.FADD: 271 case Opcodes.FSUB: 272 case Opcodes.FMUL: 273 case Opcodes.FDIV: 274 case Opcodes.FREM: 275 return new TrackingValue(Type.FLOAT_TYPE, insn); 276 case Opcodes.LALOAD: 277 case Opcodes.LADD: 278 case Opcodes.LSUB: 279 case Opcodes.LMUL: 280 case Opcodes.LDIV: 281 case Opcodes.LREM: 282 case Opcodes.LSHL: 283 case Opcodes.LSHR: 284 case Opcodes.LUSHR: 285 case Opcodes.LAND: 286 case Opcodes.LOR: 287 case Opcodes.LXOR: 288 return new TrackingValue(Type.LONG_TYPE, insn); 289 case Opcodes.DALOAD: 290 case Opcodes.DADD: 291 case Opcodes.DSUB: 292 case Opcodes.DMUL: 293 case Opcodes.DDIV: 294 case Opcodes.DREM: 295 return new TrackingValue(Type.DOUBLE_TYPE, insn); 296 case Opcodes.AALOAD: 297 return new TrackingValue(Type.getType(Object.class), insn); // reference value 298 case Opcodes.LCMP: 299 case Opcodes.FCMPL: 300 case Opcodes.FCMPG: 301 case Opcodes.DCMPL: 302 case Opcodes.DCMPG: 303 return new TrackingValue(Type.INT_TYPE, insn); 304 case Opcodes.IF_ICMPEQ: 305 case Opcodes.IF_ICMPNE: 306 case Opcodes.IF_ICMPLT: 307 case Opcodes.IF_ICMPGE: 308 case Opcodes.IF_ICMPGT: 309 case Opcodes.IF_ICMPLE: 310 case Opcodes.IF_ACMPEQ: 311 case Opcodes.IF_ACMPNE: 312 case Opcodes.PUTFIELD: 313 return null; 314 default: 315 throw DifferentiationException.createInternalError(null); 316 } 317 } 318 319 /** {@inheritDoc} */ 320 public TrackingValue ternaryOperation(final AbstractInsnNode insn, 321 final TrackingValue value1, final TrackingValue value2, 322 final TrackingValue value3) 323 throws AnalyzerException { 324 value1.addConsumer(insn); 325 value2.addConsumer(insn); 326 value3.addConsumer(insn); 327 return new TrackingValue(null, insn); 328 } 329 330 /** {@inheritDoc} */ 331 public TrackingValue naryOperation(final AbstractInsnNode insn, final List<? extends TrackingValue> values) 332 throws AnalyzerException { 333 for (final Iterator<?> iterator = values.iterator(); iterator.hasNext();) { 334 ((TrackingValue) iterator.next()).addConsumer(insn); 335 } 336 final int opcode = insn.getOpcode(); 337 if (opcode == Opcodes.MULTIANEWARRAY) { 338 return new TrackingValue(Type.getType(((MultiANewArrayInsnNode) insn).desc), insn); 339 } else if (opcode == Opcodes.INVOKEDYNAMIC) { 340 return new TrackingValue(Type.getReturnType(((InvokeDynamicInsnNode) insn).desc), insn); 341 } else { 342 return new TrackingValue(Type.getReturnType(((MethodInsnNode) insn).desc), insn); 343 } 344 } 345 346 /** {@inheritDoc} */ 347 public TrackingValue copyOperation(final AbstractInsnNode insn, final TrackingValue value) 348 throws AnalyzerException { 349 // we reuse the same instance instead of wrapping it again 350 // thus simplifying transitive dependencies propagation 351 value.addConsumer(insn); 352 value.addProducer(insn); 353 return value; 354 } 355 356 /** {@inheritDoc} */ 357 public TrackingValue merge(final TrackingValue v, final TrackingValue w) { 358 TrackingValue.merge(v, w); 359 return v; 360 } 361 362 /** {@inheritDoc} */ 363 public void returnOperation(final AbstractInsnNode insn, 364 final TrackingValue value, final TrackingValue expected) { 365 // nothing to do here, as unaryOperation has already been called 366 } 367 368 }