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