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