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