diff options
Diffstat (limited to 'src/proguard/optimize/evaluation')
8 files changed, 159 insertions, 450 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) { diff --git a/src/proguard/optimize/evaluation/EvaluationSimplifier.java b/src/proguard/optimize/evaluation/EvaluationSimplifier.java index b207108..0c3a9c7 100644 --- a/src/proguard/optimize/evaluation/EvaluationSimplifier.java +++ b/src/proguard/optimize/evaluation/EvaluationSimplifier.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 @@ -43,9 +43,6 @@ extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor { - private static int POS_ZERO_FLOAT_BITS = Float.floatToIntBits(0.0f); - private static long POS_ZERO_DOUBLE_BITS = Double.doubleToLongBits(0.0); - //* private static final boolean DEBUG = false; /*/ @@ -562,11 +559,10 @@ implements AttributeVisitor, Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0); if (pushedValue.isParticular()) { - // Make sure to distinguish between +0.0 and -0.0. float value = pushedValue.floatValue().value(); - if (value == 0.0f && Float.floatToIntBits(value) == POS_ZERO_FLOAT_BITS || - value == 1.0f || - value == 2.0f) + if (value == 0f || + value == 1f || + value == 2f) { replaceConstantPushInstruction(clazz, offset, @@ -631,9 +627,8 @@ implements AttributeVisitor, Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0); if (pushedValue.isParticular()) { - // Make sure to distinguish between +0.0 and -0.0. double value = pushedValue.doubleValue().value(); - if (value == 0.0 && Double.doubleToLongBits(value) == POS_ZERO_DOUBLE_BITS || + if (value == 0.0 || value == 1.0) { replaceConstantPushInstruction(clazz, diff --git a/src/proguard/optimize/evaluation/LivenessAnalyzer.java b/src/proguard/optimize/evaluation/LivenessAnalyzer.java index 747f993..9915027 100644 --- a/src/proguard/optimize/evaluation/LivenessAnalyzer.java +++ b/src/proguard/optimize/evaluation/LivenessAnalyzer.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 @@ -79,16 +79,6 @@ implements AttributeVisitor, /** - * Returns whether the instruction at the given offset has ever been - * executed during the partial evaluation. - */ - public boolean isTraced(int instructionOffset) - { - return partialEvaluator.isTraced(instructionOffset); - } - - - /** * Returns whether the specified variable is alive before the instruction * at the given offset. */ diff --git a/src/proguard/optimize/evaluation/LoadingInvocationUnit.java b/src/proguard/optimize/evaluation/LoadingInvocationUnit.java index 578ece5..8379c57 100644 --- a/src/proguard/optimize/evaluation/LoadingInvocationUnit.java +++ b/src/proguard/optimize/evaluation/LoadingInvocationUnit.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 @@ -35,9 +35,9 @@ import proguard.evaluation.value.*; public class LoadingInvocationUnit extends BasicInvocationUnit { - private final boolean loadFieldValues; - private final boolean loadMethodParameterValues; - private final boolean loadMethodReturnValues; + private boolean loadFieldValues; + private boolean loadMethodParameterValues; + private boolean loadMethodReturnValues; /** @@ -84,6 +84,8 @@ extends BasicInvocationUnit value.isParticular()) { return value; +// // Make sure the value is refreshed. +// return refresh(value); } } } @@ -108,6 +110,8 @@ extends BasicInvocationUnit value.isParticular()) { return value; +// // Make sure the value is refreshed. +// return refresh(value); } } } @@ -130,6 +134,8 @@ extends BasicInvocationUnit value.isParticular()) { return value; +// // Make sure the value is refreshed. +// return refresh(value); } } @@ -157,6 +163,8 @@ extends BasicInvocationUnit value.isParticular()) { return value; +// // Make sure the value is refreshed. +// return refresh(value); } } } @@ -165,8 +173,8 @@ extends BasicInvocationUnit refConstant, type); } - - +// +// // // Small utility methods. // // private Value refresh(Value value) diff --git a/src/proguard/optimize/evaluation/PartialEvaluator.java b/src/proguard/optimize/evaluation/PartialEvaluator.java index b2776d1..5790a36 100644 --- a/src/proguard/optimize/evaluation/PartialEvaluator.java +++ b/src/proguard/optimize/evaluation/PartialEvaluator.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 @@ -31,8 +31,6 @@ import proguard.evaluation.*; import proguard.evaluation.value.*; import proguard.optimize.peephole.BranchTargetFinder; -import java.util.Arrays; - /** * This AttributeVisitor performs partial evaluation on the code attributes * that it visits. @@ -70,6 +68,7 @@ implements AttributeVisitor, private TracedStack[] stacksAfter = new TracedStack[ClassConstants.TYPICAL_CODE_LENGTH]; private boolean[] generalizedContexts = new boolean[ClassConstants.TYPICAL_CODE_LENGTH]; private int[] evaluationCounts = new int[ClassConstants.TYPICAL_CODE_LENGTH]; + private int[] initializedVariables = new int[ClassConstants.TYPICAL_CODE_LENGTH]; private boolean evaluateExceptions; private final BasicBranchUnit branchUnit; @@ -190,47 +189,6 @@ implements AttributeVisitor, if (DEBUG) { method.accept(clazz, new ClassPrinter()); - - System.out.println("Evaluation results:"); - - int offset = 0; - do - { - if (isBranchOrExceptionTarget(offset)) - { - System.out.println("Branch target from ["+branchOriginValues[offset]+"]:"); - if (isTraced(offset)) - { - System.out.println(" Vars: "+variablesBefore[offset]); - System.out.println(" Stack: "+stacksBefore[offset]); - } - } - - Instruction instruction = InstructionFactory.create(codeAttribute.code, - offset); - System.out.println(instruction.toString(offset)); - - if (isTraced(offset)) - { - int initializationOffset = branchTargetFinder.initializationOffset(offset); - if (initializationOffset != NONE) - { - System.out.println(" is to be initialized at ["+initializationOffset+"]"); - } - - InstructionOffsetValue branchTargets = branchTargets(offset); - if (branchTargets != null) - { - System.out.println(" has overall been branching to "+branchTargets); - } - - System.out.println(" Vars: "+variablesAfter[offset]); - System.out.println(" Stack: "+stacksAfter[offset]); - } - - offset += instruction.length(offset); - } - while (offset < codeAttribute.u4codeLength); } throw ex; @@ -254,8 +212,7 @@ implements AttributeVisitor, TracedStack stack = new TracedStack(codeAttribute.u2maxStack); // Initialize the reusable arrays and variables. - initializeArrays(codeAttribute); - initializeParameters(clazz, method, codeAttribute, variables); + initializeVariables(clazz, method, codeAttribute, variables, stack); // Find all instruction offsets,... codeAttribute.accept(clazz, method, branchTargetFinder); @@ -292,6 +249,12 @@ implements AttributeVisitor, if (isTraced(offset)) { + int variableIndex = initializedVariable(offset); + if (variableIndex >= 0) + { + System.out.println(" is initializing variable v"+variableIndex); + } + int initializationOffset = branchTargetFinder.initializationOffset(offset); if (initializationOffset != NONE) { @@ -516,6 +479,16 @@ implements AttributeVisitor, } + /** + * Returns the variable that is initialized at the given instruction offset, + * or <code>NONE</code> if no variable was initialized. + */ + public int initializedVariable(int instructionOffset) + { + return initializedVariables[instructionOffset]; + } + + // Utility methods to evaluate instruction blocks. /** @@ -729,6 +702,9 @@ implements AttributeVisitor, // Reset the trace value. InstructionOffsetValue traceValue = InstructionOffsetValue.EMPTY_VALUE; + // Reset the initialization flag. + variables.resetInitialization(); + // Note that the instruction is only volatile. Instruction instruction = InstructionFactory.create(code, instructionOffset); @@ -767,6 +743,9 @@ implements AttributeVisitor, throw ex; } + // Collect the offsets of the instructions whose results were used. + initializedVariables[instructionOffset] = variables.getInitializationIndex(); + // Collect the branch targets from the branch unit. InstructionOffsetValue branchTargets = branchUnit.getTraceBranchTargets(); int branchTargetCount = branchTargets.instructionOffsetCount(); @@ -917,7 +896,11 @@ implements AttributeVisitor, subroutinePartialEvaluator = new PartialEvaluator(this); - subroutinePartialEvaluator.initializeArrays(codeAttribute); + subroutinePartialEvaluator.initializeVariables(clazz, + method, + codeAttribute, + variables, + stack); } // Evaluate the subroutine. @@ -969,12 +952,13 @@ implements AttributeVisitor, if (evaluationCounts[offset] == 0) { - variablesBefore[offset] = other.variablesBefore[offset]; - stacksBefore[offset] = other.stacksBefore[offset]; - variablesAfter[offset] = other.variablesAfter[offset]; - stacksAfter[offset] = other.stacksAfter[offset]; - generalizedContexts[offset] = other.generalizedContexts[offset]; - evaluationCounts[offset] = other.evaluationCounts[offset]; + variablesBefore[offset] = other.variablesBefore[offset]; + stacksBefore[offset] = other.stacksBefore[offset]; + variablesAfter[offset] = other.variablesAfter[offset]; + stacksAfter[offset] = other.stacksAfter[offset]; + generalizedContexts[offset] = other.generalizedContexts[offset]; + evaluationCounts[offset] = other.evaluationCounts[offset]; + initializedVariables[offset] = other.initializedVariables[offset]; } else { @@ -984,6 +968,7 @@ implements AttributeVisitor, stacksAfter[offset] .generalize(other.stacksAfter[offset]); //generalizedContexts[offset] evaluationCounts[offset] += other.evaluationCounts[offset]; + //initializedVariables[offset] } } } @@ -1109,7 +1094,11 @@ implements AttributeVisitor, /** * Initializes the data structures for the variables, stack, etc. */ - private void initializeArrays(CodeAttribute codeAttribute) + private void initializeVariables(Clazz clazz, + Method method, + CodeAttribute codeAttribute, + TracedVariables variables, + TracedStack stack) { int codeLength = codeAttribute.u4codeLength; @@ -1117,25 +1106,33 @@ implements AttributeVisitor, if (variablesAfter.length < codeLength) { // Create new arrays. - branchOriginValues = new InstructionOffsetValue[codeLength]; - branchTargetValues = new InstructionOffsetValue[codeLength]; - variablesBefore = new TracedVariables[codeLength]; - stacksBefore = new TracedStack[codeLength]; - variablesAfter = new TracedVariables[codeLength]; - stacksAfter = new TracedStack[codeLength]; - generalizedContexts = new boolean[codeLength]; - evaluationCounts = new int[codeLength]; + branchOriginValues = new InstructionOffsetValue[codeLength]; + branchTargetValues = new InstructionOffsetValue[codeLength]; + variablesBefore = new TracedVariables[codeLength]; + stacksBefore = new TracedStack[codeLength]; + variablesAfter = new TracedVariables[codeLength]; + stacksAfter = new TracedStack[codeLength]; + generalizedContexts = new boolean[codeLength]; + evaluationCounts = new int[codeLength]; + initializedVariables = new int[codeLength]; + + // Reset the arrays. + for (int index = 0; index < codeLength; index++) + { + initializedVariables[index] = NONE; + } } else { // Reset the arrays. - Arrays.fill(branchOriginValues, null); - Arrays.fill(branchTargetValues, null); - Arrays.fill(generalizedContexts, false); - Arrays.fill(evaluationCounts, 0); - for (int index = 0; index < codeLength; index++) { + branchOriginValues[index] = null; + branchTargetValues[index] = null; + generalizedContexts[index] = false; + evaluationCounts[index] = 0; + initializedVariables[index] = NONE; + if (variablesBefore[index] != null) { variablesBefore[index].reset(codeAttribute.u2maxLocals); @@ -1157,17 +1154,7 @@ implements AttributeVisitor, } } } - } - - /** - * Initializes the data structures for the variables, stack, etc. - */ - private void initializeParameters(Clazz clazz, - Method method, - CodeAttribute codeAttribute, - TracedVariables variables) - { // Create the method parameters. TracedVariables parameters = new TracedVariables(codeAttribute.u2maxLocals); diff --git a/src/proguard/optimize/evaluation/StoringInvocationUnit.java b/src/proguard/optimize/evaluation/StoringInvocationUnit.java index 010dab0..bcbb69f 100644 --- a/src/proguard/optimize/evaluation/StoringInvocationUnit.java +++ b/src/proguard/optimize/evaluation/StoringInvocationUnit.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 diff --git a/src/proguard/optimize/evaluation/TracedBranchUnit.java b/src/proguard/optimize/evaluation/TracedBranchUnit.java index b7dd469..fa5bb79 100644 --- a/src/proguard/optimize/evaluation/TracedBranchUnit.java +++ b/src/proguard/optimize/evaluation/TracedBranchUnit.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 diff --git a/src/proguard/optimize/evaluation/VariableOptimizer.java b/src/proguard/optimize/evaluation/VariableOptimizer.java index a824481..b3ae81c 100644 --- a/src/proguard/optimize/evaluation/VariableOptimizer.java +++ b/src/proguard/optimize/evaluation/VariableOptimizer.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 @@ -21,10 +21,10 @@ package proguard.optimize.evaluation; import proguard.classfile.*; -import proguard.classfile.attribute.visitor.*; -import proguard.classfile.editor.*; import proguard.classfile.visitor.MemberVisitor; import proguard.classfile.attribute.*; +import proguard.classfile.attribute.visitor.AttributeVisitor; +import proguard.classfile.editor.VariableRemapper; import proguard.classfile.util.*; /** @@ -35,9 +35,7 @@ import proguard.classfile.util.*; */ public class VariableOptimizer extends SimplifiedVisitor -implements AttributeVisitor, - LocalVariableInfoVisitor, - LocalVariableTypeInfoVisitor +implements AttributeVisitor { //* private static final boolean DEBUG = false; @@ -53,7 +51,6 @@ implements AttributeVisitor, private final LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer(); private final VariableRemapper variableRemapper = new VariableRemapper(); - private VariableCleaner variableCleaner = new VariableCleaner(); private int[] variableMap = new int[ClassConstants.TYPICAL_VARIABLES_SIZE]; @@ -104,11 +101,6 @@ implements AttributeVisitor, // Analyze the liveness of the variables in the code. livenessAnalyzer.visitCodeAttribute(clazz, method, codeAttribute); - // Trim the variables in the local variable tables, because even - // clipping the tables individually may leave some inconsistencies - // between them. - codeAttribute.attributesAccept(clazz, method, this); - int startIndex = (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 || reuseThis ? 0 : 1; @@ -150,19 +142,23 @@ implements AttributeVisitor, } } - // Have we been able to remap any variables? + // Remap the variables. if (remapping) { if (DEBUG) { - System.out.println("VariableOptimizer: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); - for (int index= 0; index < variableSize; index++) + System.out.println("Remapping variables:"); + System.out.println(" Class "+ ClassUtil.externalClassName(clazz.getName())); + System.out.println(" Method "+ClassUtil.externalFullMethodDescription(clazz.getName(), + 0, + method.getName(clazz), + method.getDescriptor(clazz))); + for (int index = 0; index < variableSize; index++) { - System.out.println(" v"+index+" -> "+variableMap[index]); + System.out.println(" ["+index+"] -> ["+variableMap[index]+"]"); } } - // Remap the variables. variableRemapper.setVariableMap(variableMap); variableRemapper.visitCodeAttribute(clazz, method, codeAttribute); @@ -172,59 +168,6 @@ implements AttributeVisitor, method.accept(clazz, extraVariableMemberVisitor); } } - else - { - // Just clean up any empty variables. - variableCleaner.visitCodeAttribute(clazz, method, codeAttribute); - } - } - - - public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) - { - // Trim the variables in the local variable table. - localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); - } - - - public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) - { - // Trim the variables in the local variable type table. - localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); - } - - - // Implementations for LocalVariableInfoVisitor. - - public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) - { - // Trim the local variable to the instructions at which it is alive. - int variable = localVariableInfo.u2index; - int startPC = localVariableInfo.u2startPC; - int endPC = startPC + localVariableInfo.u2length; - - startPC = firstLiveness(startPC, endPC, variable); - endPC = lastLiveness(startPC, endPC, variable); - - localVariableInfo.u2startPC = startPC; - localVariableInfo.u2length = endPC - startPC; - } - - - // Implementations for LocalVariableTypeInfoVisitor. - - public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) - { - // Trim the local variable type to the instructions at which it is alive. - int variable = localVariableTypeInfo.u2index; - int startPC = localVariableTypeInfo.u2startPC; - int endPC = startPC + localVariableTypeInfo.u2length; - - startPC = firstLiveness(startPC, endPC, variable); - endPC = lastLiveness(startPC, endPC, variable); - - localVariableTypeInfo.u2startPC = startPC; - localVariableTypeInfo.u2length = endPC - startPC; } @@ -298,48 +241,4 @@ implements AttributeVisitor, } } } - - - /** - * Returns the first instruction offset between the given offsets at which - * the given variable goes alive. - */ - private int firstLiveness(int startOffset, int endOffset, int variableIndex) - { - for (int offset = startOffset; offset < endOffset; offset++) - { - if (livenessAnalyzer.isTraced(offset) && - livenessAnalyzer.isAliveBefore(offset, variableIndex)) - { - return offset; - } - } - - return endOffset; - } - - - /** - * Returns the last instruction offset between the given offsets before - * which the given variable is still alive. - */ - private int lastLiveness(int startOffset, int endOffset, int variableIndex) - { - int previousOffset = endOffset; - - for (int offset = endOffset-1; offset >= startOffset; offset--) - { - if (livenessAnalyzer.isTraced(offset)) - { - if (livenessAnalyzer.isAliveBefore(offset, variableIndex)) - { - return previousOffset; - } - - previousOffset = offset; - } - } - - return endOffset; - } } |