94
94
private final PartialEvaluator partialEvaluator;
95
95
private final PartialEvaluator simplePartialEvaluator = new PartialEvaluator();
96
private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true);
96
private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true, true);
97
97
private final MyUnusedParameterSimplifier unusedParameterSimplifier = new MyUnusedParameterSimplifier();
98
98
private final MyProducerMarker producerMarker = new MyProducerMarker();
99
99
private final MyVariableInitializationMarker variableInitializationMarker = new MyVariableInitializationMarker();
100
100
private final MyStackConsistencyFixer stackConsistencyFixer = new MyStackConsistencyFixer();
101
private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false);
101
private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false, false);
103
private boolean[][] variablesNecessaryAfter = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_VARIABLES_SIZE];
104
private boolean[][] stacksNecessaryAfter = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
105
private boolean[][] stacksSimplifiedBefore = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
106
private boolean[] instructionsNecessary = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
103
private boolean[][] stacksNecessaryAfter = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
104
private boolean[][] stacksSimplifiedBefore = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
105
private boolean[] instructionsNecessary = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
108
107
private int maxMarkedOffset;
703
697
public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
705
if (!variableInstruction.isLoad())
699
// Is the variable being loaded or incremented?
700
if (variableInstruction.isLoad())
707
int variableIndex = variableInstruction.variableIndex;
709
if (isVariableInitialization(offset,
711
isVariableInitializationNecessary(clazz,
717
markInstruction(offset);
702
// Mark any variable initializations for this variable load that
703
// are required according to the JVM.
704
markVariableInitializersBefore(offset, variableInstruction.variableIndex);
750
738
int stackSize = tracedStack.size();
740
int requiredPopCount = 0;
752
741
int requiredPushCount = 0;
753
742
for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++)
755
if (!isStackSimplifiedBefore(offset, stackIndex))
744
boolean stackSimplifiedBefore =
745
isStackSimplifiedBefore(offset, stackIndex);
746
boolean stackEntryPresentBefore =
747
isStackEntryPresentBefore(offset, stackIndex);
749
if (stackSimplifiedBefore)
751
// Is this stack entry pushed by any producer
752
// (maybe an exception in an exception handler)?
753
if (isStackEntryPresentBefore(offset, stackIndex))
755
// Mark all produced stack entries.
756
markStackEntryProducers(offset, stackIndex);
758
// Remember to pop it.
757
764
// Is this stack entry pushed by any producer
758
765
// (because it is required by other consumers)?
759
if (isStackEntryPresentBefore(offset, stackIndex))
766
if (stackEntryPresentBefore)
761
768
// Mark all produced stack entries.
762
769
markStackEntryProducers(offset, stackIndex);
1417
1432
// Small utility methods.
1420
* Marks the variable and the corresponding producing instructions
1421
* of the consumer at the given offset.
1422
* @param consumerOffset the offset of the consumer.
1423
* @param variableIndex the index of the variable to be marked.
1435
* Marks the producing instructions of the variable consumer at the given
1437
* @param consumerOffset the offset of the variable consumer.
1438
* @param variableIndex the index of the variable that is loaded.
1425
1440
private void markVariableProducers(int consumerOffset,
1426
1441
int variableIndex)
1428
TracedVariables tracedVariables =
1429
partialEvaluator.getVariablesBefore(consumerOffset);
1431
// Mark the producer of the loaded value.
1432
markVariableProducers(tracedVariables.getProducerValue(variableIndex).instructionOffsetValue(),
1438
* Marks the variable and its producing instructions at the given offsets.
1439
* @param producerOffsets the offsets of the producers to be marked.
1440
* @param variableIndex the index of the variable to be marked.
1442
private void markVariableProducers(InstructionOffsetValue producerOffsets,
1443
InstructionOffsetValue producerOffsets =
1444
partialEvaluator.getVariablesBefore(consumerOffset).getProducerValue(variableIndex).instructionOffsetValue();
1445
1446
if (producerOffsets != null)
1447
1448
int offsetCount = producerOffsets.instructionOffsetCount();
1462
* Ensures that the given variable is initialized before the specified
1463
* consumer of that variable, in the JVM's view.
1464
* @param consumerOffset the instruction offset before which the variable
1465
* needs to be initialized.
1466
* @param variableIndex the index of the variable.
1468
private void markVariableInitializersBefore(int consumerOffset,
1471
// Make sure the variable is initialized after all producers.
1472
// Use the simple evaluator, to get the JVM's view of what is
1474
InstructionOffsetValue producerOffsets =
1475
simplePartialEvaluator.getVariablesBefore(consumerOffset).getProducerValue(variableIndex).instructionOffsetValue();
1477
int offsetCount = producerOffsets.instructionOffsetCount();
1478
for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++)
1480
// Avoid infinite loops by only looking at producers before
1482
int producerOffset =
1483
producerOffsets.instructionOffset(offsetIndex);
1484
if (producerOffset < consumerOffset)
1486
markVariableInitializersAfter(producerOffset, variableIndex);
1493
* Ensures that the given variable is initialized after the specified
1494
* producer of that variable, in the JVM's view.
1495
* @param producerOffset the instruction offset after which the variable
1496
* needs to be initialized.
1497
* @param variableIndex the index of the variable.
1499
private void markVariableInitializersAfter(int producerOffset,
1502
// No problem if the producer has already been marked.
1503
if (!isInstructionNecessary(producerOffset))
1505
// Is the unmarked producer a variable initialization?
1506
if (isVariableInitialization(producerOffset, variableIndex))
1508
// Mark the producer.
1509
if (DEBUG) System.out.print(" Marking initialization of v"+variableIndex+" at ");
1511
markInstruction(producerOffset);
1513
if (DEBUG) System.out.println();
1517
// Don't mark the producer, but recursively look at the
1518
// preceding producers of the same variable. Their values
1519
// will fall through, replacing this producer.
1520
markVariableInitializersBefore(producerOffset, variableIndex);
1462
1527
* Marks the stack entries and their producing instructions of the
1463
1528
* consumer at the given offset.
1464
1529
* @param clazz the containing class.
1647
1713
if (DEBUG) System.out.println(": "+replacementInstruction.toString(offset));
1649
1715
// Replace or insert the push instruction.
1652
// Replace the push instruction.
1653
codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
1657
// Insert the push instruction.
1658
codeAttributeEditor.insertBeforeInstruction(offset, replacementInstruction);
1660
if (extraAddedInstructionVisitor != null)
1662
replacementInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor);
1716
insertInstruction(offset, replace, before, replacementInstruction);
1761
1792
popInstructions[popCount / 2] = popInstruction;
1766
codeAttributeEditor.replaceInstruction(offset, popInstructions);
1768
for (int index = 1; index < popInstructions.length; index++)
1770
if (extraAddedInstructionVisitor != null)
1772
popInstructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor);
1778
codeAttributeEditor.insertAfterInstruction(offset, popInstructions);
1780
for (int index = 0; index < popInstructions.length; index++)
1782
if (extraAddedInstructionVisitor != null)
1784
popInstructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor);
1795
insertInstructions(offset,
1807
* Inserts or replaces the given instruction at the given offset.
1809
private void insertInstruction(int offset,
1812
Instruction instruction)
1816
codeAttributeEditor.replaceInstruction(offset, instruction);
1822
codeAttributeEditor.insertBeforeInstruction(offset, instruction);
1826
codeAttributeEditor.insertAfterInstruction(offset, instruction);
1829
if (extraAddedInstructionVisitor != null)
1831
instruction.accept(null, null, null, offset, extraAddedInstructionVisitor);
1838
* Inserts or replaces the given instruction at the given offset.
1840
private void insertInstructions(int offset,
1843
Instruction instruction,
1844
Instruction[] instructions)
1848
codeAttributeEditor.replaceInstruction(offset, instructions);
1850
if (extraAddedInstructionVisitor != null)
1852
for (int index = 1; index < instructions.length; index++)
1854
instructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor);
1862
codeAttributeEditor.insertBeforeInstruction(offset, instructions);
1866
codeAttributeEditor.insertAfterInstruction(offset, instructions);
1869
for (int index = 0; index < instructions.length; index++)
1871
if (extraAddedInstructionVisitor != null)
1873
instructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor);
1795
1881
* Replaces the instruction at a given offset by a static invocation.
1797
1883
private void replaceByStaticInvocation(Clazz clazz,
2025
* Returns whether the specified variable must be initialized at the
2026
* specified offset, according to the verifier of the JVM.
2028
private boolean isVariableInitializationNecessary(Clazz clazz,
2030
CodeAttribute codeAttribute,
2031
int initializationOffset,
2034
int codeLength = codeAttribute.u4codeLength;
2036
// Is the variable necessary anywhere at all?
2037
if (isVariableNecessaryAfterAny(0, codeLength, variableIndex))
2039
if (DEBUG) System.out.println("Simple partial evaluation for initialization of variable v"+variableIndex+" at ["+initializationOffset+"]");
2041
// Lazily perform simple partial evaluation, the way the JVM
2042
// verifier would do it.
2043
simplePartialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
2045
if (DEBUG) System.out.println("End of simple partial evaluation for initialization of variable v"+variableIndex+" at ["+initializationOffset+"]");
2047
// Check if the variable is necessary elsewhere.
2048
for (int offset = 0; offset < codeLength; offset++)
2050
if (partialEvaluator.isTraced(offset))
2052
Value producer = partialEvaluator.getVariablesBefore(offset).getProducerValue(variableIndex);
2053
if (producer != null)
2055
Value simpleProducer = simplePartialEvaluator.getVariablesBefore(offset).getProducerValue(variableIndex);
2056
if (simpleProducer != null)
2058
InstructionOffsetValue producerOffsets =
2059
producer.instructionOffsetValue();
2060
InstructionOffsetValue simpleProducerOffsets =
2061
simpleProducer.instructionOffsetValue();
2065
System.out.println(" ["+offset+"] producers ["+producerOffsets+"], simple producers ["+simpleProducerOffsets+"]");
2068
// Is the variable being used without all of its
2069
// immediate simple producers being marked?
2070
if (isVariableNecessaryAfterAny(producerOffsets, variableIndex) &&
2071
!isVariableNecessaryAfterAll(simpleProducerOffsets, variableIndex))
2075
System.out.println(" => initialization of variable v"+variableIndex+" at ["+initializationOffset+"] necessary");
2078
// Then the initialization may be necessary.
2089
System.out.println(" => initialization of variable v"+variableIndex+" at ["+initializationOffset+"] not necessary");
2096
private void markVariableAfter(int instructionOffset,
2099
if (!isVariableNecessaryAfter(instructionOffset, variableIndex))
2101
if (DEBUG) System.out.print("["+instructionOffset+".v"+variableIndex+"],");
2103
variablesNecessaryAfter[instructionOffset][variableIndex] = true;
2105
if (maxMarkedOffset < instructionOffset)
2107
maxMarkedOffset = instructionOffset;
2114
* Returns whether the specified variable is ever necessary after any
2115
* instructions in the specified block.
2117
private boolean isVariableNecessaryAfterAny(int startOffset,
2121
for (int offset = startOffset; offset < endOffset; offset++)
2123
if (isVariableNecessaryAfter(offset, variableIndex))
2134
* Returns whether the specified variable is ever necessary after any
2135
* instructions in the specified set of instructions offsets.
2137
private boolean isVariableNecessaryAfterAny(InstructionOffsetValue instructionOffsetValue,
2140
int count = instructionOffsetValue.instructionOffsetCount();
2142
for (int index = 0; index < count; index++)
2144
if (isVariableNecessaryAfter(instructionOffsetValue.instructionOffset(index),
2156
* Returns whether the specified variable is ever necessary after all
2157
* instructions in the specified set of instructions offsets.
2159
private boolean isVariableNecessaryAfterAll(InstructionOffsetValue instructionOffsetValue,
2162
int count = instructionOffsetValue.instructionOffsetCount();
2164
for (int index = 0; index < count; index++)
2166
if (!isVariableNecessaryAfter(instructionOffsetValue.instructionOffset(index),
2177
private boolean isVariableNecessaryAfter(int instructionOffset,
2180
return instructionOffset == PartialEvaluator.AT_METHOD_ENTRY ||
2181
variablesNecessaryAfter[instructionOffset][variableIndex];
2186
2106
* Marks the stack entry after the given offset.
2187
2107
* @param instructionOffset the offset of the stack entry to be marked.
2188
2108
* @param stackIndex the index of the stack entry to be marked