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