• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // ASM: a very small and fast Java bytecode manipulation framework
2 // Copyright (c) 2000-2011 INRIA, France Telecom
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions
7 // are met:
8 // 1. Redistributions of source code must retain the above copyright
9 //    notice, this list of conditions and the following disclaimer.
10 // 2. Redistributions in binary form must reproduce the above copyright
11 //    notice, this list of conditions and the following disclaimer in the
12 //    documentation and/or other materials provided with the distribution.
13 // 3. Neither the name of the copyright holders nor the names of its
14 //    contributors may be used to endorse or promote products derived from
15 //    this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 // THE POSSIBILITY OF SUCH DAMAGE.
28 package org.objectweb.asm.tree.analysis;
29 
30 import java.util.HashSet;
31 import java.util.List;
32 import java.util.Set;
33 import org.objectweb.asm.Opcodes;
34 import org.objectweb.asm.Type;
35 import org.objectweb.asm.tree.AbstractInsnNode;
36 import org.objectweb.asm.tree.FieldInsnNode;
37 import org.objectweb.asm.tree.InvokeDynamicInsnNode;
38 import org.objectweb.asm.tree.LdcInsnNode;
39 import org.objectweb.asm.tree.MethodInsnNode;
40 
41 /**
42  * An {@link Interpreter} for {@link SourceValue} values.
43  *
44  * @author Eric Bruneton
45  */
46 public class SourceInterpreter extends Interpreter<SourceValue> implements Opcodes {
47 
48   /**
49    * Constructs a new {@link SourceInterpreter} for the latest ASM API version. <i>Subclasses must
50    * not use this constructor</i>. Instead, they must use the {@link #SourceInterpreter(int)}
51    * version.
52    */
SourceInterpreter()53   public SourceInterpreter() {
54     super(/* latest api = */ ASM9);
55     if (getClass() != SourceInterpreter.class) {
56       throw new IllegalStateException();
57     }
58   }
59 
60   /**
61    * Constructs a new {@link SourceInterpreter}.
62    *
63    * @param api the ASM API version supported by this interpreter. Must be one of the {@code
64    *     ASM}<i>x</i> values in {@link Opcodes}.
65    */
SourceInterpreter(final int api)66   protected SourceInterpreter(final int api) {
67     super(api);
68   }
69 
70   @Override
newValue(final Type type)71   public SourceValue newValue(final Type type) {
72     if (type == Type.VOID_TYPE) {
73       return null;
74     }
75     return new SourceValue(type == null ? 1 : type.getSize());
76   }
77 
78   @Override
newOperation(final AbstractInsnNode insn)79   public SourceValue newOperation(final AbstractInsnNode insn) {
80     int size;
81     switch (insn.getOpcode()) {
82       case LCONST_0:
83       case LCONST_1:
84       case DCONST_0:
85       case DCONST_1:
86         size = 2;
87         break;
88       case LDC:
89         Object value = ((LdcInsnNode) insn).cst;
90         size = value instanceof Long || value instanceof Double ? 2 : 1;
91         break;
92       case GETSTATIC:
93         size = Type.getType(((FieldInsnNode) insn).desc).getSize();
94         break;
95       default:
96         size = 1;
97         break;
98     }
99     return new SourceValue(size, insn);
100   }
101 
102   @Override
copyOperation(final AbstractInsnNode insn, final SourceValue value)103   public SourceValue copyOperation(final AbstractInsnNode insn, final SourceValue value) {
104     return new SourceValue(value.getSize(), insn);
105   }
106 
107   @Override
unaryOperation(final AbstractInsnNode insn, final SourceValue value)108   public SourceValue unaryOperation(final AbstractInsnNode insn, final SourceValue value) {
109     int size;
110     switch (insn.getOpcode()) {
111       case LNEG:
112       case DNEG:
113       case I2L:
114       case I2D:
115       case L2D:
116       case F2L:
117       case F2D:
118       case D2L:
119         size = 2;
120         break;
121       case GETFIELD:
122         size = Type.getType(((FieldInsnNode) insn).desc).getSize();
123         break;
124       default:
125         size = 1;
126         break;
127     }
128     return new SourceValue(size, insn);
129   }
130 
131   @Override
binaryOperation( final AbstractInsnNode insn, final SourceValue value1, final SourceValue value2)132   public SourceValue binaryOperation(
133       final AbstractInsnNode insn, final SourceValue value1, final SourceValue value2) {
134     int size;
135     switch (insn.getOpcode()) {
136       case LALOAD:
137       case DALOAD:
138       case LADD:
139       case DADD:
140       case LSUB:
141       case DSUB:
142       case LMUL:
143       case DMUL:
144       case LDIV:
145       case DDIV:
146       case LREM:
147       case DREM:
148       case LSHL:
149       case LSHR:
150       case LUSHR:
151       case LAND:
152       case LOR:
153       case LXOR:
154         size = 2;
155         break;
156       default:
157         size = 1;
158         break;
159     }
160     return new SourceValue(size, insn);
161   }
162 
163   @Override
ternaryOperation( final AbstractInsnNode insn, final SourceValue value1, final SourceValue value2, final SourceValue value3)164   public SourceValue ternaryOperation(
165       final AbstractInsnNode insn,
166       final SourceValue value1,
167       final SourceValue value2,
168       final SourceValue value3) {
169     return new SourceValue(1, insn);
170   }
171 
172   @Override
naryOperation( final AbstractInsnNode insn, final List<? extends SourceValue> values)173   public SourceValue naryOperation(
174       final AbstractInsnNode insn, final List<? extends SourceValue> values) {
175     int size;
176     int opcode = insn.getOpcode();
177     if (opcode == MULTIANEWARRAY) {
178       size = 1;
179     } else if (opcode == INVOKEDYNAMIC) {
180       size = Type.getReturnType(((InvokeDynamicInsnNode) insn).desc).getSize();
181     } else {
182       size = Type.getReturnType(((MethodInsnNode) insn).desc).getSize();
183     }
184     return new SourceValue(size, insn);
185   }
186 
187   @Override
returnOperation( final AbstractInsnNode insn, final SourceValue value, final SourceValue expected)188   public void returnOperation(
189       final AbstractInsnNode insn, final SourceValue value, final SourceValue expected) {
190     // Nothing to do.
191   }
192 
193   @Override
merge(final SourceValue value1, final SourceValue value2)194   public SourceValue merge(final SourceValue value1, final SourceValue value2) {
195     if (value1.insns instanceof SmallSet && value2.insns instanceof SmallSet) {
196       Set<AbstractInsnNode> setUnion =
197           ((SmallSet<AbstractInsnNode>) value1.insns)
198               .union((SmallSet<AbstractInsnNode>) value2.insns);
199       if (setUnion == value1.insns && value1.size == value2.size) {
200         return value1;
201       } else {
202         return new SourceValue(Math.min(value1.size, value2.size), setUnion);
203       }
204     }
205     if (value1.size != value2.size || !containsAll(value1.insns, value2.insns)) {
206       HashSet<AbstractInsnNode> setUnion = new HashSet<>();
207       setUnion.addAll(value1.insns);
208       setUnion.addAll(value2.insns);
209       return new SourceValue(Math.min(value1.size, value2.size), setUnion);
210     }
211     return value1;
212   }
213 
containsAll(final Set<E> self, final Set<E> other)214   private static <E> boolean containsAll(final Set<E> self, final Set<E> other) {
215     if (self.size() < other.size()) {
216       return false;
217     }
218     return self.containsAll(other);
219   }
220 }
221