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