1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 only, as
6  * published by the Free Software Foundation.  Oracle designates this
7  * particular file as subject to the "Classpath" exception as provided
8  * by Oracle in the LICENSE file that accompanied this code.
9  *
10  * This code is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * version 2 for more details (a copy is included in the LICENSE file that
14  * accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License version
17  * 2 along with this work; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21  * or visit www.oracle.com if you need additional information or have any
22  * questions.
23  */
24 
25 /*
26  * This file is available under and governed by the GNU General Public
27  * License version 2 only, as published by the Free Software Foundation.
28  * However, the following notice accompanied the original version of this
29  * file:
30  *
31  * ASM: a very small and fast Java bytecode manipulation framework
32  * Copyright (c) 2000-2011 INRIA, France Telecom
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  * 1. Redistributions of source code must retain the above copyright
39  *    notice, this list of conditions and the following disclaimer.
40  * 2. Redistributions in binary form must reproduce the above copyright
41  *    notice, this list of conditions and the following disclaimer in the
42  *    documentation and/or other materials provided with the distribution.
43  * 3. Neither the name of the copyright holders nor the names of its
44  *    contributors may be used to endorse or promote products derived from
45  *    this software without specific prior written permission.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
51  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
57  * THE POSSIBILITY OF SUCH DAMAGE.
58  */
59 package jdk.internal.org.objectweb.asm.tree.analysis;
60 
61 import java.util.HashSet;
62 import java.util.List;
63 import java.util.Set;
64 import jdk.internal.org.objectweb.asm.Opcodes;
65 import jdk.internal.org.objectweb.asm.Type;
66 import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode;
67 import jdk.internal.org.objectweb.asm.tree.FieldInsnNode;
68 import jdk.internal.org.objectweb.asm.tree.InvokeDynamicInsnNode;
69 import jdk.internal.org.objectweb.asm.tree.LdcInsnNode;
70 import jdk.internal.org.objectweb.asm.tree.MethodInsnNode;
71 
72 /**
73  * An {@link Interpreter} for {@link SourceValue} values.
74  *
75  * @author Eric Bruneton
76  */
77 public class SourceInterpreter extends Interpreter<SourceValue> implements Opcodes {
78 
79     /**
80       * Constructs a new {@link SourceInterpreter} for the latest ASM API version. <i>Subclasses must
81       * not use this constructor</i>. Instead, they must use the {@link #SourceInterpreter(int)}
82       * version.
83       */
SourceInterpreter()84     public SourceInterpreter() {
85         super(/* latest api = */ ASM8);
86         if (getClass() != SourceInterpreter.class) {
87             throw new IllegalStateException();
88         }
89     }
90 
91     /**
92       * Constructs a new {@link SourceInterpreter}.
93       *
94       * @param api the ASM API version supported by this interpreter. Must be one of {@link
95       *     jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
96       *     jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
97       *     jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
98       */
SourceInterpreter(final int api)99     protected SourceInterpreter(final int api) {
100         super(api);
101     }
102 
103     @Override
newValue(final Type type)104     public SourceValue newValue(final Type type) {
105         if (type == Type.VOID_TYPE) {
106             return null;
107         }
108         return new SourceValue(type == null ? 1 : type.getSize());
109     }
110 
111     @Override
newOperation(final AbstractInsnNode insn)112     public SourceValue newOperation(final AbstractInsnNode insn) {
113         int size;
114         switch (insn.getOpcode()) {
115             case LCONST_0:
116             case LCONST_1:
117             case DCONST_0:
118             case DCONST_1:
119                 size = 2;
120                 break;
121             case LDC:
122                 Object value = ((LdcInsnNode) insn).cst;
123                 size = value instanceof Long || value instanceof Double ? 2 : 1;
124                 break;
125             case GETSTATIC:
126                 size = Type.getType(((FieldInsnNode) insn).desc).getSize();
127                 break;
128             default:
129                 size = 1;
130                 break;
131         }
132         return new SourceValue(size, insn);
133     }
134 
135     @Override
copyOperation(final AbstractInsnNode insn, final SourceValue value)136     public SourceValue copyOperation(final AbstractInsnNode insn, final SourceValue value) {
137         return new SourceValue(value.getSize(), insn);
138     }
139 
140     @Override
unaryOperation(final AbstractInsnNode insn, final SourceValue value)141     public SourceValue unaryOperation(final AbstractInsnNode insn, final SourceValue value) {
142         int size;
143         switch (insn.getOpcode()) {
144             case LNEG:
145             case DNEG:
146             case I2L:
147             case I2D:
148             case L2D:
149             case F2L:
150             case F2D:
151             case D2L:
152                 size = 2;
153                 break;
154             case GETFIELD:
155                 size = Type.getType(((FieldInsnNode) insn).desc).getSize();
156                 break;
157             default:
158                 size = 1;
159                 break;
160         }
161         return new SourceValue(size, insn);
162     }
163 
164     @Override
binaryOperation( final AbstractInsnNode insn, final SourceValue value1, final SourceValue value2)165     public SourceValue binaryOperation(
166             final AbstractInsnNode insn, final SourceValue value1, final SourceValue value2) {
167         int size;
168         switch (insn.getOpcode()) {
169             case LALOAD:
170             case DALOAD:
171             case LADD:
172             case DADD:
173             case LSUB:
174             case DSUB:
175             case LMUL:
176             case DMUL:
177             case LDIV:
178             case DDIV:
179             case LREM:
180             case DREM:
181             case LSHL:
182             case LSHR:
183             case LUSHR:
184             case LAND:
185             case LOR:
186             case LXOR:
187                 size = 2;
188                 break;
189             default:
190                 size = 1;
191                 break;
192         }
193         return new SourceValue(size, insn);
194     }
195 
196     @Override
ternaryOperation( final AbstractInsnNode insn, final SourceValue value1, final SourceValue value2, final SourceValue value3)197     public SourceValue ternaryOperation(
198             final AbstractInsnNode insn,
199             final SourceValue value1,
200             final SourceValue value2,
201             final SourceValue value3) {
202         return new SourceValue(1, insn);
203     }
204 
205     @Override
naryOperation( final AbstractInsnNode insn, final List<? extends SourceValue> values)206     public SourceValue naryOperation(
207             final AbstractInsnNode insn, final List<? extends SourceValue> values) {
208         int size;
209         int opcode = insn.getOpcode();
210         if (opcode == MULTIANEWARRAY) {
211             size = 1;
212         } else if (opcode == INVOKEDYNAMIC) {
213             size = Type.getReturnType(((InvokeDynamicInsnNode) insn).desc).getSize();
214         } else {
215             size = Type.getReturnType(((MethodInsnNode) insn).desc).getSize();
216         }
217         return new SourceValue(size, insn);
218     }
219 
220     @Override
returnOperation( final AbstractInsnNode insn, final SourceValue value, final SourceValue expected)221     public void returnOperation(
222             final AbstractInsnNode insn, final SourceValue value, final SourceValue expected) {
223         // Nothing to do.
224     }
225 
226     @Override
merge(final SourceValue value1, final SourceValue value2)227     public SourceValue merge(final SourceValue value1, final SourceValue value2) {
228         if (value1.insns instanceof SmallSet && value2.insns instanceof SmallSet) {
229             Set<AbstractInsnNode> setUnion =
230                     ((SmallSet<AbstractInsnNode>) value1.insns)
231                             .union((SmallSet<AbstractInsnNode>) value2.insns);
232             if (setUnion == value1.insns && value1.size == value2.size) {
233                 return value1;
234             } else {
235                 return new SourceValue(Math.min(value1.size, value2.size), setUnion);
236             }
237         }
238         if (value1.size != value2.size || !containsAll(value1.insns, value2.insns)) {
239             HashSet<AbstractInsnNode> setUnion = new HashSet<>();
240             setUnion.addAll(value1.insns);
241             setUnion.addAll(value2.insns);
242             return new SourceValue(Math.min(value1.size, value2.size), setUnion);
243         }
244         return value1;
245     }
246 
containsAll(final Set<E> self, final Set<E> other)247     private static <E> boolean containsAll(final Set<E> self, final Set<E> other) {
248         if (self.size() < other.size()) {
249             return false;
250         }
251         return self.containsAll(other);
252     }
253 }
254