001/***
002 * ASM: a very small and fast Java bytecode manipulation framework
003 * Copyright (c) 2000-2011 INRIA, France Telecom
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions
008 * are met:
009 * 1. Redistributions of source code must retain the above copyright
010 *    notice, this list of conditions and the following disclaimer.
011 * 2. Redistributions in binary form must reproduce the above copyright
012 *    notice, this list of conditions and the following disclaimer in the
013 *    documentation and/or other materials provided with the distribution.
014 * 3. Neither the name of the copyright holders nor the names of its
015 *    contributors may be used to endorse or promote products derived from
016 *    this software without specific prior written permission.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
028 * THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package io.ebean.enhance.asm.tree.analysis;
031
032import io.ebean.enhance.asm.Handle;
033import io.ebean.enhance.asm.Opcodes;
034import io.ebean.enhance.asm.Type;
035import io.ebean.enhance.asm.tree.AbstractInsnNode;
036import io.ebean.enhance.asm.tree.FieldInsnNode;
037import io.ebean.enhance.asm.tree.IntInsnNode;
038import io.ebean.enhance.asm.tree.InvokeDynamicInsnNode;
039import io.ebean.enhance.asm.tree.LdcInsnNode;
040import io.ebean.enhance.asm.tree.MethodInsnNode;
041import io.ebean.enhance.asm.tree.MultiANewArrayInsnNode;
042import io.ebean.enhance.asm.tree.TypeInsnNode;
043
044import java.util.List;
045
046/**
047 * An {@link Interpreter} for {@link BasicValue} values.
048 * 
049 * @author Eric Bruneton
050 * @author Bing Ran
051 */
052public class BasicInterpreter extends Interpreter<BasicValue> implements
053                Opcodes {
054
055    public BasicInterpreter() {
056        super(ASM6);
057    }
058
059    protected BasicInterpreter(final int api) {
060        super(api);
061    }
062
063    @Override
064    public BasicValue newValue(final Type type) {
065        if (type == null) {
066            return BasicValue.UNINITIALIZED_VALUE;
067        }
068        switch (type.getSort()) {
069        case Type.VOID:
070            return null;
071        case Type.BOOLEAN:
072        case Type.CHAR:
073        case Type.BYTE:
074        case Type.SHORT:
075        case Type.INT:
076            return BasicValue.INT_VALUE;
077        case Type.FLOAT:
078            return BasicValue.FLOAT_VALUE;
079        case Type.LONG:
080            return BasicValue.LONG_VALUE;
081        case Type.DOUBLE:
082            return BasicValue.DOUBLE_VALUE;
083        case Type.ARRAY:
084        case Type.OBJECT:
085            return BasicValue.REFERENCE_VALUE;
086        default:
087            throw new Error("Internal error");
088        }
089    }
090
091    @Override
092    public BasicValue newOperation(final AbstractInsnNode insn)
093            throws AnalyzerException {
094        switch (insn.getOpcode()) {
095        case ACONST_NULL:
096            return newValue(Type.getObjectType("null"));
097        case ICONST_M1:
098        case ICONST_0:
099        case ICONST_1:
100        case ICONST_2:
101        case ICONST_3:
102        case ICONST_4:
103        case ICONST_5:
104            return BasicValue.INT_VALUE;
105        case LCONST_0:
106        case LCONST_1:
107            return BasicValue.LONG_VALUE;
108        case FCONST_0:
109        case FCONST_1:
110        case FCONST_2:
111            return BasicValue.FLOAT_VALUE;
112        case DCONST_0:
113        case DCONST_1:
114            return BasicValue.DOUBLE_VALUE;
115        case BIPUSH:
116        case SIPUSH:
117            return BasicValue.INT_VALUE;
118        case LDC:
119            Object cst = ((LdcInsnNode) insn).cst;
120            if (cst instanceof Integer) {
121                return BasicValue.INT_VALUE;
122            } else if (cst instanceof Float) {
123                return BasicValue.FLOAT_VALUE;
124            } else if (cst instanceof Long) {
125                return BasicValue.LONG_VALUE;
126            } else if (cst instanceof Double) {
127                return BasicValue.DOUBLE_VALUE;
128            } else if (cst instanceof String) {
129                return newValue(Type.getObjectType("java/lang/String"));
130            } else if (cst instanceof Type) {
131                int sort = ((Type) cst).getSort();
132                if (sort == Type.OBJECT || sort == Type.ARRAY) {
133                    return newValue(Type.getObjectType("java/lang/Class"));
134                } else if (sort == Type.METHOD) {
135                    return newValue(Type
136                            .getObjectType("java/lang/invoke/MethodType"));
137                } else {
138                    throw new IllegalArgumentException("Illegal LDC constant "
139                            + cst);
140                }
141            } else if (cst instanceof Handle) {
142                return newValue(Type
143                        .getObjectType("java/lang/invoke/MethodHandle"));
144            } else {
145                throw new IllegalArgumentException("Illegal LDC constant "
146                        + cst);
147            }
148        case JSR:
149            return BasicValue.RETURNADDRESS_VALUE;
150        case GETSTATIC:
151            return newValue(Type.getType(((FieldInsnNode) insn).desc));
152        case NEW:
153            return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
154        default:
155            throw new Error("Internal error.");
156        }
157    }
158
159    @Override
160    public BasicValue copyOperation(final AbstractInsnNode insn,
161                                    final BasicValue value) throws AnalyzerException {
162        return value;
163    }
164
165    @Override
166    public BasicValue unaryOperation(final AbstractInsnNode insn,
167                                     final BasicValue value) throws AnalyzerException {
168        switch (insn.getOpcode()) {
169        case INEG:
170        case IINC:
171        case L2I:
172        case F2I:
173        case D2I:
174        case I2B:
175        case I2C:
176        case I2S:
177            return BasicValue.INT_VALUE;
178        case FNEG:
179        case I2F:
180        case L2F:
181        case D2F:
182            return BasicValue.FLOAT_VALUE;
183        case LNEG:
184        case I2L:
185        case F2L:
186        case D2L:
187            return BasicValue.LONG_VALUE;
188        case DNEG:
189        case I2D:
190        case L2D:
191        case F2D:
192            return BasicValue.DOUBLE_VALUE;
193        case IFEQ:
194        case IFNE:
195        case IFLT:
196        case IFGE:
197        case IFGT:
198        case IFLE:
199        case TABLESWITCH:
200        case LOOKUPSWITCH:
201        case IRETURN:
202        case LRETURN:
203        case FRETURN:
204        case DRETURN:
205        case ARETURN:
206        case PUTSTATIC:
207            return null;
208        case GETFIELD:
209            return newValue(Type.getType(((FieldInsnNode) insn).desc));
210        case NEWARRAY:
211            switch (((IntInsnNode) insn).operand) {
212            case T_BOOLEAN:
213                return newValue(Type.getType("[Z"));
214            case T_CHAR:
215                return newValue(Type.getType("[C"));
216            case T_BYTE:
217                return newValue(Type.getType("[B"));
218            case T_SHORT:
219                return newValue(Type.getType("[S"));
220            case T_INT:
221                return newValue(Type.getType("[I"));
222            case T_FLOAT:
223                return newValue(Type.getType("[F"));
224            case T_DOUBLE:
225                return newValue(Type.getType("[D"));
226            case T_LONG:
227                return newValue(Type.getType("[J"));
228            default:
229                throw new AnalyzerException(insn, "Invalid array type");
230            }
231        case ANEWARRAY:
232            String desc = ((TypeInsnNode) insn).desc;
233            return newValue(Type.getType("[" + Type.getObjectType(desc)));
234        case ARRAYLENGTH:
235            return BasicValue.INT_VALUE;
236        case ATHROW:
237            return null;
238        case CHECKCAST:
239            desc = ((TypeInsnNode) insn).desc;
240            return newValue(Type.getObjectType(desc));
241        case INSTANCEOF:
242            return BasicValue.INT_VALUE;
243        case MONITORENTER:
244        case MONITOREXIT:
245        case IFNULL:
246        case IFNONNULL:
247            return null;
248        default:
249            throw new Error("Internal error.");
250        }
251    }
252
253    @Override
254    public BasicValue binaryOperation(final AbstractInsnNode insn,
255                                      final BasicValue value1, final BasicValue value2)
256            throws AnalyzerException {
257        switch (insn.getOpcode()) {
258        case IALOAD:
259        case BALOAD:
260        case CALOAD:
261        case SALOAD:
262        case IADD:
263        case ISUB:
264        case IMUL:
265        case IDIV:
266        case IREM:
267        case ISHL:
268        case ISHR:
269        case IUSHR:
270        case IAND:
271        case IOR:
272        case IXOR:
273            return BasicValue.INT_VALUE;
274        case FALOAD:
275        case FADD:
276        case FSUB:
277        case FMUL:
278        case FDIV:
279        case FREM:
280            return BasicValue.FLOAT_VALUE;
281        case LALOAD:
282        case LADD:
283        case LSUB:
284        case LMUL:
285        case LDIV:
286        case LREM:
287        case LSHL:
288        case LSHR:
289        case LUSHR:
290        case LAND:
291        case LOR:
292        case LXOR:
293            return BasicValue.LONG_VALUE;
294        case DALOAD:
295        case DADD:
296        case DSUB:
297        case DMUL:
298        case DDIV:
299        case DREM:
300            return BasicValue.DOUBLE_VALUE;
301        case AALOAD:
302            return BasicValue.REFERENCE_VALUE;
303        case LCMP:
304        case FCMPL:
305        case FCMPG:
306        case DCMPL:
307        case DCMPG:
308            return BasicValue.INT_VALUE;
309        case IF_ICMPEQ:
310        case IF_ICMPNE:
311        case IF_ICMPLT:
312        case IF_ICMPGE:
313        case IF_ICMPGT:
314        case IF_ICMPLE:
315        case IF_ACMPEQ:
316        case IF_ACMPNE:
317        case PUTFIELD:
318            return null;
319        default:
320            throw new Error("Internal error.");
321        }
322    }
323
324    @Override
325    public BasicValue ternaryOperation(final AbstractInsnNode insn,
326                                       final BasicValue value1, final BasicValue value2,
327                                       final BasicValue value3) throws AnalyzerException {
328        return null;
329    }
330
331    @Override
332    public BasicValue naryOperation(final AbstractInsnNode insn,
333                                    final List<? extends BasicValue> values) throws AnalyzerException {
334        int opcode = insn.getOpcode();
335        if (opcode == MULTIANEWARRAY) {
336            return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc));
337        } else if (opcode == INVOKEDYNAMIC) {
338            return newValue(Type
339                    .getReturnType(((InvokeDynamicInsnNode) insn).desc));
340        } else {
341            return newValue(Type.getReturnType(((MethodInsnNode) insn).desc));
342        }
343    }
344
345    @Override
346    public void returnOperation(final AbstractInsnNode insn,
347                                final BasicValue value, final BasicValue expected)
348            throws AnalyzerException {
349    }
350
351    @Override
352    public BasicValue merge(final BasicValue v, final BasicValue w) {
353        if (!v.equals(w)) {
354            return BasicValue.UNINITIALIZED_VALUE;
355        }
356        return v;
357    }
358}