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.algorithmic.forward.analysis;
018
019 import java.util.Iterator;
020 import java.util.List;
021
022 import org.objectweb.asm.Type;
023 import org.objectweb.asm.tree.AbstractInsnNode;
024 import org.objectweb.asm.tree.analysis.AnalyzerException;
025 import org.objectweb.asm.tree.analysis.BasicInterpreter;
026 import org.objectweb.asm.tree.analysis.BasicValue;
027 import org.objectweb.asm.tree.analysis.Value;
028
029 /** An interpreter tracking which instructions use which values.
030 * <p>This interpreter wraps {@link org.objectweb.asm.tree.analysis.BasicValue
031 * BasicValue} instances into {@link TrackingValue TrackingValue} instances.</p>
032 */
033 public class TrackingInterpreter extends BasicInterpreter {
034
035 /** Build an interpreter.
036 */
037 public TrackingInterpreter() {
038 }
039
040 /** {@inheritDoc} */
041 @Override
042 public Value newValue(final Type type) {
043 return (type == null) ? TrackingValue.UNINITIALIZED_VALUE : wrap(super.newValue(type), null);
044 }
045
046 /** {@inheritDoc} */
047 @Override
048 public Value newOperation(final AbstractInsnNode insn) throws AnalyzerException {
049 return wrap(super.newOperation(insn), insn);
050 }
051
052 /** {@inheritDoc} */
053 @Override
054 public Value unaryOperation(final AbstractInsnNode insn,
055 final Value value)
056 throws AnalyzerException {
057 ((TrackingValue) value).addConsumer(insn);
058 return wrap(super.unaryOperation(insn, value), insn);
059 }
060
061 /** {@inheritDoc} */
062 @Override
063 public Value binaryOperation(final AbstractInsnNode insn,
064 final Value value1, final Value value2)
065 throws AnalyzerException {
066 ((TrackingValue) value1).addConsumer(insn);
067 ((TrackingValue) value2).addConsumer(insn);
068 return wrap(super.binaryOperation(insn, value1, value2), insn);
069 }
070
071 /** {@inheritDoc} */
072 @Override
073 public Value ternaryOperation(final AbstractInsnNode insn,
074 final Value value1, final Value value2,
075 final Value value3)
076 throws AnalyzerException {
077 ((TrackingValue) value1).addConsumer(insn);
078 ((TrackingValue) value2).addConsumer(insn);
079 ((TrackingValue) value3).addConsumer(insn);
080 return wrap(super.ternaryOperation(insn, value1, value2, value3), insn);
081 }
082
083 /** {@inheritDoc} */
084 @SuppressWarnings("unchecked")
085 @Override
086 public Value naryOperation(final AbstractInsnNode insn,
087 final List values)
088 throws AnalyzerException {
089 for (final Iterator<?> iterator = values.iterator(); iterator.hasNext();) {
090 ((TrackingValue) iterator.next()).addConsumer(insn);
091 }
092 return wrap(super.naryOperation(insn, values), insn);
093 }
094
095 /** {@inheritDoc} */
096 @Override
097 public Value copyOperation(final AbstractInsnNode insn,
098 final Value value)
099 throws AnalyzerException {
100 // we reuse the same instance instead of wrapping it again
101 // thus simplifying transitive dependencies propagation
102 final TrackingValue tv = (TrackingValue) value;
103 tv.addConsumer(insn);
104 tv.addProducer(insn);
105 return value;
106 }
107
108 /** {@inheritDoc} */
109 @Override
110 public Value merge(final Value v, final Value w) {
111
112 final TrackingValue tv = (TrackingValue) v;
113 final TrackingValue tw = (TrackingValue) w;
114 TrackingValue.merge(tv, tw);
115
116 final BasicValue superMerged = (BasicValue) super.merge(tv.getValue(), tw.getValue());
117 return (superMerged == tv.getValue()) ? tv : new TrackingValue(superMerged);
118
119 }
120
121 /** Wrap a value returned by the superclass.
122 * @param value underlying value (may be null)
123 * @param producer instruction producing the value (may be null)
124 * @return the wrapped value
125 */
126 private TrackingValue wrap(final Value value,
127 final AbstractInsnNode producer) {
128
129 if (value == null) {
130 return null;
131 }
132
133 // values produced by the superclass are either BasicValue instances
134 // (like BasicValue.DOUBLE_VALUE) or already TrackingValue if the
135 // superclass called our local implementation of newValue or newOperation
136 final TrackingValue tv = (value instanceof TrackingValue) ?
137 (TrackingValue) value :
138 new TrackingValue((BasicValue) value);
139
140 if (producer != null) {
141 tv.addProducer(producer);
142 }
143
144 return tv;
145
146 }
147
148 }