~ubuntu-branches/ubuntu/oneiric/proguard/oneiric

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Sam Clegg
  • Date: 2005-11-13 09:42:59 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20051113094259-432zf4yyw4890mmn
Tags: 3.4-1
* New upstream release (Closes: #338355)
* debian/control: bump standards version
* debian/copyright: update FSF address
* increase java stack size for proguard and proguardgui

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: PartialEvaluator.java,v 1.26 2004/12/11 16:35:23 eric Exp $
 
1
/* $Id: PartialEvaluator.java,v 1.37 2005/10/22 11:55:29 eric Exp $
2
2
 *
3
3
 * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
4
4
 *
5
 
 * Copyright (c) 2002-2004 Eric Lafortune (eric@graphics.cornell.edu)
 
5
 * Copyright (c) 2002-2005 Eric Lafortune (eric@graphics.cornell.edu)
6
6
 *
7
7
 * This program is free software; you can redistribute it and/or modify it
8
8
 * under the terms of the GNU General Public License as published by the Free
22
22
 
23
23
import proguard.classfile.*;
24
24
import proguard.classfile.attribute.*;
25
 
import proguard.classfile.attribute.annotation.*;
26
 
import proguard.classfile.editor.*;
27
25
import proguard.classfile.instruction.*;
28
 
import proguard.classfile.util.*;
29
 
import proguard.classfile.visitor.*;
30
 
import proguard.optimize.*;
 
26
import proguard.classfile.util.ClassUtil;
31
27
import proguard.optimize.evaluation.value.*;
 
28
import proguard.optimize.peephole.BranchTargetFinder;
32
29
 
33
30
/**
34
 
 * This MemberInfoVisitor performs partial evaluation on the program methods
35
 
 * that it visits.
 
31
 * This class performs partial evaluation.
36
32
 *
37
33
 * @author Eric Lafortune
38
34
 */
39
35
public class PartialEvaluator
40
 
implements   MemberInfoVisitor,
41
 
             AttrInfoVisitor,
42
 
             ExceptionInfoVisitor,
43
 
             InstructionVisitor,
44
 
             CpInfoVisitor
 
36
implements   ExceptionInfoVisitor,
 
37
             InstructionVisitor
45
38
{
46
39
    //*
47
 
    private static final boolean DEBUG_RESULTS  = false;
48
 
    private static final boolean DEBUG_ANALYSIS = false;
49
 
    private static final boolean DEBUG          = false;
 
40
    private static final boolean DEBUG         = false;
 
41
    private static final boolean DEBUG_RESULTS = false;
50
42
    /*/
51
 
    private static boolean DEBUG_RESULTS  = true;
52
 
    private static boolean DEBUG_ANALYSIS = true;
53
 
    private static boolean DEBUG          = true;
 
43
    private static boolean DEBUG         = true;
 
44
    private static boolean DEBUG_RESULTS = true;
54
45
    //*/
55
46
 
56
47
    private static final int INITIAL_CODE_LENGTH = 1024;
57
48
    private static final int INITIAL_VALUE_COUNT = 32;
58
49
 
59
 
    private static final int MAXIMUM_EVALUATION_COUNT = 100;
60
 
 
61
 
 
62
 
    private InstructionOffsetValue[] varTraceValues     = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
63
 
    private InstructionOffsetValue[] stackTraceValues   = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
64
 
    private InstructionOffsetValue[] branchOriginValues = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
65
 
    private InstructionOffsetValue[] branchTargetValues = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
66
 
    private TracedVariables[]        vars               = new TracedVariables[INITIAL_CODE_LENGTH];
67
 
    private TracedStack[]            stacks             = new TracedStack[INITIAL_CODE_LENGTH];
68
 
    private int[]                    evaluationCounts   = new int[INITIAL_CODE_LENGTH];
69
 
    private boolean[]                initialization     = new boolean[INITIAL_CODE_LENGTH];
70
 
    private boolean[]                isNecessary        = new boolean[INITIAL_CODE_LENGTH];
 
50
    //private static final int MAXIMUM_EVALUATION_COUNT = 100;
 
51
 
 
52
    public static final int AT_METHOD_ENTRY = -1;
 
53
    public static final int AT_CATCH_ENTRY  = -1;
 
54
    public static final int NONE            = -1;
 
55
 
 
56
    private BranchTargetFinder branchTargetFinder = new BranchTargetFinder(1024);
 
57
 
 
58
    private InstructionOffsetValue[] varProducerValues    = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
 
59
    private InstructionOffsetValue[] stackProducerValues  = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
 
60
    private InstructionOffsetValue[] unusedProducerValues = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
 
61
    private InstructionOffsetValue[] branchOriginValues   = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
 
62
    private InstructionOffsetValue[] branchTargetValues   = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
 
63
    private TracedVariables[]        vars                 = new TracedVariables[INITIAL_CODE_LENGTH];
 
64
    private TracedStack[]            stacks               = new TracedStack[INITIAL_CODE_LENGTH];
 
65
    private int[]                    evaluationCounts     = new int[INITIAL_CODE_LENGTH];
 
66
    private int[]                    initializedVariables = new int[INITIAL_CODE_LENGTH];
71
67
    private boolean                  evaluateExceptions;
72
68
 
73
 
    private TracedVariables  parameters = new TracedVariables(INITIAL_VALUE_COUNT);
74
69
    private TracedVariables  variables  = new TracedVariables(INITIAL_VALUE_COUNT);
75
70
    private TracedStack      stack      = new TracedStack(INITIAL_VALUE_COUNT);
76
71
    private TracedBranchUnit branchUnit = new TracedBranchUnit();
77
72
 
78
 
    private ClassFileCleaner             classFileCleaner             = new ClassFileCleaner();
79
 
    private SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true);
80
 
    private CodeAttrInfoEditor           codeAttrInfoEditor           = new CodeAttrInfoEditor(INITIAL_CODE_LENGTH);
81
 
 
82
 
    private boolean isInitializer;
83
 
 
84
 
 
85
 
    // Implementations for MemberInfoVisitor.
86
 
 
87
 
    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
88
 
 
89
 
 
90
 
    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
91
 
    {
92
 
//        DEBUG = DEBUG_ANALYSIS = DEBUG_RESULTS =
93
 
//            programClassFile.getName().equals("abc/Def") &&
94
 
//            programMethodInfo.getName(programClassFile).equals("abc");
95
 
 
96
 
        // Initialize the parameters.
97
 
        boolean isStatic =
98
 
            (programMethodInfo.u2accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0;
99
 
 
100
 
        // Count the number of parameters, taking into account their Categories.
101
 
        String parameterDescriptor = programMethodInfo.getDescriptor(programClassFile);
102
 
        int count = (isStatic ? 0 : 1) +
103
 
                    ClassUtil.internalMethodParameterSize(parameterDescriptor);
104
 
 
105
 
        // Reuse the existing parameters object, ensuring the right size.
106
 
        parameters.reset(count);
107
 
 
108
 
        // Go over the parameters again.
109
 
        InternalTypeEnumeration internalTypeEnumeration =
110
 
            new InternalTypeEnumeration(parameterDescriptor);
111
 
 
112
 
        int index = 0;
113
 
 
114
 
        // Clear the store value of each parameter.
115
 
        parameters.setStoreValue(InstructionOffsetValueFactory.create());
116
 
 
117
 
        // Put the caller's reference in parameter 0.
118
 
        if (!isStatic)
119
 
        {
120
 
            parameters.store(index++, ReferenceValueFactory.create(false));
121
 
        }
122
 
 
123
 
        while (internalTypeEnumeration.hasMoreTypes())
124
 
        {
125
 
            String type = internalTypeEnumeration.nextType();
126
 
 
127
 
            // Get a generic corresponding value.
128
 
            Value value = ValueFactory.create(type);
129
 
 
130
 
            // Store the value in the parameter.
131
 
            parameters.store(index, value);
132
 
 
133
 
            // Increment the index according to the Category of the value.
134
 
            index += value.isCategory2() ? 2 : 1;
135
 
        }
136
 
 
137
 
        // Reset the return value.
138
 
        branchUnit.setTraceReturnValue(null);
139
 
 
140
 
        try
141
 
        {
142
 
            // Process the code.
143
 
            programMethodInfo.attributesAccept(programClassFile, this);
144
 
        }
145
 
        catch (RuntimeException ex)
146
 
        {
147
 
            // TODO: Remove this when the partial evaluator has stabilized.
148
 
            System.err.println("Unexpected error while optimizing after partial evaluation:");
149
 
            System.err.println("  ClassFile   = ["+programClassFile.getName()+"]");
150
 
            System.err.println("  Method      = ["+programMethodInfo.getName(programClassFile)+programMethodInfo.getDescriptor(programClassFile)+"]");
151
 
            System.err.println("Not optimizing this method");
152
 
 
153
 
            if (DEBUG)
154
 
            {
155
 
                throw ex;
156
 
            }
157
 
        }
158
 
 
159
 
        if (DEBUG)
160
 
        {
161
 
            Value returnValue = branchUnit.getTraceReturnValue();
162
 
            if (returnValue != null)
163
 
            {
164
 
                System.out.println("Return value for method "+
165
 
                                   ClassUtil.externalFullMethodDescription(programClassFile.getName(),
166
 
                                                                           0,
167
 
                                                                           programMethodInfo.getName(programClassFile),
168
 
                                                                           programMethodInfo.getDescriptor(programClassFile))+
169
 
                                   " -> ["+returnValue.toString()+"]");
170
 
                System.out.println();
171
 
            }
172
 
        }
173
 
    }
174
 
 
175
 
 
176
 
    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
177
 
    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
178
 
 
179
 
 
180
 
    // Implementations for AttrInfoVisitor.
181
 
 
182
 
    public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
183
 
    public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
184
 
    public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
185
 
    public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
186
 
    public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
187
 
    public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
188
 
    public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
189
 
    public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
190
 
    public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
191
 
    public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
192
 
    public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
193
 
    public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
194
 
    public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
195
 
    public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
196
 
    public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
197
 
    public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
198
 
    public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
199
 
    public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
200
 
 
201
 
 
202
 
    public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
203
 
    {
204
 
        if (DEBUG_RESULTS)
205
 
        {
206
 
            System.out.println();
207
 
            System.out.println("Class "+ClassUtil.externalClassName(classFile.getName()));
208
 
            System.out.println("Method "+ClassUtil.externalFullMethodDescription(classFile.getName(),
209
 
                                                                                 0,
210
 
                                                                                 methodInfo.getName(classFile),
211
 
                                                                                 methodInfo.getDescriptor(classFile)));
212
 
            System.out.println("  Params:"+parameters);
213
 
        }
214
 
 
215
 
        int codeLength = codeAttrInfo.u4codeLength;
216
 
 
217
 
        // Reset the code changes.
218
 
        codeAttrInfoEditor.reset(codeLength);
219
 
 
220
 
        if (DEBUG)
221
 
        {
222
 
            System.out.println("  Max locals = "+codeAttrInfo.u2maxLocals);
223
 
            System.out.println("  Max stack  = "+codeAttrInfo.u2maxStack);
224
 
        }
225
 
 
226
 
        // Create new arrays for storing a stack and a set of variables at each
227
 
        // branch target.
228
 
        if (isNecessary.length < codeLength)
229
 
        {
230
 
            varTraceValues     = new InstructionOffsetValue[codeLength];
231
 
            stackTraceValues   = new InstructionOffsetValue[codeLength];
232
 
            branchOriginValues = new InstructionOffsetValue[codeLength];
233
 
            branchTargetValues = new InstructionOffsetValue[codeLength];
234
 
            vars               = new TracedVariables[codeLength];
235
 
            stacks             = new TracedStack[codeLength];
236
 
            evaluationCounts   = new int[codeLength];
237
 
            initialization     = new boolean[codeLength];
238
 
            isNecessary        = new boolean[codeLength];
239
 
        }
240
 
        else
241
 
        {
242
 
            for (int index = 0; index < codeLength; index++)
243
 
            {
244
 
                varTraceValues[index]     = null;
245
 
                stackTraceValues[index]   = null;
246
 
                branchOriginValues[index] = null;
247
 
                branchTargetValues[index] = null;
248
 
                evaluationCounts[index]   = 0;
249
 
                initialization[index]     = false;
250
 
                isNecessary[index]        = false;
251
 
 
252
 
                if (vars[index] != null)
253
 
                {
254
 
                    vars[index].reset(codeAttrInfo.u2maxLocals);
255
 
                }
256
 
 
257
 
                if (stacks[index] != null)
258
 
                {
259
 
                    stacks[index].reset(codeAttrInfo.u2maxStack);
260
 
                }
261
 
            }
262
 
        }
263
 
 
264
 
        // Reuse the existing variables and stack objects, ensuring the right size.
265
 
        variables.reset(codeAttrInfo.u2maxLocals);
266
 
        stack.reset(codeAttrInfo.u2maxStack);
267
 
 
268
 
        // Initialize the local variables with the parameters.
269
 
        variables.initialize(parameters);
 
73
 
 
74
    /**
 
75
     * Performs partial evaluation of the given method with the given parameters.
 
76
     * @param classFile    the method's class file.
 
77
     * @param methodInfo   the method's header.
 
78
     * @param codeAttrInfo the method's code.
 
79
     * @param parameters   the method parameters.
 
80
     * @return             the partial result.
 
81
     */
 
82
    public Value evaluate(ClassFile    classFile,
 
83
                          MethodInfo   methodInfo,
 
84
                          CodeAttrInfo codeAttrInfo,
 
85
                          Variables    parameters)
 
86
    {
 
87
        // Initialize the reusable arrays and variables.
 
88
        initializeVariables(codeAttrInfo, parameters);
 
89
 
 
90
        // Find all instruction offsets,...
 
91
        codeAttrInfo.accept(classFile, methodInfo, branchTargetFinder);
270
92
 
271
93
        // Evaluate the instructions, starting at the entry point.
272
94
        if (DEBUG) System.out.println("Partial evaluation: ");
291
113
        }
292
114
        while (evaluateExceptions);
293
115
 
294
 
        // Clean up the visitor information in the exceptions right away.
295
 
        codeAttrInfo.exceptionsAccept(classFile, methodInfo, classFileCleaner);
296
 
 
297
 
        // Replace any instructions that can be simplified.
298
 
        if (DEBUG_ANALYSIS) System.out.println("Instruction simplification:");
299
 
 
300
 
        codeAttrInfo.instructionsAccept(classFile, methodInfo, this);
301
 
 
302
 
 
303
 
        // Mark all essential instructions that have been encountered as used.
304
 
        if (DEBUG_ANALYSIS) System.out.println("Usage initialization: ");
305
 
 
306
 
        // The invocation of the "super" or "this" <init> method inside a
307
 
        // constructor is always necessary, even if it is assumed to have no
308
 
        // side effects.
309
 
        boolean markSuperOrThis = 
310
 
            methodInfo.getName(classFile).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT);
311
 
 
312
 
        int aload0Index = 0;
313
 
 
314
 
        int index = 0;
315
 
        do
316
 
        {
317
 
            if (isTraced(index))
318
 
            {
319
 
                Instruction instruction = InstructionFactory.create(codeAttrInfo.code,
320
 
                                                                    index);
321
 
 
322
 
                // Remember the most recent aload0 instruction index.
323
 
                if (instruction.opcode == InstructionConstants.OP_ALOAD_0)
324
 
                {
325
 
                    aload0Index = index;
326
 
                }
327
 
 
328
 
                // Mark the instruction as necessary if it is the first
329
 
                // invocation of the "super" or "this" <init> method
330
 
                // inside a constructor.
331
 
                else if (markSuperOrThis &&
332
 
                         instruction.opcode == InstructionConstants.OP_INVOKESPECIAL &&
333
 
                         stackTraceValues[index].contains(aload0Index))
334
 
                {
335
 
                    markSuperOrThis = false;
336
 
                    
337
 
                    if (DEBUG_ANALYSIS) System.out.print(index+",");
338
 
                    isNecessary[index] = true;
339
 
                }
340
 
                
341
 
                // Mark the instruction as necessary if it has side effects.
342
 
                else if (sideEffectInstructionChecker.hasSideEffects(classFile,
343
 
                                                                     methodInfo,
344
 
                                                                     codeAttrInfo,
345
 
                                                                     index,
346
 
                                                                     instruction))
347
 
                {
348
 
                    if (DEBUG_ANALYSIS) System.out.print(index+",");
349
 
                    isNecessary[index] = true;
350
 
                }
351
 
            }
352
 
 
353
 
            index++;
354
 
        }
355
 
        while (index < codeLength);
356
 
        if (DEBUG_ANALYSIS) System.out.println();
357
 
 
358
 
 
359
 
        // Mark all other instructions on which the essential instructions
360
 
        // depend. Instead of doing this recursively, we loop across all
361
 
        // instructions, starting at the last one, and restarting at any
362
 
        // higher, previously unmarked instruction that is being marked.
363
 
        if (DEBUG_ANALYSIS) System.out.println("Usage marking:");
364
 
 
365
 
        int lowestNecessaryIndex = codeLength;
366
 
        index = codeLength - 1;
367
 
        do
368
 
        {
369
 
            int nextIndex = index - 1;
370
 
 
371
 
            // Update the lowest index of all marked instructions higher up.
372
 
            if (isNecessary[index])
373
 
            {
374
 
                lowestNecessaryIndex = index;
375
 
            }
376
 
 
377
 
            // Check if this instruction is a branch origin from a branch that
378
 
            // straddles some marked code.
379
 
            nextIndex = markStraddlingBranches(index,
380
 
                                               branchTargetValues[index],
381
 
                                               true,
382
 
                                               lowestNecessaryIndex,
383
 
                                               nextIndex);
384
 
 
385
 
            // Mark the instructions on which this instruction depends.
386
 
            nextIndex = markDependencies(index,
387
 
                                         nextIndex);
388
 
 
389
 
            // Update the lowest index of all marked instructions higher up.
390
 
            if (isNecessary[index])
391
 
            {
392
 
                lowestNecessaryIndex = index;
393
 
            }
394
 
 
395
 
            // Check if this instruction is a branch target from a branch that
396
 
            // straddles some marked code.
397
 
            nextIndex = markStraddlingBranches(index,
398
 
                                               branchOriginValues[index],
399
 
                                               false,
400
 
                                               lowestNecessaryIndex,
401
 
                                               nextIndex);
402
 
 
403
 
            if (DEBUG_ANALYSIS)
404
 
            {
405
 
                if (nextIndex >= index)
406
 
                {
407
 
                    System.out.println();
408
 
                }
409
 
            }
410
 
 
411
 
            // Update the lowest index of all marked instructions higher up.
412
 
            if (isNecessary[index])
413
 
            {
414
 
                lowestNecessaryIndex = index;
415
 
            }
416
 
 
417
 
            // Update the index of the instruction to be investigated next.
418
 
            index = nextIndex;
419
 
        }
420
 
        while (index >= 0);
421
 
        if (DEBUG_ANALYSIS) System.out.println();
422
 
 
423
 
 
424
 
        // Insert pop instructions where necessary, to keep the stack consistent.
425
 
        if (DEBUG_ANALYSIS) System.out.println("Stack consistency marking:");
426
 
 
427
 
        index = codeLength - 1;
428
 
        do
429
 
        {
430
 
            if (isTraced(index) &&
431
 
                !isNecessary[index])
432
 
            {
433
 
                // Make sure the stack is always consistent at this offset.
434
 
                fixStackConsistency(classFile,
435
 
                                    codeAttrInfo,
436
 
                                    index);
437
 
            }
438
 
 
439
 
            index--;
440
 
        }
441
 
        while (index >= 0);
442
 
        if (DEBUG_ANALYSIS) System.out.println();
443
 
 
444
 
 
445
 
        // Fix dup/swap instructions where necessary, to keep the stack consistent.
446
 
        if (DEBUG_ANALYSIS) System.out.println("Dup/swap fixing:");
447
 
 
448
 
        index = 0;
449
 
        do
450
 
        {
451
 
            if (isNecessary[index])
452
 
            {
453
 
                // Make sure any dup/swap instructions are always consistent at this offset.
454
 
                fixDupInstruction(codeAttrInfo,
455
 
                                  index);
456
 
            }
457
 
 
458
 
            index++;
459
 
        }
460
 
        while (index < codeLength);
461
 
        if (DEBUG_ANALYSIS) System.out.println();
462
 
 
463
 
 
464
 
        // Mark branches straddling just inserted push/pop instructions.
465
 
        if (DEBUG_ANALYSIS) System.out.println("Final straddling branch marking:");
466
 
 
467
 
        lowestNecessaryIndex = codeLength;
468
 
        index = codeLength - 1;
469
 
        do
470
 
        {
471
 
            int nextIndex = index - 1;
472
 
 
473
 
            // Update the lowest index of all marked instructions higher up.
474
 
            if (isNecessary[index])
475
 
            {
476
 
                lowestNecessaryIndex = index;
477
 
            }
478
 
 
479
 
            // Check if this instruction is a branch origin from a branch that
480
 
            // straddles some marked code.
481
 
            nextIndex = markAndSimplifyStraddlingBranches(index,
482
 
                                                          branchTargetValues[index],
483
 
                                                          lowestNecessaryIndex,
484
 
                                                          nextIndex);
485
 
 
486
 
            // Update the lowest index of all marked instructions higher up.
487
 
            if (isNecessary[index])
488
 
            {
489
 
                lowestNecessaryIndex = index;
490
 
            }
491
 
 
492
 
            // Check if this instruction is a branch target from a branch that
493
 
            // straddles some marked code.
494
 
            nextIndex = markAndSimplifyStraddlingBranches(branchOriginValues[index],
495
 
                                                          index,
496
 
                                                          lowestNecessaryIndex,
497
 
                                                          nextIndex);
498
 
 
499
 
            if (DEBUG_ANALYSIS)
500
 
            {
501
 
                if (nextIndex >= index)
502
 
                {
503
 
                    System.out.println();
504
 
                }
505
 
            }
506
 
 
507
 
            // Update the lowest index of all marked instructions higher up.
508
 
            if (isNecessary[index])
509
 
            {
510
 
                lowestNecessaryIndex = index;
511
 
            }
512
 
 
513
 
            // Update the index of the instruction to be investigated next.
514
 
            index = nextIndex;
515
 
        }
516
 
        while (index >= 0);
517
 
        if (DEBUG_ANALYSIS) System.out.println();
518
 
 
519
 
 
520
 
        // Mark variable initializations, even if they aren't strictly necessary.
521
 
        // The virtual machine is not smart enough to see this, and may complain
522
 
        // otherwise.
523
 
        if (DEBUG_ANALYSIS) System.out.println("Initialization marking: ");
524
 
 
525
 
        // TODO: Find a better way.
526
 
        index = 0;
527
 
        do
528
 
        {
529
 
            // Is it an initialization that hasn't been marked yet?
530
 
            if (initialization[index] &&
531
 
                !isNecessary[index])
532
 
            {
533
 
                if (DEBUG_ANALYSIS) System.out.println(index+",");
534
 
 
535
 
                // Figure out what kind of initialization value has to be stored.
536
 
                int pushInstructionOffset = stackTraceValues[index].instructionOffset(0);
537
 
                int pushComputationalType = stacks[pushInstructionOffset].getTop(0).computationalType();
538
 
                increaseStackSize(index, pushComputationalType, false);
539
 
            }
540
 
 
541
 
            index++;
542
 
        }
543
 
        while (index < codeLength);
544
 
        if (DEBUG_ANALYSIS) System.out.println();
545
 
 
546
 
 
547
116
        if (DEBUG_RESULTS)
548
117
        {
549
 
            System.out.println("Results:");
 
118
            System.out.println("Evaluation results:");
 
119
 
 
120
            int codeLength = codeAttrInfo.u4codeLength;
 
121
 
550
122
            int offset = 0;
551
123
            do
552
124
            {
553
125
                Instruction instruction = InstructionFactory.create(codeAttrInfo.code,
554
126
                                                                    offset);
555
 
                System.out.println((isNecessary[offset] ? " + " : " - ")+instruction.toString(offset));
 
127
                System.out.println(instruction.toString(offset));
556
128
                if (isTraced(offset))
557
129
                {
558
 
                    if (varTraceValues[offset] != null &&
559
 
                        varTraceValues[offset].instructionOffsetCount() > 0)
560
 
                    {
561
 
                        System.out.println("     has overall been using information from instructions setting vars: "+varTraceValues[offset]);
562
 
                    }
563
 
                    if (stackTraceValues[offset] != null &&
564
 
                        stackTraceValues[offset].instructionOffsetCount() > 0)
565
 
                    {
566
 
                        System.out.println("     has overall been using information from instructions setting stack: "+stackTraceValues[offset]);
567
 
                    }
568
 
                    if (branchTargetValues[offset] != null)
569
 
                    {
570
 
                        System.out.println("     has overall been branching to "+branchTargetValues[offset]);
571
 
                    }
572
 
                    if (codeAttrInfoEditor.preInsertions[offset] != null)
573
 
                    {
574
 
                        System.out.println("     is preceded by: "+codeAttrInfoEditor.preInsertions[offset]);
575
 
                    }
576
 
                    if (codeAttrInfoEditor.postInsertions[offset] != null)
577
 
                    {
578
 
                        System.out.println("     is followed by: "+codeAttrInfoEditor.preInsertions[offset]);
579
 
                    }
 
130
                    InstructionOffsetValue varProducerOffsets = varProducerOffsets(offset);
 
131
                    if (varProducerOffsets.instructionOffsetCount() > 0)
 
132
                    {
 
133
                        System.out.println("     has overall been using information from instructions setting vars: "+varProducerOffsets);
 
134
                    }
 
135
 
 
136
                    InstructionOffsetValue stackProducerOffsets = stackProducerOffsets(offset);
 
137
                    if (stackProducerOffsets.instructionOffsetCount() > 0)
 
138
                    {
 
139
                        System.out.println("     has overall been using information from instructions setting stack: "+stackProducerOffsets);
 
140
                    }
 
141
 
 
142
                    InstructionOffsetValue unusedProducerOffsets = unusedProducerOffsets(offset);
 
143
                    if (unusedProducerOffsets.instructionOffsetCount() > 0)
 
144
                    {
 
145
                        System.out.println("     no longer needs information from instructions setting stack: "+unusedProducerOffsets);
 
146
                    }
 
147
 
 
148
                    InstructionOffsetValue branchTargets = branchTargets(offset);
 
149
                    if (branchTargets != null)
 
150
                    {
 
151
                        System.out.println("     has overall been branching to "+branchTargets);
 
152
                    }
 
153
 
580
154
                    System.out.println("     Vars:  "+vars[offset]);
581
155
                    System.out.println("     Stack: "+stacks[offset]);
582
156
                }
586
160
            while (offset < codeLength);
587
161
        }
588
162
 
589
 
        // Delete all instructions that are not used.
590
 
        int offset = 0;
591
 
        do
592
 
        {
593
 
            Instruction instruction = InstructionFactory.create(codeAttrInfo.code,
594
 
                                                                offset);
595
 
            if (!isNecessary[offset])
596
 
            {
597
 
                codeAttrInfoEditor.replaceInstruction(offset, null);
598
 
                codeAttrInfoEditor.replaceInstruction2(offset, null);
599
 
            }
600
 
 
601
 
            offset += instruction.length(offset);
602
 
        }
603
 
        while (offset < codeLength);
604
 
 
605
 
        // Apply all accumulated changes to the code.
606
 
        codeAttrInfoEditor.visitCodeAttrInfo(classFile, methodInfo, codeAttrInfo);
607
 
    }
608
 
 
609
 
 
610
 
    /**
611
 
     * Marks the instructions at the given offsets, if the current instruction
612
 
     * itself has been marked.
613
 
     * @param index     the offset of the current instruction.
614
 
     * @param nextIndex the index of the instruction to be investigated next.
615
 
     * @return the updated index of the instruction to be investigated next.
616
 
     *         It is always greater than or equal, because instructions are
617
 
     *         investigated starting at the highest index.
618
 
     */
619
 
    private int markDependencies(int index,
620
 
                                 int nextIndex)
621
 
    {
622
 
        if (isNecessary[index] &&
623
 
            !codeAttrInfoEditor.isModified(index))
624
 
        {
625
 
            if (DEBUG_ANALYSIS) System.out.print(index);
626
 
 
627
 
            // Mark all instructions whose variable values are used.
628
 
            nextIndex = markDependencies(varTraceValues[index], nextIndex);
629
 
 
630
 
            // Mark all instructions whose stack values are used.
631
 
            nextIndex = markDependencies(stackTraceValues[index], nextIndex);
632
 
 
633
 
            if (DEBUG_ANALYSIS) System.out.print(",");
634
 
        }
635
 
 
636
 
        return nextIndex;
637
 
    }
638
 
 
639
 
 
640
 
    /**
641
 
     * Marks the instructions at the given offsets.
642
 
     * @param traceOffsetValue the offsets of the instructions to be marked.
643
 
     * @param nextIndex        the index of the instruction to be investigated
644
 
     *                         next.
645
 
     * @return the updated index of the instruction to be investigated next.
646
 
     *         It is always greater than or equal, because instructions are
647
 
     *         investigated starting at the highest index.
648
 
     */
649
 
    private int markDependencies(InstructionOffsetValue traceOffsetValue,
650
 
                                 int                    nextIndex)
651
 
    {
652
 
        if (traceOffsetValue != null)
653
 
        {
654
 
            int traceOffsetCount = traceOffsetValue.instructionOffsetCount();
655
 
            for (int traceOffsetIndex = 0; traceOffsetIndex < traceOffsetCount; traceOffsetIndex++)
656
 
            {
657
 
                // Has the other instruction been marked yet?
658
 
                int traceOffset = traceOffsetValue.instructionOffset(traceOffsetIndex);
659
 
                if (!isNecessary[traceOffset])
660
 
                {
661
 
                    if (DEBUG_ANALYSIS) System.out.print("["+traceOffset+"]");
662
 
 
663
 
                    // Mark it.
664
 
                    isNecessary[traceOffset] = true;
665
 
 
666
 
                    // Restart at this instruction if it has a higher offset.
667
 
                    if (nextIndex < traceOffset)
668
 
                    {
669
 
                        if (DEBUG_ANALYSIS) System.out.print("!");
670
 
 
671
 
                        nextIndex = traceOffset;
672
 
                    }
673
 
                }
674
 
            }
675
 
        }
676
 
 
677
 
        return nextIndex;
678
 
    }
679
 
 
680
 
 
681
 
    /**
682
 
     * Marks the branch instructions of straddling branches, if they straddle
683
 
     * some code that has been marked.
684
 
     * @param index                the offset of the branch origin or branch target.
685
 
     * @param branchValue          the offsets of the straddling branch targets
686
 
     *                             or branch origins.
687
 
     * @param isPointingToTargets  <code>true</code> if the above offsets are
688
 
     *                             branch targets, <code>false</code> if they
689
 
     *                             are branch origins.
690
 
     * @param lowestNecessaryIndex the lowest offset of all instructions marked
691
 
     *                             so far.
692
 
     * @param nextIndex            the index of the instruction to be investigated
693
 
     *                             next.
694
 
     * @return the updated index of the instruction to be investigated next.
695
 
     *         It is always greater than or equal the original index, because
696
 
     *         instructions are investigated starting at the highest index.
697
 
     */
698
 
    private int markStraddlingBranches(int                    index,
699
 
                                       InstructionOffsetValue branchValue,
700
 
                                       boolean                isPointingToTargets,
701
 
                                       int                    lowestNecessaryIndex,
702
 
                                       int                    nextIndex)
703
 
    {
704
 
        if (branchValue != null)
705
 
        {
706
 
            // Loop over all branch origins.
707
 
            int branchCount = branchValue.instructionOffsetCount();
708
 
            for (int branchIndex = 0; branchIndex < branchCount; branchIndex++)
709
 
            {
710
 
                // Is the branch straddling any necessary instructions?
711
 
                int branch = branchValue.instructionOffset(branchIndex);
712
 
 
713
 
                // Is the offset pointing to a branch origin or to a branch target?
714
 
                nextIndex = isPointingToTargets ?
715
 
                    markStraddlingBranch(index, branch, lowestNecessaryIndex, nextIndex) :
716
 
                    markStraddlingBranch(branch, index, lowestNecessaryIndex, nextIndex);
717
 
            }
718
 
        }
719
 
 
720
 
        return nextIndex;
721
 
    }
722
 
 
723
 
 
724
 
    /**
725
 
     * Marks the given branch instruction, if it straddles some code that has
726
 
     * been marked.
727
 
     * @param branchOrigin         the branch origin.
728
 
     * @param branchTarget         the branch target.
729
 
     * @param lowestNecessaryIndex the lowest offset of all instructions marked
730
 
     *                             so far.
731
 
     * @param nextIndex            the index of the instruction to be investigated
732
 
     *                             next.
733
 
     * @return the updated index of the instruction to be investigated next.
734
 
     *         It is always greater than or equal the original index, because
735
 
     *         instructions are investigated starting at the highest index.
736
 
     */
737
 
    private int markStraddlingBranch(int branchOrigin,
738
 
                                     int branchTarget,
739
 
                                     int lowestNecessaryIndex,
740
 
                                     int nextIndex)
741
 
    {
742
 
        // Has the branch origin been marked yet, and is it straddling the
743
 
        // lowest necessary instruction?
744
 
        if (!isNecessary[branchOrigin] &&
745
 
            isStraddlingBranch(branchOrigin, branchTarget, lowestNecessaryIndex))
746
 
        {
747
 
            if (DEBUG_ANALYSIS) System.out.print("["+branchOrigin+"->"+branchTarget+"]");
748
 
 
749
 
            // Mark the branch origin.
750
 
            isNecessary[branchOrigin] = true;
751
 
 
752
 
            // Restart at the branch origin if it has a higher offset.
753
 
            if (nextIndex < branchOrigin)
754
 
            {
755
 
                if (DEBUG_ANALYSIS) System.out.print("!");
756
 
 
757
 
                nextIndex = branchOrigin;
758
 
            }
759
 
        }
760
 
 
761
 
        return nextIndex;
762
 
    }
763
 
 
764
 
 
765
 
    /**
766
 
     * Marks and simplifies the branch instructions of straddling branches,
767
 
     * if they straddle some code that has been marked.
768
 
     * @param branchOrigin         the branch origin.
769
 
     * @param branchTargets        the branch targets.
770
 
     * @param lowestNecessaryIndex the lowest offset of all instructions marked
771
 
     *                             so far.
772
 
     * @param nextIndex            the index of the instruction to be investigated
773
 
     *                             next.
774
 
     * @return the updated index of the instruction to be investigated next.
775
 
     *         It is always greater than or equal the original index, because
776
 
     *         instructions are investigated starting at the highest index.
777
 
     */
778
 
    private int markAndSimplifyStraddlingBranches(int                    branchOrigin,
779
 
                                                  InstructionOffsetValue branchTargets,
780
 
                                                  int                    lowestNecessaryIndex,
781
 
                                                  int                    nextIndex)
782
 
    {
783
 
        if (branchTargets != null &&
784
 
            !isNecessary[branchOrigin])
785
 
        {
786
 
            // Loop over all branch targets.
787
 
            int branchCount = branchTargets.instructionOffsetCount();
788
 
            if (branchCount > 0)
789
 
            {
790
 
                for (int branchIndex = 0; branchIndex < branchCount; branchIndex++)
791
 
                {
792
 
                    // Is the branch straddling any necessary instructions?
793
 
                    int branchTarget = branchTargets.instructionOffset(branchIndex);
794
 
 
795
 
                    if (!isStraddlingBranch(branchOrigin,
796
 
                                            branchTarget,
797
 
                                            lowestNecessaryIndex))
798
 
                    {
799
 
                        return nextIndex;
800
 
                    }
801
 
                }
802
 
 
803
 
                nextIndex = markAndSimplifyStraddlingBranch(branchOrigin,
804
 
                                                            branchTargets.instructionOffset(0),
805
 
                                                            lowestNecessaryIndex,
806
 
                                                            nextIndex);
807
 
            }
808
 
        }
809
 
 
810
 
        return nextIndex;
811
 
    }
812
 
 
813
 
 
814
 
    /**
815
 
     * Marks and simplifies the branch instructions of straddling branches,
816
 
     * if they straddle some code that has been marked.
817
 
     * @param branchOrigins        the branch origins.
818
 
     * @param branchTarget         the branch target.
819
 
     * @param lowestNecessaryIndex the lowest offset of all instructions marked
820
 
     *                             so far.
821
 
     * @param nextIndex            the index of the instruction to be investigated
822
 
     *                             next.
823
 
     * @return the updated index of the instruction to be investigated next.
824
 
     *         It is always greater than or equal the original index, because
825
 
     *         instructions are investigated starting at the highest index.
826
 
     */
827
 
    private int markAndSimplifyStraddlingBranches(InstructionOffsetValue branchOrigins,
828
 
                                                  int                    branchTarget,
829
 
                                                  int                    lowestNecessaryIndex,
830
 
                                                  int                    nextIndex)
831
 
    {
832
 
        if (branchOrigins != null)
833
 
        {
834
 
            // Loop over all branch origins.
835
 
            int branchCount = branchOrigins.instructionOffsetCount();
836
 
            for (int branchIndex = 0; branchIndex < branchCount; branchIndex++)
837
 
            {
838
 
                // Is the branch straddling any necessary instructions?
839
 
                int branchOrigin = branchOrigins.instructionOffset(branchIndex);
840
 
 
841
 
                nextIndex = markAndSimplifyStraddlingBranch(branchOrigin,
842
 
                                                            branchTarget,
843
 
                                                            lowestNecessaryIndex,
844
 
                                                            nextIndex);
845
 
            }
846
 
        }
847
 
 
848
 
        return nextIndex;
849
 
    }
850
 
 
851
 
 
852
 
    /**
853
 
     * Marks and simplifies the given branch instruction, if it straddles some
854
 
     * code that has been marked.
855
 
     * @param branchOrigin         the branch origin.
856
 
     * @param branchTarget         the branch target.
857
 
     * @param lowestNecessaryIndex the lowest offset of all instructions marked
858
 
     *                             so far.
859
 
     * @param nextIndex            the index of the instruction to be investigated
860
 
     *                             next.
861
 
     * @return the updated index of the instruction to be investigated next.
862
 
     *         It is always greater than or equal the original index, because
863
 
     *         instructions are investigated starting at the highest index.
864
 
     */
865
 
    private int markAndSimplifyStraddlingBranch(int branchOrigin,
866
 
                                                int branchTarget,
867
 
                                                int lowestNecessaryIndex,
868
 
                                                int nextIndex)
869
 
    {
870
 
        // Has the branch origin been marked yet, and is it straddling the
871
 
        // lowest necessary instruction?
872
 
        if (!isNecessary[branchOrigin] &&
873
 
            isStraddlingBranch(branchOrigin, branchTarget, lowestNecessaryIndex))
874
 
        {
875
 
            if (DEBUG_ANALYSIS) System.out.print("["+branchOrigin+"->"+branchTarget+"]");
876
 
 
877
 
            // Mark the branch origin.
878
 
            isNecessary[branchOrigin] = true;
879
 
 
880
 
            // Replace the branch instruction by a simple branch instrucion.
881
 
            Instruction replacementInstruction =
882
 
                new BranchInstruction(InstructionConstants.OP_GOTO_W,
883
 
                                      branchTarget - branchOrigin).shrink();
884
 
 
885
 
            codeAttrInfoEditor.replaceInstruction(branchOrigin,
886
 
                                                  replacementInstruction);
887
 
 
888
 
            // Restart at the branch origin if it has a higher offset.
889
 
            if (nextIndex < branchOrigin)
890
 
            {
891
 
                if (DEBUG_ANALYSIS) System.out.print("!");
892
 
 
893
 
                nextIndex = branchOrigin;
894
 
            }
895
 
        }
896
 
 
897
 
        return nextIndex;
898
 
    }
899
 
 
900
 
 
901
 
    /**
902
 
     * Returns whether the given branch straddling some code that has been marked.
903
 
     * @param branchOrigin         the branch origin.
904
 
     * @param branchTarget         the branch target.
905
 
     * @param lowestNecessaryIndex the lowest offset of all instructions marked
906
 
     *                             so far.
907
 
     */
908
 
    private boolean isStraddlingBranch(int branchOrigin,
909
 
                                       int branchTarget,
910
 
                                       int lowestNecessaryIndex)
911
 
    {
912
 
        return branchOrigin <= lowestNecessaryIndex ^
913
 
               branchTarget <= lowestNecessaryIndex;
914
 
    }
915
 
 
916
 
 
917
 
    /**
918
 
     * Inserts pop instructions where necessary, in order to make sure the
919
 
     * stack is consistent at the given index.
920
 
     * @param classFile    the class file that is being checked.
921
 
     * @param codeAttrInfo the code that is being checked.
922
 
     * @param index        the offset of the dependent instruction.
923
 
     */
924
 
    private void fixStackConsistency(ClassFile    classFile,
925
 
                                     CodeAttrInfo codeAttrInfo,
926
 
                                     int          index)
927
 
    {
928
 
        // Is the unnecessary instruction popping values (but not a dup/swap
929
 
        // instruction)?
930
 
        Instruction popInstruction = InstructionFactory.create(codeAttrInfo.code,
931
 
                                                               index);
932
 
        byte popOpcode = popInstruction.opcode;
933
 
 
934
 
        int popCount = popInstruction.stackPopCount(classFile);
935
 
        if (popCount > 0) // &&
936
 
            //popOpcode != InstructionConstants.OP_DUP     &&
937
 
            //popOpcode != InstructionConstants.OP_DUP_X1  &&
938
 
            //popOpcode != InstructionConstants.OP_DUP_X2  &&
939
 
            //popOpcode != InstructionConstants.OP_DUP2    &&
940
 
            //popOpcode != InstructionConstants.OP_DUP2_X1 &&
941
 
            //popOpcode != InstructionConstants.OP_DUP2_X2 &&
942
 
            //popOpcode != InstructionConstants.OP_SWAP)
943
 
        {
944
 
            // Check the instructions on which it depends.
945
 
            InstructionOffsetValue traceOffsetValue = stackTraceValues[index];
946
 
            int traceOffsetCount = traceOffsetValue.instructionOffsetCount();
947
 
 
948
 
            if (popCount <= 4 &&
949
 
                isAllNecessary(traceOffsetValue))
950
 
            {
951
 
                if (popOpcode == InstructionConstants.OP_POP ||
952
 
                    popOpcode == InstructionConstants.OP_POP2)
953
 
                {
954
 
                    if (DEBUG_ANALYSIS) System.out.println("  Popping value again at "+popInstruction.toString(index)+" (pushed at all "+traceOffsetValue.instructionOffsetCount()+" offsets)");
955
 
 
956
 
                    // Simply mark pop and pop2 instructions.
957
 
                    isNecessary[index] = true;
958
 
                }
959
 
                else
960
 
                {
961
 
                    if (DEBUG_ANALYSIS) System.out.println("  Popping value instead of "+popInstruction.toString(index)+" (pushed at all "+traceOffsetValue.instructionOffsetCount()+" offsets)");
962
 
 
963
 
                    // Make sure the pushed value is popped again,
964
 
                    // right before this instruction.
965
 
                    decreaseStackSize(index, popCount, true, true);
966
 
                }
967
 
            }
968
 
            //else if (popCount == (popInstruction.isCategory2() ? 4 : 2) &&
969
 
            //         traceOffsetCount == 2                              &&
970
 
            //         isAnyNecessary(traceOffsetValue))
971
 
            //{
972
 
            //    if (DEBUG_ANALYSIS) System.out.println("  Popping single value instead of "+popInstruction.toString(index)+" (pushed at some of "+traceOffsetValue.instructionOffsetCount()+" offsets)");
973
 
            //
974
 
            //    // Make sure the single pushed value is popped again,
975
 
            //    // right before this instruction.
976
 
            //    decreaseStackSize(index, popCount / 2, true, true);
977
 
            //}
978
 
            else if (isAnyNecessary(traceOffsetValue))
979
 
            {
980
 
                if (DEBUG_ANALYSIS) System.out.println("  Popping value somewhere before "+index+" (pushed at some of "+traceOffsetValue.instructionOffsetCount()+" offsets):");
981
 
 
982
 
                // Go over all stack pushing instructions.
983
 
                for (int traceOffsetIndex = 0; traceOffsetIndex < traceOffsetCount; traceOffsetIndex++)
984
 
                {
985
 
                    // Has the push instruction been marked?
986
 
                    int pushInstructionOffset = traceOffsetValue.instructionOffset(traceOffsetIndex);
987
 
                    if (isNecessary[pushInstructionOffset])
988
 
                    {
989
 
                        Instruction pushInstruction = InstructionFactory.create(codeAttrInfo.code,
990
 
                                                                                pushInstructionOffset);
991
 
 
992
 
                        int lastOffset = lastPopInstructionOffset(pushInstructionOffset,
993
 
                                                                  index,
994
 
                                                                  pushInstructionOffset);
995
 
 
996
 
                        if (DEBUG_ANALYSIS) System.out.println("    Popping value right after "+lastOffset+", due to push at "+pushInstructionOffset);
997
 
 
998
 
                        // Make sure the pushed value is popped again,
999
 
                        // right after the instruction that pushes it
1000
 
                        // (or after the dup instruction that still uses it).
1001
 
                        decreaseStackSize(lastOffset,
1002
 
                                          pushInstruction.stackPushCount(classFile),
1003
 
                                          false, false);
1004
 
                    }
1005
 
                }
1006
 
            }
1007
 
        }
1008
 
    }
1009
 
 
1010
 
 
1011
 
    /**
1012
 
     * Returns the last offset of the necessary instruction that depends on the
1013
 
     * stack result of the instruction at the given index.
1014
 
     * @param startOffset           the start offset in the search.
1015
 
     * @param endOffset             the end offset in the search.
1016
 
     * @param pushInstructionOffset the offset of the instruction that pushes
1017
 
     *                              a result onto the stack.
1018
 
     * @return the last offset of the necessary instruction that uses the
1019
 
     *         above result.
1020
 
     */
1021
 
    private int lastPopInstructionOffset(int startOffset,
1022
 
                                         int endOffset,
1023
 
                                         int pushInstructionOffset)
1024
 
    {
1025
 
        int lastOffset = startOffset;
1026
 
 
 
163
        if (DEBUG)
 
164
        {
 
165
            Value returnValue = branchUnit.getTraceReturnValue();
 
166
            if (returnValue != null)
 
167
            {
 
168
                System.out.println("Return value for method "+
 
169
                                   ClassUtil.externalFullMethodDescription(classFile.getName(),
 
170
                                                                           0,
 
171
                                                                           methodInfo.getName(classFile),
 
172
                                                                           methodInfo.getDescriptor(classFile))+
 
173
                                   " -> ["+returnValue.toString()+"]");
 
174
                System.out.println();
 
175
            }
 
176
        }
 
177
 
 
178
        // Mark special dependencies of constructors.
 
179
        codeAttrInfo.instructionsAccept(classFile, methodInfo, this);
 
180
 
 
181
        return branchUnit.getTraceReturnValue();
 
182
    }
 
183
 
 
184
 
 
185
    /**
 
186
     * Returns whether a block of instructions is ever used.
 
187
     */
 
188
    public boolean isTraced(int startOffset, int endOffset)
 
189
    {
1027
190
        for (int index = startOffset; index < endOffset; index++)
1028
191
        {
1029
 
            if (isNecessary[index] &&
1030
 
                stackTraceValues[index].contains(pushInstructionOffset))
 
192
            if (isTraced(index))
1031
193
            {
1032
 
                lastOffset = index;
 
194
                return true;
1033
195
            }
1034
196
        }
1035
197
 
1036
 
        return lastOffset;
1037
 
    }
1038
 
 
1039
 
 
1040
 
    /**
1041
 
     * Puts the required push instruction before the given index. The
1042
 
     * instruction is marked as necessary.
1043
 
     * @param index             the offset of the instruction.
1044
 
     * @param computationalType the computational type on the stack, for
1045
 
     *                          push instructions.
1046
 
     * @param delete            specifies whether the instruction should be
1047
 
     *                          deleted.
1048
 
     */
1049
 
    private void increaseStackSize(int     index,
1050
 
                                   int     computationalType,
1051
 
                                   boolean delete)
1052
 
    {
1053
 
        // Mark this instruction.
1054
 
        isNecessary[index] = true;
1055
 
 
1056
 
        // Create a simple push instrucion.
1057
 
        byte replacementOpcode =
1058
 
            computationalType == Value.TYPE_INTEGER   ? InstructionConstants.OP_ICONST_0    :
1059
 
            computationalType == Value.TYPE_LONG      ? InstructionConstants.OP_LCONST_0    :
1060
 
            computationalType == Value.TYPE_FLOAT     ? InstructionConstants.OP_FCONST_0    :
1061
 
            computationalType == Value.TYPE_DOUBLE    ? InstructionConstants.OP_DCONST_0    :
1062
 
            computationalType == Value.TYPE_REFERENCE ? InstructionConstants.OP_ACONST_NULL :
1063
 
                                                        InstructionConstants.OP_NOP;
1064
 
 
1065
 
        Instruction replacementInstruction = new SimpleInstruction(replacementOpcode);
1066
 
 
1067
 
        // Insert the pop or push instruction.
1068
 
        codeAttrInfoEditor.insertBeforeInstruction(index,
1069
 
                                                   replacementInstruction);
1070
 
 
1071
 
        // Delete the original instruction if necessary.
1072
 
        if (delete)
1073
 
        {
1074
 
            codeAttrInfoEditor.deleteInstruction(index);
1075
 
        }
1076
 
    }
1077
 
 
1078
 
 
1079
 
    /**
1080
 
     * Puts the required pop instruction at the given index. The
1081
 
     * instruction is marked as necessary.
1082
 
     * @param offset   the offset of the instruction.
1083
 
     * @param popCount the required reduction of the stack size.
1084
 
     * @param before   specifies whether the pop instruction should be inserted
1085
 
     *                 before or after the present instruction.
1086
 
     * @param delete   specifies whether the instruction should be deleted.
1087
 
     */
1088
 
    private void decreaseStackSize(int     offset,
1089
 
                                   int     popCount,
1090
 
                                   boolean before,
1091
 
                                   boolean delete)
1092
 
    {
1093
 
        boolean after = !before;
1094
 
 
1095
 
        // Special case: we may replace the instruction by two pop instructions.
1096
 
        if (delete && popCount > 2)
1097
 
        {
1098
 
            before = true;
1099
 
            after  = true;
1100
 
        }
1101
 
 
1102
 
        if (popCount < 1 ||
1103
 
            popCount > 4)
1104
 
        {
1105
 
            throw new IllegalArgumentException("Unsupported stack size reduction ["+popCount+"]");
1106
 
        }
1107
 
 
1108
 
        // Mark this instruction.
1109
 
        isNecessary[offset] = true;
1110
 
 
1111
 
        if (before)
1112
 
        {
1113
 
            // Create a simple pop instrucion.
1114
 
            byte replacementOpcode = popCount == 1 || popCount == 3 ?
1115
 
                InstructionConstants.OP_POP :
1116
 
                InstructionConstants.OP_POP2;
1117
 
 
1118
 
            Instruction replacementInstruction = new SimpleInstruction(replacementOpcode);
1119
 
 
1120
 
            // Insert the pop instruction.
1121
 
            codeAttrInfoEditor.insertBeforeInstruction(offset,
1122
 
                                                       replacementInstruction);
1123
 
        }
1124
 
 
1125
 
        if (after)
1126
 
        {
1127
 
            // Create a simple pop instrucion.
1128
 
            byte replacementOpcode = popCount == 1 ?
1129
 
                InstructionConstants.OP_POP :
1130
 
                InstructionConstants.OP_POP2;
1131
 
 
1132
 
            Instruction replacementInstruction = new SimpleInstruction(replacementOpcode);
1133
 
 
1134
 
            if (DEBUG_ANALYSIS) System.out.println("    Pop instruction after ["+offset+"]: "+replacementInstruction);
1135
 
 
1136
 
            // Insert the pop instruction.
1137
 
            codeAttrInfoEditor.insertAfterInstruction(offset,
1138
 
                                                      replacementInstruction);
1139
 
        }
1140
 
 
1141
 
        // Delete the original instruction if necessary.
1142
 
        if (delete)
1143
 
        {
1144
 
            codeAttrInfoEditor.deleteInstruction(offset);
1145
 
        }
1146
 
    }
1147
 
 
1148
 
 
1149
 
    /**
1150
 
     * Replaces the specified instruction by the proper dup/swap variant,
1151
 
     * if necessary, depending on the state of the stack.
1152
 
     * @param codeAttrInfo the code that is being checked.
1153
 
     * @param offset       the offset of the instruction.
1154
 
     */
1155
 
    private void fixDupInstruction(CodeAttrInfo codeAttrInfo,
1156
 
                                   int          offset)
1157
 
    {
1158
 
        byte replacementOpcode = 0;
1159
 
 
1160
 
        // Simplify the popping instruction if possible.
1161
 
        switch (codeAttrInfo.code[offset])
1162
 
        {
1163
 
            case InstructionConstants.OP_DUP_X1:
1164
 
                if (!isStackEntryPresent(offset, 1))
1165
 
                {
1166
 
                    replacementOpcode = InstructionConstants.OP_DUP;
1167
 
                }
1168
 
                break;
1169
 
 
1170
 
            case InstructionConstants.OP_DUP_X2:
1171
 
                if (!isStackEntryPresent(offset, 1) ||
1172
 
                    !isStackEntryPresent(offset, 2))
1173
 
                {
1174
 
                    if (isStackEntryPresent(offset, 1) ||
1175
 
                        isStackEntryPresent(offset, 2))
1176
 
                    {
1177
 
                        replacementOpcode = InstructionConstants.OP_DUP_X1;
1178
 
                    }
1179
 
                    else
1180
 
                    {
1181
 
                        replacementOpcode = InstructionConstants.OP_DUP;
1182
 
                    }
1183
 
                }
1184
 
                break;
1185
 
 
1186
 
            case InstructionConstants.OP_DUP2_X1:
1187
 
                if (!isStackEntryPresent(offset, 2))
1188
 
                {
1189
 
                    replacementOpcode = InstructionConstants.OP_DUP2;
1190
 
                }
1191
 
                break;
1192
 
 
1193
 
            case InstructionConstants.OP_DUP2_X2:
1194
 
                if (!isStackEntryPresent(offset, 2) ||
1195
 
                    !isStackEntryPresent(offset, 3))
1196
 
                {
1197
 
                    if (isStackEntryPresent(offset, 2) ||
1198
 
                        isStackEntryPresent(offset, 3))
1199
 
                    {
1200
 
                        replacementOpcode = InstructionConstants.OP_DUP2_X1;
1201
 
                    }
1202
 
                    else
1203
 
                    {
1204
 
                        replacementOpcode = InstructionConstants.OP_DUP2;
1205
 
                    }
1206
 
                }
1207
 
                break;
1208
 
 
1209
 
            case InstructionConstants.OP_SWAP:
1210
 
                if (!isStackEntryPresent(offset, 0))
1211
 
                {
1212
 
                    isNecessary[offset] = false;
1213
 
                }
1214
 
                break;
1215
 
        }
1216
 
 
1217
 
        // Actually replace the instruction with the new opcde, if any.
1218
 
        if (replacementOpcode != 0)
1219
 
        {
1220
 
            Instruction replacementInstruction = new SimpleInstruction(replacementOpcode);
1221
 
            codeAttrInfoEditor.replaceInstruction(offset,
1222
 
                                                  replacementInstruction);
1223
 
 
1224
 
            if (DEBUG_ANALYSIS) System.out.println("  Replacing instruction at ["+offset+"] by "+replacementInstruction.toString());
1225
 
        }
1226
 
    }
1227
 
 
1228
 
 
1229
 
    /**
1230
 
     * Returns whether the given stack entry is present after execution of the
1231
 
     * instruction at the given offset.
1232
 
     */
1233
 
    private boolean isStackEntryPresent(int instructionOffset, int stackIndex)
1234
 
    {
1235
 
        return isAnyNecessary(stacks[instructionOffset].getTopTraceValue(stackIndex).instructionOffsetValue());
 
198
        return false;
 
199
    }
 
200
 
 
201
 
 
202
    /**
 
203
     * Returns whether the instruction at the given offset has ever been
 
204
     * executed during the partial evaluation.
 
205
     */
 
206
    public boolean isTraced(int instructionOffset)
 
207
    {
 
208
        return evaluationCounts[instructionOffset] > 0;
 
209
    }
 
210
 
 
211
 
 
212
    /**
 
213
     * Returns the variable value at the given instruction offset and variable
 
214
     * index.
 
215
     */
 
216
    public Value variableValue(int instructionOffset,
 
217
                               int variableIndex)
 
218
    {
 
219
        return vars[instructionOffset].load(variableIndex);
 
220
    }
 
221
 
 
222
 
 
223
    /**
 
224
     * Returns the instruction offsets that set the variable value at at the given
 
225
     * instruction offset and variable index.
 
226
     */
 
227
    public InstructionOffsetValue variableProducerOffsets(int instructionOffset,
 
228
                                                          int variableIndex)
 
229
    {
 
230
        return vars[instructionOffset].getStoredTraceValue(variableIndex).instructionOffsetValue();
 
231
    }
 
232
 
 
233
 
 
234
    /**
 
235
     * Returns the instruction offsets that set the variable that is being
 
236
     * used at the given instruction offset.
 
237
     */
 
238
    public InstructionOffsetValue varProducerOffsets(int instructionOffset)
 
239
    {
 
240
        return varProducerValues[instructionOffset];
 
241
    }
 
242
 
 
243
 
 
244
    /**
 
245
     * Returns the stack value at the given instruction offset and stack index.
 
246
     */
 
247
    public Value stackTopValue(int instructionOffset,
 
248
                               int stackIndex)
 
249
    {
 
250
        return stacks[instructionOffset].getTop(stackIndex);
 
251
    }
 
252
 
 
253
 
 
254
    /**
 
255
     * Returns the instruction offsets that set the stack value at at the given
 
256
     * instruction offset and stack index.
 
257
     */
 
258
    public InstructionOffsetValue stackTopProducerOffsets(int instructionOffset,
 
259
                                                          int stackIndex)
 
260
    {
 
261
        return stacks[instructionOffset].getTopProducerValue(stackIndex).instructionOffsetValue();
 
262
    }
 
263
 
 
264
 
 
265
    /**
 
266
     * Returns the instruction offsets that set the stack entries that are being
 
267
     * used at the given instruction offset.
 
268
     */
 
269
    public InstructionOffsetValue stackProducerOffsets(int instructionOffset)
 
270
    {
 
271
        return stackProducerValues[instructionOffset];
 
272
    }
 
273
 
 
274
 
 
275
    /**
 
276
     * Returns the instruction offsets that use the stack value at at the given
 
277
     * instruction offset and stack index.
 
278
     */
 
279
    public InstructionOffsetValue stackTopConsumerOffsets(int instructionOffset,
 
280
                                                          int stackIndex)
 
281
    {
 
282
        return stacks[instructionOffset].getTopConsumerValue(stackIndex).instructionOffsetValue();
 
283
    }
 
284
 
 
285
 
 
286
    /**
 
287
     * Returns the instruction offsets that set stack entries that are not being
 
288
     * used at the given instruction offset (e.g. because the parameters are not
 
289
     * being used).
 
290
     */
 
291
    public InstructionOffsetValue unusedProducerOffsets(int instructionOffset)
 
292
    {
 
293
        return unusedProducerValues[instructionOffset];
 
294
    }
 
295
 
 
296
 
 
297
    /**
 
298
     * Returns the instruction offsets that branch to the given instruction
 
299
     * offset.
 
300
     */
 
301
    public InstructionOffsetValue branchOrigins(int instructionOffset)
 
302
    {
 
303
        return branchOriginValues[instructionOffset];
 
304
    }
 
305
 
 
306
 
 
307
    /**
 
308
     * Returns the instruction offsets to which the given instruction offset
 
309
     * branches.
 
310
     */
 
311
    public InstructionOffsetValue branchTargets(int instructionOffset)
 
312
    {
 
313
        return branchTargetValues[instructionOffset];
 
314
    }
 
315
 
 
316
 
 
317
    /**
 
318
     * Returns the variable that is initialized at the given instruction offset,
 
319
     * or NONE if no variable was initialized.
 
320
     */
 
321
    public int initializedVariable(int instructionOffset)
 
322
    {
 
323
        return initializedVariables[instructionOffset];
1236
324
    }
1237
325
 
1238
326
 
1275
363
            variables.reset(codeAttrInfo.u2maxLocals);
1276
364
            stack.reset(codeAttrInfo.u2maxStack);
1277
365
 
1278
 
            // The initial stack doesn't have associated instruction offsets.
1279
 
            Value storeValue = InstructionOffsetValueFactory.create();
1280
 
            variables.setStoreValue(storeValue);
1281
 
            stack.setStoreValue(storeValue);
 
366
            // The initial stack has a generic instruction offset.
 
367
            Value storeValue = InstructionOffsetValueFactory.create(AT_CATCH_ENTRY);
 
368
            variables.setProducerValue(storeValue);
 
369
            stack.setProducerValue(storeValue);
1282
370
 
1283
371
            // Initialize the local variables and the stack.
1284
372
            variables.initialize(exceptionVariables);
1300
388
    }
1301
389
 
1302
390
 
1303
 
    /**
1304
 
     * Returns whether a block of instructions is ever used.
1305
 
     */
1306
 
    private boolean isTraced(int startOffset, int endOffset)
1307
 
    {
1308
 
        for (int index = startOffset; index < endOffset; index++)
1309
 
        {
1310
 
            if (isTraced(index))
1311
 
            {
1312
 
                return true;
1313
 
            }
1314
 
        }
1315
 
 
1316
 
        return false;
1317
 
    }
1318
 
 
1319
 
 
1320
 
    /**
1321
 
     * Generalize the local variable frames of a block of instructions.
1322
 
     */
1323
 
    private void generalizeVariables(int startOffset, int endOffset, TracedVariables generalizedVariables)
1324
 
    {
1325
 
        for (int index = startOffset; index < endOffset; index++)
1326
 
        {
1327
 
            if (isTraced(index))
1328
 
            {
1329
 
                // We can't use the return value, because local generalization
1330
 
                // can be different a couple of times, with the global
1331
 
                // generalization being the same.
1332
 
                generalizedVariables.generalize(vars[index]);
1333
 
            }
 
391
    // Implementations for InstructionVisitor.
 
392
 
 
393
    public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
 
394
    public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {}
 
395
    public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
 
396
    public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
 
397
    public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
 
398
 
 
399
 
 
400
    public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
 
401
    {
 
402
        // Make sure 'new' instructions (or subsequent 'dup' instructions)
 
403
        // depend on the subsequent initializer calls, in case these calls
 
404
        // are marked as not having any side effects.
 
405
 
 
406
        // Check if the invoked method is an initalizer.
 
407
        if (isTraced(offset) &&
 
408
            branchTargetFinder.isInitializer(offset))
 
409
        {
 
410
            // Find the previous instruction (assuming there was no branch).
 
411
            int previousOffset = offset - 1;
 
412
            while (!isTraced(previousOffset))
 
413
            {
 
414
                previousOffset--;
 
415
            }
 
416
 
 
417
            // Compute the stack index of the uninitialized object.
 
418
            int stackIndex = stacks[offset].size();
 
419
 
 
420
            // Get the (first and presumably only) offset of the instruction
 
421
            // that put it there. This is typically a dup instruction.
 
422
            int newOffset = stacks[previousOffset].getBottomProducerValue(stackIndex).instructionOffsetValue().instructionOffset(0);
 
423
 
 
424
            // Add a reverse dependency. The source instruction depends on
 
425
            // the initializer instruction, thus making sure that the latter
 
426
            // is preserved whenever the former is used.
 
427
            stackProducerValues[newOffset] = stackProducerValues[newOffset].generalize(InstructionOffsetValueFactory.create(offset)).instructionOffsetValue();
1334
428
        }
1335
429
    }
1336
430
 
1364
458
 
1365
459
        Processor processor = new Processor(variables, stack, branchUnit);
1366
460
 
 
461
        UnusedParameterCleaner unusedParameterCleaner = new UnusedParameterCleaner(stack);
 
462
 
1367
463
        // Evaluate the subsequent instructions.
1368
464
        while (true)
1369
465
        {
1371
467
            int evaluationCount = evaluationCounts[instructionOffset]++;
1372
468
            if (evaluationCount == 0)
1373
469
            {
1374
 
                varTraceValues[instructionOffset]   = InstructionOffsetValueFactory.create();
1375
 
                stackTraceValues[instructionOffset] = InstructionOffsetValueFactory.create();
 
470
                varProducerValues[instructionOffset]    = InstructionOffsetValueFactory.create();
 
471
                stackProducerValues[instructionOffset]  = InstructionOffsetValueFactory.create();
 
472
                unusedProducerValues[instructionOffset] = InstructionOffsetValueFactory.create();
1376
473
            }
1377
474
 
1378
475
            // Remember this instruction's offset with any stored value.
1379
476
            Value storeValue = InstructionOffsetValueFactory.create(instructionOffset);
1380
 
            variables.setStoreValue(storeValue);
1381
 
            stack.setStoreValue(storeValue);
 
477
            variables.setProducerValue(storeValue);
 
478
            stack.setProducerValue(storeValue);
1382
479
 
1383
480
            // Reset the trace value.
1384
481
            InstructionOffsetValue traceValue = InstructionOffsetValueFactory.create();
1385
 
            variables.setTraceValue(traceValue);
1386
 
            stack.setTraceValue(traceValue);
 
482
            variables.setCollectedProducerValue(traceValue);
 
483
            stack.setCollectedProducerValue(traceValue);
 
484
            unusedParameterCleaner.setTraceValue(traceValue);
1387
485
 
1388
486
            // Reset the initialization flag.
1389
487
            variables.resetInitialization();
1399
497
            branchUnit.resetCalled();
1400
498
            branchUnit.setTraceBranchTargets(nextInstructionOffsetValue);
1401
499
 
 
500
            // First clean all traces to unused parameters if this is a method
 
501
            // invocation.
 
502
            instruction.accept(classFile,
 
503
                               methodInfo,
 
504
                               codeAttrInfo,
 
505
                               instructionOffset,
 
506
                               unusedParameterCleaner);
1402
507
 
1403
508
            if (DEBUG)
1404
509
            {
1410
515
                // Process the instruction. The processor may call
1411
516
                // the Variables methods of 'variables',
1412
517
                // the Stack methods of 'stack', and
1413
 
                // the BranchUnit methods of this evaluator.
1414
 
                instruction.accept(classFile, methodInfo, codeAttrInfo, instructionOffset, processor);
 
518
                // the BranchUnit methods of 'branchUnit'.
 
519
                instruction.accept(classFile,
 
520
                                   methodInfo,
 
521
                                   codeAttrInfo,
 
522
                                   instructionOffset,
 
523
                                   processor);
1415
524
            }
1416
525
            catch (RuntimeException ex)
1417
526
            {
1424
533
            }
1425
534
 
1426
535
            // Collect the offsets of the instructions whose results were used.
1427
 
            InstructionOffsetValue variablesTraceValue = variables.getTraceValue().instructionOffsetValue();
1428
 
            InstructionOffsetValue stackTraceValue     = stack.getTraceValue().instructionOffsetValue();
1429
 
            varTraceValues[instructionOffset] =
1430
 
                varTraceValues[instructionOffset].generalize(variablesTraceValue).instructionOffsetValue();
1431
 
            stackTraceValues[instructionOffset] =
1432
 
                stackTraceValues[instructionOffset].generalize(stackTraceValue).instructionOffsetValue();
1433
 
            initialization[instructionOffset] =
1434
 
                initialization[instructionOffset] || variables.wasInitialization();
 
536
            InstructionOffsetValue variablesTraceValue = variables.getCollectedProducerValue().instructionOffsetValue();
 
537
            InstructionOffsetValue stackTraceValue     = stack.getCollectedProducerValue().instructionOffsetValue();
 
538
            InstructionOffsetValue unusedTraceValue    = unusedParameterCleaner.getTraceValue().instructionOffsetValue();
 
539
            varProducerValues[instructionOffset] =
 
540
                varProducerValues[instructionOffset].generalize(variablesTraceValue).instructionOffsetValue();
 
541
            stackProducerValues[instructionOffset] =
 
542
                stackProducerValues[instructionOffset].generalize(stackTraceValue).instructionOffsetValue();
 
543
            unusedProducerValues[instructionOffset] =
 
544
                unusedProducerValues[instructionOffset].generalize(unusedTraceValue).instructionOffsetValue();
 
545
            initializedVariables[instructionOffset] = variables.getInitializationIndex();
1435
546
 
1436
547
            // Collect the branch targets from the branch unit.
1437
548
            InstructionOffsetValue branchTargets = branchUnit.getTraceBranchTargets();
1438
549
            int branchTargetCount = branchTargets.instructionOffsetCount();
1439
550
 
1440
551
            // Stop tracing.
1441
 
            variables.setTraceValue(traceValue);
1442
 
            stack.setTraceValue(traceValue);
 
552
            variables.setCollectedProducerValue(traceValue);
 
553
            stack.setCollectedProducerValue(traceValue);
1443
554
            branchUnit.setTraceBranchTargets(traceValue);
1444
555
 
1445
556
            if (DEBUG)
1457
568
                    System.out.println("     is branching to "+branchTargets);
1458
569
                }
1459
570
 
1460
 
                if (varTraceValues[instructionOffset].instructionOffsetCount() > 0)
1461
 
                {
1462
 
                    System.out.println("     has up til now been using information from instructions setting vars: "+varTraceValues[instructionOffset]);
1463
 
                }
1464
 
                if (stackTraceValues[instructionOffset].instructionOffsetCount() > 0)
1465
 
                {
1466
 
                    System.out.println("     has up till now been using information from instructions setting stack: "+stackTraceValues[instructionOffset]);
 
571
                if (varProducerValues[instructionOffset].instructionOffsetCount() > 0)
 
572
                {
 
573
                    System.out.println("     has up til now been using information from instructions setting vars: "+varProducerValues[instructionOffset]);
 
574
                }
 
575
                if (stackProducerValues[instructionOffset].instructionOffsetCount() > 0)
 
576
                {
 
577
                    System.out.println("     has up till now been using information from instructions setting stack: "+stackProducerValues[instructionOffset]);
 
578
                }
 
579
                if (unusedProducerValues[instructionOffset].instructionOffsetCount() > 0)
 
580
                {
 
581
                    System.out.println("     no longer needs information from instructions setting stack: "+unusedProducerValues[instructionOffset]);
1467
582
                }
1468
583
                if (branchTargetValues[instructionOffset] != null)
1469
584
                {
1579
694
    }
1580
695
 
1581
696
 
1582
 
    // Implementations for InstructionVisitor.
1583
 
 
1584
 
    public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction)
1585
 
    {
1586
 
        if (isTraced(offset))
1587
 
        {
1588
 
            switch (simpleInstruction.opcode)
1589
 
            {
1590
 
                case InstructionConstants.OP_IALOAD:
1591
 
                case InstructionConstants.OP_BALOAD:
1592
 
                case InstructionConstants.OP_CALOAD:
1593
 
                case InstructionConstants.OP_SALOAD:
1594
 
                case InstructionConstants.OP_IADD:
1595
 
                case InstructionConstants.OP_ISUB:
1596
 
                case InstructionConstants.OP_IMUL:
1597
 
                case InstructionConstants.OP_IDIV:
1598
 
                case InstructionConstants.OP_IREM:
1599
 
                case InstructionConstants.OP_INEG:
1600
 
                case InstructionConstants.OP_ISHL:
1601
 
                case InstructionConstants.OP_ISHR:
1602
 
                case InstructionConstants.OP_IUSHR:
1603
 
                case InstructionConstants.OP_IAND:
1604
 
                case InstructionConstants.OP_IOR:
1605
 
                case InstructionConstants.OP_IXOR:
1606
 
                case InstructionConstants.OP_L2I:
1607
 
                case InstructionConstants.OP_F2I:
1608
 
                case InstructionConstants.OP_D2I:
1609
 
                case InstructionConstants.OP_I2B:
1610
 
                case InstructionConstants.OP_I2C:
1611
 
                case InstructionConstants.OP_I2S:
1612
 
                    replaceIntegerPushInstruction(offset, simpleInstruction);
1613
 
                    break;
1614
 
 
1615
 
                case InstructionConstants.OP_LALOAD:
1616
 
                case InstructionConstants.OP_LADD:
1617
 
                case InstructionConstants.OP_LSUB:
1618
 
                case InstructionConstants.OP_LMUL:
1619
 
                case InstructionConstants.OP_LDIV:
1620
 
                case InstructionConstants.OP_LREM:
1621
 
                case InstructionConstants.OP_LNEG:
1622
 
                case InstructionConstants.OP_LSHL:
1623
 
                case InstructionConstants.OP_LSHR:
1624
 
                case InstructionConstants.OP_LUSHR:
1625
 
                case InstructionConstants.OP_LAND:
1626
 
                case InstructionConstants.OP_LOR:
1627
 
                case InstructionConstants.OP_LXOR:
1628
 
                case InstructionConstants.OP_I2L:
1629
 
                case InstructionConstants.OP_F2L:
1630
 
                case InstructionConstants.OP_D2L:
1631
 
                    replaceLongPushInstruction(offset, simpleInstruction);
1632
 
                    break;
1633
 
 
1634
 
                case InstructionConstants.OP_FALOAD:
1635
 
                case InstructionConstants.OP_FADD:
1636
 
                case InstructionConstants.OP_FSUB:
1637
 
                case InstructionConstants.OP_FMUL:
1638
 
                case InstructionConstants.OP_FDIV:
1639
 
                case InstructionConstants.OP_FREM:
1640
 
                case InstructionConstants.OP_FNEG:
1641
 
                case InstructionConstants.OP_I2F:
1642
 
                case InstructionConstants.OP_L2F:
1643
 
                case InstructionConstants.OP_D2F:
1644
 
                    replaceFloatPushInstruction(offset, simpleInstruction);
1645
 
                    break;
1646
 
 
1647
 
                case InstructionConstants.OP_DALOAD:
1648
 
                case InstructionConstants.OP_DADD:
1649
 
                case InstructionConstants.OP_DSUB:
1650
 
                case InstructionConstants.OP_DMUL:
1651
 
                case InstructionConstants.OP_DDIV:
1652
 
                case InstructionConstants.OP_DREM:
1653
 
                case InstructionConstants.OP_DNEG:
1654
 
                case InstructionConstants.OP_I2D:
1655
 
                case InstructionConstants.OP_L2D:
1656
 
                case InstructionConstants.OP_F2D:
1657
 
                    replaceDoublePushInstruction(offset, simpleInstruction);
1658
 
                    break;
1659
 
 
1660
 
                case InstructionConstants.OP_AALOAD:
1661
 
                    replaceReferencePushInstruction(offset, simpleInstruction);
1662
 
                    break;
1663
 
            }
1664
 
        }
1665
 
    }
1666
 
 
1667
 
 
1668
 
    public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction)
1669
 
    {
1670
 
        if (isTraced(offset))
1671
 
        {
1672
 
            switch (variableInstruction.opcode)
1673
 
            {
1674
 
                case InstructionConstants.OP_ILOAD:
1675
 
                case InstructionConstants.OP_ILOAD_0:
1676
 
                case InstructionConstants.OP_ILOAD_1:
1677
 
                case InstructionConstants.OP_ILOAD_2:
1678
 
                case InstructionConstants.OP_ILOAD_3:
1679
 
                    replaceIntegerPushInstruction(offset, variableInstruction);
1680
 
                    break;
1681
 
 
1682
 
                case InstructionConstants.OP_LLOAD:
1683
 
                case InstructionConstants.OP_LLOAD_0:
1684
 
                case InstructionConstants.OP_LLOAD_1:
1685
 
                case InstructionConstants.OP_LLOAD_2:
1686
 
                case InstructionConstants.OP_LLOAD_3:
1687
 
                    replaceLongPushInstruction(offset, variableInstruction);
1688
 
                    break;
1689
 
 
1690
 
                case InstructionConstants.OP_FLOAD:
1691
 
                case InstructionConstants.OP_FLOAD_0:
1692
 
                case InstructionConstants.OP_FLOAD_1:
1693
 
                case InstructionConstants.OP_FLOAD_2:
1694
 
                case InstructionConstants.OP_FLOAD_3:
1695
 
                    replaceFloatPushInstruction(offset, variableInstruction);
1696
 
                    break;
1697
 
 
1698
 
                case InstructionConstants.OP_DLOAD:
1699
 
                case InstructionConstants.OP_DLOAD_0:
1700
 
                case InstructionConstants.OP_DLOAD_1:
1701
 
                case InstructionConstants.OP_DLOAD_2:
1702
 
                case InstructionConstants.OP_DLOAD_3:
1703
 
                    replaceDoublePushInstruction(offset, variableInstruction);
1704
 
                    break;
1705
 
 
1706
 
                case InstructionConstants.OP_ALOAD:
1707
 
                case InstructionConstants.OP_ALOAD_0:
1708
 
                case InstructionConstants.OP_ALOAD_1:
1709
 
                case InstructionConstants.OP_ALOAD_2:
1710
 
                case InstructionConstants.OP_ALOAD_3:
1711
 
                    replaceReferencePushInstruction(offset, variableInstruction);
1712
 
                    break;
1713
 
 
1714
 
            }
1715
 
        }
1716
 
    }
1717
 
 
1718
 
 
1719
 
    public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
1720
 
    {
1721
 
        // Make sure 'new' instructions (or subsequent 'dup' instructions)
1722
 
        // depend on the subsequent initializer calls, in case these calls
1723
 
        // are marked as not having any side effects.
1724
 
        if (isTraced(offset) &&
1725
 
            cpInstruction.opcode == InstructionConstants.OP_INVOKESPECIAL)
1726
 
        {
1727
 
            // Check if the invoked method is an initalizer.
1728
 
            classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
1729
 
 
1730
 
            if (isInitializer)
1731
 
            {
1732
 
                // Find the previous instruction (assuming there was no branch).
1733
 
                int previousOffset = offset - 1;
1734
 
                while (!isTraced(previousOffset))
1735
 
                {
1736
 
                    previousOffset--;
1737
 
                }
1738
 
 
1739
 
                // Compute the stack index of the uninitialized object.
1740
 
                int stackIndex = stacks[offset].size();
1741
 
 
1742
 
                // Get the (first and presumably only) offset of the instruction
1743
 
                // that put it there. This is typically a dup instruction.
1744
 
                int newOffset = stacks[previousOffset].getBottomTraceValue(stackIndex).instructionOffsetValue().instructionOffset(0);
1745
 
 
1746
 
                // Add a reverse dependency. The source instruction depends on
1747
 
                // the initializer instruction, thus making sure that the latter
1748
 
                // is preserved whenever the former is used.
1749
 
                stackTraceValues[newOffset] = stackTraceValues[newOffset].generalize(InstructionOffsetValueFactory.create(offset)).instructionOffsetValue();
1750
 
            }
1751
 
        }
1752
 
    }
1753
 
 
1754
 
 
1755
 
    public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction)
1756
 
    {
1757
 
        replaceBranchInstruction(offset, branchInstruction);
1758
 
    }
1759
 
 
1760
 
 
1761
 
    public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction)
1762
 
    {
1763
 
        replaceBranchInstruction(offset, tableSwitchInstruction);
1764
 
    }
1765
 
 
1766
 
 
1767
 
    public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
1768
 
    {
1769
 
        replaceBranchInstruction(offset, lookUpSwitchInstruction);
1770
 
    }
1771
 
 
1772
 
 
1773
 
    // Small utility methods.
1774
 
 
1775
 
    /**
1776
 
     * Replaces the given integer instruction by a simpler push instruction,
1777
 
     * if possible.
1778
 
     */
1779
 
    private void replaceIntegerPushInstruction(int offset, Instruction instruction)
1780
 
    {
1781
 
        Stack stack = stacks[offset];
1782
 
        Value pushedValue = stack.getTop(0);
1783
 
        if (pushedValue.isSpecific())
1784
 
        {
1785
 
            int value = pushedValue.integerValue().value();
1786
 
            if (value << 16 >> 16 == value)
1787
 
            {
1788
 
                replacePushInstruction(offset,
1789
 
                                       InstructionConstants.OP_SIPUSH,
1790
 
                                       value);
1791
 
            }
1792
 
        }
1793
 
    }
1794
 
 
1795
 
 
1796
 
    /**
1797
 
     * Replaces the given long instruction by a simpler push instruction,
1798
 
     * if possible.
1799
 
     */
1800
 
    private void replaceLongPushInstruction(int offset, Instruction instruction)
1801
 
    {
1802
 
        Stack stack = stacks[offset];
1803
 
        Value pushedValue = stack.getTop(0);
1804
 
        if (pushedValue.isSpecific())
1805
 
        {
1806
 
            long value = pushedValue.longValue().value();
1807
 
            if (value == 0L ||
1808
 
                value == 1L)
1809
 
            {
1810
 
                replacePushInstruction(offset,
1811
 
                                       (byte)(InstructionConstants.OP_LCONST_0 + value),
1812
 
                                       0);
1813
 
            }
1814
 
        }
1815
 
    }
1816
 
 
1817
 
 
1818
 
    /**
1819
 
     * Replaces the given float instruction by a simpler push instruction,
1820
 
     * if possible.
1821
 
     */
1822
 
    private void replaceFloatPushInstruction(int offset, Instruction instruction)
1823
 
    {
1824
 
        Stack stack = stacks[offset];
1825
 
        Value pushedValue = stack.getTop(0);
1826
 
        if (pushedValue.isSpecific())
1827
 
        {
1828
 
            float value = pushedValue.floatValue().value();
1829
 
            if (value == 0f ||
1830
 
                value == 1f ||
1831
 
                value == 2f)
1832
 
            {
1833
 
                replacePushInstruction(offset,
1834
 
                                       (byte)(InstructionConstants.OP_FCONST_0 + value),
1835
 
                                       0);
1836
 
            }
1837
 
        }
1838
 
    }
1839
 
 
1840
 
 
1841
 
    /**
1842
 
     * Replaces the given double instruction by a simpler push instruction,
1843
 
     * if possible.
1844
 
     */
1845
 
    private void replaceDoublePushInstruction(int offset, Instruction instruction)
1846
 
    {
1847
 
        Stack stack = stacks[offset];
1848
 
        Value pushedValue = stack.getTop(0);
1849
 
        if (pushedValue.isSpecific())
1850
 
        {
1851
 
            double value = pushedValue.doubleValue().value();
1852
 
            if (value == 0.0 ||
1853
 
                value == 1.0)
1854
 
            {
1855
 
                replacePushInstruction(offset,
1856
 
                                       (byte)(InstructionConstants.OP_DCONST_0 + value),
1857
 
                                       0);
1858
 
            }
1859
 
        }
1860
 
    }
1861
 
 
1862
 
 
1863
 
    /**
1864
 
     * Replaces the given reference instruction by a simpler push instruction,
1865
 
     * if possible.
1866
 
     */
1867
 
    private void replaceReferencePushInstruction(int offset, Instruction instruction)
1868
 
    {
1869
 
        Stack stack = stacks[offset];
1870
 
        Value pushedValue = stack.getTop(0);
1871
 
        if (pushedValue.isSpecific())
1872
 
        {
1873
 
            ReferenceValue value = pushedValue.referenceValue();
1874
 
            if (value.isNull() == Value.ALWAYS)
1875
 
            {
1876
 
                replacePushInstruction(offset,
1877
 
                                       InstructionConstants.OP_ACONST_NULL,
1878
 
                                       0);
1879
 
            }
1880
 
        }
1881
 
    }
1882
 
 
1883
 
 
1884
 
    /**
1885
 
     * Replaces the instruction at a given offset by a given push instruction.
1886
 
     */
1887
 
    private void replacePushInstruction(int offset, byte opcode, int value)
1888
 
    {
1889
 
        // Remember the replacement instruction.
1890
 
        Instruction replacementInstruction =
1891
 
             new SimpleInstruction(opcode, value).shrink();
1892
 
 
1893
 
        if (DEBUG_ANALYSIS) System.out.println("  Replacing instruction at ["+offset+"] by "+replacementInstruction.toString());
1894
 
 
1895
 
        codeAttrInfoEditor.replaceInstruction(offset, replacementInstruction);
1896
 
    }
1897
 
 
1898
 
 
1899
 
    /**
1900
 
     * Deletes the given branch instruction, or replaces it by a simpler branch
1901
 
     * instruction, if possible.
1902
 
     */
1903
 
    private void replaceBranchInstruction(int offset, Instruction instruction)
1904
 
    {
1905
 
        if (isTraced(offset))
1906
 
        {
1907
 
            InstructionOffsetValue branchTargetValue = branchTargetValues[offset];
1908
 
 
1909
 
            // Is there exactly one branch target (not from a goto or jsr)?
1910
 
            if (branchTargetValue != null &&
1911
 
                branchTargetValue.instructionOffsetCount() == 1      &&
1912
 
                instruction.opcode != InstructionConstants.OP_GOTO   &&
1913
 
                instruction.opcode != InstructionConstants.OP_GOTO_W &&
1914
 
                instruction.opcode != InstructionConstants.OP_JSR    &&
1915
 
                instruction.opcode != InstructionConstants.OP_JSR_W)
1916
 
            {
1917
 
                // Is it branching to the next instruction?
1918
 
                int branchOffset = branchTargetValue.instructionOffset(0) - offset;
1919
 
                if (branchOffset == instruction.length(offset))
1920
 
                {
1921
 
                    if (DEBUG_ANALYSIS) System.out.println("  Deleting zero branch instruction at ["+offset+"]");
1922
 
 
1923
 
                    // Delete the branch instruction.
1924
 
                    codeAttrInfoEditor.deleteInstruction(offset);
1925
 
                }
1926
 
                else
1927
 
                {
1928
 
                    // Replace the branch instruction by a simple branch instrucion.
1929
 
                    Instruction replacementInstruction =
1930
 
                        new BranchInstruction(InstructionConstants.OP_GOTO_W,
1931
 
                                              branchOffset).shrink();
1932
 
 
1933
 
                    if (DEBUG_ANALYSIS) System.out.println("  Replacing branch instruction at ["+offset+"] by "+replacementInstruction.toString());
1934
 
 
1935
 
                    codeAttrInfoEditor.replaceInstruction2(offset,
1936
 
                                                           replacementInstruction);
1937
 
                }
1938
 
            }
1939
 
        }
1940
 
    }
1941
 
 
1942
 
 
1943
 
    // Implementations for CpInfoVisitor.
1944
 
 
1945
 
    public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
1946
 
    public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
1947
 
    public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
1948
 
    public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
1949
 
    public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
1950
 
    public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
1951
 
    public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
1952
 
    public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
1953
 
    public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
1954
 
    public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
1955
 
 
1956
 
 
1957
 
    public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
1958
 
    {
1959
 
        isInitializer = methodrefCpInfo.getName(classFile).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT);
1960
 
    }
1961
 
 
1962
 
 
1963
 
    // Small utility methods.
1964
 
 
1965
 
    /**
1966
 
     * Returns whether any of the instructions at the given offsets are marked as
1967
 
     * necessary.
1968
 
     */
1969
 
    private boolean isAnyNecessary(InstructionOffsetValue traceValue)
1970
 
    {
1971
 
        int traceCount = traceValue.instructionOffsetCount();
1972
 
        if (traceCount == 0)
1973
 
        {
1974
 
            return true;
1975
 
        }
1976
 
 
1977
 
        for (int traceIndex = 0; traceIndex < traceCount; traceIndex++)
1978
 
        {
1979
 
            if (isNecessary[traceValue.instructionOffset(traceIndex)])
1980
 
            {
1981
 
                return true;
1982
 
            }
1983
 
        }
1984
 
 
1985
 
        return false;
1986
 
    }
1987
 
 
1988
 
 
1989
 
    /**
1990
 
     * Returns whether all of the instructions at the given offsets are marked as
1991
 
     * necessary.
1992
 
     */
1993
 
    private boolean isAllNecessary(InstructionOffsetValue traceValue)
1994
 
    {
1995
 
        int traceCount = traceValue.instructionOffsetCount();
1996
 
        for (int traceIndex = 0; traceIndex < traceCount; traceIndex++)
1997
 
        {
1998
 
            if (!isNecessary[traceValue.instructionOffset(traceIndex)])
1999
 
            {
2000
 
                return false;
2001
 
            }
2002
 
        }
2003
 
 
2004
 
        return true;
2005
 
    }
2006
 
 
2007
 
 
2008
 
    /**
2009
 
     * Returns whether the instruction at the given offset has ever been
2010
 
     * executed during the partial evaluation.
2011
 
     */
2012
 
    private boolean isTraced(int instructionOffset)
2013
 
    {
2014
 
        return evaluationCounts[instructionOffset] > 0;
 
697
    // Small utility methods.
 
698
 
 
699
    /**
 
700
     * Initializes the data structures for the variables, stack, etc.
 
701
     */
 
702
    private void initializeVariables(CodeAttrInfo codeAttrInfo,
 
703
                                     Variables    parameters)
 
704
    {
 
705
        int codeLength = codeAttrInfo.u4codeLength;
 
706
 
 
707
        if (DEBUG)
 
708
        {
 
709
            System.out.println("  Max locals = "+codeAttrInfo.u2maxLocals);
 
710
            System.out.println("  Max stack  = "+codeAttrInfo.u2maxStack);
 
711
        }
 
712
 
 
713
        // Create new arrays for storing information at each instruction offset.
 
714
        if (vars.length < codeLength)
 
715
        {
 
716
            varProducerValues    = new InstructionOffsetValue[codeLength];
 
717
            stackProducerValues  = new InstructionOffsetValue[codeLength];
 
718
            unusedProducerValues = new InstructionOffsetValue[codeLength];
 
719
            branchOriginValues   = new InstructionOffsetValue[codeLength];
 
720
            branchTargetValues   = new InstructionOffsetValue[codeLength];
 
721
            vars                 = new TracedVariables[codeLength];
 
722
            stacks               = new TracedStack[codeLength];
 
723
            evaluationCounts     = new int[codeLength];
 
724
            initializedVariables = new int[codeLength];
 
725
 
 
726
            for (int index = 0; index < codeLength; index++)
 
727
            {
 
728
                initializedVariables[index] = NONE;
 
729
            }
 
730
        }
 
731
        else
 
732
        {
 
733
            for (int index = 0; index < codeLength; index++)
 
734
            {
 
735
                varProducerValues[index]    = null;
 
736
                stackProducerValues[index]  = null;
 
737
                unusedProducerValues[index] = null;
 
738
                branchOriginValues[index]   = null;
 
739
                branchTargetValues[index]   = null;
 
740
                evaluationCounts[index]     = 0;
 
741
                initializedVariables[index] = NONE;
 
742
 
 
743
                if (vars[index] != null)
 
744
                {
 
745
                    vars[index].reset(codeAttrInfo.u2maxLocals);
 
746
                }
 
747
 
 
748
                if (stacks[index] != null)
 
749
                {
 
750
                    stacks[index].reset(codeAttrInfo.u2maxStack);
 
751
                }
 
752
            }
 
753
        }
 
754
 
 
755
        // Reuse the existing variables and stack objects, ensuring the right size.
 
756
        variables.reset(codeAttrInfo.u2maxLocals);
 
757
        stack.reset(codeAttrInfo.u2maxStack);
 
758
 
 
759
        // Initialize the variables with the parameters.
 
760
        variables.initialize(parameters);
 
761
 
 
762
        // Set the store value of each parameter variable.
 
763
        InstructionOffsetValue atMethodEntry = InstructionOffsetValueFactory.create(PartialEvaluator.AT_METHOD_ENTRY);
 
764
 
 
765
        for (int index = 0; index < parameters.size(); index++)
 
766
        {
 
767
            variables.setStoredTraceValue(index, atMethodEntry);
 
768
        }
 
769
 
 
770
        // Reset the return value.
 
771
        branchUnit.setTraceReturnValue(null);
 
772
    }
 
773
 
 
774
 
 
775
    /**
 
776
     * Generalize the local variable frames of a block of instructions.
 
777
     */
 
778
    private void generalizeVariables(int startOffset, int endOffset, TracedVariables generalizedVariables)
 
779
    {
 
780
        for (int index = startOffset; index < endOffset; index++)
 
781
        {
 
782
            if (isTraced(index))
 
783
            {
 
784
                // We can't use the return value, because local generalization
 
785
                // can be different a couple of times, with the global
 
786
                // generalization being the same.
 
787
                generalizedVariables.generalize(vars[index]);
 
788
            }
 
789
        }
2015
790
    }
2016
791
}