• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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