View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.nabla.automatic.analysis;
18  
19  import java.util.Iterator;
20  import java.util.List;
21  
22  import org.objectweb.asm.Type;
23  import org.objectweb.asm.tree.AbstractInsnNode;
24  import org.objectweb.asm.tree.analysis.AnalyzerException;
25  import org.objectweb.asm.tree.analysis.BasicInterpreter;
26  import org.objectweb.asm.tree.analysis.BasicValue;
27  import org.objectweb.asm.tree.analysis.Value;
28  
29  /** An interpreter tracking which instructions use which values.
30   * <p>This interpreter wraps {@link org.objectweb.asm.tree.analysis.BasicValue
31   * BasicValue} instances into {@link TrackingValue TrackingValue} instances.</p>
32   */
33  public class TrackingInterpreter extends BasicInterpreter {
34  
35      /** Build an interpreter.
36       */
37      public TrackingInterpreter() {
38      }
39  
40      /** {@inheritDoc} */
41      @Override
42      public Value newValue(final Type type) {
43          return (type == null) ? TrackingValue.UNINITIALIZED_VALUE : wrap(super.newValue(type), null);
44      }
45  
46      /** {@inheritDoc} */
47      @Override
48      public Value newOperation(final AbstractInsnNode insn) {
49          return wrap(super.newOperation(insn), insn);
50      }
51  
52      /** {@inheritDoc} */
53      @Override
54      public Value unaryOperation(final AbstractInsnNode insn,
55                                  final Value value)
56          throws AnalyzerException {
57          ((TrackingValue) value).addConsumer(insn);
58          return wrap(super.unaryOperation(insn, value), insn);
59      }
60  
61      /** {@inheritDoc} */
62      @Override
63      public Value binaryOperation(final AbstractInsnNode insn,
64                                   final Value value1, final Value value2)
65          throws AnalyzerException {
66          ((TrackingValue) value1).addConsumer(insn);
67          ((TrackingValue) value2).addConsumer(insn);
68          return wrap(super.binaryOperation(insn, value1, value2), insn);
69      }
70  
71      /** {@inheritDoc} */
72      @Override
73      public Value ternaryOperation(final AbstractInsnNode insn,
74                                    final Value value1, final Value value2,
75                                    final Value value3)
76          throws AnalyzerException {
77          ((TrackingValue) value1).addConsumer(insn);
78          ((TrackingValue) value2).addConsumer(insn);
79          ((TrackingValue) value3).addConsumer(insn);
80          return wrap(super.ternaryOperation(insn, value1, value2, value3), insn);
81      }
82  
83      /** {@inheritDoc} */
84      @SuppressWarnings("unchecked")
85      @Override
86      public Value naryOperation(final AbstractInsnNode insn,
87                                 final List values)
88          throws AnalyzerException {
89          for (final Iterator<?> iterator = values.iterator(); iterator.hasNext();) {
90              ((TrackingValue) iterator.next()).addConsumer(insn);
91          }
92          return wrap(super.naryOperation(insn, values), insn);
93      }
94  
95      /** {@inheritDoc} */
96      @Override
97      public Value copyOperation(final AbstractInsnNode insn,
98                                 final Value value)
99          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 }