1/***
2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2007 INRIA, France Telecom
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 *    contributors may be used to endorse or promote products derived from
16 *    this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 */
30package org.mockito.asm.tree.analysis;
31
32import java.util.List;
33
34import org.mockito.asm.Opcodes;
35import org.mockito.asm.Type;
36import org.mockito.asm.tree.AbstractInsnNode;
37import org.mockito.asm.tree.FieldInsnNode;
38import org.mockito.asm.tree.IntInsnNode;
39import org.mockito.asm.tree.LdcInsnNode;
40import org.mockito.asm.tree.MethodInsnNode;
41import org.mockito.asm.tree.MultiANewArrayInsnNode;
42import org.mockito.asm.tree.TypeInsnNode;
43
44/**
45 * An {@link Interpreter} for {@link BasicValue} values.
46 *
47 * @author Eric Bruneton
48 * @author Bing Ran
49 */
50public class BasicInterpreter implements Opcodes, Interpreter {
51
52    public Value newValue(final Type type) {
53        if (type == null) {
54            return BasicValue.UNINITIALIZED_VALUE;
55        }
56        switch (type.getSort()) {
57            case Type.VOID:
58                return null;
59            case Type.BOOLEAN:
60            case Type.CHAR:
61            case Type.BYTE:
62            case Type.SHORT:
63            case Type.INT:
64                return BasicValue.INT_VALUE;
65            case Type.FLOAT:
66                return BasicValue.FLOAT_VALUE;
67            case Type.LONG:
68                return BasicValue.LONG_VALUE;
69            case Type.DOUBLE:
70                return BasicValue.DOUBLE_VALUE;
71            case Type.ARRAY:
72            case Type.OBJECT:
73                return BasicValue.REFERENCE_VALUE;
74            default:
75                throw new Error("Internal error");
76        }
77    }
78
79    public Value newOperation(final AbstractInsnNode insn) {
80        switch (insn.getOpcode()) {
81            case ACONST_NULL:
82                return newValue(Type.getObjectType("null"));
83            case ICONST_M1:
84            case ICONST_0:
85            case ICONST_1:
86            case ICONST_2:
87            case ICONST_3:
88            case ICONST_4:
89            case ICONST_5:
90                return BasicValue.INT_VALUE;
91            case LCONST_0:
92            case LCONST_1:
93                return BasicValue.LONG_VALUE;
94            case FCONST_0:
95            case FCONST_1:
96            case FCONST_2:
97                return BasicValue.FLOAT_VALUE;
98            case DCONST_0:
99            case DCONST_1:
100                return BasicValue.DOUBLE_VALUE;
101            case BIPUSH:
102            case SIPUSH:
103                return BasicValue.INT_VALUE;
104            case LDC:
105                Object cst = ((LdcInsnNode) insn).cst;
106                if (cst instanceof Integer) {
107                    return BasicValue.INT_VALUE;
108                } else if (cst instanceof Float) {
109                    return BasicValue.FLOAT_VALUE;
110                } else if (cst instanceof Long) {
111                    return BasicValue.LONG_VALUE;
112                } else if (cst instanceof Double) {
113                    return BasicValue.DOUBLE_VALUE;
114                } else if (cst instanceof Type) {
115                    return newValue(Type.getObjectType("java/lang/Class"));
116                } else {
117                    return newValue(Type.getType(cst.getClass()));
118                }
119            case JSR:
120                return BasicValue.RETURNADDRESS_VALUE;
121            case GETSTATIC:
122                return newValue(Type.getType(((FieldInsnNode) insn).desc));
123            case NEW:
124                return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
125            default:
126                throw new Error("Internal error.");
127        }
128    }
129
130    public Value copyOperation(final AbstractInsnNode insn, final Value value)
131            throws AnalyzerException
132    {
133        return value;
134    }
135
136    public Value unaryOperation(final AbstractInsnNode insn, final Value value)
137            throws AnalyzerException
138    {
139        switch (insn.getOpcode()) {
140            case INEG:
141            case IINC:
142            case L2I:
143            case F2I:
144            case D2I:
145            case I2B:
146            case I2C:
147            case I2S:
148                return BasicValue.INT_VALUE;
149            case FNEG:
150            case I2F:
151            case L2F:
152            case D2F:
153                return BasicValue.FLOAT_VALUE;
154            case LNEG:
155            case I2L:
156            case F2L:
157            case D2L:
158                return BasicValue.LONG_VALUE;
159            case DNEG:
160            case I2D:
161            case L2D:
162            case F2D:
163                return BasicValue.DOUBLE_VALUE;
164            case IFEQ:
165            case IFNE:
166            case IFLT:
167            case IFGE:
168            case IFGT:
169            case IFLE:
170            case TABLESWITCH:
171            case LOOKUPSWITCH:
172            case IRETURN:
173            case LRETURN:
174            case FRETURN:
175            case DRETURN:
176            case ARETURN:
177            case PUTSTATIC:
178                return null;
179            case GETFIELD:
180                return newValue(Type.getType(((FieldInsnNode) insn).desc));
181            case NEWARRAY:
182                switch (((IntInsnNode) insn).operand) {
183                    case T_BOOLEAN:
184                        return newValue(Type.getType("[Z"));
185                    case T_CHAR:
186                        return newValue(Type.getType("[C"));
187                    case T_BYTE:
188                        return newValue(Type.getType("[B"));
189                    case T_SHORT:
190                        return newValue(Type.getType("[S"));
191                    case T_INT:
192                        return newValue(Type.getType("[I"));
193                    case T_FLOAT:
194                        return newValue(Type.getType("[F"));
195                    case T_DOUBLE:
196                        return newValue(Type.getType("[D"));
197                    case T_LONG:
198                        return newValue(Type.getType("[J"));
199                    default:
200                        throw new AnalyzerException("Invalid array type");
201                }
202            case ANEWARRAY:
203                String desc = ((TypeInsnNode) insn).desc;
204                return newValue(Type.getType("[" + Type.getObjectType(desc)));
205            case ARRAYLENGTH:
206                return BasicValue.INT_VALUE;
207            case ATHROW:
208                return null;
209            case CHECKCAST:
210                desc = ((TypeInsnNode) insn).desc;
211                return newValue(Type.getObjectType(desc));
212            case INSTANCEOF:
213                return BasicValue.INT_VALUE;
214            case MONITORENTER:
215            case MONITOREXIT:
216            case IFNULL:
217            case IFNONNULL:
218                return null;
219            default:
220                throw new Error("Internal error.");
221        }
222    }
223
224    public Value binaryOperation(
225        final AbstractInsnNode insn,
226        final Value value1,
227        final Value value2) throws AnalyzerException
228    {
229        switch (insn.getOpcode()) {
230            case IALOAD:
231            case BALOAD:
232            case CALOAD:
233            case SALOAD:
234            case IADD:
235            case ISUB:
236            case IMUL:
237            case IDIV:
238            case IREM:
239            case ISHL:
240            case ISHR:
241            case IUSHR:
242            case IAND:
243            case IOR:
244            case IXOR:
245                return BasicValue.INT_VALUE;
246            case FALOAD:
247            case FADD:
248            case FSUB:
249            case FMUL:
250            case FDIV:
251            case FREM:
252                return BasicValue.FLOAT_VALUE;
253            case LALOAD:
254            case LADD:
255            case LSUB:
256            case LMUL:
257            case LDIV:
258            case LREM:
259            case LSHL:
260            case LSHR:
261            case LUSHR:
262            case LAND:
263            case LOR:
264            case LXOR:
265                return BasicValue.LONG_VALUE;
266            case DALOAD:
267            case DADD:
268            case DSUB:
269            case DMUL:
270            case DDIV:
271            case DREM:
272                return BasicValue.DOUBLE_VALUE;
273            case AALOAD:
274                return BasicValue.REFERENCE_VALUE;
275            case LCMP:
276            case FCMPL:
277            case FCMPG:
278            case DCMPL:
279            case DCMPG:
280                return BasicValue.INT_VALUE;
281            case IF_ICMPEQ:
282            case IF_ICMPNE:
283            case IF_ICMPLT:
284            case IF_ICMPGE:
285            case IF_ICMPGT:
286            case IF_ICMPLE:
287            case IF_ACMPEQ:
288            case IF_ACMPNE:
289            case PUTFIELD:
290                return null;
291            default:
292                throw new Error("Internal error.");
293        }
294    }
295
296    public Value ternaryOperation(
297        final AbstractInsnNode insn,
298        final Value value1,
299        final Value value2,
300        final Value value3) throws AnalyzerException
301    {
302        return null;
303    }
304
305    public Value naryOperation(final AbstractInsnNode insn, final List values)
306            throws AnalyzerException
307    {
308        if (insn.getOpcode() == MULTIANEWARRAY) {
309            return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc));
310        } else {
311            return newValue(Type.getReturnType(((MethodInsnNode) insn).desc));
312        }
313    }
314
315    public Value merge(final Value v, final Value w) {
316        if (!v.equals(w)) {
317            return BasicValue.UNINITIALIZED_VALUE;
318        }
319        return v;
320    }
321}
322