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    }