1 // ASM: a very small and fast Java bytecode manipulation framework 2 // Copyright (c) 2000-2011 INRIA, France Telecom 3 // All rights reserved. 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions 7 // are met: 8 // 1. Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // 2. Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // 3. Neither the name of the copyright holders nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 // THE POSSIBILITY OF SUCH DAMAGE. 28 package org.objectweb.asm.tree.analysis; 29 30 import java.util.ArrayList; 31 import java.util.List; 32 import org.objectweb.asm.Opcodes; 33 import org.objectweb.asm.Type; 34 import org.objectweb.asm.tree.AbstractInsnNode; 35 import org.objectweb.asm.tree.IincInsnNode; 36 import org.objectweb.asm.tree.InvokeDynamicInsnNode; 37 import org.objectweb.asm.tree.LabelNode; 38 import org.objectweb.asm.tree.MethodInsnNode; 39 import org.objectweb.asm.tree.MultiANewArrayInsnNode; 40 import org.objectweb.asm.tree.VarInsnNode; 41 42 /** 43 * A symbolic execution stack frame. A stack frame contains a set of local variable slots, and an 44 * operand stack. Warning: long and double values are represented with <i>two</i> slots in local 45 * variables, and with <i>one</i> slot in the operand stack. 46 * 47 * @param <V> type of the Value used for the analysis. 48 * @author Eric Bruneton 49 */ 50 public class Frame<V extends Value> { 51 52 /** The maximum size of the operand stack of any method. */ 53 private static final int MAX_STACK_SIZE = 65536; 54 55 /** 56 * The expected return type of the analyzed method, or {@literal null} if the method returns void. 57 */ 58 private V returnValue; 59 60 /** 61 * The local variables and the operand stack of this frame. The first {@link #numLocals} elements 62 * correspond to the local variables. The following {@link #numStack} elements correspond to the 63 * operand stack. Long and double values are represented with two elements in the local variables 64 * section, and with one element in the operand stack section. 65 */ 66 private V[] values; 67 68 /** 69 * The number of local variables of this frame. Long and double values are represented with two 70 * elements. 71 */ 72 private int numLocals; 73 74 /** 75 * The number of elements in the operand stack. Long and double values are represented with a 76 * single element. 77 */ 78 private int numStack; 79 80 /** 81 * The maximum number of elements in the operand stack. Long and double values are represented 82 * with a single element. 83 */ 84 private int maxStack; 85 86 /** 87 * Constructs a new frame with the given size. 88 * 89 * @param numLocals the number of local variables of the frame. Long and double values are 90 * represented with two elements. 91 * @param maxStack the maximum number of elements in the operand stack, or -1 if there is no 92 * maximum value. Long and double values are represented with a single element. 93 */ 94 @SuppressWarnings("unchecked") Frame(final int numLocals, final int maxStack)95 public Frame(final int numLocals, final int maxStack) { 96 this.values = (V[]) new Value[numLocals + (maxStack >= 0 ? maxStack : 4)]; 97 this.numLocals = numLocals; 98 this.numStack = 0; 99 this.maxStack = maxStack >= 0 ? maxStack : MAX_STACK_SIZE; 100 } 101 102 /** 103 * Constructs a copy of the given Frame. 104 * 105 * @param frame a frame. 106 */ Frame(final Frame<? extends V> frame)107 public Frame(final Frame<? extends V> frame) { 108 this(frame.numLocals, frame.values.length - frame.numLocals); 109 init(frame); // NOPMD(ConstructorCallsOverridableMethod): can't fix for backward compatibility. 110 } 111 112 /** 113 * Copies the state of the given frame into this frame. 114 * 115 * @param frame a frame. 116 * @return this frame. 117 */ init(final Frame<? extends V> frame)118 public Frame<V> init(final Frame<? extends V> frame) { 119 returnValue = frame.returnValue; 120 if (values.length < frame.values.length) { 121 values = frame.values.clone(); 122 } else { 123 System.arraycopy(frame.values, 0, values, 0, frame.values.length); 124 } 125 numLocals = frame.numLocals; 126 numStack = frame.numStack; 127 maxStack = frame.maxStack; 128 return this; 129 } 130 131 /** 132 * Initializes a frame corresponding to the target or to the successor of a jump instruction. This 133 * method is called by {@link Analyzer#analyze(String, org.objectweb.asm.tree.MethodNode)} while 134 * interpreting jump instructions. It is called once for each possible target of the jump 135 * instruction, and once for its successor instruction (except for GOTO and JSR), before the frame 136 * is merged with the existing frame at this location. The default implementation of this method 137 * does nothing. 138 * 139 * <p>Overriding this method and changing the frame values allows implementing branch-sensitive 140 * analyses. 141 * 142 * @param opcode the opcode of the jump instruction. Can be IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, 143 * IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, 144 * GOTO, JSR, IFNULL, IFNONNULL, TABLESWITCH or LOOKUPSWITCH. 145 * @param target a target of the jump instruction this frame corresponds to, or {@literal null} if 146 * this frame corresponds to the successor of the jump instruction (i.e. the next instruction 147 * in the instructions sequence). 148 */ initJumpTarget(final int opcode, final LabelNode target)149 public void initJumpTarget(final int opcode, final LabelNode target) { 150 // Does nothing by default. 151 } 152 153 /** 154 * Sets the expected return type of the analyzed method. 155 * 156 * @param v the expected return type of the analyzed method, or {@literal null} if the method 157 * returns void. 158 */ setReturn(final V v)159 public void setReturn(final V v) { 160 returnValue = v; 161 } 162 163 /** 164 * Returns the maximum number of local variables of this frame. Long and double values are 165 * represented with two variables. 166 * 167 * @return the maximum number of local variables of this frame. 168 */ getLocals()169 public int getLocals() { 170 return numLocals; 171 } 172 173 /** 174 * Returns the maximum number of elements in the operand stack of this frame. Long and double 175 * values are represented with a single element. 176 * 177 * @return the maximum number of elements in the operand stack of this frame. 178 */ getMaxStackSize()179 public int getMaxStackSize() { 180 return maxStack; 181 } 182 183 /** 184 * Returns the value of the given local variable. Long and double values are represented with two 185 * variables. 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 get an inexistant local variable " + index); 194 } 195 return values[index]; 196 } 197 198 /** 199 * Sets the value of the given local variable. Long and double values are represented with two 200 * variables. 201 * 202 * @param index a local variable index. 203 * @param value the new value of this local variable. 204 * @throws IndexOutOfBoundsException if the variable does not exist. 205 */ setLocal(final int index, final V value)206 public void setLocal(final int index, final V value) { 207 if (index >= numLocals) { 208 throw new IndexOutOfBoundsException("Trying to set an inexistant local variable " + index); 209 } 210 values[index] = value; 211 } 212 213 /** 214 * Returns the number of elements in the operand stack of this frame. Long and double values are 215 * represented with a single element. 216 * 217 * @return the number of elements in the operand stack of this frame. 218 */ getStackSize()219 public int getStackSize() { 220 return numStack; 221 } 222 223 /** 224 * Returns the value of the given operand stack slot. 225 * 226 * @param index the index of an operand stack slot. 227 * @return the value of the given operand stack slot. 228 * @throws IndexOutOfBoundsException if the operand stack slot does not exist. 229 */ getStack(final int index)230 public V getStack(final int index) { 231 return values[numLocals + index]; 232 } 233 234 /** 235 * Sets the value of the given stack slot. 236 * 237 * @param index the index of an operand stack slot. 238 * @param value the new value of the stack slot. 239 * @throws IndexOutOfBoundsException if the stack slot does not exist. 240 */ setStack(final int index, final V value)241 public void setStack(final int index, final V value) { 242 values[numLocals + index] = value; 243 } 244 245 /** Clears the operand stack of this frame. */ clearStack()246 public void clearStack() { 247 numStack = 0; 248 } 249 250 /** 251 * Pops a value from the operand stack of this frame. 252 * 253 * @return the value that has been popped from the stack. 254 * @throws IndexOutOfBoundsException if the operand stack is empty. 255 */ pop()256 public V pop() { 257 if (numStack == 0) { 258 throw new IndexOutOfBoundsException("Cannot pop operand off an empty stack."); 259 } 260 return values[numLocals + (--numStack)]; 261 } 262 263 /** 264 * Pushes a value into the operand stack of this frame. 265 * 266 * @param value the value that must be pushed into the stack. 267 * @throws IndexOutOfBoundsException if the operand stack is full. 268 */ 269 @SuppressWarnings("unchecked") push(final V value)270 public void push(final V value) { 271 if (numLocals + numStack >= values.length) { 272 if (numLocals + numStack >= maxStack) { 273 throw new IndexOutOfBoundsException("Insufficient maximum stack size."); 274 } 275 V[] oldValues = values; 276 values = (V[]) new Value[2 * values.length]; 277 System.arraycopy(oldValues, 0, values, 0, oldValues.length); 278 } 279 values[numLocals + (numStack++)] = value; 280 } 281 282 /** 283 * Simulates the execution of the given instruction on this execution stack frame. 284 * 285 * @param insn the instruction to execute. 286 * @param interpreter the interpreter to use to compute values from other values. 287 * @throws AnalyzerException if the instruction cannot be executed on this execution frame (e.g. a 288 * POP on an empty operand stack). 289 */ execute(final AbstractInsnNode insn, final Interpreter<V> interpreter)290 public void execute(final AbstractInsnNode insn, final Interpreter<V> interpreter) 291 throws AnalyzerException { 292 V value1; 293 V value2; 294 V value3; 295 V value4; 296 int varIndex; 297 298 switch (insn.getOpcode()) { 299 case Opcodes.NOP: 300 break; 301 case Opcodes.ACONST_NULL: 302 case Opcodes.ICONST_M1: 303 case Opcodes.ICONST_0: 304 case Opcodes.ICONST_1: 305 case Opcodes.ICONST_2: 306 case Opcodes.ICONST_3: 307 case Opcodes.ICONST_4: 308 case Opcodes.ICONST_5: 309 case Opcodes.LCONST_0: 310 case Opcodes.LCONST_1: 311 case Opcodes.FCONST_0: 312 case Opcodes.FCONST_1: 313 case Opcodes.FCONST_2: 314 case Opcodes.DCONST_0: 315 case Opcodes.DCONST_1: 316 case Opcodes.BIPUSH: 317 case Opcodes.SIPUSH: 318 case Opcodes.LDC: 319 push(interpreter.newOperation(insn)); 320 break; 321 case Opcodes.ILOAD: 322 case Opcodes.LLOAD: 323 case Opcodes.FLOAD: 324 case Opcodes.DLOAD: 325 case Opcodes.ALOAD: 326 push(interpreter.copyOperation(insn, getLocal(((VarInsnNode) insn).var))); 327 break; 328 case Opcodes.ISTORE: 329 case Opcodes.LSTORE: 330 case Opcodes.FSTORE: 331 case Opcodes.DSTORE: 332 case Opcodes.ASTORE: 333 value1 = interpreter.copyOperation(insn, pop()); 334 varIndex = ((VarInsnNode) insn).var; 335 setLocal(varIndex, value1); 336 if (value1.getSize() == 2) { 337 setLocal(varIndex + 1, interpreter.newEmptyValue(varIndex + 1)); 338 } 339 if (varIndex > 0) { 340 Value local = getLocal(varIndex - 1); 341 if (local != null && local.getSize() == 2) { 342 setLocal(varIndex - 1, interpreter.newEmptyValue(varIndex - 1)); 343 } 344 } 345 break; 346 case Opcodes.IASTORE: 347 case Opcodes.LASTORE: 348 case Opcodes.FASTORE: 349 case Opcodes.DASTORE: 350 case Opcodes.AASTORE: 351 case Opcodes.BASTORE: 352 case Opcodes.CASTORE: 353 case Opcodes.SASTORE: 354 value3 = pop(); 355 value2 = pop(); 356 value1 = pop(); 357 interpreter.ternaryOperation(insn, value1, value2, value3); 358 break; 359 case Opcodes.POP: 360 if (pop().getSize() == 2) { 361 throw new AnalyzerException(insn, "Illegal use of POP"); 362 } 363 break; 364 case Opcodes.POP2: 365 if (pop().getSize() == 1 && pop().getSize() != 1) { 366 throw new AnalyzerException(insn, "Illegal use of POP2"); 367 } 368 break; 369 case Opcodes.DUP: 370 value1 = pop(); 371 if (value1.getSize() != 1) { 372 throw new AnalyzerException(insn, "Illegal use of DUP"); 373 } 374 push(value1); 375 push(interpreter.copyOperation(insn, value1)); 376 break; 377 case Opcodes.DUP_X1: 378 value1 = pop(); 379 value2 = pop(); 380 if (value1.getSize() != 1 || value2.getSize() != 1) { 381 throw new AnalyzerException(insn, "Illegal use of DUP_X1"); 382 } 383 push(interpreter.copyOperation(insn, value1)); 384 push(value2); 385 push(value1); 386 break; 387 case Opcodes.DUP_X2: 388 value1 = pop(); 389 if (value1.getSize() == 1 && executeDupX2(insn, value1, interpreter)) { 390 break; 391 } 392 throw new AnalyzerException(insn, "Illegal use of DUP_X2"); 393 case Opcodes.DUP2: 394 value1 = pop(); 395 if (value1.getSize() == 1) { 396 value2 = pop(); 397 if (value2.getSize() == 1) { 398 push(value2); 399 push(value1); 400 push(interpreter.copyOperation(insn, value2)); 401 push(interpreter.copyOperation(insn, value1)); 402 break; 403 } 404 } else { 405 push(value1); 406 push(interpreter.copyOperation(insn, value1)); 407 break; 408 } 409 throw new AnalyzerException(insn, "Illegal use of DUP2"); 410 case Opcodes.DUP2_X1: 411 value1 = pop(); 412 if (value1.getSize() == 1) { 413 value2 = pop(); 414 if (value2.getSize() == 1) { 415 value3 = pop(); 416 if (value3.getSize() == 1) { 417 push(interpreter.copyOperation(insn, value2)); 418 push(interpreter.copyOperation(insn, value1)); 419 push(value3); 420 push(value2); 421 push(value1); 422 break; 423 } 424 } 425 } else { 426 value2 = pop(); 427 if (value2.getSize() == 1) { 428 push(interpreter.copyOperation(insn, value1)); 429 push(value2); 430 push(value1); 431 break; 432 } 433 } 434 throw new AnalyzerException(insn, "Illegal use of DUP2_X1"); 435 case Opcodes.DUP2_X2: 436 value1 = pop(); 437 if (value1.getSize() == 1) { 438 value2 = pop(); 439 if (value2.getSize() == 1) { 440 value3 = pop(); 441 if (value3.getSize() == 1) { 442 value4 = pop(); 443 if (value4.getSize() == 1) { 444 push(interpreter.copyOperation(insn, value2)); 445 push(interpreter.copyOperation(insn, value1)); 446 push(value4); 447 push(value3); 448 push(value2); 449 push(value1); 450 break; 451 } 452 } else { 453 push(interpreter.copyOperation(insn, value2)); 454 push(interpreter.copyOperation(insn, value1)); 455 push(value3); 456 push(value2); 457 push(value1); 458 break; 459 } 460 } 461 } else if (executeDupX2(insn, value1, interpreter)) { 462 break; 463 } 464 throw new AnalyzerException(insn, "Illegal use of DUP2_X2"); 465 case Opcodes.SWAP: 466 value2 = pop(); 467 value1 = pop(); 468 if (value1.getSize() != 1 || value2.getSize() != 1) { 469 throw new AnalyzerException(insn, "Illegal use of SWAP"); 470 } 471 push(interpreter.copyOperation(insn, value2)); 472 push(interpreter.copyOperation(insn, value1)); 473 break; 474 case Opcodes.IALOAD: 475 case Opcodes.LALOAD: 476 case Opcodes.FALOAD: 477 case Opcodes.DALOAD: 478 case Opcodes.AALOAD: 479 case Opcodes.BALOAD: 480 case Opcodes.CALOAD: 481 case Opcodes.SALOAD: 482 case Opcodes.IADD: 483 case Opcodes.LADD: 484 case Opcodes.FADD: 485 case Opcodes.DADD: 486 case Opcodes.ISUB: 487 case Opcodes.LSUB: 488 case Opcodes.FSUB: 489 case Opcodes.DSUB: 490 case Opcodes.IMUL: 491 case Opcodes.LMUL: 492 case Opcodes.FMUL: 493 case Opcodes.DMUL: 494 case Opcodes.IDIV: 495 case Opcodes.LDIV: 496 case Opcodes.FDIV: 497 case Opcodes.DDIV: 498 case Opcodes.IREM: 499 case Opcodes.LREM: 500 case Opcodes.FREM: 501 case Opcodes.DREM: 502 case Opcodes.ISHL: 503 case Opcodes.LSHL: 504 case Opcodes.ISHR: 505 case Opcodes.LSHR: 506 case Opcodes.IUSHR: 507 case Opcodes.LUSHR: 508 case Opcodes.IAND: 509 case Opcodes.LAND: 510 case Opcodes.IOR: 511 case Opcodes.LOR: 512 case Opcodes.IXOR: 513 case Opcodes.LXOR: 514 case Opcodes.LCMP: 515 case Opcodes.FCMPL: 516 case Opcodes.FCMPG: 517 case Opcodes.DCMPL: 518 case Opcodes.DCMPG: 519 value2 = pop(); 520 value1 = pop(); 521 push(interpreter.binaryOperation(insn, value1, value2)); 522 break; 523 case Opcodes.INEG: 524 case Opcodes.LNEG: 525 case Opcodes.FNEG: 526 case Opcodes.DNEG: 527 push(interpreter.unaryOperation(insn, pop())); 528 break; 529 case Opcodes.IINC: 530 varIndex = ((IincInsnNode) insn).var; 531 setLocal(varIndex, interpreter.unaryOperation(insn, getLocal(varIndex))); 532 break; 533 case Opcodes.I2L: 534 case Opcodes.I2F: 535 case Opcodes.I2D: 536 case Opcodes.L2I: 537 case Opcodes.L2F: 538 case Opcodes.L2D: 539 case Opcodes.F2I: 540 case Opcodes.F2L: 541 case Opcodes.F2D: 542 case Opcodes.D2I: 543 case Opcodes.D2L: 544 case Opcodes.D2F: 545 case Opcodes.I2B: 546 case Opcodes.I2C: 547 case Opcodes.I2S: 548 push(interpreter.unaryOperation(insn, pop())); 549 break; 550 case Opcodes.IFEQ: 551 case Opcodes.IFNE: 552 case Opcodes.IFLT: 553 case Opcodes.IFGE: 554 case Opcodes.IFGT: 555 case Opcodes.IFLE: 556 interpreter.unaryOperation(insn, pop()); 557 break; 558 case Opcodes.IF_ICMPEQ: 559 case Opcodes.IF_ICMPNE: 560 case Opcodes.IF_ICMPLT: 561 case Opcodes.IF_ICMPGE: 562 case Opcodes.IF_ICMPGT: 563 case Opcodes.IF_ICMPLE: 564 case Opcodes.IF_ACMPEQ: 565 case Opcodes.IF_ACMPNE: 566 case Opcodes.PUTFIELD: 567 value2 = pop(); 568 value1 = pop(); 569 interpreter.binaryOperation(insn, value1, value2); 570 break; 571 case Opcodes.GOTO: 572 break; 573 case Opcodes.JSR: 574 push(interpreter.newOperation(insn)); 575 break; 576 case Opcodes.RET: 577 break; 578 case Opcodes.TABLESWITCH: 579 case Opcodes.LOOKUPSWITCH: 580 interpreter.unaryOperation(insn, pop()); 581 break; 582 case Opcodes.IRETURN: 583 case Opcodes.LRETURN: 584 case Opcodes.FRETURN: 585 case Opcodes.DRETURN: 586 case Opcodes.ARETURN: 587 value1 = pop(); 588 interpreter.unaryOperation(insn, value1); 589 interpreter.returnOperation(insn, value1, returnValue); 590 break; 591 case Opcodes.RETURN: 592 if (returnValue != null) { 593 throw new AnalyzerException(insn, "Incompatible return type"); 594 } 595 break; 596 case Opcodes.GETSTATIC: 597 push(interpreter.newOperation(insn)); 598 break; 599 case Opcodes.PUTSTATIC: 600 interpreter.unaryOperation(insn, pop()); 601 break; 602 case Opcodes.GETFIELD: 603 push(interpreter.unaryOperation(insn, pop())); 604 break; 605 case Opcodes.INVOKEVIRTUAL: 606 case Opcodes.INVOKESPECIAL: 607 case Opcodes.INVOKESTATIC: 608 case Opcodes.INVOKEINTERFACE: 609 executeInvokeInsn(insn, ((MethodInsnNode) insn).desc, interpreter); 610 break; 611 case Opcodes.INVOKEDYNAMIC: 612 executeInvokeInsn(insn, ((InvokeDynamicInsnNode) insn).desc, interpreter); 613 break; 614 case Opcodes.NEW: 615 push(interpreter.newOperation(insn)); 616 break; 617 case Opcodes.NEWARRAY: 618 case Opcodes.ANEWARRAY: 619 case Opcodes.ARRAYLENGTH: 620 push(interpreter.unaryOperation(insn, pop())); 621 break; 622 case Opcodes.ATHROW: 623 interpreter.unaryOperation(insn, pop()); 624 break; 625 case Opcodes.CHECKCAST: 626 case Opcodes.INSTANCEOF: 627 push(interpreter.unaryOperation(insn, pop())); 628 break; 629 case Opcodes.MONITORENTER: 630 case Opcodes.MONITOREXIT: 631 interpreter.unaryOperation(insn, pop()); 632 break; 633 case Opcodes.MULTIANEWARRAY: 634 List<V> valueList = new ArrayList<>(); 635 for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) { 636 valueList.add(0, pop()); 637 } 638 push(interpreter.naryOperation(insn, valueList)); 639 break; 640 case Opcodes.IFNULL: 641 case Opcodes.IFNONNULL: 642 interpreter.unaryOperation(insn, pop()); 643 break; 644 default: 645 throw new AnalyzerException(insn, "Illegal opcode " + insn.getOpcode()); 646 } 647 } 648 executeDupX2( final AbstractInsnNode insn, final V value1, final Interpreter<V> interpreter)649 private boolean executeDupX2( 650 final AbstractInsnNode insn, final V value1, final Interpreter<V> interpreter) 651 throws AnalyzerException { 652 V value2 = pop(); 653 if (value2.getSize() == 1) { 654 V value3 = pop(); 655 if (value3.getSize() == 1) { 656 push(interpreter.copyOperation(insn, value1)); 657 push(value3); 658 push(value2); 659 push(value1); 660 return true; 661 } 662 } else { 663 push(interpreter.copyOperation(insn, value1)); 664 push(value2); 665 push(value1); 666 return true; 667 } 668 return false; 669 } 670 executeInvokeInsn( final AbstractInsnNode insn, final String methodDescriptor, final Interpreter<V> interpreter)671 private void executeInvokeInsn( 672 final AbstractInsnNode insn, final String methodDescriptor, final Interpreter<V> interpreter) 673 throws AnalyzerException { 674 ArrayList<V> valueList = new ArrayList<>(); 675 for (int i = Type.getArgumentCount(methodDescriptor); i > 0; --i) { 676 valueList.add(0, pop()); 677 } 678 if (insn.getOpcode() != Opcodes.INVOKESTATIC && insn.getOpcode() != Opcodes.INVOKEDYNAMIC) { 679 valueList.add(0, pop()); 680 } 681 if (Type.getReturnType(methodDescriptor) == Type.VOID_TYPE) { 682 interpreter.naryOperation(insn, valueList); 683 } else { 684 push(interpreter.naryOperation(insn, valueList)); 685 } 686 } 687 688 /** 689 * Merges the given frame into this frame. 690 * 691 * @param frame a frame. This frame is left unchanged by this method. 692 * @param interpreter the interpreter used to merge values. 693 * @return {@literal true} if this frame has been changed as a result of the merge operation, or 694 * {@literal false} otherwise. 695 * @throws AnalyzerException if the frames have incompatible sizes. 696 */ merge(final Frame<? extends V> frame, final Interpreter<V> interpreter)697 public boolean merge(final Frame<? extends V> frame, final Interpreter<V> interpreter) 698 throws AnalyzerException { 699 if (numStack != frame.numStack) { 700 throw new AnalyzerException(null, "Incompatible stack heights"); 701 } 702 boolean changed = false; 703 for (int i = 0; i < numLocals + numStack; ++i) { 704 V v = interpreter.merge(values[i], frame.values[i]); 705 if (!v.equals(values[i])) { 706 values[i] = v; 707 changed = true; 708 } 709 } 710 return changed; 711 } 712 713 /** 714 * Merges the given frame into this frame (case of a subroutine). The operand stacks are not 715 * merged, and only the local variables that have not been used by the subroutine are merged. 716 * 717 * @param frame a frame. This frame is left unchanged by this method. 718 * @param localsUsed the local variables that are read or written by the subroutine. The i-th 719 * element is true if and only if the local variable at index i is read or written by the 720 * subroutine. 721 * @return {@literal true} if this frame has been changed as a result of the merge operation, or 722 * {@literal false} otherwise. 723 */ merge(final Frame<? extends V> frame, final boolean[] localsUsed)724 public boolean merge(final Frame<? extends V> frame, final boolean[] localsUsed) { 725 boolean changed = false; 726 for (int i = 0; i < numLocals; ++i) { 727 if (!localsUsed[i] && !values[i].equals(frame.values[i])) { 728 values[i] = frame.values[i]; 729 changed = true; 730 } 731 } 732 return changed; 733 } 734 735 /** 736 * Returns a string representation of this frame. 737 * 738 * @return a string representation of this frame. 739 */ 740 @Override toString()741 public String toString() { 742 StringBuilder stringBuilder = new StringBuilder(); 743 for (int i = 0; i < getLocals(); ++i) { 744 stringBuilder.append(getLocal(i)); 745 } 746 stringBuilder.append(' '); 747 for (int i = 0; i < getStackSize(); ++i) { 748 stringBuilder.append(getStack(i).toString()); 749 } 750 return stringBuilder.toString(); 751 } 752 } 753