• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
21 package proguard.evaluation;
22 
23 import proguard.classfile.*;
24 import proguard.classfile.attribute.CodeAttribute;
25 import proguard.classfile.constant.*;
26 import proguard.classfile.constant.visitor.ConstantVisitor;
27 import proguard.classfile.instruction.*;
28 import proguard.classfile.instruction.visitor.InstructionVisitor;
29 import proguard.classfile.util.SimplifiedVisitor;
30 import 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  */
38 public class Processor
39 extends      SimplifiedVisitor
40 implements   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      */
Processor(Variables variables, Stack stack, ValueFactory valueFactory, BranchUnit branchUnit, InvocationUnit invocationUnit)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 
visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)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 
visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)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 
visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)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 
visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)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 
visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction)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 
visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)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 
visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)914     public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
915     {
916         cpValue = valueFactory.createIntegerValue(integerConstant.getValue());
917     }
918 
visitLongConstant(Clazz clazz, LongConstant longConstant)919     public void visitLongConstant(Clazz clazz, LongConstant longConstant)
920     {
921         cpValue = valueFactory.createLongValue(longConstant.getValue());
922     }
923 
visitFloatConstant(Clazz clazz, FloatConstant floatConstant)924     public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
925     {
926         cpValue = valueFactory.createFloatValue(floatConstant.getValue());
927     }
928 
visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)929     public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
930     {
931         cpValue = valueFactory.createDoubleValue(doubleConstant.getValue());
932     }
933 
visitStringConstant(Clazz clazz, StringConstant stringConstant)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 
visitClassConstant(Clazz clazz, ClassConstant classConstant)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      */
cpValue(Clazz clazz, int constantIndex)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      */
cpValue(Clazz clazz, int constantIndex, boolean handleClassConstantAsClassValue)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