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.Type;
033import io.ebean.enhance.asm.tree.AbstractInsnNode;
034import io.ebean.enhance.asm.tree.FieldInsnNode;
035import io.ebean.enhance.asm.tree.InvokeDynamicInsnNode;
036import io.ebean.enhance.asm.tree.MethodInsnNode;
037
038import java.util.List;
039
040/**
041 * An extended {@link BasicInterpreter} that checks that bytecode instructions
042 * are correctly used.
043 * 
044 * @author Eric Bruneton
045 * @author Bing Ran
046 */
047public class BasicVerifier extends BasicInterpreter {
048
049    public BasicVerifier() {
050        super(ASM6);
051    }
052
053    protected BasicVerifier(final int api) {
054        super(api);
055    }
056
057    @Override
058    public BasicValue copyOperation(final AbstractInsnNode insn,
059                                    final BasicValue value) throws AnalyzerException {
060        Value expected;
061        switch (insn.getOpcode()) {
062        case ILOAD:
063        case ISTORE:
064            expected = BasicValue.INT_VALUE;
065            break;
066        case FLOAD:
067        case FSTORE:
068            expected = BasicValue.FLOAT_VALUE;
069            break;
070        case LLOAD:
071        case LSTORE:
072            expected = BasicValue.LONG_VALUE;
073            break;
074        case DLOAD:
075        case DSTORE:
076            expected = BasicValue.DOUBLE_VALUE;
077            break;
078        case ALOAD:
079            if (!value.isReference()) {
080                throw new AnalyzerException(insn, null, "an object reference",
081                        value);
082            }
083            return value;
084        case ASTORE:
085            if (!value.isReference()
086                    && !BasicValue.RETURNADDRESS_VALUE.equals(value)) {
087                throw new AnalyzerException(insn, null,
088                        "an object reference or a return address", value);
089            }
090            return value;
091        default:
092            return value;
093        }
094        if (!expected.equals(value)) {
095            throw new AnalyzerException(insn, null, expected, value);
096        }
097        return value;
098    }
099
100    @Override
101    public BasicValue unaryOperation(final AbstractInsnNode insn,
102                                     final BasicValue value) throws AnalyzerException {
103        BasicValue expected;
104        switch (insn.getOpcode()) {
105        case INEG:
106        case IINC:
107        case I2F:
108        case I2L:
109        case I2D:
110        case I2B:
111        case I2C:
112        case I2S:
113        case IFEQ:
114        case IFNE:
115        case IFLT:
116        case IFGE:
117        case IFGT:
118        case IFLE:
119        case TABLESWITCH:
120        case LOOKUPSWITCH:
121        case IRETURN:
122        case NEWARRAY:
123        case ANEWARRAY:
124            expected = BasicValue.INT_VALUE;
125            break;
126        case FNEG:
127        case F2I:
128        case F2L:
129        case F2D:
130        case FRETURN:
131            expected = BasicValue.FLOAT_VALUE;
132            break;
133        case LNEG:
134        case L2I:
135        case L2F:
136        case L2D:
137        case LRETURN:
138            expected = BasicValue.LONG_VALUE;
139            break;
140        case DNEG:
141        case D2I:
142        case D2F:
143        case D2L:
144        case DRETURN:
145            expected = BasicValue.DOUBLE_VALUE;
146            break;
147        case GETFIELD:
148            expected = newValue(Type
149                    .getObjectType(((FieldInsnNode) insn).owner));
150            break;
151        case CHECKCAST:
152            if (!value.isReference()) {
153                throw new AnalyzerException(insn, null, "an object reference",
154                        value);
155            }
156            return super.unaryOperation(insn, value);
157        case ARRAYLENGTH:
158            if (!isArrayValue(value)) {
159                throw new AnalyzerException(insn, null, "an array reference",
160                        value);
161            }
162            return super.unaryOperation(insn, value);
163        case ARETURN:
164        case ATHROW:
165        case INSTANCEOF:
166        case MONITORENTER:
167        case MONITOREXIT:
168        case IFNULL:
169        case IFNONNULL:
170            if (!value.isReference()) {
171                throw new AnalyzerException(insn, null, "an object reference",
172                        value);
173            }
174            return super.unaryOperation(insn, value);
175        case PUTSTATIC:
176            expected = newValue(Type.getType(((FieldInsnNode) insn).desc));
177            break;
178        default:
179            throw new Error("Internal error.");
180        }
181        if (!isSubTypeOf(value, expected)) {
182            throw new AnalyzerException(insn, null, expected, value);
183        }
184        return super.unaryOperation(insn, value);
185    }
186
187    @Override
188    public BasicValue binaryOperation(final AbstractInsnNode insn,
189                                      final BasicValue value1, final BasicValue value2)
190            throws AnalyzerException {
191        BasicValue expected1;
192        BasicValue expected2;
193        switch (insn.getOpcode()) {
194        case IALOAD:
195            expected1 = newValue(Type.getType("[I"));
196            expected2 = BasicValue.INT_VALUE;
197            break;
198        case BALOAD:
199            if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
200                expected1 = newValue(Type.getType("[Z"));
201            } else {
202                expected1 = newValue(Type.getType("[B"));
203            }
204            expected2 = BasicValue.INT_VALUE;
205            break;
206        case CALOAD:
207            expected1 = newValue(Type.getType("[C"));
208            expected2 = BasicValue.INT_VALUE;
209            break;
210        case SALOAD:
211            expected1 = newValue(Type.getType("[S"));
212            expected2 = BasicValue.INT_VALUE;
213            break;
214        case LALOAD:
215            expected1 = newValue(Type.getType("[J"));
216            expected2 = BasicValue.INT_VALUE;
217            break;
218        case FALOAD:
219            expected1 = newValue(Type.getType("[F"));
220            expected2 = BasicValue.INT_VALUE;
221            break;
222        case DALOAD:
223            expected1 = newValue(Type.getType("[D"));
224            expected2 = BasicValue.INT_VALUE;
225            break;
226        case AALOAD:
227            expected1 = newValue(Type.getType("[Ljava/lang/Object;"));
228            expected2 = BasicValue.INT_VALUE;
229            break;
230        case IADD:
231        case ISUB:
232        case IMUL:
233        case IDIV:
234        case IREM:
235        case ISHL:
236        case ISHR:
237        case IUSHR:
238        case IAND:
239        case IOR:
240        case IXOR:
241        case IF_ICMPEQ:
242        case IF_ICMPNE:
243        case IF_ICMPLT:
244        case IF_ICMPGE:
245        case IF_ICMPGT:
246        case IF_ICMPLE:
247            expected1 = BasicValue.INT_VALUE;
248            expected2 = BasicValue.INT_VALUE;
249            break;
250        case FADD:
251        case FSUB:
252        case FMUL:
253        case FDIV:
254        case FREM:
255        case FCMPL:
256        case FCMPG:
257            expected1 = BasicValue.FLOAT_VALUE;
258            expected2 = BasicValue.FLOAT_VALUE;
259            break;
260        case LADD:
261        case LSUB:
262        case LMUL:
263        case LDIV:
264        case LREM:
265        case LAND:
266        case LOR:
267        case LXOR:
268        case LCMP:
269            expected1 = BasicValue.LONG_VALUE;
270            expected2 = BasicValue.LONG_VALUE;
271            break;
272        case LSHL:
273        case LSHR:
274        case LUSHR:
275            expected1 = BasicValue.LONG_VALUE;
276            expected2 = BasicValue.INT_VALUE;
277            break;
278        case DADD:
279        case DSUB:
280        case DMUL:
281        case DDIV:
282        case DREM:
283        case DCMPL:
284        case DCMPG:
285            expected1 = BasicValue.DOUBLE_VALUE;
286            expected2 = BasicValue.DOUBLE_VALUE;
287            break;
288        case IF_ACMPEQ:
289        case IF_ACMPNE:
290            expected1 = BasicValue.REFERENCE_VALUE;
291            expected2 = BasicValue.REFERENCE_VALUE;
292            break;
293        case PUTFIELD:
294            FieldInsnNode fin = (FieldInsnNode) insn;
295            expected1 = newValue(Type.getObjectType(fin.owner));
296            expected2 = newValue(Type.getType(fin.desc));
297            break;
298        default:
299            throw new Error("Internal error.");
300        }
301        if (!isSubTypeOf(value1, expected1)) {
302            throw new AnalyzerException(insn, "First argument", expected1,
303                    value1);
304        } else if (!isSubTypeOf(value2, expected2)) {
305            throw new AnalyzerException(insn, "Second argument", expected2,
306                    value2);
307        }
308        if (insn.getOpcode() == AALOAD) {
309            return getElementValue(value1);
310        } else {
311            return super.binaryOperation(insn, value1, value2);
312        }
313    }
314
315    @Override
316    public BasicValue ternaryOperation(final AbstractInsnNode insn,
317                                       final BasicValue value1, final BasicValue value2,
318                                       final BasicValue value3) throws AnalyzerException {
319        BasicValue expected1;
320        BasicValue expected3;
321        switch (insn.getOpcode()) {
322        case IASTORE:
323            expected1 = newValue(Type.getType("[I"));
324            expected3 = BasicValue.INT_VALUE;
325            break;
326        case BASTORE:
327            if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
328                expected1 = newValue(Type.getType("[Z"));
329            } else {
330                expected1 = newValue(Type.getType("[B"));
331            }
332            expected3 = BasicValue.INT_VALUE;
333            break;
334        case CASTORE:
335            expected1 = newValue(Type.getType("[C"));
336            expected3 = BasicValue.INT_VALUE;
337            break;
338        case SASTORE:
339            expected1 = newValue(Type.getType("[S"));
340            expected3 = BasicValue.INT_VALUE;
341            break;
342        case LASTORE:
343            expected1 = newValue(Type.getType("[J"));
344            expected3 = BasicValue.LONG_VALUE;
345            break;
346        case FASTORE:
347            expected1 = newValue(Type.getType("[F"));
348            expected3 = BasicValue.FLOAT_VALUE;
349            break;
350        case DASTORE:
351            expected1 = newValue(Type.getType("[D"));
352            expected3 = BasicValue.DOUBLE_VALUE;
353            break;
354        case AASTORE:
355            expected1 = value1;
356            expected3 = BasicValue.REFERENCE_VALUE;
357            break;
358        default:
359            throw new Error("Internal error.");
360        }
361        if (!isSubTypeOf(value1, expected1)) {
362            throw new AnalyzerException(insn, "First argument", "a "
363                    + expected1 + " array reference", value1);
364        } else if (!BasicValue.INT_VALUE.equals(value2)) {
365            throw new AnalyzerException(insn, "Second argument",
366                    BasicValue.INT_VALUE, value2);
367        } else if (!isSubTypeOf(value3, expected3)) {
368            throw new AnalyzerException(insn, "Third argument", expected3,
369                    value3);
370        }
371        return null;
372    }
373
374    @Override
375    public BasicValue naryOperation(final AbstractInsnNode insn,
376                                    final List<? extends BasicValue> values) throws AnalyzerException {
377        int opcode = insn.getOpcode();
378        if (opcode == MULTIANEWARRAY) {
379            for (int i = 0; i < values.size(); ++i) {
380                if (!BasicValue.INT_VALUE.equals(values.get(i))) {
381                    throw new AnalyzerException(insn, null,
382                            BasicValue.INT_VALUE, values.get(i));
383                }
384            }
385        } else {
386            int i = 0;
387            int j = 0;
388            if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) {
389                Type owner = Type.getObjectType(((MethodInsnNode) insn).owner);
390                if (!isSubTypeOf(values.get(i++), newValue(owner))) {
391                    throw new AnalyzerException(insn, "Method owner",
392                            newValue(owner), values.get(0));
393                }
394            }
395            String desc = (opcode == INVOKEDYNAMIC) ? ((InvokeDynamicInsnNode) insn).desc
396                    : ((MethodInsnNode) insn).desc;
397            Type[] args = Type.getArgumentTypes(desc);
398            while (i < values.size()) {
399                BasicValue expected = newValue(args[j++]);
400                BasicValue encountered = values.get(i++);
401                if (!isSubTypeOf(encountered, expected)) {
402                    throw new AnalyzerException(insn, "Argument " + j,
403                            expected, encountered);
404                }
405            }
406        }
407        return super.naryOperation(insn, values);
408    }
409
410    @Override
411    public void returnOperation(final AbstractInsnNode insn,
412                                final BasicValue value, final BasicValue expected)
413            throws AnalyzerException {
414        if (!isSubTypeOf(value, expected)) {
415            throw new AnalyzerException(insn, "Incompatible return type",
416                    expected, value);
417        }
418    }
419
420    protected boolean isArrayValue(final BasicValue value) {
421        return value.isReference();
422    }
423
424    protected BasicValue getElementValue(final BasicValue objectArrayValue)
425            throws AnalyzerException {
426        return BasicValue.REFERENCE_VALUE;
427    }
428
429    protected boolean isSubTypeOf(final BasicValue value,
430            final BasicValue expected) {
431        return value.equals(expected);
432    }
433}