diff options
Diffstat (limited to 'src/proguard/optimize/evaluation/EvaluationShrinker.java')
-rw-r--r-- | src/proguard/optimize/evaluation/EvaluationShrinker.java | 280 |
1 files changed, 178 insertions, 102 deletions
diff --git a/src/proguard/optimize/evaluation/EvaluationShrinker.java b/src/proguard/optimize/evaluation/EvaluationShrinker.java index 2e86532..daccec1 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-2013 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2014 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 @@ -30,7 +30,7 @@ import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; -import proguard.evaluation.*; +import proguard.evaluation.TracedStack; import proguard.evaluation.value.*; import proguard.optimize.info.*; @@ -50,8 +50,8 @@ implements AttributeVisitor private static final boolean DEBUG_RESULTS = false; private static final boolean DEBUG = false; /*/ - private static boolean DEBUG_RESULTS = true; - private static boolean DEBUG = true; + private static boolean DEBUG = System.getProperty("es") != null; + private static boolean DEBUG_RESULTS = DEBUG; //*/ private static final int UNSUPPORTED = -1; @@ -177,11 +177,7 @@ implements AttributeVisitor if (DEBUG_RESULTS) { System.out.println(); - System.out.println("Class "+ClassUtil.externalClassName(clazz.getName())); - System.out.println("Method "+ClassUtil.externalFullMethodDescription(clazz.getName(), - 0, - method.getName(clazz), - method.getDescriptor(clazz))); + System.out.println("EvaluationShrinker ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]"); } // Initialize the necessary array. @@ -542,7 +538,7 @@ implements AttributeVisitor int parameterSize = ParameterUsageMarker.getParameterSize(programMethod); // Make the method invocation static, if possible. - if ((programMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) == 0 && + if ((programMethod.getAccessFlags() & ClassConstants.ACC_STATIC) == 0 && !ParameterUsageMarker.isParameterUsed(programMethod, 0)) { replaceByStaticInvocation(programClass, @@ -705,7 +701,7 @@ implements AttributeVisitor { // Mark any variable initializations for this variable load that // are required according to the JVM. - markVariableInitializers(offset, variableInstruction.variableIndex); + markVariableInitializersBefore(offset, variableInstruction.variableIndex); } } } @@ -729,6 +725,8 @@ implements AttributeVisitor if (isInstructionNecessary(offset)) { // Check all stack entries that are popped. + // Unusual case: an exception handler with an exception that is + // no longer consumed directly by a method. // Typical case: a freshly marked variable initialization that // requires some value on the stack. int popCount = instruction.stackPopCount(clazz); @@ -739,17 +737,36 @@ implements AttributeVisitor int stackSize = tracedStack.size(); + int requiredPopCount = 0; int requiredPushCount = 0; for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++) { - if (!isStackSimplifiedBefore(offset, stackIndex)) + boolean stackSimplifiedBefore = + isStackSimplifiedBefore(offset, stackIndex); + boolean stackEntryPresentBefore = + isStackEntryPresentBefore(offset, stackIndex); + + if (stackSimplifiedBefore) { // Is this stack entry pushed by any producer - // (because it is required by other consumers)? + // (maybe an exception in an exception handler)? if (isStackEntryPresentBefore(offset, stackIndex)) { // Mark all produced stack entries. markStackEntryProducers(offset, stackIndex); + + // Remember to pop it. + requiredPopCount++; + } + } + else + { + // Is this stack entry pushed by any producer + // (because it is required by other consumers)? + if (stackEntryPresentBefore) + { + // Mark all produced stack entries. + markStackEntryProducers(offset, stackIndex); } else { @@ -759,6 +776,14 @@ implements AttributeVisitor } } + // Pop some unnecessary stack entries. + if (requiredPopCount > 0) + { + if (DEBUG) System.out.println(" Inserting before marked consumer "+instruction.toString(offset)); + + insertPopInstructions(offset, false, true, popCount); + } + // Push some necessary stack entries. if (requiredPushCount > 0) { @@ -769,7 +794,7 @@ implements AttributeVisitor throw new IllegalArgumentException("Unsupported stack size increment ["+requiredPushCount+"] at ["+offset+"]"); } - insertPushInstructions(offset, false, tracedStack.getTop(0).computationalType()); + insertPushInstructions(offset, false, true, tracedStack.getTop(0).computationalType()); } } @@ -826,7 +851,7 @@ implements AttributeVisitor { if (DEBUG) System.out.println(" Inserting after marked producer "+instruction.toString(offset)); - insertPopInstructions(offset, false, requiredPopCount); + insertPopInstructions(offset, false, false, requiredPopCount); } } } @@ -863,7 +888,7 @@ implements AttributeVisitor { if (DEBUG) System.out.println(" Replacing unmarked consumer "+instruction.toString(offset)); - insertPopInstructions(offset, true, expectedPopCount); + insertPopInstructions(offset, true, false, expectedPopCount); } } @@ -893,7 +918,7 @@ implements AttributeVisitor { if (DEBUG) System.out.println(" Replacing unmarked producer "+instruction.toString(offset)); - insertPushInstructions(offset, true, tracedStack.getTop(0).computationalType()); + insertPushInstructions(offset, true, false, tracedStack.getTop(0).computationalType()); } } } @@ -1434,35 +1459,65 @@ implements AttributeVisitor /** - * Marks the initializing instructions of the variable consumer at the given - * offset. - * @param consumerOffset the offset of the variable consumer. - * @param variableIndex the index of the variable that is loaded. + * Ensures that the given variable is initialized before the specified + * consumer of that variable, in the JVM's view. + * @param consumerOffset the instruction offset before which the variable + * needs to be initialized. + * @param variableIndex the index of the variable. */ - private void markVariableInitializers(int consumerOffset, - int variableIndex) + private void markVariableInitializersBefore(int consumerOffset, + int variableIndex) { + // Make sure the variable is initialized after all producers. + // Use the simple evaluator, to get the JVM's view of what is + // initialized. InstructionOffsetValue producerOffsets = simplePartialEvaluator.getVariablesBefore(consumerOffset).getProducerValue(variableIndex).instructionOffsetValue(); - if (producerOffsets != null) + int offsetCount = producerOffsets.instructionOffsetCount(); + for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++) { - int offsetCount = producerOffsets.instructionOffsetCount(); - for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++) + // Avoid infinite loops by only looking at producers before + // the consumer. + int producerOffset = + producerOffsets.instructionOffset(offsetIndex); + if (producerOffset < consumerOffset) { - // Make sure the variable and the instruction are marked - // at the producing offset. - int offset = producerOffsets.instructionOffset(offsetIndex); + markVariableInitializersAfter(producerOffset, variableIndex); + } + } + } - if (!isInstructionNecessary(offset) && - isVariableInitialization(offset, variableIndex)) - { - if (DEBUG) System.out.print(" Marking initialization of v"+variableIndex+" at "); - markInstruction(offset); + /** + * Ensures that the given variable is initialized after the specified + * producer of that variable, in the JVM's view. + * @param producerOffset the instruction offset after which the variable + * needs to be initialized. + * @param variableIndex the index of the variable. + */ + private void markVariableInitializersAfter(int producerOffset, + int variableIndex) + { + // No problem if the producer has already been marked. + if (!isInstructionNecessary(producerOffset)) + { + // Is the unmarked producer a variable initialization? + if (isVariableInitialization(producerOffset, variableIndex)) + { + // Mark the producer. + if (DEBUG) System.out.print(" Marking initialization of v"+variableIndex+" at "); - if (DEBUG) System.out.println(); - } + markInstruction(producerOffset); + + if (DEBUG) System.out.println(); + } + else + { + // Don't mark the producer, but recursively look at the + // preceding producers of the same variable. Their values + // will fall through, replacing this producer. + markVariableInitializersBefore(producerOffset, variableIndex); } } } @@ -1645,6 +1700,7 @@ implements AttributeVisitor */ private void insertPushInstructions(int offset, boolean replace, + boolean before, int computationalType) { // Mark this instruction. @@ -1657,21 +1713,7 @@ implements AttributeVisitor if (DEBUG) System.out.println(": "+replacementInstruction.toString(offset)); // Replace or insert the push instruction. - if (replace) - { - // Replace the push instruction. - codeAttributeEditor.replaceInstruction(offset, replacementInstruction); - } - else - { - // Insert the push instruction. - codeAttributeEditor.insertBeforeInstruction(offset, replacementInstruction); - - if (extraAddedInstructionVisitor != null) - { - replacementInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor); - } - } + insertInstruction(offset, replace, before, replacementInstruction); } @@ -1700,7 +1742,10 @@ implements AttributeVisitor * Pops the given number of stack entries at or after the given offset. * The instructions are marked as necessary. */ - private void insertPopInstructions(int offset, boolean replace, int popCount) + private void insertPopInstructions(int offset, + boolean replace, + boolean before, + int popCount) { // Mark this instruction. markInstruction(offset); @@ -1713,19 +1758,7 @@ implements AttributeVisitor Instruction popInstruction = new SimpleInstruction(InstructionConstants.OP_POP); - if (replace) - { - codeAttributeEditor.replaceInstruction(offset, popInstruction); - } - else - { - codeAttributeEditor.insertAfterInstruction(offset, popInstruction); - - if (extraAddedInstructionVisitor != null) - { - popInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor); - } - } + insertInstruction(offset, replace, before, popInstruction); break; } case 2: @@ -1734,19 +1767,7 @@ implements AttributeVisitor Instruction popInstruction = new SimpleInstruction(InstructionConstants.OP_POP2); - if (replace) - { - codeAttributeEditor.replaceInstruction(offset, popInstruction); - } - else - { - codeAttributeEditor.insertAfterInstruction(offset, popInstruction); - - if (extraAddedInstructionVisitor != null) - { - popInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor); - } - } + insertInstruction(offset, replace, before, popInstruction); break; } default: @@ -1771,31 +1792,86 @@ implements AttributeVisitor popInstructions[popCount / 2] = popInstruction; } - if (replace) - { - codeAttributeEditor.replaceInstruction(offset, popInstructions); + insertInstructions(offset, + replace, + before, + popInstruction, + popInstructions); + break; + } + } + } - for (int index = 1; index < popInstructions.length; index++) - { - if (extraAddedInstructionVisitor != null) - { - popInstructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor); - } - } - } - else + + /** + * Inserts or replaces the given instruction at the given offset. + */ + private void insertInstruction(int offset, + boolean replace, + boolean before, + Instruction instruction) + { + if (replace) + { + codeAttributeEditor.replaceInstruction(offset, instruction); + } + else + { + if (before) + { + codeAttributeEditor.insertBeforeInstruction(offset, instruction); + } + else + { + codeAttributeEditor.insertAfterInstruction(offset, instruction); + } + + if (extraAddedInstructionVisitor != null) + { + instruction.accept(null, null, null, offset, extraAddedInstructionVisitor); + } + } + } + + + /** + * Inserts or replaces the given instruction at the given offset. + */ + private void insertInstructions(int offset, + boolean replace, + boolean before, + Instruction instruction, + Instruction[] instructions) + { + if (replace) + { + codeAttributeEditor.replaceInstruction(offset, instructions); + + if (extraAddedInstructionVisitor != null) + { + for (int index = 1; index < instructions.length; index++) { - codeAttributeEditor.insertAfterInstruction(offset, popInstructions); + instructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor); + } + } + } + else + { + if (before) + { + codeAttributeEditor.insertBeforeInstruction(offset, instructions); + } + else + { + codeAttributeEditor.insertAfterInstruction(offset, instructions); + } - for (int index = 0; index < popInstructions.length; index++) - { - if (extraAddedInstructionVisitor != null) - { - popInstructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor); - } - } + for (int index = 0; index < instructions.length; index++) + { + if (extraAddedInstructionVisitor != null) + { + instructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor); } - break; } } } @@ -1998,14 +2074,14 @@ implements AttributeVisitor int variableIndex) { // Wasn't the variable set yet? - Value valueBefore = partialEvaluator.getVariablesBefore(instructionOffset).getValue(variableIndex); + Value valueBefore = simplePartialEvaluator.getVariablesBefore(instructionOffset).getValue(variableIndex); if (valueBefore == null) { return true; } // Is the computational type different now? - Value valueAfter = partialEvaluator.getVariablesAfter(instructionOffset).getValue(variableIndex); + Value valueAfter = simplePartialEvaluator.getVariablesAfter(instructionOffset).getValue(variableIndex); if (valueAfter.computationalType() != valueBefore.computationalType()) { return true; @@ -2020,7 +2096,7 @@ implements AttributeVisitor } // Was the producer an argument (which may be removed)? - Value producersBefore = partialEvaluator.getVariablesBefore(instructionOffset).getProducerValue(variableIndex); + Value producersBefore = simplePartialEvaluator.getVariablesBefore(instructionOffset).getProducerValue(variableIndex); return producersBefore.instructionOffsetValue().instructionOffsetCount() == 1 && producersBefore.instructionOffsetValue().instructionOffset(0) == PartialEvaluator.AT_METHOD_ENTRY; } |