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.tree.analysis;
  60 
  61 import java.util.ArrayList;
  62 import java.util.List;
  63 
  64 import jdk.internal.org.objectweb.asm.Opcodes;
  65 import jdk.internal.org.objectweb.asm.Type;
  66 import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode;
  67 import jdk.internal.org.objectweb.asm.tree.IincInsnNode;
  68 import jdk.internal.org.objectweb.asm.tree.InvokeDynamicInsnNode;
  69 import jdk.internal.org.objectweb.asm.tree.MethodInsnNode;
  70 import jdk.internal.org.objectweb.asm.tree.MultiANewArrayInsnNode;
  71 import jdk.internal.org.objectweb.asm.tree.VarInsnNode;
  72 
  73 /**
  74  * A symbolic execution stack frame. A stack frame contains a set of local
  75  * variable slots, and an operand stack. Warning: long and double values are
  76  * represented by <i>two</i> slots in local variables, and by <i>one</i> slot in
  77  * the operand stack.
  78  *
  79  * @param <V>
  80  *            type of the Value used for the analysis.
  81  *
  82  * @author Eric Bruneton
  83  */
  84 public class Frame<V extends Value> {
  85 
  86     /**
  87      * The expected return type of the analyzed method, or <tt>null</tt> if the
  88      * method returns void.
  89      */
  90     private V returnValue;
  91 
  92     /**
  93      * The local variables and operand stack of this frame.
  94      */
  95     private V[] values;
  96 
  97     /**
  98      * The number of local variables of this frame.
  99      */
 100     private int locals;
 101 
 102     /**
 103      * The number of elements in the operand stack.
 104      */
 105     private int top;
 106 
 107     /**
 108      * Constructs a new frame with the given size.
 109      *
 110      * @param nLocals
 111      *            the maximum number of local variables of the frame.
 112      * @param nStack
 113      *            the maximum stack size of the frame.
 114      */
 115     public Frame(final int nLocals, final int nStack) {
 116         this.values = (V[]) new Value[nLocals + nStack];
 117         this.locals = nLocals;
 118     }
 119 
 120     /**
 121      * Constructs a new frame that is identical to the given frame.
 122      *
 123      * @param src
 124      *            a frame.
 125      */
 126     public Frame(final Frame<? extends V> src) {
 127         this(src.locals, src.values.length - src.locals);
 128         init(src);
 129     }
 130 
 131     /**
 132      * Copies the state of the given frame into this frame.
 133      *
 134      * @param src
 135      *            a frame.
 136      * @return this frame.
 137      */
 138     public Frame<V> init(final Frame<? extends V> src) {
 139         returnValue = src.returnValue;
 140         System.arraycopy(src.values, 0, values, 0, values.length);
 141         top = src.top;
 142         return this;
 143     }
 144 
 145     /**
 146      * Sets the expected return type of the analyzed method.
 147      *
 148      * @param v
 149      *            the expected return type of the analyzed method, or
 150      *            <tt>null</tt> if the method returns void.
 151      */
 152     public void setReturn(final V v) {
 153         returnValue = v;
 154     }
 155 
 156     /**
 157      * Returns the maximum number of local variables of this frame.
 158      *
 159      * @return the maximum number of local variables of this frame.
 160      */
 161     public int getLocals() {
 162         return locals;
 163     }
 164 
 165     /**
 166      * Returns the maximum stack size of this frame.
 167      *
 168      * @return the maximum stack size of this frame.
 169      */
 170     public int getMaxStackSize() {
 171         return values.length - locals;
 172     }
 173 
 174     /**
 175      * Returns the value of the given local variable.
 176      *
 177      * @param i
 178      *            a local variable index.
 179      * @return the value of the given local variable.
 180      * @throws IndexOutOfBoundsException
 181      *             if the variable does not exist.
 182      */
 183     public V getLocal(final int i) throws IndexOutOfBoundsException {
 184         if (i >= locals) {
 185             throw new IndexOutOfBoundsException(
 186                     "Trying to access an inexistant local variable");
 187         }
 188         return values[i];
 189     }
 190 
 191     /**
 192      * Sets the value of the given local variable.
 193      *
 194      * @param i
 195      *            a local variable index.
 196      * @param value
 197      *            the new value of this local variable.
 198      * @throws IndexOutOfBoundsException
 199      *             if the variable does not exist.
 200      */
 201     public void setLocal(final int i, final V value)
 202             throws IndexOutOfBoundsException {
 203         if (i >= locals) {
 204             throw new IndexOutOfBoundsException(
 205                     "Trying to access an inexistant local variable " + i);
 206         }
 207         values[i] = value;
 208     }
 209 
 210     /**
 211      * Returns the number of values in the operand stack of this frame. Long and
 212      * double values are treated as single values.
 213      *
 214      * @return the number of values in the operand stack of this frame.
 215      */
 216     public int getStackSize() {
 217         return top;
 218     }
 219 
 220     /**
 221      * Returns the value of the given operand stack slot.
 222      *
 223      * @param i
 224      *            the index of an operand stack slot.
 225      * @return the value of the given operand stack slot.
 226      * @throws IndexOutOfBoundsException
 227      *             if the operand stack slot does not exist.
 228      */
 229     public V getStack(final int i) throws IndexOutOfBoundsException {
 230         return values[i + locals];
 231     }
 232 
 233     /**
 234      * Clears the operand stack of this frame.
 235      */
 236     public void clearStack() {
 237         top = 0;
 238     }
 239 
 240     /**
 241      * Pops a value from the operand stack of this frame.
 242      *
 243      * @return the value that has been popped from the stack.
 244      * @throws IndexOutOfBoundsException
 245      *             if the operand stack is empty.
 246      */
 247     public V pop() throws IndexOutOfBoundsException {
 248         if (top == 0) {
 249             throw new IndexOutOfBoundsException(
 250                     "Cannot pop operand off an empty stack.");
 251         }
 252         return values[--top + locals];
 253     }
 254 
 255     /**
 256      * Pushes a value into the operand stack of this frame.
 257      *
 258      * @param value
 259      *            the value that must be pushed into the stack.
 260      * @throws IndexOutOfBoundsException
 261      *             if the operand stack is full.
 262      */
 263     public void push(final V value) throws IndexOutOfBoundsException {
 264         if (top + locals >= values.length) {
 265             throw new IndexOutOfBoundsException(
 266                     "Insufficient maximum stack size.");
 267         }
 268         values[top++ + locals] = value;
 269     }
 270 
 271     public void execute(final AbstractInsnNode insn,
 272             final Interpreter<V> interpreter) throws AnalyzerException {
 273         V value1, value2, value3, value4;
 274         List<V> values;
 275         int var;
 276 
 277         switch (insn.getOpcode()) {
 278         case Opcodes.NOP:
 279             break;
 280         case Opcodes.ACONST_NULL:
 281         case Opcodes.ICONST_M1:
 282         case Opcodes.ICONST_0:
 283         case Opcodes.ICONST_1:
 284         case Opcodes.ICONST_2:
 285         case Opcodes.ICONST_3:
 286         case Opcodes.ICONST_4:
 287         case Opcodes.ICONST_5:
 288         case Opcodes.LCONST_0:
 289         case Opcodes.LCONST_1:
 290         case Opcodes.FCONST_0:
 291         case Opcodes.FCONST_1:
 292         case Opcodes.FCONST_2:
 293         case Opcodes.DCONST_0:
 294         case Opcodes.DCONST_1:
 295         case Opcodes.BIPUSH:
 296         case Opcodes.SIPUSH:
 297         case Opcodes.LDC:
 298             push(interpreter.newOperation(insn));
 299             break;
 300         case Opcodes.ILOAD:
 301         case Opcodes.LLOAD:
 302         case Opcodes.FLOAD:
 303         case Opcodes.DLOAD:
 304         case Opcodes.ALOAD:
 305             push(interpreter.copyOperation(insn,
 306                     getLocal(((VarInsnNode) insn).var)));
 307             break;
 308         case Opcodes.IALOAD:
 309         case Opcodes.LALOAD:
 310         case Opcodes.FALOAD:
 311         case Opcodes.DALOAD:
 312         case Opcodes.AALOAD:
 313         case Opcodes.BALOAD:
 314         case Opcodes.CALOAD:
 315         case Opcodes.SALOAD:
 316             value2 = pop();
 317             value1 = pop();
 318             push(interpreter.binaryOperation(insn, value1, value2));
 319             break;
 320         case Opcodes.ISTORE:
 321         case Opcodes.LSTORE:
 322         case Opcodes.FSTORE:
 323         case Opcodes.DSTORE:
 324         case Opcodes.ASTORE:
 325             value1 = interpreter.copyOperation(insn, pop());
 326             var = ((VarInsnNode) insn).var;
 327             setLocal(var, value1);
 328             if (value1.getSize() == 2) {
 329                 setLocal(var + 1, interpreter.newValue(null));
 330             }
 331             if (var > 0) {
 332                 Value local = getLocal(var - 1);
 333                 if (local != null && local.getSize() == 2) {
 334                     setLocal(var - 1, interpreter.newValue(null));
 335                 }
 336             }
 337             break;
 338         case Opcodes.IASTORE:
 339         case Opcodes.LASTORE:
 340         case Opcodes.FASTORE:
 341         case Opcodes.DASTORE:
 342         case Opcodes.AASTORE:
 343         case Opcodes.BASTORE:
 344         case Opcodes.CASTORE:
 345         case Opcodes.SASTORE:
 346             value3 = pop();
 347             value2 = pop();
 348             value1 = pop();
 349             interpreter.ternaryOperation(insn, value1, value2, value3);
 350             break;
 351         case Opcodes.POP:
 352             if (pop().getSize() == 2) {
 353                 throw new AnalyzerException(insn, "Illegal use of POP");
 354             }
 355             break;
 356         case Opcodes.POP2:
 357             if (pop().getSize() == 1) {
 358                 if (pop().getSize() != 1) {
 359                     throw new AnalyzerException(insn, "Illegal use of POP2");
 360                 }
 361             }
 362             break;
 363         case Opcodes.DUP:
 364             value1 = pop();
 365             if (value1.getSize() != 1) {
 366                 throw new AnalyzerException(insn, "Illegal use of DUP");
 367             }
 368             push(value1);
 369             push(interpreter.copyOperation(insn, value1));
 370             break;
 371         case Opcodes.DUP_X1:
 372             value1 = pop();
 373             value2 = pop();
 374             if (value1.getSize() != 1 || value2.getSize() != 1) {
 375                 throw new AnalyzerException(insn, "Illegal use of DUP_X1");
 376             }
 377             push(interpreter.copyOperation(insn, value1));
 378             push(value2);
 379             push(value1);
 380             break;
 381         case Opcodes.DUP_X2:
 382             value1 = pop();
 383             if (value1.getSize() == 1) {
 384                 value2 = pop();
 385                 if (value2.getSize() == 1) {
 386                     value3 = pop();
 387                     if (value3.getSize() == 1) {
 388                         push(interpreter.copyOperation(insn, value1));
 389                         push(value3);
 390                         push(value2);
 391                         push(value1);
 392                         break;
 393                     }
 394                 } else {
 395                     push(interpreter.copyOperation(insn, value1));
 396                     push(value2);
 397                     push(value1);
 398                     break;
 399                 }
 400             }
 401             throw new AnalyzerException(insn, "Illegal use of DUP_X2");
 402         case Opcodes.DUP2:
 403             value1 = pop();
 404             if (value1.getSize() == 1) {
 405                 value2 = pop();
 406                 if (value2.getSize() == 1) {
 407                     push(value2);
 408                     push(value1);
 409                     push(interpreter.copyOperation(insn, value2));
 410                     push(interpreter.copyOperation(insn, value1));
 411                     break;
 412                 }
 413             } else {
 414                 push(value1);
 415                 push(interpreter.copyOperation(insn, value1));
 416                 break;
 417             }
 418             throw new AnalyzerException(insn, "Illegal use of DUP2");
 419         case Opcodes.DUP2_X1:
 420             value1 = pop();
 421             if (value1.getSize() == 1) {
 422                 value2 = pop();
 423                 if (value2.getSize() == 1) {
 424                     value3 = pop();
 425                     if (value3.getSize() == 1) {
 426                         push(interpreter.copyOperation(insn, value2));
 427                         push(interpreter.copyOperation(insn, value1));
 428                         push(value3);
 429                         push(value2);
 430                         push(value1);
 431                         break;
 432                     }
 433                 }
 434             } else {
 435                 value2 = pop();
 436                 if (value2.getSize() == 1) {
 437                     push(interpreter.copyOperation(insn, value1));
 438                     push(value2);
 439                     push(value1);
 440                     break;
 441                 }
 442             }
 443             throw new AnalyzerException(insn, "Illegal use of DUP2_X1");
 444         case Opcodes.DUP2_X2:
 445             value1 = pop();
 446             if (value1.getSize() == 1) {
 447                 value2 = pop();
 448                 if (value2.getSize() == 1) {
 449                     value3 = pop();
 450                     if (value3.getSize() == 1) {
 451                         value4 = pop();
 452                         if (value4.getSize() == 1) {
 453                             push(interpreter.copyOperation(insn, value2));
 454                             push(interpreter.copyOperation(insn, value1));
 455                             push(value4);
 456                             push(value3);
 457                             push(value2);
 458                             push(value1);
 459                             break;
 460                         }
 461                     } else {
 462                         push(interpreter.copyOperation(insn, value2));
 463                         push(interpreter.copyOperation(insn, value1));
 464                         push(value3);
 465                         push(value2);
 466                         push(value1);
 467                         break;
 468                     }
 469                 }
 470             } else {
 471                 value2 = pop();
 472                 if (value2.getSize() == 1) {
 473                     value3 = pop();
 474                     if (value3.getSize() == 1) {
 475                         push(interpreter.copyOperation(insn, value1));
 476                         push(value3);
 477                         push(value2);
 478                         push(value1);
 479                         break;
 480                     }
 481                 } else {
 482                     push(interpreter.copyOperation(insn, value1));
 483                     push(value2);
 484                     push(value1);
 485                     break;
 486                 }
 487             }
 488             throw new AnalyzerException(insn, "Illegal use of DUP2_X2");
 489         case Opcodes.SWAP:
 490             value2 = pop();
 491             value1 = pop();
 492             if (value1.getSize() != 1 || value2.getSize() != 1) {
 493                 throw new AnalyzerException(insn, "Illegal use of SWAP");
 494             }
 495             push(interpreter.copyOperation(insn, value2));
 496             push(interpreter.copyOperation(insn, value1));
 497             break;
 498         case Opcodes.IADD:
 499         case Opcodes.LADD:
 500         case Opcodes.FADD:
 501         case Opcodes.DADD:
 502         case Opcodes.ISUB:
 503         case Opcodes.LSUB:
 504         case Opcodes.FSUB:
 505         case Opcodes.DSUB:
 506         case Opcodes.IMUL:
 507         case Opcodes.LMUL:
 508         case Opcodes.FMUL:
 509         case Opcodes.DMUL:
 510         case Opcodes.IDIV:
 511         case Opcodes.LDIV:
 512         case Opcodes.FDIV:
 513         case Opcodes.DDIV:
 514         case Opcodes.IREM:
 515         case Opcodes.LREM:
 516         case Opcodes.FREM:
 517         case Opcodes.DREM:
 518             value2 = pop();
 519             value1 = pop();
 520             push(interpreter.binaryOperation(insn, value1, value2));
 521             break;
 522         case Opcodes.INEG:
 523         case Opcodes.LNEG:
 524         case Opcodes.FNEG:
 525         case Opcodes.DNEG:
 526             push(interpreter.unaryOperation(insn, pop()));
 527             break;
 528         case Opcodes.ISHL:
 529         case Opcodes.LSHL:
 530         case Opcodes.ISHR:
 531         case Opcodes.LSHR:
 532         case Opcodes.IUSHR:
 533         case Opcodes.LUSHR:
 534         case Opcodes.IAND:
 535         case Opcodes.LAND:
 536         case Opcodes.IOR:
 537         case Opcodes.LOR:
 538         case Opcodes.IXOR:
 539         case Opcodes.LXOR:
 540             value2 = pop();
 541             value1 = pop();
 542             push(interpreter.binaryOperation(insn, value1, value2));
 543             break;
 544         case Opcodes.IINC:
 545             var = ((IincInsnNode) insn).var;
 546             setLocal(var, interpreter.unaryOperation(insn, getLocal(var)));
 547             break;
 548         case Opcodes.I2L:
 549         case Opcodes.I2F:
 550         case Opcodes.I2D:
 551         case Opcodes.L2I:
 552         case Opcodes.L2F:
 553         case Opcodes.L2D:
 554         case Opcodes.F2I:
 555         case Opcodes.F2L:
 556         case Opcodes.F2D:
 557         case Opcodes.D2I:
 558         case Opcodes.D2L:
 559         case Opcodes.D2F:
 560         case Opcodes.I2B:
 561         case Opcodes.I2C:
 562         case Opcodes.I2S:
 563             push(interpreter.unaryOperation(insn, pop()));
 564             break;
 565         case Opcodes.LCMP:
 566         case Opcodes.FCMPL:
 567         case Opcodes.FCMPG:
 568         case Opcodes.DCMPL:
 569         case Opcodes.DCMPG:
 570             value2 = pop();
 571             value1 = pop();
 572             push(interpreter.binaryOperation(insn, value1, value2));
 573             break;
 574         case Opcodes.IFEQ:
 575         case Opcodes.IFNE:
 576         case Opcodes.IFLT:
 577         case Opcodes.IFGE:
 578         case Opcodes.IFGT:
 579         case Opcodes.IFLE:
 580             interpreter.unaryOperation(insn, pop());
 581             break;
 582         case Opcodes.IF_ICMPEQ:
 583         case Opcodes.IF_ICMPNE:
 584         case Opcodes.IF_ICMPLT:
 585         case Opcodes.IF_ICMPGE:
 586         case Opcodes.IF_ICMPGT:
 587         case Opcodes.IF_ICMPLE:
 588         case Opcodes.IF_ACMPEQ:
 589         case Opcodes.IF_ACMPNE:
 590             value2 = pop();
 591             value1 = pop();
 592             interpreter.binaryOperation(insn, value1, value2);
 593             break;
 594         case Opcodes.GOTO:
 595             break;
 596         case Opcodes.JSR:
 597             push(interpreter.newOperation(insn));
 598             break;
 599         case Opcodes.RET:
 600             break;
 601         case Opcodes.TABLESWITCH:
 602         case Opcodes.LOOKUPSWITCH:
 603             interpreter.unaryOperation(insn, pop());
 604             break;
 605         case Opcodes.IRETURN:
 606         case Opcodes.LRETURN:
 607         case Opcodes.FRETURN:
 608         case Opcodes.DRETURN:
 609         case Opcodes.ARETURN:
 610             value1 = pop();
 611             interpreter.unaryOperation(insn, value1);
 612             interpreter.returnOperation(insn, value1, returnValue);
 613             break;
 614         case Opcodes.RETURN:
 615             if (returnValue != null) {
 616                 throw new AnalyzerException(insn, "Incompatible return type");
 617             }
 618             break;
 619         case Opcodes.GETSTATIC:
 620             push(interpreter.newOperation(insn));
 621             break;
 622         case Opcodes.PUTSTATIC:
 623             interpreter.unaryOperation(insn, pop());
 624             break;
 625         case Opcodes.GETFIELD:
 626             push(interpreter.unaryOperation(insn, pop()));
 627             break;
 628         case Opcodes.PUTFIELD:
 629             value2 = pop();
 630             value1 = pop();
 631             interpreter.binaryOperation(insn, value1, value2);
 632             break;
 633         case Opcodes.INVOKEVIRTUAL:
 634         case Opcodes.INVOKESPECIAL:
 635         case Opcodes.INVOKESTATIC:
 636         case Opcodes.INVOKEINTERFACE: {
 637             values = new ArrayList<V>();
 638             String desc = ((MethodInsnNode) insn).desc;
 639             for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) {
 640                 values.add(0, pop());
 641             }
 642             if (insn.getOpcode() != Opcodes.INVOKESTATIC) {
 643                 values.add(0, pop());
 644             }
 645             if (Type.getReturnType(desc) == Type.VOID_TYPE) {
 646                 interpreter.naryOperation(insn, values);
 647             } else {
 648                 push(interpreter.naryOperation(insn, values));
 649             }
 650             break;
 651         }
 652         case Opcodes.INVOKEDYNAMIC: {
 653             values = new ArrayList<V>();
 654             String desc = ((InvokeDynamicInsnNode) insn).desc;
 655             for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) {
 656                 values.add(0, pop());
 657             }
 658             if (Type.getReturnType(desc) == Type.VOID_TYPE) {
 659                 interpreter.naryOperation(insn, values);
 660             } else {
 661                 push(interpreter.naryOperation(insn, values));
 662             }
 663             break;
 664         }
 665         case Opcodes.NEW:
 666             push(interpreter.newOperation(insn));
 667             break;
 668         case Opcodes.NEWARRAY:
 669         case Opcodes.ANEWARRAY:
 670         case Opcodes.ARRAYLENGTH:
 671             push(interpreter.unaryOperation(insn, pop()));
 672             break;
 673         case Opcodes.ATHROW:
 674             interpreter.unaryOperation(insn, pop());
 675             break;
 676         case Opcodes.CHECKCAST:
 677         case Opcodes.INSTANCEOF:
 678             push(interpreter.unaryOperation(insn, pop()));
 679             break;
 680         case Opcodes.MONITORENTER:
 681         case Opcodes.MONITOREXIT:
 682             interpreter.unaryOperation(insn, pop());
 683             break;
 684         case Opcodes.MULTIANEWARRAY:
 685             values = new ArrayList<V>();
 686             for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) {
 687                 values.add(0, pop());
 688             }
 689             push(interpreter.naryOperation(insn, values));
 690             break;
 691         case Opcodes.IFNULL:
 692         case Opcodes.IFNONNULL:
 693             interpreter.unaryOperation(insn, pop());
 694             break;
 695         default:
 696             throw new RuntimeException("Illegal opcode " + insn.getOpcode());
 697         }
 698     }
 699 
 700     /**
 701      * Merges this frame with the given frame.
 702      *
 703      * @param frame
 704      *            a frame.
 705      * @param interpreter
 706      *            the interpreter used to merge values.
 707      * @return <tt>true</tt> if this frame has been changed as a result of the
 708      *         merge operation, or <tt>false</tt> otherwise.
 709      * @throws AnalyzerException
 710      *             if the frames have incompatible sizes.
 711      */
 712     public boolean merge(final Frame<? extends V> frame,
 713             final Interpreter<V> interpreter) throws AnalyzerException {
 714         if (top != frame.top) {
 715             throw new AnalyzerException(null, "Incompatible stack heights");
 716         }
 717         boolean changes = false;
 718         for (int i = 0; i < locals + top; ++i) {
 719             V v = interpreter.merge(values[i], frame.values[i]);
 720             if (!v.equals(values[i])) {
 721                 values[i] = v;
 722                 changes = true;
 723             }
 724         }
 725         return changes;
 726     }
 727 
 728     /**
 729      * Merges this frame with the given frame (case of a RET instruction).
 730      *
 731      * @param frame
 732      *            a frame
 733      * @param access
 734      *            the local variables that have been accessed by the subroutine
 735      *            to which the RET instruction corresponds.
 736      * @return <tt>true</tt> if this frame has been changed as a result of the
 737      *         merge operation, or <tt>false</tt> otherwise.
 738      */
 739     public boolean merge(final Frame<? extends V> frame, final boolean[] access) {
 740         boolean changes = false;
 741         for (int i = 0; i < locals; ++i) {
 742             if (!access[i] && !values[i].equals(frame.values[i])) {
 743                 values[i] = frame.values[i];
 744                 changes = true;
 745             }
 746         }
 747         return changes;
 748     }
 749 
 750     /**
 751      * Returns a string representation of this frame.
 752      *
 753      * @return a string representation of this frame.
 754      */
 755     @Override
 756     public String toString() {
 757         StringBuilder sb = new StringBuilder();
 758         for (int i = 0; i < getLocals(); ++i) {
 759             sb.append(getLocal(i));
 760         }
 761         sb.append(' ');
 762         for (int i = 0; i < getStackSize(); ++i) {
 763             sb.append(getStack(i).toString());
 764         }
 765         return sb.toString();
 766     }
 767 }