1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21package proguard.evaluation;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.CodeAttribute;
25import proguard.classfile.instruction.*;
26import proguard.classfile.instruction.visitor.InstructionVisitor;
27import proguard.evaluation.value.*;
28
29/**
30 * This InstructionVisitor executes the instructions that it visits on a given
31 * local variable frame and stack.
32 *
33 * @author Eric Lafortune
34 */
35public class Processor
36implements   InstructionVisitor
37{
38    private final Variables      variables;
39    private final Stack          stack;
40    private final ValueFactory   valueFactory;
41    private final BranchUnit     branchUnit;
42    private final InvocationUnit invocationUnit;
43    private final boolean        alwaysCast;
44
45    private final ConstantValueFactory      constantValueFactory;
46    private final ClassConstantValueFactory classConstantValueFactory;
47
48
49    /**
50     * Creates a new processor that operates on the given environment.
51     * @param variables      the local variable frame.
52     * @param stack          the local stack.
53     * @param branchUnit     the class that can affect the program counter.
54     * @param invocationUnit the class that can access other program members.
55     * @param alwaysCast     a flag that specifies whether downcasts or casts
56     *                       of null values should always be performed.
57     */
58    public Processor(Variables      variables,
59                     Stack          stack,
60                     ValueFactory   valueFactory,
61                     BranchUnit     branchUnit,
62                     InvocationUnit invocationUnit,
63                     boolean        alwaysCast)
64    {
65        this.variables      = variables;
66        this.stack          = stack;
67        this.valueFactory   = valueFactory;
68        this.branchUnit     = branchUnit;
69        this.invocationUnit = invocationUnit;
70        this.alwaysCast    = alwaysCast;
71
72        constantValueFactory      = new ConstantValueFactory(valueFactory);
73        classConstantValueFactory = new ClassConstantValueFactory(valueFactory);
74    }
75
76
77    // Implementations for InstructionVisitor.
78
79    public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
80    {
81        switch (simpleInstruction.opcode)
82        {
83            case InstructionConstants.OP_NOP:
84                break;
85
86            case InstructionConstants.OP_ACONST_NULL:
87                stack.push(valueFactory.createReferenceValueNull());
88                break;
89
90            case InstructionConstants.OP_ICONST_M1:
91            case InstructionConstants.OP_ICONST_0:
92            case InstructionConstants.OP_ICONST_1:
93            case InstructionConstants.OP_ICONST_2:
94            case InstructionConstants.OP_ICONST_3:
95            case InstructionConstants.OP_ICONST_4:
96            case InstructionConstants.OP_ICONST_5:
97            case InstructionConstants.OP_BIPUSH:
98            case InstructionConstants.OP_SIPUSH:
99                stack.push(valueFactory.createIntegerValue(simpleInstruction.constant));
100                break;
101
102            case InstructionConstants.OP_LCONST_0:
103            case InstructionConstants.OP_LCONST_1:
104                stack.push(valueFactory.createLongValue(simpleInstruction.constant));
105                break;
106
107            case InstructionConstants.OP_FCONST_0:
108            case InstructionConstants.OP_FCONST_1:
109            case InstructionConstants.OP_FCONST_2:
110                stack.push(valueFactory.createFloatValue((float)simpleInstruction.constant));
111                break;
112
113            case InstructionConstants.OP_DCONST_0:
114            case InstructionConstants.OP_DCONST_1:
115                stack.push(valueFactory.createDoubleValue((double)simpleInstruction.constant));
116                break;
117
118            case InstructionConstants.OP_IALOAD:
119            case InstructionConstants.OP_BALOAD:
120            case InstructionConstants.OP_CALOAD:
121            case InstructionConstants.OP_SALOAD:
122            {
123                IntegerValue   arrayIndex     = stack.ipop();
124                ReferenceValue arrayReference = stack.apop();
125                stack.push(arrayReference.integerArrayLoad(arrayIndex, valueFactory));
126                break;
127            }
128            case InstructionConstants.OP_LALOAD:
129            {
130                IntegerValue   arrayIndex     = stack.ipop();
131                ReferenceValue arrayReference = stack.apop();
132                stack.push(arrayReference.longArrayLoad(arrayIndex, valueFactory));
133                break;
134            }
135            case InstructionConstants.OP_FALOAD:
136            {
137                IntegerValue   arrayIndex     = stack.ipop();
138                ReferenceValue arrayReference = stack.apop();
139                stack.push(arrayReference.floatArrayLoad(arrayIndex, valueFactory));
140                break;
141            }
142            case InstructionConstants.OP_DALOAD:
143            {
144                IntegerValue   arrayIndex     = stack.ipop();
145                ReferenceValue arrayReference = stack.apop();
146                stack.push(arrayReference.doubleArrayLoad(arrayIndex, valueFactory));
147                break;
148            }
149            case InstructionConstants.OP_AALOAD:
150            {
151                IntegerValue   arrayIndex     = stack.ipop();
152                ReferenceValue arrayReference = stack.apop();
153                stack.push(arrayReference.referenceArrayLoad(arrayIndex, valueFactory));
154                break;
155            }
156            case InstructionConstants.OP_IASTORE:
157            case InstructionConstants.OP_BASTORE:
158            case InstructionConstants.OP_CASTORE:
159            case InstructionConstants.OP_SASTORE:
160            {
161                Value          value          = stack.ipop();
162                IntegerValue   arrayIndex     = stack.ipop();
163                ReferenceValue arrayReference = stack.apop();
164                arrayReference.arrayStore(arrayIndex, value);
165                break;
166            }
167            case InstructionConstants.OP_LASTORE:
168            {
169                Value          value          = stack.lpop();
170                IntegerValue   arrayIndex     = stack.ipop();
171                ReferenceValue arrayReference = stack.apop();
172                arrayReference.arrayStore(arrayIndex, value);
173                break;
174            }
175            case InstructionConstants.OP_FASTORE:
176            {
177                Value          value          = stack.fpop();
178                IntegerValue   arrayIndex     = stack.ipop();
179                ReferenceValue arrayReference = stack.apop();
180                arrayReference.arrayStore(arrayIndex, value);
181                break;
182            }
183            case InstructionConstants.OP_DASTORE:
184            {
185                Value          value          = stack.dpop();
186                IntegerValue   arrayIndex     = stack.ipop();
187                ReferenceValue arrayReference = stack.apop();
188                arrayReference.arrayStore(arrayIndex, value);
189                break;
190            }
191            case InstructionConstants.OP_AASTORE:
192            {
193                Value          value          = stack.apop();
194                IntegerValue   arrayIndex     = stack.ipop();
195                ReferenceValue arrayReference = stack.apop();
196                arrayReference.arrayStore(arrayIndex, value);
197                break;
198            }
199            case InstructionConstants.OP_POP:
200                stack.pop1();
201                break;
202
203            case InstructionConstants.OP_POP2:
204                stack.pop2();
205                break;
206
207            case InstructionConstants.OP_DUP:
208                stack.dup();
209                break;
210
211            case InstructionConstants.OP_DUP_X1:
212                stack.dup_x1();
213                break;
214
215            case InstructionConstants.OP_DUP_X2:
216                stack.dup_x2();
217                break;
218
219            case InstructionConstants.OP_DUP2:
220                stack.dup2();
221                break;
222
223            case InstructionConstants.OP_DUP2_X1:
224                stack.dup2_x1();
225                break;
226
227            case InstructionConstants.OP_DUP2_X2:
228                stack.dup2_x2();
229                break;
230
231            case InstructionConstants.OP_SWAP:
232                stack.swap();
233                break;
234
235            case InstructionConstants.OP_IADD:
236                stack.push(stack.ipop().add(stack.ipop()));
237                break;
238
239            case InstructionConstants.OP_LADD:
240                stack.push(stack.lpop().add(stack.lpop()));
241                break;
242
243            case InstructionConstants.OP_FADD:
244                stack.push(stack.fpop().add(stack.fpop()));
245                break;
246
247            case InstructionConstants.OP_DADD:
248                stack.push(stack.dpop().add(stack.dpop()));
249                break;
250
251            case InstructionConstants.OP_ISUB:
252                stack.push(stack.ipop().subtractFrom(stack.ipop()));
253                break;
254
255            case InstructionConstants.OP_LSUB:
256                stack.push(stack.lpop().subtractFrom(stack.lpop()));
257                break;
258
259            case InstructionConstants.OP_FSUB:
260                stack.push(stack.fpop().subtractFrom(stack.fpop()));
261                break;
262
263            case InstructionConstants.OP_DSUB:
264                stack.push(stack.dpop().subtractFrom(stack.dpop()));
265                break;
266
267            case InstructionConstants.OP_IMUL:
268                stack.push(stack.ipop().multiply(stack.ipop()));
269                break;
270
271            case InstructionConstants.OP_LMUL:
272                stack.push(stack.lpop().multiply(stack.lpop()));
273                break;
274
275            case InstructionConstants.OP_FMUL:
276                stack.push(stack.fpop().multiply(stack.fpop()));
277                break;
278
279            case InstructionConstants.OP_DMUL:
280                stack.push(stack.dpop().multiply(stack.dpop()));
281                break;
282
283            case InstructionConstants.OP_IDIV:
284                try
285                {
286                    stack.push(stack.ipop().divideOf(stack.ipop()));
287                }
288                catch (ArithmeticException ex)
289                {
290                    stack.push(valueFactory.createIntegerValue());
291                    // TODO: Forward ArithmeticExceptions.
292                    //stack.clear();
293                    //stack.push(valueFactory.createReference(false));
294                    //branchUnit.throwException();
295                }
296                break;
297
298            case InstructionConstants.OP_LDIV:
299                try
300                {
301                    stack.push(stack.lpop().divideOf(stack.lpop()));
302                }
303                catch (ArithmeticException ex)
304                {
305                    stack.push(valueFactory.createLongValue());
306                    // TODO: Forward ArithmeticExceptions.
307                    //stack.clear();
308                    //stack.push(valueFactory.createReference(false));
309                    //branchUnit.throwException();
310                }
311                break;
312
313            case InstructionConstants.OP_FDIV:
314                stack.push(stack.fpop().divideOf(stack.fpop()));
315                break;
316
317            case InstructionConstants.OP_DDIV:
318                stack.push(stack.dpop().divideOf(stack.dpop()));
319                break;
320
321            case InstructionConstants.OP_IREM:
322                try
323                {
324                    stack.push(stack.ipop().remainderOf(stack.ipop()));
325                }
326                catch (ArithmeticException ex)
327                {
328                    stack.push(valueFactory.createIntegerValue());
329                    // TODO: Forward ArithmeticExceptions.
330                    //stack.clear();
331                    //stack.push(valueFactory.createReference(false));
332                    //branchUnit.throwException();
333                }
334                break;
335
336            case InstructionConstants.OP_LREM:
337                try
338                {
339                    stack.push(stack.lpop().remainderOf(stack.lpop()));
340                }
341                catch (ArithmeticException ex)
342                {
343                    stack.push(valueFactory.createLongValue());
344                    // TODO: Forward ArithmeticExceptions.
345                    //stack.clear();
346                    //stack.push(valueFactory.createReference(false));
347                    //branchUnit.throwException();
348                }
349                break;
350
351            case InstructionConstants.OP_FREM:
352                stack.push(stack.fpop().remainderOf(stack.fpop()));
353                break;
354
355            case InstructionConstants.OP_DREM:
356                stack.push(stack.dpop().remainderOf(stack.dpop()));
357                break;
358
359            case InstructionConstants.OP_INEG:
360                stack.push(stack.ipop().negate());
361                break;
362
363            case InstructionConstants.OP_LNEG:
364                stack.push(stack.lpop().negate());
365                break;
366
367            case InstructionConstants.OP_FNEG:
368                stack.push(stack.fpop().negate());
369                break;
370
371            case InstructionConstants.OP_DNEG:
372                stack.push(stack.dpop().negate());
373                break;
374
375            case InstructionConstants.OP_ISHL:
376                stack.push(stack.ipop().shiftLeftOf(stack.ipop()));
377                break;
378
379            case InstructionConstants.OP_LSHL:
380                stack.push(stack.ipop().shiftLeftOf(stack.lpop()));
381                break;
382
383            case InstructionConstants.OP_ISHR:
384                stack.push(stack.ipop().shiftRightOf(stack.ipop()));
385                break;
386
387            case InstructionConstants.OP_LSHR:
388                stack.push(stack.ipop().shiftRightOf(stack.lpop()));
389                break;
390
391            case InstructionConstants.OP_IUSHR:
392                stack.push(stack.ipop().unsignedShiftRightOf(stack.ipop()));
393                break;
394
395            case InstructionConstants.OP_LUSHR:
396                stack.push(stack.ipop().unsignedShiftRightOf(stack.lpop()));
397                break;
398
399            case InstructionConstants.OP_IAND:
400                stack.push(stack.ipop().and(stack.ipop()));
401                break;
402
403            case InstructionConstants.OP_LAND:
404                stack.push(stack.lpop().and(stack.lpop()));
405                break;
406
407            case InstructionConstants.OP_IOR:
408                stack.push(stack.ipop().or(stack.ipop()));
409                break;
410
411            case InstructionConstants.OP_LOR:
412                stack.push(stack.lpop().or(stack.lpop()));
413                break;
414
415            case InstructionConstants.OP_IXOR:
416                stack.push(stack.ipop().xor(stack.ipop()));
417                break;
418
419            case InstructionConstants.OP_LXOR:
420                stack.push(stack.lpop().xor(stack.lpop()));
421                break;
422
423            case InstructionConstants.OP_I2L:
424                stack.push(stack.ipop().convertToLong());
425                break;
426
427            case InstructionConstants.OP_I2F:
428                stack.push(stack.ipop().convertToFloat());
429                break;
430
431            case InstructionConstants.OP_I2D:
432                stack.push(stack.ipop().convertToDouble());
433                break;
434
435            case InstructionConstants.OP_L2I:
436                stack.push(stack.lpop().convertToInteger());
437                break;
438
439            case InstructionConstants.OP_L2F:
440                stack.push(stack.lpop().convertToFloat());
441                break;
442
443            case InstructionConstants.OP_L2D:
444                stack.push(stack.lpop().convertToDouble());
445                break;
446
447            case InstructionConstants.OP_F2I:
448                stack.push(stack.fpop().convertToInteger());
449                break;
450
451            case InstructionConstants.OP_F2L:
452                stack.push(stack.fpop().convertToLong());
453                break;
454
455            case InstructionConstants.OP_F2D:
456                stack.push(stack.fpop().convertToDouble());
457                break;
458
459            case InstructionConstants.OP_D2I:
460                stack.push(stack.dpop().convertToInteger());
461                break;
462
463            case InstructionConstants.OP_D2L:
464                stack.push(stack.dpop().convertToLong());
465                break;
466
467            case InstructionConstants.OP_D2F:
468                stack.push(stack.dpop().convertToFloat());
469                break;
470
471            case InstructionConstants.OP_I2B:
472                stack.push(stack.ipop().convertToByte());
473                break;
474
475            case InstructionConstants.OP_I2C:
476                stack.push(stack.ipop().convertToCharacter());
477                break;
478
479            case InstructionConstants.OP_I2S:
480                stack.push(stack.ipop().convertToShort());
481                break;
482
483            case InstructionConstants.OP_LCMP:
484//                stack.push(stack.lpop().compareReverse(stack.lpop()));
485
486                LongValue longValue1 = stack.lpop();
487                LongValue longValue2 = stack.lpop();
488                stack.push(longValue2.compare(longValue1));
489                break;
490
491            case InstructionConstants.OP_FCMPL:
492                FloatValue floatValue1 = stack.fpop();
493                FloatValue floatValue2 = stack.fpop();
494                stack.push(floatValue2.compare(floatValue1));
495                break;
496
497            case InstructionConstants.OP_FCMPG:
498                stack.push(stack.fpop().compareReverse(stack.fpop()));
499                break;
500
501            case InstructionConstants.OP_DCMPL:
502                DoubleValue doubleValue1 = stack.dpop();
503                DoubleValue doubleValue2 = stack.dpop();
504                stack.push(doubleValue2.compare(doubleValue1));
505                break;
506
507            case InstructionConstants.OP_DCMPG:
508                stack.push(stack.dpop().compareReverse(stack.dpop()));
509                break;
510
511            case InstructionConstants.OP_IRETURN:
512                invocationUnit.exitMethod(clazz, method, stack.ipop());
513                branchUnit.returnFromMethod();
514                break;
515
516            case InstructionConstants.OP_LRETURN:
517                invocationUnit.exitMethod(clazz, method, stack.lpop());
518                branchUnit.returnFromMethod();
519                break;
520
521            case InstructionConstants.OP_FRETURN:
522                invocationUnit.exitMethod(clazz, method, stack.fpop());
523                branchUnit.returnFromMethod();
524                break;
525
526            case InstructionConstants.OP_DRETURN:
527                invocationUnit.exitMethod(clazz, method, stack.dpop());
528                branchUnit.returnFromMethod();
529                break;
530
531            case InstructionConstants.OP_ARETURN:
532                invocationUnit.exitMethod(clazz, method, stack.apop());
533                branchUnit.returnFromMethod();
534                break;
535
536            case InstructionConstants.OP_RETURN:
537                branchUnit.returnFromMethod();
538                break;
539
540            case InstructionConstants.OP_NEWARRAY:
541                IntegerValue arrayLength = stack.ipop();
542                stack.push(valueFactory.createArrayReferenceValue(String.valueOf(InstructionUtil.internalTypeFromArrayType((byte)simpleInstruction.constant)),
543                                                                  null,
544                                                                  arrayLength));
545                break;
546
547            case InstructionConstants.OP_ARRAYLENGTH:
548                ReferenceValue referenceValue = stack.apop();
549                stack.push(referenceValue.arrayLength(valueFactory));
550                break;
551
552            case InstructionConstants.OP_ATHROW:
553                ReferenceValue exceptionReferenceValue = stack.apop();
554                stack.clear();
555                stack.push(exceptionReferenceValue);
556                branchUnit.throwException();
557                break;
558
559            case InstructionConstants.OP_MONITORENTER:
560            case InstructionConstants.OP_MONITOREXIT:
561                stack.apop();
562                break;
563
564            default:
565                throw new IllegalArgumentException("Unknown simple instruction ["+simpleInstruction.opcode+"]");
566        }
567    }
568
569
570    public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
571    {
572        int constantIndex = constantInstruction.constantIndex;
573
574        switch (constantInstruction.opcode)
575        {
576            case InstructionConstants.OP_LDC:
577            case InstructionConstants.OP_LDC_W:
578            case InstructionConstants.OP_LDC2_W:
579                stack.push(classConstantValueFactory.constantValue(clazz, constantIndex));
580                break;
581
582            case InstructionConstants.OP_GETSTATIC:
583            case InstructionConstants.OP_PUTSTATIC:
584            case InstructionConstants.OP_GETFIELD:
585            case InstructionConstants.OP_PUTFIELD:
586            case InstructionConstants.OP_INVOKEVIRTUAL:
587            case InstructionConstants.OP_INVOKESPECIAL:
588            case InstructionConstants.OP_INVOKESTATIC:
589            case InstructionConstants.OP_INVOKEINTERFACE:
590            case InstructionConstants.OP_INVOKEDYNAMIC:
591                invocationUnit.invokeMember(clazz, method, codeAttribute, offset, constantInstruction, stack);
592                break;
593
594            case InstructionConstants.OP_NEW:
595                stack.push(constantValueFactory.constantValue(clazz, constantIndex).referenceValue());
596                break;
597
598            case InstructionConstants.OP_ANEWARRAY:
599            {
600                ReferenceValue referenceValue = constantValueFactory.constantValue(clazz, constantIndex).referenceValue();
601
602                stack.push(valueFactory.createArrayReferenceValue(referenceValue.internalType(),
603                                                                  referenceValue.getReferencedClass(),
604                                                                  stack.ipop()));
605                break;
606            }
607
608            case InstructionConstants.OP_CHECKCAST:
609                // TODO: Check cast.
610                ReferenceValue castValue = stack.apop();
611                ReferenceValue castResultValue =
612                    !alwaysCast &&
613                    castValue.isNull() == Value.ALWAYS ? castValue :
614                    castValue.isNull() == Value.NEVER  ? constantValueFactory.constantValue(clazz, constantIndex).referenceValue() :
615                                                         constantValueFactory.constantValue(clazz, constantIndex).referenceValue().generalize(valueFactory.createReferenceValueNull());
616                stack.push(castResultValue);
617                break;
618
619            case InstructionConstants.OP_INSTANCEOF:
620            {
621                ReferenceValue referenceValue = constantValueFactory.constantValue(clazz, constantIndex).referenceValue();
622
623                int instanceOf = stack.apop().instanceOf(referenceValue.getType(),
624                                                         referenceValue.getReferencedClass());
625
626                stack.push(instanceOf == Value.NEVER  ? valueFactory.createIntegerValue(0) :
627                           instanceOf == Value.ALWAYS ? valueFactory.createIntegerValue(1) :
628                                                        valueFactory.createIntegerValue());
629                break;
630            }
631
632            case InstructionConstants.OP_MULTIANEWARRAY:
633            {
634                int dimensionCount = constantInstruction.constant;
635                for (int dimension = 0; dimension < dimensionCount; dimension++)
636                {
637                    // TODO: Use array lengths.
638                    IntegerValue arrayLength = stack.ipop();
639                }
640
641                stack.push(constantValueFactory.constantValue(clazz, constantIndex).referenceValue());
642                break;
643            }
644
645            default:
646                throw new IllegalArgumentException("Unknown constant pool instruction ["+constantInstruction.opcode+"]");
647        }
648    }
649
650
651    public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
652    {
653        int variableIndex = variableInstruction.variableIndex;
654
655        switch (variableInstruction.opcode)
656        {
657            case InstructionConstants.OP_ILOAD:
658            case InstructionConstants.OP_ILOAD_0:
659            case InstructionConstants.OP_ILOAD_1:
660            case InstructionConstants.OP_ILOAD_2:
661            case InstructionConstants.OP_ILOAD_3:
662                stack.push(variables.iload(variableIndex));
663                break;
664
665            case InstructionConstants.OP_LLOAD:
666            case InstructionConstants.OP_LLOAD_0:
667            case InstructionConstants.OP_LLOAD_1:
668            case InstructionConstants.OP_LLOAD_2:
669            case InstructionConstants.OP_LLOAD_3:
670                stack.push(variables.lload(variableIndex));
671                break;
672
673            case InstructionConstants.OP_FLOAD:
674            case InstructionConstants.OP_FLOAD_0:
675            case InstructionConstants.OP_FLOAD_1:
676            case InstructionConstants.OP_FLOAD_2:
677            case InstructionConstants.OP_FLOAD_3:
678                stack.push(variables.fload(variableIndex));
679                break;
680
681            case InstructionConstants.OP_DLOAD:
682            case InstructionConstants.OP_DLOAD_0:
683            case InstructionConstants.OP_DLOAD_1:
684            case InstructionConstants.OP_DLOAD_2:
685            case InstructionConstants.OP_DLOAD_3:
686                stack.push(variables.dload(variableIndex));
687                break;
688
689            case InstructionConstants.OP_ALOAD:
690            case InstructionConstants.OP_ALOAD_0:
691            case InstructionConstants.OP_ALOAD_1:
692            case InstructionConstants.OP_ALOAD_2:
693            case InstructionConstants.OP_ALOAD_3:
694                stack.push(variables.aload(variableIndex));
695                break;
696
697            case InstructionConstants.OP_ISTORE:
698            case InstructionConstants.OP_ISTORE_0:
699            case InstructionConstants.OP_ISTORE_1:
700            case InstructionConstants.OP_ISTORE_2:
701            case InstructionConstants.OP_ISTORE_3:
702                variables.store(variableIndex, stack.ipop());
703                break;
704
705            case InstructionConstants.OP_LSTORE:
706            case InstructionConstants.OP_LSTORE_0:
707            case InstructionConstants.OP_LSTORE_1:
708            case InstructionConstants.OP_LSTORE_2:
709            case InstructionConstants.OP_LSTORE_3:
710                variables.store(variableIndex, stack.lpop());
711                break;
712
713            case InstructionConstants.OP_FSTORE:
714            case InstructionConstants.OP_FSTORE_0:
715            case InstructionConstants.OP_FSTORE_1:
716            case InstructionConstants.OP_FSTORE_2:
717            case InstructionConstants.OP_FSTORE_3:
718                variables.store(variableIndex, stack.fpop());
719                break;
720
721            case InstructionConstants.OP_DSTORE:
722            case InstructionConstants.OP_DSTORE_0:
723            case InstructionConstants.OP_DSTORE_1:
724            case InstructionConstants.OP_DSTORE_2:
725            case InstructionConstants.OP_DSTORE_3:
726                variables.store(variableIndex, stack.dpop());
727                break;
728
729            case InstructionConstants.OP_ASTORE:
730            case InstructionConstants.OP_ASTORE_0:
731            case InstructionConstants.OP_ASTORE_1:
732            case InstructionConstants.OP_ASTORE_2:
733            case InstructionConstants.OP_ASTORE_3:
734                // The operand on the stack can be a reference or a return
735                // address, so we'll relax the pop operation.
736                //variables.store(variableIndex, stack.apop());
737                variables.store(variableIndex, stack.pop());
738                break;
739
740            case InstructionConstants.OP_IINC:
741                variables.store(variableIndex,
742                                variables.iload(variableIndex).add(
743                                valueFactory.createIntegerValue(variableInstruction.constant)));
744                break;
745
746            case InstructionConstants.OP_RET:
747                // The return address should be in the last offset of the
748                // given instruction offset variable (even though there may
749                // be other offsets).
750                InstructionOffsetValue instructionOffsetValue = variables.oload(variableIndex);
751                branchUnit.branch(clazz,
752                                  codeAttribute,
753                                  offset,
754                                  instructionOffsetValue.instructionOffset(instructionOffsetValue.instructionOffsetCount()-1));
755                break;
756
757            default:
758                throw new IllegalArgumentException("Unknown variable instruction ["+variableInstruction.opcode+"]");
759        }
760    }
761
762
763    public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
764    {
765        int branchTarget = offset + branchInstruction.branchOffset;
766
767        switch (branchInstruction.opcode)
768        {
769            case InstructionConstants.OP_IFEQ:
770                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
771                    stack.ipop().equal(valueFactory.createIntegerValue(0)));
772                break;
773
774            case InstructionConstants.OP_IFNE:
775                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
776                    stack.ipop().notEqual(valueFactory.createIntegerValue(0)));
777                break;
778
779            case InstructionConstants.OP_IFLT:
780                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
781                    stack.ipop().lessThan(valueFactory.createIntegerValue(0)));
782                break;
783
784            case InstructionConstants.OP_IFGE:
785                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
786                    stack.ipop().greaterThanOrEqual(valueFactory.createIntegerValue(0)));
787                break;
788
789            case InstructionConstants.OP_IFGT:
790                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
791                    stack.ipop().greaterThan(valueFactory.createIntegerValue(0)));
792                break;
793
794            case InstructionConstants.OP_IFLE:
795                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
796                    stack.ipop().lessThanOrEqual(valueFactory.createIntegerValue(0)));
797                break;
798
799
800            case InstructionConstants.OP_IFICMPEQ:
801                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
802                    stack.ipop().equal(stack.ipop()));
803                break;
804
805            case InstructionConstants.OP_IFICMPNE:
806                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
807                    stack.ipop().notEqual(stack.ipop()));
808                break;
809
810            case InstructionConstants.OP_IFICMPLT:
811                // Note that the stack entries are popped in reverse order.
812                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
813                    stack.ipop().greaterThan(stack.ipop()));
814                break;
815
816            case InstructionConstants.OP_IFICMPGE:
817                // Note that the stack entries are popped in reverse order.
818                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
819                    stack.ipop().lessThanOrEqual(stack.ipop()));
820                break;
821
822            case InstructionConstants.OP_IFICMPGT:
823                // Note that the stack entries are popped in reverse order.
824                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
825                    stack.ipop().lessThan(stack.ipop()));
826                break;
827
828            case InstructionConstants.OP_IFICMPLE:
829                // Note that the stack entries are popped in reverse order.
830                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
831                    stack.ipop().greaterThanOrEqual(stack.ipop()));
832                break;
833
834            case InstructionConstants.OP_IFACMPEQ:
835                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
836                    stack.apop().equal(stack.apop()));
837                break;
838
839            case InstructionConstants.OP_IFACMPNE:
840                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
841                    stack.apop().notEqual(stack.apop()));
842                break;
843
844            case InstructionConstants.OP_GOTO:
845            case InstructionConstants.OP_GOTO_W:
846                branchUnit.branch(clazz, codeAttribute, offset, branchTarget);
847                break;
848
849
850            case InstructionConstants.OP_JSR:
851            case InstructionConstants.OP_JSR_W:
852                stack.push(new InstructionOffsetValue(offset +
853                                                      branchInstruction.length(offset)));
854                branchUnit.branch(clazz, codeAttribute, offset, branchTarget);
855                break;
856
857            case InstructionConstants.OP_IFNULL:
858                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
859                    stack.apop().isNull());
860                break;
861
862            case InstructionConstants.OP_IFNONNULL:
863                branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
864                    stack.apop().isNotNull());
865                break;
866
867            default:
868                throw new IllegalArgumentException("Unknown branch instruction ["+branchInstruction.opcode+"]");
869        }
870    }
871
872
873    public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction)
874    {
875        IntegerValue indexValue = stack.ipop();
876
877        // If there is no definite branch in any of the cases below,
878        // branch to the default offset.
879        branchUnit.branch(clazz, codeAttribute,
880                          offset,
881                          offset + tableSwitchInstruction.defaultOffset);
882
883        for (int index = 0; index < tableSwitchInstruction.jumpOffsets.length; index++)
884        {
885            int conditional = indexValue.equal(valueFactory.createIntegerValue(
886                tableSwitchInstruction.lowCase + index));
887            branchUnit.branchConditionally(clazz, codeAttribute,
888                                           offset,
889                                           offset + tableSwitchInstruction.jumpOffsets[index],
890                                           conditional);
891
892            // If this branch is always taken, we can skip the rest.
893            if (conditional == Value.ALWAYS)
894            {
895                break;
896            }
897        }
898    }
899
900
901    public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
902    {
903        IntegerValue indexValue = stack.ipop();
904
905        // If there is no definite branch in any of the cases below,
906        // branch to the default offset.
907        branchUnit.branch(clazz, codeAttribute,
908                          offset,
909                          offset + lookUpSwitchInstruction.defaultOffset);
910
911        for (int index = 0; index < lookUpSwitchInstruction.jumpOffsets.length; index++)
912        {
913            int conditional = indexValue.equal(valueFactory.createIntegerValue(
914                lookUpSwitchInstruction.cases[index]));
915            branchUnit.branchConditionally(clazz, codeAttribute,
916                                           offset,
917                                           offset + lookUpSwitchInstruction.jumpOffsets[index],
918                                           conditional);
919
920            // If this branch is always taken, we can skip the rest.
921            if (conditional == Value.ALWAYS)
922            {
923                break;
924            }
925        }
926    }
927}
928