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.commons;
60 
61 import java.util.ArrayList;
62 import java.util.HashMap;
63 import java.util.List;
64 import java.util.Map;
65 import jdk.internal.org.objectweb.asm.ConstantDynamic;
66 import jdk.internal.org.objectweb.asm.Handle;
67 import jdk.internal.org.objectweb.asm.Label;
68 import jdk.internal.org.objectweb.asm.MethodVisitor;
69 import jdk.internal.org.objectweb.asm.Opcodes;
70 import jdk.internal.org.objectweb.asm.Type;
71 
72 /**
73  * A {@link MethodVisitor} that keeps track of stack map frame changes between {@link
74  * #visitFrame(int, int, Object[], int, Object[])} calls. This adapter must be used with the {@link
75  * jdk.internal.org.objectweb.asm.ClassReader#EXPAND_FRAMES} option. Each visit<i>X</i> instruction delegates to
76  * the next visitor in the chain, if any, and then simulates the effect of this instruction on the
77  * stack map frame, represented by {@link #locals} and {@link #stack}. The next visitor in the chain
78  * can get the state of the stack map frame <i>before</i> each instruction by reading the value of
79  * these fields in its visit<i>X</i> methods (this requires a reference to the AnalyzerAdapter that
80  * is before it in the chain). If this adapter is used with a class that does not contain stack map
81  * table attributes (i.e., pre Java 6 classes) then this adapter may not be able to compute the
82  * stack map frame for each instruction. In this case no exception is thrown but the {@link #locals}
83  * and {@link #stack} fields will be null for these instructions.
84  *
85  * @author Eric Bruneton
86  */
87 public class AnalyzerAdapter extends MethodVisitor {
88 
89     /**
90       * The local variable slots for the current execution frame. Primitive types are represented by
91       * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
92       * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and
93       * double are represented by two elements, the second one being TOP). Reference types are
94       * represented by String objects (representing internal names), and uninitialized types by Label
95       * objects (this label designates the NEW instruction that created this uninitialized value). This
96       * field is {@literal null} for unreachable instructions.
97       */
98     public List<Object> locals;
99 
100     /**
101       * The operand stack slots for the current execution frame. Primitive types are represented by
102       * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
103       * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and
104       * double are represented by two elements, the second one being TOP). Reference types are
105       * represented by String objects (representing internal names), and uninitialized types by Label
106       * objects (this label designates the NEW instruction that created this uninitialized value). This
107       * field is {@literal null} for unreachable instructions.
108       */
109     public List<Object> stack;
110 
111     /** The labels that designate the next instruction to be visited. May be {@literal null}. */
112     private List<Label> labels;
113 
114     /**
115       * The uninitialized types in the current execution frame. This map associates internal names to
116       * Label objects. Each label designates a NEW instruction that created the currently uninitialized
117       * types, and the associated internal name represents the NEW operand, i.e. the final, initialized
118       * type value.
119       */
120     public Map<Object, Object> uninitializedTypes;
121 
122     /** The maximum stack size of this method. */
123     private int maxStack;
124 
125     /** The maximum number of local variables of this method. */
126     private int maxLocals;
127 
128     /** The owner's class name. */
129     private String owner;
130 
131     /**
132       * Constructs a new {@link AnalyzerAdapter}. <i>Subclasses must not use this constructor</i>.
133       * Instead, they must use the {@link #AnalyzerAdapter(int, String, int, String, String,
134       * MethodVisitor)} version.
135       *
136       * @param owner the owner's class name.
137       * @param access the method's access flags (see {@link Opcodes}).
138       * @param name the method's name.
139       * @param descriptor the method's descriptor (see {@link Type}).
140       * @param methodVisitor the method visitor to which this adapter delegates calls. May be {@literal
141       *     null}.
142       * @throws IllegalStateException If a subclass calls this constructor.
143       */
AnalyzerAdapter( final String owner, final int access, final String name, final String descriptor, final MethodVisitor methodVisitor)144     public AnalyzerAdapter(
145             final String owner,
146             final int access,
147             final String name,
148             final String descriptor,
149             final MethodVisitor methodVisitor) {
150         this(Opcodes.ASM7, owner, access, name, descriptor, methodVisitor);
151         if (getClass() != AnalyzerAdapter.class) {
152             throw new IllegalStateException();
153         }
154     }
155 
156     /**
157       * Constructs a new {@link AnalyzerAdapter}.
158       *
159       * @param api the ASM API version implemented by this visitor. Must be one of {@link
160       *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
161       * @param owner the owner's class name.
162       * @param access the method's access flags (see {@link Opcodes}).
163       * @param name the method's name.
164       * @param descriptor the method's descriptor (see {@link Type}).
165       * @param methodVisitor the method visitor to which this adapter delegates calls. May be {@literal
166       *     null}.
167       */
AnalyzerAdapter( final int api, final String owner, final int access, final String name, final String descriptor, final MethodVisitor methodVisitor)168     protected AnalyzerAdapter(
169             final int api,
170             final String owner,
171             final int access,
172             final String name,
173             final String descriptor,
174             final MethodVisitor methodVisitor) {
175         super(api, methodVisitor);
176         this.owner = owner;
177         locals = new ArrayList<Object>();
178         stack = new ArrayList<Object>();
179         uninitializedTypes = new HashMap<Object, Object>();
180 
181         if ((access & Opcodes.ACC_STATIC) == 0) {
182             if ("<init>".equals(name)) {
183                 locals.add(Opcodes.UNINITIALIZED_THIS);
184             } else {
185                 locals.add(owner);
186             }
187         }
188         for (Type argumentType : Type.getArgumentTypes(descriptor)) {
189             switch (argumentType.getSort()) {
190                 case Type.BOOLEAN:
191                 case Type.CHAR:
192                 case Type.BYTE:
193                 case Type.SHORT:
194                 case Type.INT:
195                     locals.add(Opcodes.INTEGER);
196                     break;
197                 case Type.FLOAT:
198                     locals.add(Opcodes.FLOAT);
199                     break;
200                 case Type.LONG:
201                     locals.add(Opcodes.LONG);
202                     locals.add(Opcodes.TOP);
203                     break;
204                 case Type.DOUBLE:
205                     locals.add(Opcodes.DOUBLE);
206                     locals.add(Opcodes.TOP);
207                     break;
208                 case Type.ARRAY:
209                     locals.add(argumentType.getDescriptor());
210                     break;
211                 case Type.OBJECT:
212                     locals.add(argumentType.getInternalName());
213                     break;
214                 default:
215                     throw new AssertionError();
216             }
217         }
218         maxLocals = locals.size();
219     }
220 
221     @Override
visitFrame( final int type, final int numLocal, final Object[] local, final int numStack, final Object[] stack)222     public void visitFrame(
223             final int type,
224             final int numLocal,
225             final Object[] local,
226             final int numStack,
227             final Object[] stack) {
228         if (type != Opcodes.F_NEW) { // Uncompressed frame.
229             throw new IllegalArgumentException(
230                     "AnalyzerAdapter only accepts expanded frames (see ClassReader.EXPAND_FRAMES)");
231         }
232 
233         super.visitFrame(type, numLocal, local, numStack, stack);
234 
235         if (this.locals != null) {
236             this.locals.clear();
237             this.stack.clear();
238         } else {
239             this.locals = new ArrayList<Object>();
240             this.stack = new ArrayList<Object>();
241         }
242         visitFrameTypes(numLocal, local, this.locals);
243         visitFrameTypes(numStack, stack, this.stack);
244         maxLocals = Math.max(maxLocals, this.locals.size());
245         maxStack = Math.max(maxStack, this.stack.size());
246     }
247 
visitFrameTypes( final int numTypes, final Object[] frameTypes, final List<Object> result)248     private static void visitFrameTypes(
249             final int numTypes, final Object[] frameTypes, final List<Object> result) {
250         for (int i = 0; i < numTypes; ++i) {
251             Object frameType = frameTypes[i];
252             result.add(frameType);
253             if (frameType == Opcodes.LONG || frameType == Opcodes.DOUBLE) {
254                 result.add(Opcodes.TOP);
255             }
256         }
257     }
258 
259     @Override
visitInsn(final int opcode)260     public void visitInsn(final int opcode) {
261         super.visitInsn(opcode);
262         execute(opcode, 0, null);
263         if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) {
264             this.locals = null;
265             this.stack = null;
266         }
267     }
268 
269     @Override
visitIntInsn(final int opcode, final int operand)270     public void visitIntInsn(final int opcode, final int operand) {
271         super.visitIntInsn(opcode, operand);
272         execute(opcode, operand, null);
273     }
274 
275     @Override
visitVarInsn(final int opcode, final int var)276     public void visitVarInsn(final int opcode, final int var) {
277         super.visitVarInsn(opcode, var);
278         boolean isLongOrDouble =
279                 opcode == Opcodes.LLOAD
280                         || opcode == Opcodes.DLOAD
281                         || opcode == Opcodes.LSTORE
282                         || opcode == Opcodes.DSTORE;
283         maxLocals = Math.max(maxLocals, var + (isLongOrDouble ? 2 : 1));
284         execute(opcode, var, null);
285     }
286 
287     @Override
visitTypeInsn(final int opcode, final String type)288     public void visitTypeInsn(final int opcode, final String type) {
289         if (opcode == Opcodes.NEW) {
290             if (labels == null) {
291                 Label label = new Label();
292                 labels = new ArrayList<Label>(3);
293                 labels.add(label);
294                 if (mv != null) {
295                     mv.visitLabel(label);
296                 }
297             }
298             for (Label label : labels) {
299                 uninitializedTypes.put(label, type);
300             }
301         }
302         super.visitTypeInsn(opcode, type);
303         execute(opcode, 0, type);
304     }
305 
306     @Override
visitFieldInsn( final int opcode, final String owner, final String name, final String descriptor)307     public void visitFieldInsn(
308             final int opcode, final String owner, final String name, final String descriptor) {
309         super.visitFieldInsn(opcode, owner, name, descriptor);
310         execute(opcode, 0, descriptor);
311     }
312 
313     /**
314       * Deprecated.
315       *
316       * @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
317       */
318     @Deprecated
319     @Override
visitMethodInsn( final int opcode, final String owner, final String name, final String descriptor)320     public void visitMethodInsn(
321             final int opcode, final String owner, final String name, final String descriptor) {
322         if (api >= Opcodes.ASM5) {
323             super.visitMethodInsn(opcode, owner, name, descriptor);
324             return;
325         }
326         doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
327     }
328 
329     @Override
visitMethodInsn( final int opcode, final String owner, final String name, final String descriptor, final boolean isInterface)330     public void visitMethodInsn(
331             final int opcode,
332             final String owner,
333             final String name,
334             final String descriptor,
335             final boolean isInterface) {
336         if (api < Opcodes.ASM5) {
337             super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
338             return;
339         }
340         doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
341     }
342 
doVisitMethodInsn( final int opcode, final String owner, final String name, final String descriptor, final boolean isInterface)343     private void doVisitMethodInsn(
344             final int opcode,
345             final String owner,
346             final String name,
347             final String descriptor,
348             final boolean isInterface) {
349         if (mv != null) {
350             mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
351         }
352         if (this.locals == null) {
353             labels = null;
354             return;
355         }
356         pop(descriptor);
357         if (opcode != Opcodes.INVOKESTATIC) {
358             Object value = pop();
359             if (opcode == Opcodes.INVOKESPECIAL && name.equals("<init>")) {
360                 Object initializedValue;
361                 if (value == Opcodes.UNINITIALIZED_THIS) {
362                     initializedValue = this.owner;
363                 } else {
364                     initializedValue = uninitializedTypes.get(value);
365                 }
366                 for (int i = 0; i < locals.size(); ++i) {
367                     if (locals.get(i) == value) {
368                         locals.set(i, initializedValue);
369                     }
370                 }
371                 for (int i = 0; i < stack.size(); ++i) {
372                     if (stack.get(i) == value) {
373                         stack.set(i, initializedValue);
374                     }
375                 }
376             }
377         }
378         pushDescriptor(descriptor);
379         labels = null;
380     }
381 
382     @Override
visitInvokeDynamicInsn( final String name, final String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments)383     public void visitInvokeDynamicInsn(
384             final String name,
385             final String descriptor,
386             final Handle bootstrapMethodHandle,
387             final Object... bootstrapMethodArguments) {
388         super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
389         if (this.locals == null) {
390             labels = null;
391             return;
392         }
393         pop(descriptor);
394         pushDescriptor(descriptor);
395         labels = null;
396     }
397 
398     @Override
visitJumpInsn(final int opcode, final Label label)399     public void visitJumpInsn(final int opcode, final Label label) {
400         super.visitJumpInsn(opcode, label);
401         execute(opcode, 0, null);
402         if (opcode == Opcodes.GOTO) {
403             this.locals = null;
404             this.stack = null;
405         }
406     }
407 
408     @Override
visitLabel(final Label label)409     public void visitLabel(final Label label) {
410         super.visitLabel(label);
411         if (labels == null) {
412             labels = new ArrayList<Label>(3);
413         }
414         labels.add(label);
415     }
416 
417     @Override
visitLdcInsn(final Object value)418     public void visitLdcInsn(final Object value) {
419         super.visitLdcInsn(value);
420         if (this.locals == null) {
421             labels = null;
422             return;
423         }
424         if (value instanceof Integer) {
425             push(Opcodes.INTEGER);
426         } else if (value instanceof Long) {
427             push(Opcodes.LONG);
428             push(Opcodes.TOP);
429         } else if (value instanceof Float) {
430             push(Opcodes.FLOAT);
431         } else if (value instanceof Double) {
432             push(Opcodes.DOUBLE);
433             push(Opcodes.TOP);
434         } else if (value instanceof String) {
435             push("java/lang/String");
436         } else if (value instanceof Type) {
437             int sort = ((Type) value).getSort();
438             if (sort == Type.OBJECT || sort == Type.ARRAY) {
439                 push("java/lang/Class");
440             } else if (sort == Type.METHOD) {
441                 push("java/lang/invoke/MethodType");
442             } else {
443                 throw new IllegalArgumentException();
444             }
445         } else if (value instanceof Handle) {
446             push("java/lang/invoke/MethodHandle");
447         } else if (value instanceof ConstantDynamic) {
448             pushDescriptor(((ConstantDynamic) value).getDescriptor());
449         } else {
450             throw new IllegalArgumentException();
451         }
452         labels = null;
453     }
454 
455     @Override
visitIincInsn(final int var, final int increment)456     public void visitIincInsn(final int var, final int increment) {
457         super.visitIincInsn(var, increment);
458         maxLocals = Math.max(maxLocals, var + 1);
459         execute(Opcodes.IINC, var, null);
460     }
461 
462     @Override
visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label... labels)463     public void visitTableSwitchInsn(
464             final int min, final int max, final Label dflt, final Label... labels) {
465         super.visitTableSwitchInsn(min, max, dflt, labels);
466         execute(Opcodes.TABLESWITCH, 0, null);
467         this.locals = null;
468         this.stack = null;
469     }
470 
471     @Override
visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels)472     public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
473         super.visitLookupSwitchInsn(dflt, keys, labels);
474         execute(Opcodes.LOOKUPSWITCH, 0, null);
475         this.locals = null;
476         this.stack = null;
477     }
478 
479     @Override
visitMultiANewArrayInsn(final String descriptor, final int numDimensions)480     public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
481         super.visitMultiANewArrayInsn(descriptor, numDimensions);
482         execute(Opcodes.MULTIANEWARRAY, numDimensions, descriptor);
483     }
484 
485     @Override
visitLocalVariable( final String name, final String descriptor, final String signature, final Label start, final Label end, final int index)486     public void visitLocalVariable(
487             final String name,
488             final String descriptor,
489             final String signature,
490             final Label start,
491             final Label end,
492             final int index) {
493         char firstDescriptorChar = descriptor.charAt(0);
494         maxLocals =
495                 Math.max(
496                         maxLocals, index + (firstDescriptorChar == 'J' || firstDescriptorChar == 'D' ? 2 : 1));
497         super.visitLocalVariable(name, descriptor, signature, start, end, index);
498     }
499 
500     @Override
visitMaxs(final int maxStack, final int maxLocals)501     public void visitMaxs(final int maxStack, final int maxLocals) {
502         if (mv != null) {
503             this.maxStack = Math.max(this.maxStack, maxStack);
504             this.maxLocals = Math.max(this.maxLocals, maxLocals);
505             mv.visitMaxs(this.maxStack, this.maxLocals);
506         }
507     }
508 
509     // -----------------------------------------------------------------------------------------------
510 
get(final int local)511     private Object get(final int local) {
512         maxLocals = Math.max(maxLocals, local + 1);
513         return local < locals.size() ? locals.get(local) : Opcodes.TOP;
514     }
515 
set(final int local, final Object type)516     private void set(final int local, final Object type) {
517         maxLocals = Math.max(maxLocals, local + 1);
518         while (local >= locals.size()) {
519             locals.add(Opcodes.TOP);
520         }
521         locals.set(local, type);
522     }
523 
push(final Object type)524     private void push(final Object type) {
525         stack.add(type);
526         maxStack = Math.max(maxStack, stack.size());
527     }
528 
pushDescriptor(final String descriptor)529     private void pushDescriptor(final String descriptor) {
530         int index = descriptor.charAt(0) == '(' ? descriptor.indexOf(')') + 1 : 0;
531         switch (descriptor.charAt(index)) {
532             case 'V':
533                 return;
534             case 'Z':
535             case 'C':
536             case 'B':
537             case 'S':
538             case 'I':
539                 push(Opcodes.INTEGER);
540                 return;
541             case 'F':
542                 push(Opcodes.FLOAT);
543                 return;
544             case 'J':
545                 push(Opcodes.LONG);
546                 push(Opcodes.TOP);
547                 return;
548             case 'D':
549                 push(Opcodes.DOUBLE);
550                 push(Opcodes.TOP);
551                 return;
552             case '[':
553                 if (index == 0) {
554                     push(descriptor);
555                 } else {
556                     push(descriptor.substring(index, descriptor.length()));
557                 }
558                 break;
559             case 'L':
560                 if (index == 0) {
561                     push(descriptor.substring(1, descriptor.length() - 1));
562                 } else {
563                     push(descriptor.substring(index + 1, descriptor.length() - 1));
564                 }
565                 break;
566             default:
567                 throw new AssertionError();
568         }
569     }
570 
pop()571     private Object pop() {
572         return stack.remove(stack.size() - 1);
573     }
574 
pop(final int numSlots)575     private void pop(final int numSlots) {
576         int size = stack.size();
577         int end = size - numSlots;
578         for (int i = size - 1; i >= end; --i) {
579             stack.remove(i);
580         }
581     }
582 
pop(final String descriptor)583     private void pop(final String descriptor) {
584         char firstDescriptorChar = descriptor.charAt(0);
585         if (firstDescriptorChar == '(') {
586             int numSlots = 0;
587             Type[] types = Type.getArgumentTypes(descriptor);
588             for (Type type : types) {
589                 numSlots += type.getSize();
590             }
591             pop(numSlots);
592         } else if (firstDescriptorChar == 'J' || firstDescriptorChar == 'D') {
593             pop(2);
594         } else {
595             pop(1);
596         }
597     }
598 
execute(final int opcode, final int intArg, final String stringArg)599     private void execute(final int opcode, final int intArg, final String stringArg) {
600         if (this.locals == null) {
601             labels = null;
602             return;
603         }
604         Object value1;
605         Object value2;
606         Object value3;
607         Object t4;
608         switch (opcode) {
609             case Opcodes.NOP:
610             case Opcodes.INEG:
611             case Opcodes.LNEG:
612             case Opcodes.FNEG:
613             case Opcodes.DNEG:
614             case Opcodes.I2B:
615             case Opcodes.I2C:
616             case Opcodes.I2S:
617             case Opcodes.GOTO:
618             case Opcodes.RETURN:
619                 break;
620             case Opcodes.ACONST_NULL:
621                 push(Opcodes.NULL);
622                 break;
623             case Opcodes.ICONST_M1:
624             case Opcodes.ICONST_0:
625             case Opcodes.ICONST_1:
626             case Opcodes.ICONST_2:
627             case Opcodes.ICONST_3:
628             case Opcodes.ICONST_4:
629             case Opcodes.ICONST_5:
630             case Opcodes.BIPUSH:
631             case Opcodes.SIPUSH:
632                 push(Opcodes.INTEGER);
633                 break;
634             case Opcodes.LCONST_0:
635             case Opcodes.LCONST_1:
636                 push(Opcodes.LONG);
637                 push(Opcodes.TOP);
638                 break;
639             case Opcodes.FCONST_0:
640             case Opcodes.FCONST_1:
641             case Opcodes.FCONST_2:
642                 push(Opcodes.FLOAT);
643                 break;
644             case Opcodes.DCONST_0:
645             case Opcodes.DCONST_1:
646                 push(Opcodes.DOUBLE);
647                 push(Opcodes.TOP);
648                 break;
649             case Opcodes.ILOAD:
650             case Opcodes.FLOAD:
651             case Opcodes.ALOAD:
652                 push(get(intArg));
653                 break;
654             case Opcodes.LLOAD:
655             case Opcodes.DLOAD:
656                 push(get(intArg));
657                 push(Opcodes.TOP);
658                 break;
659             case Opcodes.LALOAD:
660             case Opcodes.D2L:
661                 pop(2);
662                 push(Opcodes.LONG);
663                 push(Opcodes.TOP);
664                 break;
665             case Opcodes.DALOAD:
666             case Opcodes.L2D:
667                 pop(2);
668                 push(Opcodes.DOUBLE);
669                 push(Opcodes.TOP);
670                 break;
671             case Opcodes.AALOAD:
672                 pop(1);
673                 value1 = pop();
674                 if (value1 instanceof String) {
675                     pushDescriptor(((String) value1).substring(1));
676                 } else if (value1 == Opcodes.NULL) {
677                     push(value1);
678                 } else {
679                     push("java/lang/Object");
680                 }
681                 break;
682             case Opcodes.ISTORE:
683             case Opcodes.FSTORE:
684             case Opcodes.ASTORE:
685                 value1 = pop();
686                 set(intArg, value1);
687                 if (intArg > 0) {
688                     value2 = get(intArg - 1);
689                     if (value2 == Opcodes.LONG || value2 == Opcodes.DOUBLE) {
690                         set(intArg - 1, Opcodes.TOP);
691                     }
692                 }
693                 break;
694             case Opcodes.LSTORE:
695             case Opcodes.DSTORE:
696                 pop(1);
697                 value1 = pop();
698                 set(intArg, value1);
699                 set(intArg + 1, Opcodes.TOP);
700                 if (intArg > 0) {
701                     value2 = get(intArg - 1);
702                     if (value2 == Opcodes.LONG || value2 == Opcodes.DOUBLE) {
703                         set(intArg - 1, Opcodes.TOP);
704                     }
705                 }
706                 break;
707             case Opcodes.IASTORE:
708             case Opcodes.BASTORE:
709             case Opcodes.CASTORE:
710             case Opcodes.SASTORE:
711             case Opcodes.FASTORE:
712             case Opcodes.AASTORE:
713                 pop(3);
714                 break;
715             case Opcodes.LASTORE:
716             case Opcodes.DASTORE:
717                 pop(4);
718                 break;
719             case Opcodes.POP:
720             case Opcodes.IFEQ:
721             case Opcodes.IFNE:
722             case Opcodes.IFLT:
723             case Opcodes.IFGE:
724             case Opcodes.IFGT:
725             case Opcodes.IFLE:
726             case Opcodes.IRETURN:
727             case Opcodes.FRETURN:
728             case Opcodes.ARETURN:
729             case Opcodes.TABLESWITCH:
730             case Opcodes.LOOKUPSWITCH:
731             case Opcodes.ATHROW:
732             case Opcodes.MONITORENTER:
733             case Opcodes.MONITOREXIT:
734             case Opcodes.IFNULL:
735             case Opcodes.IFNONNULL:
736                 pop(1);
737                 break;
738             case Opcodes.POP2:
739             case Opcodes.IF_ICMPEQ:
740             case Opcodes.IF_ICMPNE:
741             case Opcodes.IF_ICMPLT:
742             case Opcodes.IF_ICMPGE:
743             case Opcodes.IF_ICMPGT:
744             case Opcodes.IF_ICMPLE:
745             case Opcodes.IF_ACMPEQ:
746             case Opcodes.IF_ACMPNE:
747             case Opcodes.LRETURN:
748             case Opcodes.DRETURN:
749                 pop(2);
750                 break;
751             case Opcodes.DUP:
752                 value1 = pop();
753                 push(value1);
754                 push(value1);
755                 break;
756             case Opcodes.DUP_X1:
757                 value1 = pop();
758                 value2 = pop();
759                 push(value1);
760                 push(value2);
761                 push(value1);
762                 break;
763             case Opcodes.DUP_X2:
764                 value1 = pop();
765                 value2 = pop();
766                 value3 = pop();
767                 push(value1);
768                 push(value3);
769                 push(value2);
770                 push(value1);
771                 break;
772             case Opcodes.DUP2:
773                 value1 = pop();
774                 value2 = pop();
775                 push(value2);
776                 push(value1);
777                 push(value2);
778                 push(value1);
779                 break;
780             case Opcodes.DUP2_X1:
781                 value1 = pop();
782                 value2 = pop();
783                 value3 = pop();
784                 push(value2);
785                 push(value1);
786                 push(value3);
787                 push(value2);
788                 push(value1);
789                 break;
790             case Opcodes.DUP2_X2:
791                 value1 = pop();
792                 value2 = pop();
793                 value3 = pop();
794                 t4 = pop();
795                 push(value2);
796                 push(value1);
797                 push(t4);
798                 push(value3);
799                 push(value2);
800                 push(value1);
801                 break;
802             case Opcodes.SWAP:
803                 value1 = pop();
804                 value2 = pop();
805                 push(value1);
806                 push(value2);
807                 break;
808             case Opcodes.IALOAD:
809             case Opcodes.BALOAD:
810             case Opcodes.CALOAD:
811             case Opcodes.SALOAD:
812             case Opcodes.IADD:
813             case Opcodes.ISUB:
814             case Opcodes.IMUL:
815             case Opcodes.IDIV:
816             case Opcodes.IREM:
817             case Opcodes.IAND:
818             case Opcodes.IOR:
819             case Opcodes.IXOR:
820             case Opcodes.ISHL:
821             case Opcodes.ISHR:
822             case Opcodes.IUSHR:
823             case Opcodes.L2I:
824             case Opcodes.D2I:
825             case Opcodes.FCMPL:
826             case Opcodes.FCMPG:
827                 pop(2);
828                 push(Opcodes.INTEGER);
829                 break;
830             case Opcodes.LADD:
831             case Opcodes.LSUB:
832             case Opcodes.LMUL:
833             case Opcodes.LDIV:
834             case Opcodes.LREM:
835             case Opcodes.LAND:
836             case Opcodes.LOR:
837             case Opcodes.LXOR:
838                 pop(4);
839                 push(Opcodes.LONG);
840                 push(Opcodes.TOP);
841                 break;
842             case Opcodes.FALOAD:
843             case Opcodes.FADD:
844             case Opcodes.FSUB:
845             case Opcodes.FMUL:
846             case Opcodes.FDIV:
847             case Opcodes.FREM:
848             case Opcodes.L2F:
849             case Opcodes.D2F:
850                 pop(2);
851                 push(Opcodes.FLOAT);
852                 break;
853             case Opcodes.DADD:
854             case Opcodes.DSUB:
855             case Opcodes.DMUL:
856             case Opcodes.DDIV:
857             case Opcodes.DREM:
858                 pop(4);
859                 push(Opcodes.DOUBLE);
860                 push(Opcodes.TOP);
861                 break;
862             case Opcodes.LSHL:
863             case Opcodes.LSHR:
864             case Opcodes.LUSHR:
865                 pop(3);
866                 push(Opcodes.LONG);
867                 push(Opcodes.TOP);
868                 break;
869             case Opcodes.IINC:
870                 set(intArg, Opcodes.INTEGER);
871                 break;
872             case Opcodes.I2L:
873             case Opcodes.F2L:
874                 pop(1);
875                 push(Opcodes.LONG);
876                 push(Opcodes.TOP);
877                 break;
878             case Opcodes.I2F:
879                 pop(1);
880                 push(Opcodes.FLOAT);
881                 break;
882             case Opcodes.I2D:
883             case Opcodes.F2D:
884                 pop(1);
885                 push(Opcodes.DOUBLE);
886                 push(Opcodes.TOP);
887                 break;
888             case Opcodes.F2I:
889             case Opcodes.ARRAYLENGTH:
890             case Opcodes.INSTANCEOF:
891                 pop(1);
892                 push(Opcodes.INTEGER);
893                 break;
894             case Opcodes.LCMP:
895             case Opcodes.DCMPL:
896             case Opcodes.DCMPG:
897                 pop(4);
898                 push(Opcodes.INTEGER);
899                 break;
900             case Opcodes.JSR:
901             case Opcodes.RET:
902                 throw new IllegalArgumentException("JSR/RET are not supported");
903             case Opcodes.GETSTATIC:
904                 pushDescriptor(stringArg);
905                 break;
906             case Opcodes.PUTSTATIC:
907                 pop(stringArg);
908                 break;
909             case Opcodes.GETFIELD:
910                 pop(1);
911                 pushDescriptor(stringArg);
912                 break;
913             case Opcodes.PUTFIELD:
914                 pop(stringArg);
915                 pop();
916                 break;
917             case Opcodes.NEW:
918                 push(labels.get(0));
919                 break;
920             case Opcodes.NEWARRAY:
921                 pop();
922                 switch (intArg) {
923                     case Opcodes.T_BOOLEAN:
924                         pushDescriptor("[Z");
925                         break;
926                     case Opcodes.T_CHAR:
927                         pushDescriptor("[C");
928                         break;
929                     case Opcodes.T_BYTE:
930                         pushDescriptor("[B");
931                         break;
932                     case Opcodes.T_SHORT:
933                         pushDescriptor("[S");
934                         break;
935                     case Opcodes.T_INT:
936                         pushDescriptor("[I");
937                         break;
938                     case Opcodes.T_FLOAT:
939                         pushDescriptor("[F");
940                         break;
941                     case Opcodes.T_DOUBLE:
942                         pushDescriptor("[D");
943                         break;
944                     case Opcodes.T_LONG:
945                         pushDescriptor("[J");
946                         break;
947                     default:
948                         throw new IllegalArgumentException("Invalid array type " + intArg);
949                 }
950                 break;
951             case Opcodes.ANEWARRAY:
952                 pop();
953                 pushDescriptor("[" + Type.getObjectType(stringArg));
954                 break;
955             case Opcodes.CHECKCAST:
956                 pop();
957                 pushDescriptor(Type.getObjectType(stringArg).getDescriptor());
958                 break;
959             case Opcodes.MULTIANEWARRAY:
960                 pop(intArg);
961                 pushDescriptor(stringArg);
962                 break;
963             default:
964                 throw new IllegalArgumentException("Invalid opcode " + opcode);
965         }
966         labels = null;
967     }
968 }
969