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 }