diff options
Diffstat (limited to 'src/proguard/optimize/evaluation/EvaluationShrinker.java')
-rw-r--r-- | src/proguard/optimize/evaluation/EvaluationShrinker.java | 290 |
1 files changed, 60 insertions, 230 deletions
diff --git a/src/proguard/optimize/evaluation/EvaluationShrinker.java b/src/proguard/optimize/evaluation/EvaluationShrinker.java index bc5f658..1463feb 100644 --- a/src/proguard/optimize/evaluation/EvaluationShrinker.java +++ b/src/proguard/optimize/evaluation/EvaluationShrinker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2011 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -34,8 +34,6 @@ import proguard.evaluation.*; import proguard.evaluation.value.*; import proguard.optimize.info.*; -import java.util.Arrays; - /** * This AttributeVisitor simplifies the code attributes that it visits, based * on partial evaluation. @@ -57,14 +55,13 @@ implements AttributeVisitor private final InstructionVisitor extraDeletedInstructionVisitor; private final InstructionVisitor extraAddedInstructionVisitor; - private final PartialEvaluator partialEvaluator; - private final PartialEvaluator simplePartialEvaluator = new PartialEvaluator(); - private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true); - private final MyUnusedParameterSimplifier unusedParameterSimplifier = new MyUnusedParameterSimplifier(); - private final MyProducerMarker producerMarker = new MyProducerMarker(); - private final MyVariableInitializationMarker variableInitializationMarker = new MyVariableInitializationMarker(); - private final MyStackConsistencyFixer stackConsistencyFixer = new MyStackConsistencyFixer(); - private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false); + private final PartialEvaluator partialEvaluator; + private final PartialEvaluator simplePartialEvaluator = new PartialEvaluator(); + private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true); + private final MyUnusedParameterSimplifier unusedParameterSimplifier = new MyUnusedParameterSimplifier(); + private final MyProducerMarker producerMarker = new MyProducerMarker(); + private final MyStackConsistencyFixer stackConsistencyFixer = new MyStackConsistencyFixer(); + private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false); private boolean[][] variablesNecessaryAfter = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_VARIABLES_SIZE]; private boolean[][] stacksNecessaryAfter = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE]; @@ -279,10 +276,18 @@ implements AttributeVisitor if (partialEvaluator.isTraced(offset) && !isInstructionNecessary(offset)) { - Instruction instruction = InstructionFactory.create(codeAttribute.code, - offset); - - instruction.accept(clazz, method, codeAttribute, offset, variableInitializationMarker); + // Is the corresponding variable necessary anywhere in the code, + // accoriding to a simple partial evaluation? + int variableIndex = partialEvaluator.initializedVariable(offset); + if (variableIndex >= 0 && + isVariableInitializationNecessary(clazz, + method, + codeAttribute, + offset, + variableIndex)) + { + markInstruction(offset); + } } } if (DEBUG) System.out.println(); @@ -462,9 +467,7 @@ implements AttributeVisitor */ private class MyUnusedParameterSimplifier extends SimplifiedVisitor - implements InstructionVisitor, - ConstantVisitor, - MemberVisitor + implements InstructionVisitor, ConstantVisitor, MemberVisitor { private int invocationOffset; private ConstantInstruction invocationInstruction; @@ -654,40 +657,6 @@ implements AttributeVisitor /** - * This InstructionVisitor marks variable initializations that are - * necessary to appease the JVM. - */ - private class MyVariableInitializationMarker - extends SimplifiedVisitor - implements InstructionVisitor - { - // Implementations for InstructionVisitor. - - public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} - - - public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) - { - if (!variableInstruction.isLoad()) - { - int variableIndex = variableInstruction.variableIndex; - - if (isVariableInitialization(offset, - variableIndex) && - isVariableInitializationNecessary(clazz, - method, - codeAttribute, - offset, - variableIndex)) - { - markInstruction(offset); - } - } - } - } - - - /** * This InstructionVisitor fixes instructions locally, popping any unused * produced stack entries after marked instructions, and popping produced * stack entries and pushing missing stack entries instead of unmarked @@ -718,23 +687,12 @@ implements AttributeVisitor int requiredPushCount = 0; for (int stackIndex = 0; stackIndex < popCount; stackIndex++) { - InstructionOffsetValue producerOffsets = - tracedStack.getTopProducerValue(stackIndex).instructionOffsetValue(); - - if (!isStackSimplifiedBefore(offset, top - stackIndex)) + // Is the stack entry required by other consumers? + if (!isStackSimplifiedBefore(offset, top - stackIndex) && + !isAnyStackEntryNecessaryAfter(tracedStack.getTopProducerValue(stackIndex).instructionOffsetValue(), top - stackIndex)) { - // Is the stack entry pushed by any producer, - // because it is required by other consumers? - if (isAnyStackEntryNecessaryAfter(producerOffsets, top - stackIndex)) - { - // Make sure it is pushed after all producers. - markStackEntriesAfter(producerOffsets, top - stackIndex); - } - else - { - // Remember to push it. - requiredPushCount++; - } + // Remember to push it. + requiredPushCount++; } } @@ -799,16 +757,9 @@ implements AttributeVisitor int expectedPopCount = 0; for (int stackIndex = 0; stackIndex < popCount; stackIndex++) { - InstructionOffsetValue producerOffsets = - tracedStack.getTopProducerValue(stackIndex).instructionOffsetValue(); - - // Is the stack entry pushed by any producer, - // because it is required by other consumers? - if (isAnyStackEntryNecessaryAfter(producerOffsets, top - stackIndex)) + // Is the stack entry required by other consumers? + if (isAnyStackEntryNecessaryAfter(tracedStack.getTopProducerValue(stackIndex).instructionOffsetValue(), top - stackIndex)) { - // Make sure it is pushed after all producers. - markStackEntriesAfter(producerOffsets, top - stackIndex); - // Remember to pop it. expectedPopCount++; } @@ -1101,7 +1052,6 @@ implements AttributeVisitor byte oldOpcode = instruction.opcode; byte newOpcode = 0; - byte addOpcode = 0; // Simplify the popping instruction if possible. switch (oldOpcode) @@ -1282,20 +1232,9 @@ implements AttributeVisitor stackEntryPresent1) { // Will both elements be present? - if (!stackEntryPresent1) - { - // Pop the original top element (later bottom element). - newOpcode = InstructionConstants.OP_POP; - } - else if (!stackEntryPresent0) - { - // Swap both elements and pop the top one. - newOpcode = InstructionConstants.OP_SWAP; - addOpcode = InstructionConstants.OP_POP; - } - else + if (stackEntryPresent0 && + stackEntryPresent1) { - // Just swap both elements. newOpcode = InstructionConstants.OP_SWAP; } } @@ -1303,7 +1242,6 @@ implements AttributeVisitor } } - // Is there a replacement opcode? if (newOpcode == 0) { // Delete the instruction. @@ -1332,21 +1270,6 @@ implements AttributeVisitor if (DEBUG) System.out.println(" Replacing instruction "+instruction.toString(dupOffset)+" by "+replacementInstruction.toString()); } - - // Is there an additional opcode? - if (addOpcode != 0) - { - // Add the instruction. - Instruction additionalInstruction = new SimpleInstruction(addOpcode); - codeAttributeEditor.insertAfterInstruction(dupOffset, additionalInstruction); - - if (extraAddedInstructionVisitor != null) - { - extraAddedInstructionVisitor.visitSimpleInstruction(null, null, null, dupOffset, null); - } - - if (DEBUG) System.out.println(" Adding instruction "+additionalInstruction.toString(dupOffset)); - } } @@ -1673,7 +1596,10 @@ implements AttributeVisitor { for (int offset = 0; offset < codeLength; offset++) { - Arrays.fill(variablesNecessaryAfter[offset], 0, maxLocals, false); + for (int index = 0; index < maxLocals; index++) + { + variablesNecessaryAfter[offset][index] = false; + } } } @@ -1686,7 +1612,10 @@ implements AttributeVisitor { for (int offset = 0; offset < codeLength; offset++) { - Arrays.fill(stacksNecessaryAfter[offset], 0, maxStack, false); + for (int index = 0; index < maxStack; index++) + { + stacksNecessaryAfter[offset][index] = false; + } } } @@ -1699,7 +1628,10 @@ implements AttributeVisitor { for (int offset = 0; offset < codeLength; offset++) { - Arrays.fill(stacksSimplifiedBefore[offset], 0, maxStack, false); + for (int index = 0; index < maxStack; index++) + { + stacksSimplifiedBefore[offset][index] = false; + } } } @@ -1709,7 +1641,10 @@ implements AttributeVisitor } else { - Arrays.fill(instructionsNecessary, 0, codeLength, false); + for (int index = 0; index < codeLength; index++) + { + instructionsNecessary[index] = false; + } } } @@ -1735,34 +1670,6 @@ implements AttributeVisitor /** - * Returns whether the specified variable is initialized at the specified - * offset. - */ - private boolean isVariableInitialization(int instructionOffset, - int variableIndex) - { - // Wasn't the variable set yet? - Value valueBefore = partialEvaluator.getVariablesBefore(instructionOffset).getValue(variableIndex); - if (valueBefore == null) - { - return true; - } - - // Is the computational type different now? - Value valueAfter = partialEvaluator.getVariablesAfter(instructionOffset).getValue(variableIndex); - if (valueAfter.computationalType() != valueBefore.computationalType()) - { - return true; - } - - // Was the producer an argument (which may be removed)? - Value producersBefore = partialEvaluator.getVariablesBefore(instructionOffset).getProducerValue(variableIndex); - return producersBefore.instructionOffsetValue().instructionOffsetCount() == 1 && - producersBefore.instructionOffsetValue().instructionOffset(0) == PartialEvaluator.AT_METHOD_ENTRY; - } - - - /** * Returns whether the specified variable must be initialized at the * specified offset, according to the verifier of the JVM. */ @@ -1779,8 +1686,8 @@ implements AttributeVisitor { if (DEBUG) System.out.println("Simple partial evaluation for initialization of variable v"+variableIndex+" at ["+initializationOffset+"]"); - // Lazily perform simple partial evaluation, the way the JVM - // verifier would do it. + // Lazily compute perform simple partial evaluation, the way the + // JVM preverifier would do it. simplePartialEvaluator.visitCodeAttribute(clazz, method, codeAttribute); if (DEBUG) System.out.println("End of simple partial evaluation for initialization of variable v"+variableIndex+" at ["+initializationOffset+"]"); @@ -1788,7 +1695,7 @@ implements AttributeVisitor // Check if the variable is necessary elsewhere. for (int offset = 0; offset < codeLength; offset++) { - if (partialEvaluator.isTraced(offset)) + if (isInstructionNecessary(offset)) { Value producer = partialEvaluator.getVariablesBefore(offset).getProducerValue(variableIndex); if (producer != null) @@ -1801,22 +1708,16 @@ implements AttributeVisitor InstructionOffsetValue simpleProducerOffsets = simpleProducer.instructionOffsetValue(); - if (DEBUG) + // Does the sophisticated partial evaluation have fewer + // producers than the simple one? + // And does the simple partial evaluation point to an + // initialization of the variable? + if (producerOffsets.instructionOffsetCount() < + simpleProducerOffsets.instructionOffsetCount() && + isVariableNecessaryAfterAny(producerOffsets, variableIndex) && + simpleProducerOffsets.contains(initializationOffset)) { - System.out.println(" ["+offset+"] producers ["+producerOffsets+"], simple producers ["+simpleProducerOffsets+"]"); - } - - // Is the variable being used without all of its - // immediate simple producers being marked? - if (isVariableNecessaryAfterAny(producerOffsets, variableIndex) && - !isVariableNecessaryAfterAll(simpleProducerOffsets, variableIndex)) - { - if (DEBUG) - { - System.out.println(" => initialization of variable v"+variableIndex+" at ["+initializationOffset+"] necessary"); - } - - // Then the initialization may be necessary. + // Then the initialization is necessary. return true; } } @@ -1825,11 +1726,6 @@ implements AttributeVisitor } } - if (DEBUG) - { - System.out.println(" => initialization of variable v"+variableIndex+" at ["+initializationOffset+"] not necessary"); - } - return false; } @@ -1853,7 +1749,7 @@ implements AttributeVisitor /** * Returns whether the specified variable is ever necessary after any - * instructions in the specified block. + * instruction in the specified block. */ private boolean isVariableNecessaryAfterAny(int startOffset, int endOffset, @@ -1873,7 +1769,7 @@ implements AttributeVisitor /** * Returns whether the specified variable is ever necessary after any - * instructions in the specified set of instructions offsets. + * instruction in the specified set of instructions offsets. */ private boolean isVariableNecessaryAfterAny(InstructionOffsetValue instructionOffsetValue, int variableIndex) @@ -1893,28 +1789,6 @@ implements AttributeVisitor } - /** - * Returns whether the specified variable is ever necessary after all - * instructions in the specified set of instructions offsets. - */ - private boolean isVariableNecessaryAfterAll(InstructionOffsetValue instructionOffsetValue, - int variableIndex) - { - int count = instructionOffsetValue.instructionOffsetCount(); - - for (int index = 0; index < count; index++) - { - if (!isVariableNecessaryAfter(instructionOffsetValue.instructionOffset(index), - variableIndex)) - { - return false; - } - } - - return true; - } - - private boolean isVariableNecessaryAfter(int instructionOffset, int variableIndex) { @@ -1923,36 +1797,6 @@ implements AttributeVisitor } - /** - * Marks the stack entries after the given offsets. - * @param instructionOffsets the offsets of the stack entries to be marked. - * @param stackIndex the index of the stack entries to be marked - * (counting from the bottom). - */ - private void markStackEntriesAfter(InstructionOffsetValue instructionOffsets, - int stackIndex) - { - if (instructionOffsets != null) - { - int offsetCount = instructionOffsets.instructionOffsetCount(); - for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++) - { - // Make sure the stack entry and the instruction are marked - // at the producing offset. - int offset = instructionOffsets.instructionOffset(offsetIndex); - - markStackEntryAfter(offset, stackIndex); - } - } - } - - - /** - * Marks the stack entry after the given offset. - * @param instructionOffset the offset of the stack entry to be marked. - * @param stackIndex the index of the stack entry to be marked - * (counting from the bottom). - */ private void markStackEntryAfter(int instructionOffset, int stackIndex) { @@ -1970,13 +1814,6 @@ implements AttributeVisitor } - /** - * Returns whether any of the stack entries after the given offsets are - * necessary. - * @param instructionOffsets the offsets of the stack entries to be checked. - * @param stackIndex the index of the stack entries to be checked - * (counting from the bottom). - */ private boolean isAnyStackEntryNecessaryAfter(InstructionOffsetValue instructionOffsets, int stackIndex) { @@ -1994,13 +1831,6 @@ implements AttributeVisitor } - /** - * Returns whether any of the stack entries after the given offset are - * necessary. - * @param instructionOffset the offset of the stack entry to be checked. - * @param stackIndex the index of the stack entry to be checked - * (counting from the bottom). - */ private boolean isStackEntryNecessaryAfter(int instructionOffset, int stackIndex) { |