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