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