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