~ubuntu-branches/ubuntu/breezy/proguard/breezy

« back to all changes in this revision

Viewing changes to src/proguard/optimize/evaluation/Processor.java

  • Committer: Bazaar Package Importer
  • Author(s): Sam Clegg
  • Date: 2005-06-17 14:25:24 UTC
  • Revision ID: james.westby@ubuntu.com-20050617142524-thz2yfa3vemy3j9d
Tags: upstream-3.2
ImportĀ upstreamĀ versionĀ 3.2

Show diffs side-by-side

added added

removed removed

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