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