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