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             case 'Q':
537                 push(descriptor.substring(1, descriptor.length() - 1));
538                 break;
539             default:
540                 throw new AssertionError();
541         }
542     }
543 
544     private Object pop() {
545         return stack.remove(stack.size() - 1);
546     }
547 
548     private void pop(final int numSlots) {
549         int size = stack.size();
550         int end = size - numSlots;
551         for (int i = size - 1; i >= end; --i) {
552             stack.remove(i);
553         }
554     }
555 
556     private void pop(final String descriptor) {
557         char firstDescriptorChar = descriptor.charAt(0);
558         if (firstDescriptorChar == '(') {
559             int numSlots = 0;
560             Type[] types = Type.getArgumentTypes(descriptor);
561             for (Type type : types) {
562                 numSlots += type.getSize();
563             }
564             pop(numSlots);
565         } else if (firstDescriptorChar == 'J' || firstDescriptorChar == 'D') {
566             pop(2);
567         } else {
568             pop(1);
569         }
570     }
571 
572     private void execute(final int opcode, final int intArg, final String stringArg) {
573         if (opcode == Opcodes.JSR || opcode == Opcodes.RET) {
574             throw new IllegalArgumentException("JSR/RET are not supported");
575         }
576         if (this.locals == null) {
577             labels = null;
578             return;
579         }
580         Object value1;
581         Object value2;
582         Object value3;
583         Object t4;
584         switch (opcode) {
585             case Opcodes.NOP:
586             case Opcodes.INEG:
587             case Opcodes.LNEG:
588             case Opcodes.FNEG:
589             case Opcodes.DNEG:
590             case Opcodes.I2B:
591             case Opcodes.I2C:
592             case Opcodes.I2S:
593             case Opcodes.GOTO:
594             case Opcodes.RETURN:
595                 break;
596             case Opcodes.ACONST_NULL:
597                 push(Opcodes.NULL);
598                 break;
599             case Opcodes.ICONST_M1:
600             case Opcodes.ICONST_0:
601             case Opcodes.ICONST_1:
602             case Opcodes.ICONST_2:
603             case Opcodes.ICONST_3:
604             case Opcodes.ICONST_4:
605             case Opcodes.ICONST_5:
606             case Opcodes.BIPUSH:
607             case Opcodes.SIPUSH:
608                 push(Opcodes.INTEGER);
609                 break;
610             case Opcodes.LCONST_0:
611             case Opcodes.LCONST_1:
612                 push(Opcodes.LONG);
613                 push(Opcodes.TOP);
614                 break;
615             case Opcodes.FCONST_0:
616             case Opcodes.FCONST_1:
617             case Opcodes.FCONST_2:
618                 push(Opcodes.FLOAT);
619                 break;
620             case Opcodes.DCONST_0:
621             case Opcodes.DCONST_1:
622                 push(Opcodes.DOUBLE);
623                 push(Opcodes.TOP);
624                 break;
625             case Opcodes.ILOAD:
626             case Opcodes.FLOAD:
627             case Opcodes.ALOAD:
628                 push(get(intArg));
629                 break;
630             case Opcodes.LLOAD:
631             case Opcodes.DLOAD:
632                 push(get(intArg));
633                 push(Opcodes.TOP);
634                 break;
635             case Opcodes.LALOAD:
636             case Opcodes.D2L:
637                 pop(2);
638                 push(Opcodes.LONG);
639                 push(Opcodes.TOP);
640                 break;
641             case Opcodes.DALOAD:
642             case Opcodes.L2D:
643                 pop(2);
644                 push(Opcodes.DOUBLE);
645                 push(Opcodes.TOP);
646                 break;
647             case Opcodes.AALOAD:
648                 pop(1);
649                 value1 = pop();
650                 if (value1 instanceof String) {
651                     pushDescriptor(((String) value1).substring(1));
652                 } else if (value1 == Opcodes.NULL) {
653                     push(value1);
654                 } else {
655                     push("java/lang/Object");
656                 }
657                 break;
658             case Opcodes.ISTORE:
659             case Opcodes.FSTORE:
660             case Opcodes.ASTORE:
661                 value1 = pop();
662                 set(intArg, value1);
663                 if (intArg > 0) {
664                     value2 = get(intArg - 1);
665                     if (value2 == Opcodes.LONG || value2 == Opcodes.DOUBLE) {
666                         set(intArg - 1, Opcodes.TOP);
667                     }
668                 }
669                 break;
670             case Opcodes.LSTORE:
671             case Opcodes.DSTORE:
672                 pop(1);
673                 value1 = pop();
674                 set(intArg, value1);
675                 set(intArg + 1, Opcodes.TOP);
676                 if (intArg > 0) {
677                     value2 = get(intArg - 1);
678                     if (value2 == Opcodes.LONG || value2 == Opcodes.DOUBLE) {
679                         set(intArg - 1, Opcodes.TOP);
680                     }
681                 }
682                 break;
683             case Opcodes.IASTORE:
684             case Opcodes.BASTORE:
685             case Opcodes.CASTORE:
686             case Opcodes.SASTORE:
687             case Opcodes.FASTORE:
688             case Opcodes.AASTORE:
689                 pop(3);
690                 break;
691             case Opcodes.LASTORE:
692             case Opcodes.DASTORE:
693                 pop(4);
694                 break;
695             case Opcodes.POP:
696             case Opcodes.IFEQ:
697             case Opcodes.IFNE:
698             case Opcodes.IFLT:
699             case Opcodes.IFGE:
700             case Opcodes.IFGT:
701             case Opcodes.IFLE:
702             case Opcodes.IRETURN:
703             case Opcodes.FRETURN:
704             case Opcodes.ARETURN:
705             case Opcodes.TABLESWITCH:
706             case Opcodes.LOOKUPSWITCH:
707             case Opcodes.ATHROW:
708             case Opcodes.MONITORENTER:
709             case Opcodes.MONITOREXIT:
710             case Opcodes.IFNULL:
711             case Opcodes.IFNONNULL:
712                 pop(1);
713                 break;
714             case Opcodes.POP2:
715             case Opcodes.IF_ICMPEQ:
716             case Opcodes.IF_ICMPNE:
717             case Opcodes.IF_ICMPLT:
718             case Opcodes.IF_ICMPGE:
719             case Opcodes.IF_ICMPGT:
720             case Opcodes.IF_ICMPLE:
721             case Opcodes.IF_ACMPEQ:
722             case Opcodes.IF_ACMPNE:
723             case Opcodes.LRETURN:
724             case Opcodes.DRETURN:
725                 pop(2);
726                 break;
727             case Opcodes.DUP:
728                 value1 = pop();
729                 push(value1);
730                 push(value1);
731                 break;
732             case Opcodes.DUP_X1:
733                 value1 = pop();
734                 value2 = pop();
735                 push(value1);
736                 push(value2);
737                 push(value1);
738                 break;
739             case Opcodes.DUP_X2:
740                 value1 = pop();
741                 value2 = pop();
742                 value3 = pop();
743                 push(value1);
744                 push(value3);
745                 push(value2);
746                 push(value1);
747                 break;
748             case Opcodes.DUP2:
749                 value1 = pop();
750                 value2 = pop();
751                 push(value2);
752                 push(value1);
753                 push(value2);
754                 push(value1);
755                 break;
756             case Opcodes.DUP2_X1:
757                 value1 = pop();
758                 value2 = pop();
759                 value3 = pop();
760                 push(value2);
761                 push(value1);
762                 push(value3);
763                 push(value2);
764                 push(value1);
765                 break;
766             case Opcodes.DUP2_X2:
767                 value1 = pop();
768                 value2 = pop();
769                 value3 = pop();
770                 t4 = pop();
771                 push(value2);
772                 push(value1);
773                 push(t4);
774                 push(value3);
775                 push(value2);
776                 push(value1);
777                 break;
778             case Opcodes.SWAP:
779                 value1 = pop();
780                 value2 = pop();
781                 push(value1);
782                 push(value2);
783                 break;
784             case Opcodes.IALOAD:
785             case Opcodes.BALOAD:
786             case Opcodes.CALOAD:
787             case Opcodes.SALOAD:
788             case Opcodes.IADD:
789             case Opcodes.ISUB:
790             case Opcodes.IMUL:
791             case Opcodes.IDIV:
792             case Opcodes.IREM:
793             case Opcodes.IAND:
794             case Opcodes.IOR:
795             case Opcodes.IXOR:
796             case Opcodes.ISHL:
797             case Opcodes.ISHR:
798             case Opcodes.IUSHR:
799             case Opcodes.L2I:
800             case Opcodes.D2I:
801             case Opcodes.FCMPL:
802             case Opcodes.FCMPG:
803                 pop(2);
804                 push(Opcodes.INTEGER);
805                 break;
806             case Opcodes.LADD:
807             case Opcodes.LSUB:
808             case Opcodes.LMUL:
809             case Opcodes.LDIV:
810             case Opcodes.LREM:
811             case Opcodes.LAND:
812             case Opcodes.LOR:
813             case Opcodes.LXOR:
814                 pop(4);
815                 push(Opcodes.LONG);
816                 push(Opcodes.TOP);
817                 break;
818             case Opcodes.FALOAD:
819             case Opcodes.FADD:
820             case Opcodes.FSUB:
821             case Opcodes.FMUL:
822             case Opcodes.FDIV:
823             case Opcodes.FREM:
824             case Opcodes.L2F:
825             case Opcodes.D2F:
826                 pop(2);
827                 push(Opcodes.FLOAT);
828                 break;
829             case Opcodes.DADD:
830             case Opcodes.DSUB:
831             case Opcodes.DMUL:
832             case Opcodes.DDIV:
833             case Opcodes.DREM:
834                 pop(4);
835                 push(Opcodes.DOUBLE);
836                 push(Opcodes.TOP);
837                 break;
838             case Opcodes.LSHL:
839             case Opcodes.LSHR:
840             case Opcodes.LUSHR:
841                 pop(3);
842                 push(Opcodes.LONG);
843                 push(Opcodes.TOP);
844                 break;
845             case Opcodes.IINC:
846                 set(intArg, Opcodes.INTEGER);
847                 break;
848             case Opcodes.I2L:
849             case Opcodes.F2L:
850                 pop(1);
851                 push(Opcodes.LONG);
852                 push(Opcodes.TOP);
853                 break;
854             case Opcodes.I2F:
855                 pop(1);
856                 push(Opcodes.FLOAT);
857                 break;
858             case Opcodes.I2D:
859             case Opcodes.F2D:
860                 pop(1);
861                 push(Opcodes.DOUBLE);
862                 push(Opcodes.TOP);
863                 break;
864             case Opcodes.F2I:
865             case Opcodes.ARRAYLENGTH:
866             case Opcodes.INSTANCEOF:
867                 pop(1);
868                 push(Opcodes.INTEGER);
869                 break;
870             case Opcodes.LCMP:
871             case Opcodes.DCMPL:
872             case Opcodes.DCMPG:
873                 pop(4);
874                 push(Opcodes.INTEGER);
875                 break;
876             case Opcodes.GETSTATIC:
877                 pushDescriptor(stringArg);
878                 break;
879             case Opcodes.PUTSTATIC:
880                 pop(stringArg);
881                 break;
882             case Opcodes.GETFIELD:
883                 pop(1);
884                 pushDescriptor(stringArg);
885                 break;
886             case Opcodes.PUTFIELD:
887                 pop(stringArg);
888                 pop();
889                 break;
890             case Opcodes.NEW:
891                 push(labels.get(0));
892                 break;
893             case Opcodes.NEWARRAY:
894                 pop();
895                 switch (intArg) {
896                     case Opcodes.T_BOOLEAN:
897                         pushDescriptor("[Z");
898                         break;
899                     case Opcodes.T_CHAR:
900                         pushDescriptor("[C");
901                         break;
902                     case Opcodes.T_BYTE:
903                         pushDescriptor("[B");
904                         break;
905                     case Opcodes.T_SHORT:
906                         pushDescriptor("[S");
907                         break;
908                     case Opcodes.T_INT:
909                         pushDescriptor("[I");
910                         break;
911                     case Opcodes.T_FLOAT:
912                         pushDescriptor("[F");
913                         break;
914                     case Opcodes.T_DOUBLE:
915                         pushDescriptor("[D");
916                         break;
917                     case Opcodes.T_LONG:
918                         pushDescriptor("[J");
919                         break;
920                     default:
921                         throw new IllegalArgumentException("Invalid array type " + intArg);
922                 }
923                 break;
924             case Opcodes.ANEWARRAY:
925                 pop();
926                 pushDescriptor("[" + Type.getObjectType(stringArg));
927                 break;
928             case Opcodes.CHECKCAST:
929                 pop();
930                 pushDescriptor(Type.getObjectType(stringArg).getDescriptor());
931                 break;
932             case Opcodes.MULTIANEWARRAY:
933                 pop(intArg);
934                 pushDescriptor(stringArg);
935                 break;
936             default:
937                 throw new IllegalArgumentException("Invalid opcode " + opcode);
938         }
939         labels = null;
940     }
941 }