summaryrefslogtreecommitdiff
path: root/src/proguard/optimize/evaluation
diff options
context:
space:
mode:
Diffstat (limited to 'src/proguard/optimize/evaluation')
-rw-r--r--src/proguard/optimize/evaluation/EvaluationShrinker.java2298
-rw-r--r--src/proguard/optimize/evaluation/EvaluationSimplifier.java1360
-rw-r--r--src/proguard/optimize/evaluation/LivenessAnalyzer.java526
-rw-r--r--src/proguard/optimize/evaluation/LoadingInvocationUnit.java164
-rw-r--r--src/proguard/optimize/evaluation/PartialEvaluator.java1282
-rw-r--r--src/proguard/optimize/evaluation/SimpleEnumArrayPropagator.java94
-rw-r--r--src/proguard/optimize/evaluation/SimpleEnumClassChecker.java74
-rw-r--r--src/proguard/optimize/evaluation/SimpleEnumClassSimplifier.java164
-rw-r--r--src/proguard/optimize/evaluation/SimpleEnumDescriptorSimplifier.java583
-rw-r--r--src/proguard/optimize/evaluation/SimpleEnumUseChecker.java760
-rw-r--r--src/proguard/optimize/evaluation/SimpleEnumUseSimplifier.java820
-rw-r--r--src/proguard/optimize/evaluation/StoringInvocationUnit.java207
-rw-r--r--src/proguard/optimize/evaluation/TracedBranchUnit.java59
-rw-r--r--src/proguard/optimize/evaluation/VariableOptimizer.java357
-rw-r--r--src/proguard/optimize/evaluation/package.html4
15 files changed, 0 insertions, 8752 deletions
diff --git a/src/proguard/optimize/evaluation/EvaluationShrinker.java b/src/proguard/optimize/evaluation/EvaluationShrinker.java
deleted file mode 100644
index daccec1..0000000
--- a/src/proguard/optimize/evaluation/EvaluationShrinker.java
+++ /dev/null
@@ -1,2298 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * 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
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.optimize.evaluation;
-
-import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.visitor.AttributeVisitor;
-import proguard.classfile.constant.RefConstant;
-import proguard.classfile.constant.visitor.ConstantVisitor;
-import proguard.classfile.editor.CodeAttributeEditor;
-import proguard.classfile.instruction.*;
-import proguard.classfile.instruction.visitor.InstructionVisitor;
-import proguard.classfile.util.*;
-import proguard.classfile.visitor.*;
-import proguard.evaluation.TracedStack;
-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.
- *
- * @author Eric Lafortune
- */
-public class EvaluationShrinker
-extends SimplifiedVisitor
-implements AttributeVisitor
-{
- //*
- private static final boolean DEBUG_RESULTS = false;
- private static final boolean DEBUG = false;
- /*/
- private static boolean DEBUG = System.getProperty("es") != null;
- private static boolean DEBUG_RESULTS = DEBUG;
- //*/
-
- private static final int UNSUPPORTED = -1;
- private static final int NOP = InstructionConstants.OP_NOP & 0xff;
- private static final int POP = InstructionConstants.OP_POP & 0xff;
- private static final int POP2 = InstructionConstants.OP_POP2 & 0xff;
- private static final int DUP = InstructionConstants.OP_DUP & 0xff;
- private static final int DUP_X1 = InstructionConstants.OP_DUP_X1 & 0xff;
- private static final int DUP_X2 = InstructionConstants.OP_DUP_X2 & 0xff;
- private static final int DUP2 = InstructionConstants.OP_DUP2 & 0xff;
- private static final int DUP2_X1 = InstructionConstants.OP_DUP2_X1 & 0xff;
- private static final int DUP2_X2 = InstructionConstants.OP_DUP2_X2 & 0xff;
- private static final int SWAP = InstructionConstants.OP_SWAP & 0xff;
- private static final int MOV_X2 = DUP_X2 | (POP << 8);
- private static final int MOV2_X1 = DUP2_X1 | (POP2 << 8);
- private static final int MOV2_X2 = DUP2_X2 | (POP2 << 8);
- private static final int POP_X1 = SWAP | (POP << 8);
- private static final int POP_X2 = DUP2_X1 | (POP2 << 8) | (POP << 16);
- private static final int POP_X3 = UNSUPPORTED;
- private static final int POP2_X1 = DUP_X2 | (POP << 8) | (POP2 << 16);
- private static final int POP2_X2 = DUP2_X2 | (POP2 << 8) | (POP2 << 16);
- private static final int POP3 = POP2 | (POP << 8);
- private static final int POP4 = POP2 | (POP2 << 8);
- private static final int POP_DUP = POP | (DUP << 8);
- private static final int POP_SWAP_POP = POP | (SWAP << 8) | (POP << 16);
- private static final int POP2_SWAP_POP = POP2 | (SWAP << 8) | (POP << 16);
- private static final int SWAP_DUP_X1 = SWAP | (DUP_X1 << 8);
- private static final int SWAP_DUP_X1_SWAP = SWAP | (DUP_X1 << 8) | (SWAP << 16);
- private static final int SWAP_POP_DUP = SWAP | (POP << 8) | (DUP << 16);
- private static final int SWAP_POP_DUP_X1 = SWAP | (POP << 8) | (DUP_X1 << 16);
- private static final int DUP_X2_POP2 = DUP_X2 | (POP2 << 8);
- private static final int DUP2_X1_POP3 = DUP2_X1 | (POP2 << 8) | (POP << 16);
- private static final int DUP2_X2_POP3 = DUP2_X2 | (POP2 << 8) | (POP << 16);
- private static final int DUP2_X2_SWAP_POP = DUP2_X2 | (SWAP << 8) | (POP << 16);
-
-
- 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, 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, false);
-
- private boolean[][] stacksNecessaryAfter = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
- private boolean[][] stacksSimplifiedBefore = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
- private boolean[] instructionsNecessary = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
-
- private int maxMarkedOffset;
-
-
- /**
- * Creates a new EvaluationShrinker.
- */
- public EvaluationShrinker()
- {
- this(new PartialEvaluator(), null, null);
- }
-
-
- /**
- * Creates a new EvaluationShrinker.
- * @param partialEvaluator the partial evaluator that will
- * execute the code and provide
- * information about the results.
- * @param extraDeletedInstructionVisitor an optional extra visitor for all
- * deleted instructions.
- * @param extraAddedInstructionVisitor an optional extra visitor for all
- * added instructions.
- */
- public EvaluationShrinker(PartialEvaluator partialEvaluator,
- InstructionVisitor extraDeletedInstructionVisitor,
- InstructionVisitor extraAddedInstructionVisitor)
- {
- this.partialEvaluator = partialEvaluator;
- this.extraDeletedInstructionVisitor = extraDeletedInstructionVisitor;
- this.extraAddedInstructionVisitor = extraAddedInstructionVisitor;
- }
-
-
- // Implementations for AttributeVisitor.
-
- public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
-
-
- public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
-// DEBUG = DEBUG_RESULTS =
-// clazz.getName().equals("abc/Def") &&
-// method.getName(clazz).equals("abc");
-
- // TODO: Remove this when the evaluation shrinker has stabilized.
- // Catch any unexpected exceptions from the actual visiting method.
- try
- {
- // Process the code.
- visitCodeAttribute0(clazz, method, codeAttribute);
- }
- catch (RuntimeException ex)
- {
- System.err.println("Unexpected error while shrinking instructions after partial evaluation:");
- System.err.println(" Class = ["+clazz.getName()+"]");
- System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]");
- System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")");
- System.err.println("Not optimizing this method");
-
- if (DEBUG)
- {
- method.accept(clazz, new ClassPrinter());
-
- throw ex;
- }
- }
- }
-
-
- public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
- if (DEBUG_RESULTS)
- {
- System.out.println();
- System.out.println("EvaluationShrinker ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]");
- }
-
- // Initialize the necessary array.
- initializeNecessary(codeAttribute);
-
- // Evaluate the method.
- partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
-
- // Evaluate the method the way the JVM verifier would do it.
- simplePartialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
-
- int codeLength = codeAttribute.u4codeLength;
-
- // Reset the code changes.
- codeAttributeEditor.reset(codeLength);
-
- // Mark any unused method parameters on the stack.
- if (DEBUG) System.out.println("Invocation simplification:");
-
- for (int offset = 0; offset < codeLength; offset++)
- {
- if (partialEvaluator.isTraced(offset))
- {
- Instruction instruction = InstructionFactory.create(codeAttribute.code,
- offset);
-
- instruction.accept(clazz, method, codeAttribute, offset, unusedParameterSimplifier);
- }
- }
-
- // Mark all essential instructions that have been encountered as used.
- if (DEBUG) System.out.println("Usage initialization: ");
-
- maxMarkedOffset = -1;
-
- // The invocation of the "super" or "this" <init> method inside a
- // constructor is always necessary.
- int superInitializationOffset = partialEvaluator.superInitializationOffset();
- if (superInitializationOffset != PartialEvaluator.NONE)
- {
- if (DEBUG) System.out.print("(super.<init>)");
-
- markInstruction(superInitializationOffset);
- }
-
- // Also mark infinite loops and instructions that cause side effects.
- for (int offset = 0; offset < codeLength; offset++)
- {
- if (partialEvaluator.isTraced(offset))
- {
- Instruction instruction = InstructionFactory.create(codeAttribute.code,
- offset);
-
- // Mark that the instruction is necessary if it is an infinite loop.
- if (instruction.opcode == InstructionConstants.OP_GOTO &&
- ((BranchInstruction)instruction).branchOffset == 0)
- {
- if (DEBUG) System.out.print("(infinite loop)");
- markInstruction(offset);
- }
-
- // Mark that the instruction is necessary if it has side effects.
- else if (sideEffectInstructionChecker.hasSideEffects(clazz,
- method,
- codeAttribute,
- offset,
- instruction))
- {
- markInstruction(offset);
- }
- }
- }
- if (DEBUG) System.out.println();
-
-
- // Globally mark instructions and their produced variables and stack
- // entries on which necessary instructions depend.
- // Instead of doing this recursively, we loop across all instructions,
- // starting at the highest previously unmarked instruction that has
- // been been marked.
- if (DEBUG) System.out.println("Usage marking:");
-
- while (maxMarkedOffset >= 0)
- {
- int offset = maxMarkedOffset;
-
- maxMarkedOffset = offset - 1;
-
- if (partialEvaluator.isTraced(offset))
- {
- if (isInstructionNecessary(offset))
- {
- Instruction instruction = InstructionFactory.create(codeAttribute.code,
- offset);
-
- instruction.accept(clazz, method, codeAttribute, offset, producerMarker);
- }
-
- // Check if this instruction is a branch origin from a branch
- // that straddles some marked code.
- markStraddlingBranches(offset,
- partialEvaluator.branchTargets(offset),
- true);
-
- // Check if this instruction is a branch target from a branch
- // that straddles some marked code.
- markStraddlingBranches(offset,
- partialEvaluator.branchOrigins(offset),
- false);
- }
-
- if (DEBUG)
- {
- if (maxMarkedOffset > offset)
- {
- System.out.println(" -> "+maxMarkedOffset);
- }
- }
- }
- if (DEBUG) System.out.println();
-
-
- // Mark variable initializations, even if they aren't strictly necessary.
- // The virtual machine's verification step is not smart enough to see
- // this, and may complain otherwise.
- if (DEBUG) System.out.println("Initialization marking: ");
-
- for (int offset = 0; offset < codeLength; offset++)
- {
- if (isInstructionNecessary(offset))
- {
- // Mark initializations of the required instruction.
- Instruction instruction = InstructionFactory.create(codeAttribute.code,
- offset);
-
- instruction.accept(clazz, method, codeAttribute, offset, variableInitializationMarker);
- }
- }
- if (DEBUG) System.out.println();
-
-
- // Locally fix instructions, in order to keep the stack consistent.
- if (DEBUG) System.out.println("Stack consistency fixing:");
-
- maxMarkedOffset = codeLength - 1;
-
- while (maxMarkedOffset >= 0)
- {
- int offset = maxMarkedOffset;
-
- maxMarkedOffset = offset - 1;
-
- if (partialEvaluator.isTraced(offset))
- {
- Instruction instruction = InstructionFactory.create(codeAttribute.code,
- offset);
-
- instruction.accept(clazz, method, codeAttribute, offset, stackConsistencyFixer);
-
- // Check if this instruction is a branch origin from a branch
- // that straddles some marked code.
- markStraddlingBranches(offset,
- partialEvaluator.branchTargets(offset),
- true);
-
- // Check if this instruction is a branch target from a branch
- // that straddles some marked code.
- markStraddlingBranches(offset,
- partialEvaluator.branchOrigins(offset),
- false);
- }
- }
- if (DEBUG) System.out.println();
-
-
- // Replace traced but unmarked backward branches by infinite loops.
- // The virtual machine's verification step is not smart enough to see
- // the code isn't reachable, and may complain otherwise.
- // Any clearly unreachable code will still be removed elsewhere.
- if (DEBUG) System.out.println("Infinite loop fixing:");
-
- for (int offset = 0; offset < codeLength; offset++)
- {
- // Is it a traced but unmarked backward branch, without an unmarked
- // straddling forward branch? Note that this is still a heuristic.
- if (partialEvaluator.isTraced(offset) &&
- !isInstructionNecessary(offset) &&
- isAllSmallerThanOrEqual(partialEvaluator.branchTargets(offset),
- offset) &&
- !isAnyUnnecessaryInstructionBranchingOver(lastNecessaryInstructionOffset(offset),
- offset))
- {
- replaceByInfiniteLoop(clazz, offset);
- }
- }
- if (DEBUG) System.out.println();
-
-
- // Insert infinite loops after jumps to subroutines that don't return.
- // The virtual machine's verification step is not smart enough to see
- // the code isn't reachable, and may complain otherwise.
- if (DEBUG) System.out.println("Non-returning subroutine fixing:");
-
- for (int offset = 0; offset < codeLength; offset++)
- {
- // Is it a traced but unmarked backward branch, without an unmarked
- // straddling forward branch? Note that this is still a heuristic.
- if (isInstructionNecessary(offset) &&
- partialEvaluator.isSubroutineInvocation(offset))
- {
- Instruction instruction = InstructionFactory.create(codeAttribute.code,
- offset);
-
- int nextOffset = offset + instruction.length(offset);
- if (!isInstructionNecessary(nextOffset))
- {
- replaceByInfiniteLoop(clazz, nextOffset);
- }
- }
- }
- if (DEBUG) System.out.println();
-
-
- // Delete all instructions that are not used.
- int offset = 0;
- do
- {
- Instruction instruction = InstructionFactory.create(codeAttribute.code,
- offset);
- if (!isInstructionNecessary(offset))
- {
- codeAttributeEditor.clearModifications(offset);
- codeAttributeEditor.deleteInstruction(offset);
-
- // Visit the instruction, if required.
- if (extraDeletedInstructionVisitor != null)
- {
- instruction.accept(clazz, method, codeAttribute, offset, extraDeletedInstructionVisitor);
- }
- }
-
- offset += instruction.length(offset);
- }
- while (offset < codeLength);
-
-
- if (DEBUG_RESULTS)
- {
- System.out.println("Simplification results:");
-
- offset = 0;
- do
- {
- Instruction instruction = InstructionFactory.create(codeAttribute.code,
- offset);
- System.out.println((isInstructionNecessary(offset) ? " + " : " - ")+instruction.toString(offset));
-
- if (partialEvaluator.isTraced(offset))
- {
- int initializationOffset = partialEvaluator.initializationOffset(offset);
- if (initializationOffset != PartialEvaluator.NONE)
- {
- System.out.println(" is to be initialized at ["+initializationOffset+"]");
- }
-
- InstructionOffsetValue branchTargets = partialEvaluator.branchTargets(offset);
- if (branchTargets != null)
- {
- System.out.println(" has overall been branching to "+branchTargets);
- }
-
- boolean deleted = codeAttributeEditor.deleted[offset];
- if (isInstructionNecessary(offset) && deleted)
- {
- System.out.println(" is deleted");
- }
-
- Instruction preInsertion = codeAttributeEditor.preInsertions[offset];
- if (preInsertion != null)
- {
- System.out.println(" is preceded by: "+preInsertion);
- }
-
- Instruction replacement = codeAttributeEditor.replacements[offset];
- if (replacement != null)
- {
- System.out.println(" is replaced by: "+replacement);
- }
-
- Instruction postInsertion = codeAttributeEditor.postInsertions[offset];
- if (postInsertion != null)
- {
- System.out.println(" is followed by: "+postInsertion);
- }
- }
-
- offset += instruction.length(offset);
- }
- while (offset < codeLength);
- }
-
- // Apply all accumulated changes to the code.
- codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
- }
-
-
- /**
- * This MemberVisitor marks stack entries that aren't necessary because
- * parameters aren't used in the methods that are visited.
- */
- private class MyUnusedParameterSimplifier
- extends SimplifiedVisitor
- implements InstructionVisitor,
- ConstantVisitor,
- MemberVisitor
- {
- private int invocationOffset;
- private ConstantInstruction invocationInstruction;
-
-
- // Implementations for InstructionVisitor.
-
- public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
-
-
- public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
- {
- switch (constantInstruction.opcode)
- {
- case InstructionConstants.OP_INVOKEVIRTUAL:
- case InstructionConstants.OP_INVOKESPECIAL:
- case InstructionConstants.OP_INVOKESTATIC:
- case InstructionConstants.OP_INVOKEINTERFACE:
- this.invocationOffset = offset;
- this.invocationInstruction = constantInstruction;
- clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
- break;
- }
- }
-
-
- // Implementations for ConstantVisitor.
-
- public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
- {
- refConstant.referencedMemberAccept(this);
- }
-
-
- // Implementations for MemberVisitor.
-
- public void visitAnyMember(Clazz clazz, Member member) {}
-
-
- public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
- {
- // Get the total size of the parameters.
- int parameterSize = ParameterUsageMarker.getParameterSize(programMethod);
-
- // Make the method invocation static, if possible.
- if ((programMethod.getAccessFlags() & ClassConstants.ACC_STATIC) == 0 &&
- !ParameterUsageMarker.isParameterUsed(programMethod, 0))
- {
- replaceByStaticInvocation(programClass,
- invocationOffset,
- invocationInstruction);
- }
-
- // Remove unused parameters.
- for (int index = 0; index < parameterSize; index++)
- {
- if (!ParameterUsageMarker.isParameterUsed(programMethod, index))
- {
- TracedStack stack =
- partialEvaluator.getStackBefore(invocationOffset);
-
- int stackIndex = stack.size() - parameterSize + index;
-
- if (DEBUG)
- {
- System.out.println(" ["+invocationOffset+"] Ignoring parameter #"+index+" of "+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"] (stack entry #"+stackIndex+" ["+stack.getBottom(stackIndex)+"])");
- System.out.println(" Full stack: "+stack);
- }
-
- markStackSimplificationBefore(invocationOffset, stackIndex);
- }
- }
- }
- }
-
-
- /**
- * This InstructionVisitor marks the producing instructions and produced
- * variables and stack entries of the instructions that it visits.
- * Simplified method arguments are ignored.
- */
- private class MyProducerMarker
- extends SimplifiedVisitor
- implements InstructionVisitor
- {
- // Implementations for InstructionVisitor.
-
- public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
- {
- markStackProducers(clazz, offset, instruction);
- }
-
-
- public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
- {
- switch (simpleInstruction.opcode)
- {
- case InstructionConstants.OP_DUP:
- conditionallyMarkStackEntryProducers(offset, 0, 0);
- conditionallyMarkStackEntryProducers(offset, 1, 0);
- break;
- case InstructionConstants.OP_DUP_X1:
- conditionallyMarkStackEntryProducers(offset, 0, 0);
- conditionallyMarkStackEntryProducers(offset, 1, 1);
- conditionallyMarkStackEntryProducers(offset, 2, 0);
- break;
- case InstructionConstants.OP_DUP_X2:
- conditionallyMarkStackEntryProducers(offset, 0, 0);
- conditionallyMarkStackEntryProducers(offset, 1, 1);
- conditionallyMarkStackEntryProducers(offset, 2, 2);
- conditionallyMarkStackEntryProducers(offset, 3, 0);
- break;
- case InstructionConstants.OP_DUP2:
- conditionallyMarkStackEntryProducers(offset, 0, 0);
- conditionallyMarkStackEntryProducers(offset, 1, 1);
- conditionallyMarkStackEntryProducers(offset, 2, 0);
- conditionallyMarkStackEntryProducers(offset, 3, 1);
- break;
- case InstructionConstants.OP_DUP2_X1:
- conditionallyMarkStackEntryProducers(offset, 0, 0);
- conditionallyMarkStackEntryProducers(offset, 1, 1);
- conditionallyMarkStackEntryProducers(offset, 2, 2);
- conditionallyMarkStackEntryProducers(offset, 3, 0);
- conditionallyMarkStackEntryProducers(offset, 4, 1);
- break;
- case InstructionConstants.OP_DUP2_X2:
- conditionallyMarkStackEntryProducers(offset, 0, 0);
- conditionallyMarkStackEntryProducers(offset, 1, 1);
- conditionallyMarkStackEntryProducers(offset, 2, 2);
- conditionallyMarkStackEntryProducers(offset, 3, 3);
- conditionallyMarkStackEntryProducers(offset, 4, 0);
- conditionallyMarkStackEntryProducers(offset, 5, 1);
- break;
- case InstructionConstants.OP_SWAP:
- conditionallyMarkStackEntryProducers(offset, 0, 1);
- conditionallyMarkStackEntryProducers(offset, 1, 0);
- break;
- default:
- markStackProducers(clazz, offset, simpleInstruction);
- break;
- }
- }
-
-
- public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
- {
- // Is the variable being loaded or incremented?
- if (variableInstruction.isLoad())
- {
- markVariableProducers(offset, variableInstruction.variableIndex);
- }
- else
- {
- markStackProducers(clazz, offset, variableInstruction);
- }
- }
-
-
- public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
- {
- // Mark the initializer invocation, if this is a 'new' instruction.
- if (constantInstruction.opcode == InstructionConstants.OP_NEW)
- {
- markInitialization(offset);
- }
-
- markStackProducers(clazz, offset, constantInstruction);
- }
-
-
- public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
- {
- // Explicitly mark the produced stack entry of a 'jsr' instruction,
- // because the consuming 'astore' instruction of the subroutine is
- // cleared every time it is traced.
- if (branchInstruction.opcode == InstructionConstants.OP_JSR ||
- branchInstruction.opcode == InstructionConstants.OP_JSR_W)
- {
- markStackEntryAfter(offset, 0);
- }
- else
- {
- markStackProducers(clazz, offset, branchInstruction);
- }
- }
- }
-
-
- /**
- * 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)
- {
- // Is the variable being loaded or incremented?
- if (variableInstruction.isLoad())
- {
- // Mark any variable initializations for this variable load that
- // are required according to the JVM.
- markVariableInitializersBefore(offset, variableInstruction.variableIndex);
- }
- }
- }
-
-
- /**
- * 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
- * instructions.
- */
- private class MyStackConsistencyFixer
- extends SimplifiedVisitor
- implements InstructionVisitor
- {
- // Implementations for InstructionVisitor.
-
- public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
- {
- // Has the instruction been marked?
- 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);
- if (popCount > 0)
- {
- TracedStack tracedStack =
- partialEvaluator.getStackBefore(offset);
-
- int stackSize = tracedStack.size();
-
- int requiredPopCount = 0;
- int requiredPushCount = 0;
- for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++)
- {
- boolean stackSimplifiedBefore =
- isStackSimplifiedBefore(offset, stackIndex);
- boolean stackEntryPresentBefore =
- isStackEntryPresentBefore(offset, stackIndex);
-
- if (stackSimplifiedBefore)
- {
- // Is this stack entry pushed by any producer
- // (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
- {
- // Remember to push it.
- requiredPushCount++;
- }
- }
- }
-
- // 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)
- {
- if (DEBUG) System.out.println(" Inserting before marked consumer "+instruction.toString(offset));
-
- if (requiredPushCount > (instruction.isCategory2() ? 2 : 1))
- {
- throw new IllegalArgumentException("Unsupported stack size increment ["+requiredPushCount+"] at ["+offset+"]");
- }
-
- insertPushInstructions(offset, false, true, tracedStack.getTop(0).computationalType());
- }
- }
-
- // Check all other stack entries, if this is a return
- // instruction.
- // Typical case: the code returns, but there are still other
- // entries left on the stack. These have to be consistent.
- InstructionOffsetValue branchTargets =
- partialEvaluator.branchTargets(offset);
- if (branchTargets != null &&
- branchTargets.instructionOffsetCount() == 0)
- {
- TracedStack tracedStack =
- partialEvaluator.getStackBefore(offset);
-
- int unpoppedStackSize = tracedStack.size() - popCount;
-
- for (int stackIndex = 0; stackIndex < unpoppedStackSize; stackIndex++)
- {
- // Is this stack entry pushed by any producer
- // (because it is required by other consumers)?
- if (isStackEntryPresentBefore(offset, stackIndex))
- {
- // Mark all produced stack entries.
- markStackEntryProducers(offset, stackIndex);
- }
- }
- }
-
- // Check all stack entries that are pushed.
- // Typical case: a return value that wasn't really required and
- // that should be popped.
- int pushCount = instruction.stackPushCount(clazz);
- if (pushCount > 0)
- {
- TracedStack tracedStack =
- partialEvaluator.getStackAfter(offset);
-
- int stackSize = tracedStack.size();
-
- int requiredPopCount = 0;
- for (int stackIndex = stackSize - pushCount; stackIndex < stackSize; stackIndex++)
- {
- // Is the stack entry required by consumers?
- if (!isStackEntryNecessaryAfter(offset, stackIndex))
- {
- // Remember to pop it.
- requiredPopCount++;
- }
- }
-
- // Pop the unnecessary stack entries.
- if (requiredPopCount > 0)
- {
- if (DEBUG) System.out.println(" Inserting after marked producer "+instruction.toString(offset));
-
- insertPopInstructions(offset, false, false, requiredPopCount);
- }
- }
- }
- else
- {
- // Check all stack entries that would be popped.
- // Typical case: a stack value that is required elsewhere and
- // that still has to be popped.
- int popCount = instruction.stackPopCount(clazz);
- if (popCount > 0)
- {
- TracedStack tracedStack =
- partialEvaluator.getStackBefore(offset);
-
- int stackSize = tracedStack.size();
-
- int expectedPopCount = 0;
- for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++)
- {
- // Is this stack entry pushed by any producer
- // (because it is required by other consumers)?
- if (isStackEntryPresentBefore(offset, stackIndex))
- {
- // Mark all produced stack entries.
- markStackEntryProducers(offset, stackIndex);
-
- // Remember to pop it.
- expectedPopCount++;
- }
- }
-
- // Pop the unnecessary stack entries.
- if (expectedPopCount > 0)
- {
- if (DEBUG) System.out.println(" Replacing unmarked consumer "+instruction.toString(offset));
-
- insertPopInstructions(offset, true, false, expectedPopCount);
- }
- }
-
- // Check all stack entries that would be pushed.
- // Typical case: never.
- int pushCount = instruction.stackPushCount(clazz);
- if (pushCount > 0)
- {
- TracedStack tracedStack =
- partialEvaluator.getStackAfter(offset);
-
- int stackSize = tracedStack.size();
-
- int expectedPushCount = 0;
- for (int stackIndex = stackSize - pushCount; stackIndex < stackSize; stackIndex++)
- {
- // Is the stack entry required by consumers?
- if (isStackEntryNecessaryAfter(offset, stackIndex))
- {
- // Remember to push it.
- expectedPushCount++;
- }
- }
-
- // Push some necessary stack entries.
- if (expectedPushCount > 0)
- {
- if (DEBUG) System.out.println(" Replacing unmarked producer "+instruction.toString(offset));
-
- insertPushInstructions(offset, true, false, tracedStack.getTop(0).computationalType());
- }
- }
- }
- }
-
-
- public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
- {
- if (isInstructionNecessary(offset) &&
- isDupOrSwap(simpleInstruction))
- {
- int stackSizeBefore = partialEvaluator.getStackBefore(offset).size();
-
- // Check all stack entries that are popped.
- // Typical case: a freshly marked variable initialization that
- // requires some value on the stack.
- int popCount = simpleInstruction.stackPopCount(clazz);
- if (popCount > 0)
- {
- for (int stackIndex = stackSizeBefore - popCount; stackIndex < stackSizeBefore; stackIndex++)
- {
- // Is this stack entry pushed by any producer
- // (because it is required by other consumers)?
- if (isStackEntryPresentBefore(offset, stackIndex))
- {
- // Mark all produced stack entries.
- markStackEntryProducers(offset, stackIndex);
- }
- }
- }
-
- int topBefore = stackSizeBefore - 1;
- int topAfter = partialEvaluator.getStackAfter(offset).size() - 1;
-
- byte oldOpcode = simpleInstruction.opcode;
-
- // Simplify the dup/swap instruction if possible.
- int newOpcodes = fixDupSwap(offset, oldOpcode, topBefore, topAfter);
-
- // Did we find a suitabe (extended) opcode?
- if (newOpcodes == UNSUPPORTED)
- {
- // We can't easily emulate some constructs.
- throw new UnsupportedOperationException("Can't handle "+simpleInstruction.toString()+" instruction at ["+offset +"]");
- }
-
- // Is there a single replacement opcode?
- if ((newOpcodes & ~0xff) == 0)
- {
- byte newOpcode = (byte)newOpcodes;
-
- if (newOpcode == InstructionConstants.OP_NOP)
- {
- // Delete the instruction.
- codeAttributeEditor.deleteInstruction(offset);
-
- if (extraDeletedInstructionVisitor != null)
- {
- extraDeletedInstructionVisitor.visitSimpleInstruction(null, null, null, offset, null);
- }
-
- if (DEBUG) System.out.println(" Deleting marked instruction "+simpleInstruction.toString(offset));
- }
- else if (newOpcode == oldOpcode)
- {
- // Leave the instruction unchanged.
- codeAttributeEditor.undeleteInstruction(offset);
-
- if (DEBUG) System.out.println(" Marking unchanged instruction "+simpleInstruction.toString(offset));
- }
- else
- {
- // Replace the instruction.
- Instruction replacementInstruction = new SimpleInstruction(newOpcode);
- codeAttributeEditor.replaceInstruction(offset,
- replacementInstruction);
-
- if (DEBUG) System.out.println(" Replacing instruction "+simpleInstruction.toString(offset)+" by "+replacementInstruction.toString());
- }
- }
- else
- {
- // Collect the replacement instructions.
- Instruction[] replacementInstructions = new Instruction[4];
-
- if (DEBUG) System.out.println(" Replacing instruction "+simpleInstruction.toString(offset)+" by");
- int count = 0;
- while (newOpcodes != 0)
- {
- SimpleInstruction replacementInstruction = new SimpleInstruction((byte)newOpcodes);
- replacementInstructions[count++] = replacementInstruction;
-
- if (DEBUG) System.out.println(" "+replacementInstruction.toString());
- newOpcodes >>>= 8;
- }
-
- // Create a properly sized array.
- if (count < 4)
- {
- Instruction[] newInstructions = new Instruction[count];
- System.arraycopy(replacementInstructions, 0, newInstructions, 0, count);
- replacementInstructions = newInstructions;
- }
-
- codeAttributeEditor.replaceInstruction(offset,
- replacementInstructions);
- }
- }
- else
- {
- visitAnyInstruction(clazz, method, codeAttribute, offset, simpleInstruction);
- }
- }
-
-
- /**
- * Returns a dup/swap opcode that is corrected for the stack entries
- * that are present before the instruction and necessary after the
- * instruction. The returned integer opcode may contain multiple byte
- * opcodes (least significant byte first).
- * @param instructionOffset the offset of the dup/swap instruction.
- * @param dupSwapOpcode the original dup/swap opcode.
- * @param topBefore the index of the top stack entry before
- * the instruction (counting from the bottom).
- * @param topAfter the index of the top stack entry after
- * the instruction (counting from the bottom).
- * @return the corrected opcode.
- */
- private int fixDupSwap(int instructionOffset,
- byte dupSwapOpcode,
- int topBefore,
- int topAfter)
- {
- switch (dupSwapOpcode)
- {
- case InstructionConstants.OP_DUP: return fixedDup (instructionOffset, topBefore, topAfter);
- case InstructionConstants.OP_DUP_X1: return fixedDup_x1 (instructionOffset, topBefore, topAfter);
- case InstructionConstants.OP_DUP_X2: return fixedDup_x2 (instructionOffset, topBefore, topAfter);
- case InstructionConstants.OP_DUP2: return fixedDup2 (instructionOffset, topBefore, topAfter);
- case InstructionConstants.OP_DUP2_X1: return fixedDup2_x1(instructionOffset, topBefore, topAfter);
- case InstructionConstants.OP_DUP2_X2: return fixedDup2_x2(instructionOffset, topBefore, topAfter);
- case InstructionConstants.OP_SWAP: return fixedSwap (instructionOffset, topBefore, topAfter);
- default: throw new IllegalArgumentException("Not a dup/swap opcode ["+dupSwapOpcode+"]");
- }
- }
-
-
- private int fixedDup(int instructionOffset, int topBefore, int topAfter)
- {
- boolean stackEntryPresent0 = isStackEntryPresentBefore(instructionOffset, topBefore - 0);
-
- boolean stackEntryNecessary0 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 0);
- boolean stackEntryNecessary1 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 1);
-
- // Figure out which stack entries should be moved,
- // copied, or removed.
- return
- stackEntryNecessary0 ?
- stackEntryNecessary1 ? DUP : // ...O -> ...OO
- NOP : // ...O -> ...O
- stackEntryNecessary1 ? NOP : // ...O -> ...O
- stackEntryPresent0 ? POP : // ...O -> ...
- NOP; // ... -> ...
- }
-
-
- private int fixedDup_x1(int instructionOffset, int topBefore, int topAfter)
- {
- boolean stackEntryPresent0 = isStackEntryPresentBefore(instructionOffset, topBefore - 0);
- boolean stackEntryPresent1 = isStackEntryPresentBefore(instructionOffset, topBefore - 1);
-
- boolean stackEntryNecessary0 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 0);
- boolean stackEntryNecessary1 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 1);
- boolean stackEntryNecessary2 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 2);
-
- // Figure out which stack entries should be moved,
- // copied, or removed.
- return
- stackEntryNecessary1 ?
- stackEntryNecessary2 ?
- stackEntryNecessary0 ? DUP_X1 : // ...XO -> ...OXO
- SWAP : // ...XO -> ...OX
- // !stackEntryNecessary2
- stackEntryNecessary0 ? NOP : // ...XO -> ...XO
- stackEntryPresent0 ? POP : // ...XO -> ...X
- NOP : // ...X -> ...X
- stackEntryPresent1 ?
- stackEntryNecessary2 ?
- stackEntryNecessary0 ? SWAP_POP_DUP : // ...XO -> ...OO
- POP_X1 : // ...XO -> ...O
- // !stackEntryNecessary2
- stackEntryNecessary0 ? POP_X1 : // ...XO -> ...O
- stackEntryPresent0 ? POP2 : // ...XO -> ...
- POP : // ...X -> ...
- // !stackEntryPresent1
- stackEntryNecessary2 ?
- stackEntryNecessary0 ? DUP : // ...O -> ...OO
- NOP : // ...O -> ...O
- // !stackEntryNecessary2
- stackEntryNecessary0 ? NOP : // ...O -> ...O
- stackEntryPresent0 ? POP : // ...O -> ...
- NOP; // ... -> ...
- }
-
-
- private int fixedDup_x2(int instructionOffset, int topBefore, int topAfter)
- {
- boolean stackEntryPresent0 = isStackEntryPresentBefore(instructionOffset, topBefore - 0);
- boolean stackEntryPresent1 = isStackEntryPresentBefore(instructionOffset, topBefore - 1);
- boolean stackEntryPresent2 = isStackEntryPresentBefore(instructionOffset, topBefore - 2);
-
- boolean stackEntryNecessary0 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 0);
- boolean stackEntryNecessary1 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 1);
- boolean stackEntryNecessary2 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 2);
- boolean stackEntryNecessary3 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 3);
-
- // Figure out which stack entries should be moved,
- // copied, or removed.
- return
- stackEntryNecessary1 ?
- stackEntryNecessary2 ?
- stackEntryNecessary3 ?
- stackEntryNecessary0 ? DUP_X2 : // ...XYO -> ...OXYO
- MOV_X2 : // ...XYO -> ...OXY
- // !stackEntryNecessary3
- stackEntryNecessary0 ? NOP : // ...XYO -> ...XYO
- stackEntryPresent0 ? POP : // ...XYO -> ...XY
- NOP : // ...XY -> ...XY
- stackEntryPresent2 ?
- stackEntryNecessary3 ?
- // stackEntryNecessary0 ? UNSUPPORTED : // ...XYO -> ...OYO
- UNSUPPORTED : // ...XYO -> ...OY
- // !stackEntryNecessary3
- stackEntryNecessary0 ? POP_X2 : // ...XYO -> ...YO
- stackEntryPresent0 ? POP_SWAP_POP : // ...XYO -> ...Y
- POP_X1 : // ...XY -> ...Y
- // !stackEntryPresent2
- stackEntryNecessary3 ?
- stackEntryNecessary0 ? DUP_X1 : // ...YO -> ...OYO
- SWAP : // ...YO -> ...OY
- // !stackEntryNecessary3
- stackEntryNecessary0 ? NOP : // ...YO -> ...YO
- stackEntryPresent0 ? POP : // ...YO -> ...Y
- NOP : // ...Y -> ...Y
- stackEntryPresent1 ?
- stackEntryNecessary2 ?
- stackEntryNecessary3 ?
- stackEntryNecessary0 ? SWAP_POP_DUP_X1 : // ...XYO -> ...OXO
- DUP_X2_POP2 : // ...XYO -> ...OX
- // !stackEntryNecessary3
- stackEntryNecessary0 ? POP_X1 : // ...XYO -> ...XO
- stackEntryPresent0 ? POP2 : // ...XYO -> ...X
- POP : // ...XY -> ...X
- stackEntryPresent2 ?
- stackEntryNecessary3 ?
- stackEntryNecessary0 ? UNSUPPORTED : // ...XYO -> ...OO
- POP2_X1 : // ...XYO -> ...O
- // !stackEntryNecessary3
- stackEntryNecessary0 ? POP2_X1 : // ...XYO -> ...O
- stackEntryPresent0 ? POP3 : // ...XYO -> ...
- POP2 : // ...XY -> ...
- // !stackEntryPresent2
- stackEntryNecessary3 ?
- stackEntryNecessary0 ? SWAP_POP_DUP : // ...YO -> ...OO
- POP_X1 : // ...YO -> ...O
- // !stackEntryNecessary3
- stackEntryNecessary0 ? POP_X1 : // ...YO -> ...O
- stackEntryPresent0 ? POP2 : // ...YO -> ...
- POP : // ...Y -> ...
- // !stackEntryPresent1
- stackEntryNecessary2 ?
- stackEntryNecessary3 ?
- stackEntryNecessary0 ? DUP_X1 : // ...XO -> ...OXO
- SWAP : // ...XO -> ...OX
- // !stackEntryNecessary3
- stackEntryNecessary0 ? NOP : // ...XO -> ...XO
- stackEntryPresent0 ? POP : // ...XO -> ...X
- NOP : // ...X -> ...X
- stackEntryPresent2 ?
- stackEntryNecessary3 ?
- stackEntryNecessary0 ? SWAP_POP_DUP : // ...XO -> ...OO
- POP_X1 : // ...XO -> ...O
- // !stackEntryNecessary3
- stackEntryNecessary0 ? POP_X1 : // ...XO -> ...O
- stackEntryPresent0 ? POP2 : // ...XO -> ...
- POP : // ...X -> ...
- // !stackEntryPresent2
- stackEntryNecessary3 ?
- stackEntryNecessary0 ? DUP : // ...O -> ...OO
- NOP : // ...O -> ...O
- // !stackEntryNecessary3
- stackEntryNecessary0 ? NOP : // ...O -> ...O
- stackEntryPresent0 ? POP : // ...O -> ...
- NOP; // ... -> ...
- }
-
-
- private int fixedDup2(int instructionOffset, int topBefore, int topAfter)
- {
- boolean stackEntryPresent0 = isStackEntryPresentBefore(instructionOffset, topBefore - 0);
- boolean stackEntryPresent1 = isStackEntryPresentBefore(instructionOffset, topBefore - 1);
-
- boolean stackEntryNecessary0 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 0);
- boolean stackEntryNecessary1 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 1);
- boolean stackEntryNecessary2 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 2);
- boolean stackEntryNecessary3 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 3);
-
- return
- stackEntryNecessary3 ?
- stackEntryNecessary2 ?
- stackEntryNecessary1 ?
- stackEntryNecessary0 ? DUP2 : // ...AB -> ...ABAB
- SWAP_DUP_X1 : // ...AB -> ...ABA
- // !stackEntryNecessary1
- stackEntryNecessary0 ? DUP : // ...AB -> ...ABB
- NOP : // ...AB -> ...AB
- // !stackEntryNecessary2
- stackEntryNecessary1 ?
- stackEntryNecessary0 ? SWAP_DUP_X1_SWAP : // ...AB -> ...AAB
- stackEntryPresent0 ? POP_DUP : // ...AB -> ...AA
- DUP : // ...A -> ...AA
- // !stackEntryNecessary1
- stackEntryNecessary0 ? NOP : // ...AB -> ...AB
- stackEntryPresent0 ? POP : // ...AB -> ...A
- NOP : // ...A -> ...A
- // !stackEntryNecessary3
- stackEntryNecessary2 ?
- stackEntryNecessary1 ?
- stackEntryNecessary0 ? DUP_X1 : // ...AB -> ...BAB
- SWAP : // ...AB -> ...BA
- stackEntryPresent1 ?
- stackEntryNecessary0 ? SWAP_POP_DUP : // ...AB -> ...BB
- POP_X1 : // ...AB -> ...B
- // !stackEntryPresent1
- stackEntryNecessary0 ? POP : // ...B -> ...BB
- NOP : // ...B -> ...B
- // !stackEntryNecessary2
- stackEntryNecessary1 ?
- stackEntryNecessary0 ? NOP : // ...AB -> ...AB
- stackEntryPresent0 ? POP : // ...AB -> ...A
- NOP : // ...A -> ...A
- stackEntryPresent1 ?
- stackEntryNecessary0 ? POP_X1 : // ...AB -> ...B
- stackEntryPresent0 ? POP2 : // ...AB -> ...
- POP : // ...A -> ...
- // !stackEntryPresent1
- stackEntryNecessary0 ? NOP : // ...B -> ...B
- stackEntryPresent0 ? POP : // ...B -> ...
- NOP; // ... -> ...
- }
-
-
- private int fixedDup2_x1(int instructionOffset, int topBefore, int topAfter)
- {
- // We're currently assuming the value to be duplicated
- // is a long or a double, taking up two slots, or at
- // least consistent.
- boolean stackEntriesPresent01 = isStackEntriesPresentBefore(instructionOffset, topBefore - 0, topBefore - 1);
- boolean stackEntryPresent2 = isStackEntryPresentBefore( instructionOffset, topBefore - 2);
-
- boolean stackEntriesNecessary01 = isStackEntriesNecessaryAfter(instructionOffset, topAfter - 0, topAfter - 1);
- boolean stackEntryNecessary2 = isStackEntryNecessaryAfter( instructionOffset, topAfter - 2);
- boolean stackEntriesNecessary34 = isStackEntriesNecessaryAfter(instructionOffset, topAfter - 3, topAfter - 4);
-
- // Figure out which stack entries should be moved,
- // copied, or removed.
- return
- stackEntryNecessary2 ?
- stackEntriesNecessary34 ?
- stackEntriesNecessary01 ? DUP2_X1 : // ...XAB -> ...ABXAB
- MOV2_X1 : // ...XAB -> ...ABX
- // !stackEntriesNecessary34
- stackEntriesNecessary01 ? NOP : // ...XAB -> ...XAB
- stackEntriesPresent01 ? POP2 : // ...XAB -> ...X
- NOP : // ...X -> ...X
- stackEntryPresent2 ?
- stackEntriesNecessary34 ?
- stackEntriesNecessary01 ? UNSUPPORTED : // ...XAB -> ...ABAB
- POP_X2 : // ...XAB -> ...AB
- // !stackEntriesNecessary34
- stackEntriesNecessary01 ? DUP2_X1_POP3 : // ...XAB -> ...AB
- stackEntriesPresent01 ? POP3 : // ...XAB -> ...
- POP : // ...X -> ...
- // !stackEntryPresent2
- stackEntriesNecessary34 ?
- stackEntriesNecessary01 ? DUP2 : // ...AB -> ...ABAB
- NOP : // ...AB -> ...AB
- // !stackEntriesNecessary34
- stackEntriesNecessary01 ? NOP : // ...AB -> ...AB
- stackEntriesPresent01 ? POP2 : // ...AB -> ...
- NOP; // ... -> ...
- }
-
-
- private int fixedDup2_x2(int instructionOffset, int topBefore, int topAfter)
- {
- // We're currently assuming the value to be duplicated
- // is a long or a double, taking up two slots, or at
- // least consistent.
- boolean stackEntriesPresent01 = isStackEntriesPresentBefore(instructionOffset, topBefore - 0, topBefore - 1);
- boolean stackEntryPresent2 = isStackEntryPresentBefore( instructionOffset, topBefore - 2);
- boolean stackEntryPresent3 = isStackEntryPresentBefore( instructionOffset, topBefore - 3);
-
- boolean stackEntriesNecessary01 = isStackEntriesNecessaryAfter(instructionOffset, topAfter - 0, topAfter - 1);
- boolean stackEntryNecessary2 = isStackEntryNecessaryAfter( instructionOffset, topAfter - 2);
- boolean stackEntryNecessary3 = isStackEntryNecessaryAfter( instructionOffset, topAfter - 3);
- boolean stackEntriesNecessary45 = isStackEntriesNecessaryAfter(instructionOffset, topAfter - 4, topAfter - 5);
-
- // Figure out which stack entries should be moved,
- // copied, or removed.
- return
- stackEntryNecessary2 ?
- stackEntryNecessary3 ?
- stackEntriesNecessary45 ?
- stackEntriesNecessary01 ? DUP2_X2 : // ...XYAB -> ...ABXYAB
- MOV2_X2 : // ...XYAB -> ...ABXY
- // !stackEntriesNecessary45
- stackEntriesNecessary01 ? NOP : // ...XYAB -> ...XYAB
- stackEntriesPresent01 ? POP2 : // ...XYAB -> ...XY
- NOP : // ...XY -> ...XY
- stackEntryPresent3 ?
- stackEntriesNecessary45 ?
- stackEntriesNecessary01 ? UNSUPPORTED : // ...XYAB -> ...ABYAB
- DUP2_X2_SWAP_POP : // ...XYAB -> ...ABY
- // !stackEntriesNecessary45
- stackEntriesNecessary01 ? POP_X3 : // ...XYAB -> ...YAB
- stackEntriesPresent01 ? POP2_SWAP_POP : // ...XYAB -> ...Y
- POP_X1 : // ...XY -> ...Y
- // !stackEntryPresent3
- stackEntriesNecessary45 ?
- stackEntriesNecessary01 ? DUP2_X1 : // ...YAB -> ...ABYAB
- MOV2_X1 : // ...YAB -> ...ABY
- // !stackEntriesNecessary45
- stackEntriesNecessary01 ? NOP : // ...YAB -> ...YAB
- stackEntriesPresent01 ? POP2 : // ...YAB -> ...Y
- NOP : // ...Y -> ...Y
- stackEntryPresent2 ?
- stackEntryNecessary3 ?
- stackEntriesNecessary45 ?
- stackEntriesNecessary01 ? UNSUPPORTED : // ...XYAB -> ...ABXAB
- DUP2_X2_POP3 : // ...XYAB -> ...ABX
- // !stackEntriesNecessary45
- stackEntriesNecessary01 ? POP_X2 : // ...XYAB -> ...XAB
- stackEntriesPresent01 ? POP3 : // ...XYAB -> ...X
- POP : // ...XY -> ...X
- stackEntryPresent3 ?
- stackEntriesNecessary45 ?
- stackEntriesNecessary01 ? UNSUPPORTED : // ...XYAB -> ...ABAB
- POP2_X2 : // ...XYAB -> ...AB
- // !stackEntriesNecessary45
- stackEntriesNecessary01 ? POP2_X2 : // ...XYAB -> ...AB
- stackEntriesPresent01 ? POP4 : // ...XYAB -> ...
- POP2 : // ...XY -> ...
- // !stackEntryPresent3
- stackEntriesNecessary45 ?
- stackEntriesNecessary01 ? UNSUPPORTED : // ...YAB -> ...ABAB
- POP_X2 : // ...YAB -> ...AB
- // !stackEntriesNecessary45
- stackEntriesNecessary01 ? POP_X2 : // ...YAB -> ...AB
- stackEntriesPresent01 ? POP3 : // ...YAB -> ...
- POP : // ...Y -> ...
- // !stackEntryPresent2
- stackEntryNecessary3 ?
- stackEntriesNecessary45 ?
- stackEntriesNecessary01 ? DUP2_X1 : // ...XAB -> ...ABXAB
- MOV2_X1 : // ...XAB -> ...ABX
- // !stackEntriesNecessary45
- stackEntriesNecessary01 ? NOP : // ...XAB -> ...XAB
- stackEntriesPresent01 ? POP2 : // ...XAB -> ...X
- NOP : // ...X -> ...X
- stackEntryPresent3 ?
- stackEntriesNecessary45 ?
- stackEntriesNecessary01 ? UNSUPPORTED : // ...XAB -> ...ABAB
- POP_X2 : // ...XAB -> ...AB
- // !stackEntriesNecessary45
- stackEntriesNecessary01 ? POP_X2 : // ...XAB -> ...AB
- stackEntriesPresent01 ? POP3 : // ...XAB -> ...
- POP : // ...X -> ...
- // !stackEntryPresent3
- stackEntriesNecessary45 ?
- stackEntriesNecessary01 ? DUP2 : // ...AB -> ...ABAB
- NOP : // ...AB -> ...AB
- // !stackEntriesNecessary45
- stackEntriesNecessary01 ? NOP : // ...AB -> ...AB
- stackEntriesPresent01 ? POP2 : // ...AB -> ...
- NOP; // ... -> ...
- }
-
-
- private int fixedSwap(int instructionOffset, int topBefore, int topAfter)
- {
- boolean stackEntryPresent0 = isStackEntryPresentBefore(instructionOffset, topBefore - 0);
- boolean stackEntryPresent1 = isStackEntryPresentBefore(instructionOffset, topBefore - 1);
-
- boolean stackEntryNecessary0 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 0);
- boolean stackEntryNecessary1 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 1);
-
- // Figure out which stack entries should be moved
- // or removed.
- return
- stackEntryNecessary0 ?
- stackEntryNecessary1 ? SWAP : // ...AB -> ...BA
- stackEntryPresent0 ? POP : // ...AB -> ...A
- NOP : // ...A -> ...A
- stackEntryPresent1 ? POP_X1 : // ...AB -> ...B
- NOP; // ...B -> ...B
- }
- }
-
-
- // Small utility methods.
-
- /**
- * Marks the producing 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.
- */
- private void markVariableProducers(int consumerOffset,
- int variableIndex)
- {
- InstructionOffsetValue producerOffsets =
- partialEvaluator.getVariablesBefore(consumerOffset).getProducerValue(variableIndex).instructionOffsetValue();
-
- if (producerOffsets != null)
- {
- int offsetCount = producerOffsets.instructionOffsetCount();
- for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++)
- {
- // Make sure the variable and the instruction are marked
- // at the producing offset.
- int offset = producerOffsets.instructionOffset(offsetIndex);
-
- markInstruction(offset);
- }
- }
- }
-
-
- /**
- * 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 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();
-
- 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)
- {
- markVariableInitializersAfter(producerOffset, variableIndex);
- }
- }
- }
-
-
- /**
- * 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 ");
-
- 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);
- }
- }
- }
-
-
- /**
- * Marks the stack entries and their producing instructions of the
- * consumer at the given offset.
- * @param clazz the containing class.
- * @param consumerOffset the offset of the consumer.
- * @param consumer the consumer of the stack entries.
- */
- private void markStackProducers(Clazz clazz,
- int consumerOffset,
- Instruction consumer)
- {
- TracedStack tracedStack =
- partialEvaluator.getStackBefore(consumerOffset);
-
- int stackSize = tracedStack.size();
-
- // Mark the producers of the popped values.
- int popCount = consumer.stackPopCount(clazz);
- for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++)
- {
- markStackEntryProducers(consumerOffset, stackIndex);
- }
- }
-
-
- /**
- * Marks the stack entry and the corresponding producing instructions
- * of the consumer at the given offset, if the stack entry of the
- * consumer is marked.
- * @param consumerOffset the offset of the consumer.
- * @param consumerTopStackIndex the index of the stack entry to be checked
- * (counting from the top).
- * @param producerTopStackIndex the index of the stack entry to be marked
- * (counting from the top).
- */
- private void conditionallyMarkStackEntryProducers(int consumerOffset,
- int consumerTopStackIndex,
- int producerTopStackIndex)
- {
- int consumerBottomStackIndex = partialEvaluator.getStackAfter(consumerOffset).size() - consumerTopStackIndex - 1;
-
- if (isStackEntryNecessaryAfter(consumerOffset, consumerBottomStackIndex))
- {
- int producerBottomStackIndex = partialEvaluator.getStackBefore(consumerOffset).size() - producerTopStackIndex - 1;
-
- markStackEntryProducers(consumerOffset, producerBottomStackIndex);
- }
- }
-
-
- /**
- * Marks the stack entry and the corresponding producing instructions
- * of the consumer at the given offset.
- * @param consumerOffset the offset of the consumer.
- * @param stackIndex the index of the stack entry to be marked
- * (counting from the bottom).
- */
- private void markStackEntryProducers(int consumerOffset,
- int stackIndex)
- {
- if (!isStackSimplifiedBefore(consumerOffset, stackIndex))
- {
- markStackEntryProducers(partialEvaluator.getStackBefore(consumerOffset).getBottomProducerValue(stackIndex).instructionOffsetValue(),
- stackIndex);
- }
- }
-
-
- /**
- * Marks the stack entry and its producing instructions at the given
- * offsets.
- * @param producerOffsets the offsets of the producers to be marked.
- * @param stackIndex the index of the stack entry to be marked
- * (counting from the bottom).
- */
- private void markStackEntryProducers(InstructionOffsetValue producerOffsets,
- int stackIndex)
- {
- if (producerOffsets != null)
- {
- int offsetCount = producerOffsets.instructionOffsetCount();
- for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++)
- {
- // Make sure the stack entry and the instruction are marked
- // at the producing offset.
- int offset = producerOffsets.instructionOffset(offsetIndex);
-
- markStackEntryAfter(offset, stackIndex);
- markInstruction(offset);
- }
- }
- }
-
-
- /**
- * Marks the stack entry and its initializing instruction
- * ('invokespecial *.<init>') for the given 'new' instruction offset.
- * @param newInstructionOffset the offset of the 'new' instruction.
- */
- private void markInitialization(int newInstructionOffset)
- {
- int initializationOffset =
- partialEvaluator.initializationOffset(newInstructionOffset);
-
- TracedStack tracedStack =
- partialEvaluator.getStackAfter(newInstructionOffset);
-
- markStackEntryAfter(initializationOffset, tracedStack.size() - 1);
- markInstruction(initializationOffset);
- }
-
-
- /**
- * Marks the branch instructions of straddling branches, if they straddle
- * some code that has been marked.
- * @param instructionOffset the offset of the branch origin or branch target.
- * @param branchOffsets the offsets of the straddling branch targets
- * or branch origins.
- * @param isPointingToTargets <code>true</code> if the above offsets are
- * branch targets, <code>false</code> if they
- * are branch origins.
- */
- private void markStraddlingBranches(int instructionOffset,
- InstructionOffsetValue branchOffsets,
- boolean isPointingToTargets)
- {
- if (branchOffsets != null)
- {
- // Loop over all branch offsets.
- int branchCount = branchOffsets.instructionOffsetCount();
- for (int branchIndex = 0; branchIndex < branchCount; branchIndex++)
- {
- // Is the branch straddling forward any necessary instructions?
- int branchOffset = branchOffsets.instructionOffset(branchIndex);
-
- // Is the offset pointing to a branch origin or to a branch target?
- if (isPointingToTargets)
- {
- markStraddlingBranch(instructionOffset,
- branchOffset,
- instructionOffset,
- branchOffset);
- }
- else
- {
- markStraddlingBranch(instructionOffset,
- branchOffset,
- branchOffset,
- instructionOffset);
- }
- }
- }
- }
-
-
- private void markStraddlingBranch(int instructionOffsetStart,
- int instructionOffsetEnd,
- int branchOrigin,
- int branchTarget)
- {
- if (!isInstructionNecessary(branchOrigin) &&
- isAnyInstructionNecessary(instructionOffsetStart, instructionOffsetEnd))
- {
- if (DEBUG) System.out.print("["+branchOrigin+"->"+branchTarget+"]");
-
- // Mark the branch instruction.
- markInstruction(branchOrigin);
- }
- }
-
-
- /**
- * Pushes a specified type of stack entry before or at the given offset.
- * The instruction is marked as necessary.
- */
- private void insertPushInstructions(int offset,
- boolean replace,
- boolean before,
- int computationalType)
- {
- // Mark this instruction.
- markInstruction(offset);
-
- // Create a simple push instrucion.
- Instruction replacementInstruction =
- new SimpleInstruction(pushOpcode(computationalType));
-
- if (DEBUG) System.out.println(": "+replacementInstruction.toString(offset));
-
- // Replace or insert the push instruction.
- insertInstruction(offset, replace, before, replacementInstruction);
- }
-
-
- /**
- * Returns the opcode of a push instruction corresponding to the given
- * computational type.
- * @param computationalType the computational type to be pushed on the stack.
- */
- private byte pushOpcode(int computationalType)
- {
- switch (computationalType)
- {
- case Value.TYPE_INTEGER: return InstructionConstants.OP_ICONST_0;
- case Value.TYPE_LONG: return InstructionConstants.OP_LCONST_0;
- case Value.TYPE_FLOAT: return InstructionConstants.OP_FCONST_0;
- case Value.TYPE_DOUBLE: return InstructionConstants.OP_DCONST_0;
- case Value.TYPE_REFERENCE:
- case Value.TYPE_INSTRUCTION_OFFSET: return InstructionConstants.OP_ACONST_NULL;
- }
-
- throw new IllegalArgumentException("No push opcode for computational type ["+computationalType+"]");
- }
-
-
- /**
- * 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,
- boolean before,
- int popCount)
- {
- // Mark this instruction.
- markInstruction(offset);
-
- switch (popCount)
- {
- case 1:
- {
- // Replace or insert a single pop instruction.
- Instruction popInstruction =
- new SimpleInstruction(InstructionConstants.OP_POP);
-
- insertInstruction(offset, replace, before, popInstruction);
- break;
- }
- case 2:
- {
- // Replace or insert a single pop2 instruction.
- Instruction popInstruction =
- new SimpleInstruction(InstructionConstants.OP_POP2);
-
- insertInstruction(offset, replace, before, popInstruction);
- break;
- }
- default:
- {
- // Replace or insert the specified number of pop instructions.
- Instruction[] popInstructions =
- new Instruction[popCount / 2 + popCount % 2];
-
- Instruction popInstruction =
- new SimpleInstruction(InstructionConstants.OP_POP2);
-
- for (int index = 0; index < popCount / 2; index++)
- {
- popInstructions[index] = popInstruction;
- }
-
- if (popCount % 2 == 1)
- {
- popInstruction =
- new SimpleInstruction(InstructionConstants.OP_POP);
-
- popInstructions[popCount / 2] = popInstruction;
- }
-
- insertInstructions(offset,
- replace,
- before,
- popInstruction,
- popInstructions);
- break;
- }
- }
- }
-
-
- /**
- * 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++)
- {
- 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 < instructions.length; index++)
- {
- if (extraAddedInstructionVisitor != null)
- {
- instructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor);
- }
- }
- }
- }
-
-
- /**
- * Replaces the instruction at a given offset by a static invocation.
- */
- private void replaceByStaticInvocation(Clazz clazz,
- int offset,
- ConstantInstruction constantInstruction)
- {
- // Remember the replacement instruction.
- Instruction replacementInstruction =
- new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC,
- constantInstruction.constantIndex);
-
- if (DEBUG) System.out.println(" Replacing by static invocation "+constantInstruction.toString(offset)+" -> "+replacementInstruction.toString());
-
- codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
- }
-
-
- /**
- * Replaces the given instruction by an infinite loop.
- */
- private void replaceByInfiniteLoop(Clazz clazz,
- int offset)
- {
- if (DEBUG) System.out.println(" Inserting infinite loop at ["+offset+"]");
-
- // Mark the instruction.
- markInstruction(offset);
-
- // Replace the instruction by an infinite loop.
- Instruction replacementInstruction =
- new BranchInstruction(InstructionConstants.OP_GOTO, 0);
-
- codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
- }
-
-
- // Small utility methods.
-
- /**
- * Returns whether the given instruction is a dup or swap instruction
- * (dup, dup_x1, dup_x2, dup2, dup2_x1, dup2_x2, swap).
- */
- private boolean isDupOrSwap(Instruction instruction)
- {
- return instruction.opcode >= InstructionConstants.OP_DUP &&
- instruction.opcode <= InstructionConstants.OP_SWAP;
- }
-
-
- /**
- * Returns whether the given instruction is a pop instruction
- * (pop, pop2).
- */
- private boolean isPop(Instruction instruction)
- {
- return instruction.opcode == InstructionConstants.OP_POP ||
- instruction.opcode == InstructionConstants.OP_POP2;
- }
-
-
- /**
- * Returns whether any traced but unnecessary instruction between the two
- * given offsets is branching over the second given offset.
- */
- private boolean isAnyUnnecessaryInstructionBranchingOver(int instructionOffset1,
- int instructionOffset2)
- {
- for (int offset = instructionOffset1; offset < instructionOffset2; offset++)
- {
- // Is it a traced but unmarked straddling branch?
- if (partialEvaluator.isTraced(offset) &&
- !isInstructionNecessary(offset) &&
- isAnyLargerThan(partialEvaluator.branchTargets(offset),
- instructionOffset2))
- {
- return true;
- }
- }
-
- return false;
- }
-
-
- /**
- * Returns whether all of the given instruction offsets (at least one)
- * are smaller than or equal to the given offset.
- */
- private boolean isAllSmallerThanOrEqual(InstructionOffsetValue instructionOffsets,
- int instructionOffset)
- {
- if (instructionOffsets != null)
- {
- // Loop over all instruction offsets.
- int branchCount = instructionOffsets.instructionOffsetCount();
- if (branchCount > 0)
- {
- for (int branchIndex = 0; branchIndex < branchCount; branchIndex++)
- {
- // Is the offset larger than the reference offset?
- if (instructionOffsets.instructionOffset(branchIndex) > instructionOffset)
- {
- return false;
- }
- }
-
- return true;
- }
- }
-
- return false;
- }
-
-
- /**
- * Returns whether any of the given instruction offsets (at least one)
- * is larger than the given offset.
- */
- private boolean isAnyLargerThan(InstructionOffsetValue instructionOffsets,
- int instructionOffset)
- {
- if (instructionOffsets != null)
- {
- // Loop over all instruction offsets.
- int branchCount = instructionOffsets.instructionOffsetCount();
- if (branchCount > 0)
- {
- for (int branchIndex = 0; branchIndex < branchCount; branchIndex++)
- {
- // Is the offset larger than the reference offset?
- if (instructionOffsets.instructionOffset(branchIndex) > instructionOffset)
- {
- return true;
- }
- }
- }
- }
-
- return false;
- }
-
-
- /**
- * Initializes the necessary data structure.
- */
- private void initializeNecessary(CodeAttribute codeAttribute)
- {
- int codeLength = codeAttribute.u4codeLength;
- int maxLocals = codeAttribute.u2maxLocals;
- int maxStack = codeAttribute.u2maxStack;
-
- // Create new arrays for storing information at each instruction offset.
- if (stacksNecessaryAfter.length < codeLength ||
- stacksNecessaryAfter[0].length < maxStack)
- {
- stacksNecessaryAfter = new boolean[codeLength][maxStack];
- }
- else
- {
- for (int offset = 0; offset < codeLength; offset++)
- {
- Arrays.fill(stacksNecessaryAfter[offset], 0, maxStack, false);
- }
- }
-
- if (stacksSimplifiedBefore.length < codeLength ||
- stacksSimplifiedBefore[0].length < maxStack)
- {
- stacksSimplifiedBefore = new boolean[codeLength][maxStack];
- }
- else
- {
- for (int offset = 0; offset < codeLength; offset++)
- {
- Arrays.fill(stacksSimplifiedBefore[offset], 0, maxStack, false);
- }
- }
-
- if (instructionsNecessary.length < codeLength)
- {
- instructionsNecessary = new boolean[codeLength];
- }
- else
- {
- Arrays.fill(instructionsNecessary, 0, codeLength, false);
- }
- }
-
-
- /**
- * 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 = simplePartialEvaluator.getVariablesBefore(instructionOffset).getValue(variableIndex);
- if (valueBefore == null)
- {
- return true;
- }
-
- // Is the computational type different now?
- Value valueAfter = simplePartialEvaluator.getVariablesAfter(instructionOffset).getValue(variableIndex);
- if (valueAfter.computationalType() != valueBefore.computationalType())
- {
- return true;
- }
-
- // Is the reference type different now?
- if (valueAfter.computationalType() == Value.TYPE_REFERENCE &&
- (valueAfter.referenceValue().isNull() == Value.ALWAYS ||
- !valueAfter.referenceValue().getType().equals(valueBefore.referenceValue().getType())))
- {
- return true;
- }
-
- // Was the producer an argument (which may be removed)?
- Value producersBefore = simplePartialEvaluator.getVariablesBefore(instructionOffset).getProducerValue(variableIndex);
- return producersBefore.instructionOffsetValue().instructionOffsetCount() == 1 &&
- producersBefore.instructionOffsetValue().instructionOffset(0) == PartialEvaluator.AT_METHOD_ENTRY;
- }
-
-
- /**
- * 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)
- {
- if (!isStackEntryNecessaryAfter(instructionOffset, stackIndex))
- {
- if (DEBUG) System.out.print("["+instructionOffset+".s"+stackIndex+"],");
-
- stacksNecessaryAfter[instructionOffset][stackIndex] = true;
-
- if (maxMarkedOffset < instructionOffset)
- {
- maxMarkedOffset = instructionOffset;
- }
- }
- }
-
-
-
- /**
- * Returns whether the stack specified entries before the given offset are
- * present.
- */
- private boolean isStackEntriesPresentBefore(int instructionOffset,
- int stackIndex1,
- int stackIndex2)
- {
- boolean present1 = isStackEntryPresentBefore(instructionOffset, stackIndex1);
- boolean present2 = isStackEntryPresentBefore(instructionOffset, stackIndex2);
-
-// if (present1 ^ present2)
-// {
-// throw new UnsupportedOperationException("Can't handle partial use of dup2 instructions");
-// }
-
- return present1 || present2;
- }
-
-
- /**
- * Returns whether the specified stack entry before the given offset is
- * present.
- * @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 isStackEntryPresentBefore(int instructionOffset,
- int stackIndex)
- {
- TracedStack tracedStack =
- partialEvaluator.getStackBefore(instructionOffset);
-
- InstructionOffsetValue producerOffsets =
- tracedStack.getBottomProducerValue(stackIndex).instructionOffsetValue();
-
- return isAnyStackEntryNecessaryAfter(producerOffsets, stackIndex);
- }
-
-
- /**
- * Returns whether the stack specified entries after the given offset are
- * necessary.
- */
- private boolean isStackEntriesNecessaryAfter(int instructionOffset,
- int stackIndex1,
- int stackIndex2)
- {
- boolean present1 = isStackEntryNecessaryAfter(instructionOffset, stackIndex1);
- boolean present2 = isStackEntryNecessaryAfter(instructionOffset, stackIndex2);
-
-// if (present1 ^ present2)
-// {
-// throw new UnsupportedOperationException("Can't handle partial use of dup2 instructions");
-// }
-
- return present1 || present2;
- }
-
-
- /**
- * 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)
- {
- int offsetCount = instructionOffsets.instructionOffsetCount();
-
- for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++)
- {
- if (isStackEntryNecessaryAfter(instructionOffsets.instructionOffset(offsetIndex), stackIndex))
- {
- return true;
- }
- }
-
- return false;
- }
-
-
- /**
- * Returns whether the specified stack entry after the given offset is
- * 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)
- {
- return instructionOffset == PartialEvaluator.AT_CATCH_ENTRY ||
- stacksNecessaryAfter[instructionOffset][stackIndex];
- }
-
-
- private void markStackSimplificationBefore(int instructionOffset,
- int stackIndex)
- {
- stacksSimplifiedBefore[instructionOffset][stackIndex] = true;
- }
-
-
- private boolean isStackSimplifiedBefore(int instructionOffset,
- int stackIndex)
- {
- return stacksSimplifiedBefore[instructionOffset][stackIndex];
- }
-
-
- private void markInstruction(int instructionOffset)
- {
- if (!isInstructionNecessary(instructionOffset))
- {
- if (DEBUG) System.out.print(instructionOffset+",");
-
- instructionsNecessary[instructionOffset] = true;
-
- if (maxMarkedOffset < instructionOffset)
- {
- maxMarkedOffset = instructionOffset;
- }
- }
- }
-
-
- private boolean isAnyInstructionNecessary(int instructionOffset1,
- int instructionOffset2)
- {
- for (int instructionOffset = instructionOffset1;
- instructionOffset < instructionOffset2;
- instructionOffset++)
- {
- if (isInstructionNecessary(instructionOffset))
- {
- return true;
- }
- }
-
- return false;
- }
-
-
- /**
- * Returns the highest offset of an instruction that has been marked as
- * necessary, before the given offset.
- */
- private int lastNecessaryInstructionOffset(int instructionOffset)
- {
- for (int offset = instructionOffset-1; offset >= 0; offset--)
- {
- if (isInstructionNecessary(instructionOffset))
- {
- return offset;
- }
- }
-
- return 0;
- }
-
-
- private boolean isInstructionNecessary(int instructionOffset)
- {
- return instructionOffset == PartialEvaluator.AT_METHOD_ENTRY ||
- instructionsNecessary[instructionOffset];
- }
-}
diff --git a/src/proguard/optimize/evaluation/EvaluationSimplifier.java b/src/proguard/optimize/evaluation/EvaluationSimplifier.java
deleted file mode 100644
index 8187342..0000000
--- a/src/proguard/optimize/evaluation/EvaluationSimplifier.java
+++ /dev/null
@@ -1,1360 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * 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
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.optimize.evaluation;
-
-import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.visitor.AttributeVisitor;
-import proguard.classfile.editor.*;
-import proguard.classfile.instruction.*;
-import proguard.classfile.instruction.visitor.InstructionVisitor;
-import proguard.classfile.util.*;
-import proguard.classfile.visitor.ClassPrinter;
-import proguard.evaluation.TracedVariables;
-import proguard.evaluation.value.*;
-import proguard.optimize.info.SideEffectInstructionChecker;
-
-import java.util.Arrays;
-
-/**
- * This AttributeVisitor simplifies the code attributes that it visits, based
- * on partial evaluation.
- *
- * @author Eric Lafortune
- */
-public class EvaluationSimplifier
-extends SimplifiedVisitor
-implements AttributeVisitor,
- InstructionVisitor
-{
- private static final int POS_ZERO_FLOAT_BITS = Float.floatToIntBits(0.0f);
- private static final long POS_ZERO_DOUBLE_BITS = Double.doubleToLongBits(0.0);
-
- //*
- private static final boolean DEBUG = false;
- /*/
- private static boolean DEBUG = System.getProperty("es") != null;
- //*/
-
- private final InstructionVisitor extraInstructionVisitor;
-
- private final PartialEvaluator partialEvaluator;
- private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true, true);
- private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false, true);
-
-
- /**
- * Creates a new EvaluationSimplifier.
- */
- public EvaluationSimplifier()
- {
- this(new PartialEvaluator(), null);
- }
-
-
- /**
- * Creates a new EvaluationSimplifier.
- * @param partialEvaluator the partial evaluator that will
- * execute the code and provide
- * information about the results.
- * @param extraInstructionVisitor an optional extra visitor for all
- * simplified instructions.
- */
- public EvaluationSimplifier(PartialEvaluator partialEvaluator,
- InstructionVisitor extraInstructionVisitor)
- {
- this.partialEvaluator = partialEvaluator;
- this.extraInstructionVisitor = extraInstructionVisitor;
- }
-
-
- // Implementations for AttributeVisitor.
-
- public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
-
-
- public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
-// DEBUG =
-// clazz.getName().equals("abc/Def") &&
-// method.getName(clazz).equals("abc");
-
- // TODO: Remove this when the evaluation simplifier has stabilized.
- // Catch any unexpected exceptions from the actual visiting method.
- try
- {
- // Process the code.
- visitCodeAttribute0(clazz, method, codeAttribute);
- }
- catch (RuntimeException ex)
- {
- System.err.println("Unexpected error while simplifying instructions after partial evaluation:");
- System.err.println(" Class = ["+clazz.getName()+"]");
- System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]");
- System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")");
- System.err.println("Not optimizing this method");
-
- if (DEBUG)
- {
- method.accept(clazz, new ClassPrinter());
-
- throw ex;
- }
- }
- }
-
-
- public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
- if (DEBUG)
- {
- System.out.println();
- System.out.println("EvaluationSimplifier ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]");
- }
-
- // Evaluate the method.
- partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
-
- int codeLength = codeAttribute.u4codeLength;
-
- // Reset the code changes.
- codeAttributeEditor.reset(codeLength);
-
- // Replace any instructions that can be simplified.
- for (int offset = 0; offset < codeLength; offset++)
- {
- if (partialEvaluator.isTraced(offset))
- {
- Instruction instruction = InstructionFactory.create(codeAttribute.code,
- offset);
-
- instruction.accept(clazz, method, codeAttribute, offset, this);
- }
- }
-
- // Apply all accumulated changes to the code.
- codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
- }
-
-
- // Implementations for InstructionVisitor.
-
- public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
- {
- switch (simpleInstruction.opcode)
- {
- case InstructionConstants.OP_IALOAD:
- case InstructionConstants.OP_BALOAD:
- case InstructionConstants.OP_CALOAD:
- case InstructionConstants.OP_SALOAD:
- case InstructionConstants.OP_IADD:
- case InstructionConstants.OP_ISUB:
- case InstructionConstants.OP_IMUL:
- case InstructionConstants.OP_IDIV:
- case InstructionConstants.OP_IREM:
- case InstructionConstants.OP_INEG:
- case InstructionConstants.OP_ISHL:
- case InstructionConstants.OP_ISHR:
- case InstructionConstants.OP_IUSHR:
- case InstructionConstants.OP_IAND:
- case InstructionConstants.OP_IOR:
- case InstructionConstants.OP_IXOR:
- case InstructionConstants.OP_L2I:
- case InstructionConstants.OP_F2I:
- case InstructionConstants.OP_D2I:
- case InstructionConstants.OP_I2B:
- case InstructionConstants.OP_I2C:
- case InstructionConstants.OP_I2S:
- case InstructionConstants.OP_ARRAYLENGTH:
- replaceIntegerPushInstruction(clazz, offset, simpleInstruction);
- break;
-
- case InstructionConstants.OP_LALOAD:
- case InstructionConstants.OP_LADD:
- case InstructionConstants.OP_LSUB:
- case InstructionConstants.OP_LMUL:
- case InstructionConstants.OP_LDIV:
- case InstructionConstants.OP_LREM:
- case InstructionConstants.OP_LNEG:
- case InstructionConstants.OP_LSHL:
- case InstructionConstants.OP_LSHR:
- case InstructionConstants.OP_LUSHR:
- case InstructionConstants.OP_LAND:
- case InstructionConstants.OP_LOR:
- case InstructionConstants.OP_LXOR:
- case InstructionConstants.OP_I2L:
- case InstructionConstants.OP_F2L:
- case InstructionConstants.OP_D2L:
- replaceLongPushInstruction(clazz, offset, simpleInstruction);
- break;
-
- case InstructionConstants.OP_FALOAD:
- case InstructionConstants.OP_FADD:
- case InstructionConstants.OP_FSUB:
- case InstructionConstants.OP_FMUL:
- case InstructionConstants.OP_FDIV:
- case InstructionConstants.OP_FREM:
- case InstructionConstants.OP_FNEG:
- case InstructionConstants.OP_I2F:
- case InstructionConstants.OP_L2F:
- case InstructionConstants.OP_D2F:
- replaceFloatPushInstruction(clazz, offset, simpleInstruction);
- break;
-
- case InstructionConstants.OP_DALOAD:
- case InstructionConstants.OP_DADD:
- case InstructionConstants.OP_DSUB:
- case InstructionConstants.OP_DMUL:
- case InstructionConstants.OP_DDIV:
- case InstructionConstants.OP_DREM:
- case InstructionConstants.OP_DNEG:
- case InstructionConstants.OP_I2D:
- case InstructionConstants.OP_L2D:
- case InstructionConstants.OP_F2D:
- replaceDoublePushInstruction(clazz, offset, simpleInstruction);
- break;
-
- case InstructionConstants.OP_AALOAD:
- replaceReferencePushInstruction(clazz, offset, simpleInstruction);
- break;
- }
- }
-
-
- public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
- {
- int variableIndex = variableInstruction.variableIndex;
-
- switch (variableInstruction.opcode)
- {
- case InstructionConstants.OP_ILOAD:
- case InstructionConstants.OP_ILOAD_0:
- case InstructionConstants.OP_ILOAD_1:
- case InstructionConstants.OP_ILOAD_2:
- case InstructionConstants.OP_ILOAD_3:
- replaceIntegerPushInstruction(clazz, offset, variableInstruction, variableIndex);
- break;
-
- case InstructionConstants.OP_LLOAD:
- case InstructionConstants.OP_LLOAD_0:
- case InstructionConstants.OP_LLOAD_1:
- case InstructionConstants.OP_LLOAD_2:
- case InstructionConstants.OP_LLOAD_3:
- replaceLongPushInstruction(clazz, offset, variableInstruction, variableIndex);
- break;
-
- case InstructionConstants.OP_FLOAD:
- case InstructionConstants.OP_FLOAD_0:
- case InstructionConstants.OP_FLOAD_1:
- case InstructionConstants.OP_FLOAD_2:
- case InstructionConstants.OP_FLOAD_3:
- replaceFloatPushInstruction(clazz, offset, variableInstruction, variableIndex);
- break;
-
- case InstructionConstants.OP_DLOAD:
- case InstructionConstants.OP_DLOAD_0:
- case InstructionConstants.OP_DLOAD_1:
- case InstructionConstants.OP_DLOAD_2:
- case InstructionConstants.OP_DLOAD_3:
- replaceDoublePushInstruction(clazz, offset, variableInstruction, variableIndex);
- break;
-
- case InstructionConstants.OP_ALOAD:
- case InstructionConstants.OP_ALOAD_0:
- case InstructionConstants.OP_ALOAD_1:
- case InstructionConstants.OP_ALOAD_2:
- case InstructionConstants.OP_ALOAD_3:
- replaceReferencePushInstruction(clazz, offset, variableInstruction);
- break;
-
- case InstructionConstants.OP_ASTORE:
- case InstructionConstants.OP_ASTORE_0:
- case InstructionConstants.OP_ASTORE_1:
- case InstructionConstants.OP_ASTORE_2:
- case InstructionConstants.OP_ASTORE_3:
- deleteReferencePopInstruction(clazz, offset, variableInstruction);
- break;
-
- case InstructionConstants.OP_RET:
- replaceBranchInstruction(clazz, offset, variableInstruction);
- break;
- }
- }
-
-
- public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
- {
- switch (constantInstruction.opcode)
- {
- case InstructionConstants.OP_GETSTATIC:
- case InstructionConstants.OP_GETFIELD:
- replaceAnyPushInstruction(clazz, offset, constantInstruction);
- break;
-
- case InstructionConstants.OP_INVOKEVIRTUAL:
- case InstructionConstants.OP_INVOKESPECIAL:
- case InstructionConstants.OP_INVOKESTATIC:
- case InstructionConstants.OP_INVOKEINTERFACE:
- if (constantInstruction.stackPushCount(clazz) > 0 &&
- !sideEffectInstructionChecker.hasSideEffects(clazz,
- method,
- codeAttribute,
- offset,
- constantInstruction))
- {
- replaceAnyPushInstruction(clazz, offset, constantInstruction);
- }
-
- break;
-
- case InstructionConstants.OP_CHECKCAST:
- replaceReferencePushInstruction(clazz, offset, constantInstruction);
- break;
- }
- }
-
-
- public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
- {
- switch (branchInstruction.opcode)
- {
- case InstructionConstants.OP_GOTO:
- case InstructionConstants.OP_GOTO_W:
- // Don't replace unconditional branches.
- break;
-
- case InstructionConstants.OP_JSR:
- case InstructionConstants.OP_JSR_W:
- replaceJsrInstruction(clazz, offset, branchInstruction);
- break;
-
- default:
- replaceBranchInstruction(clazz, offset, branchInstruction);
- break;
- }
- }
-
-
- public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction)
- {
- // First try to simplify it to a simple branch.
- replaceBranchInstruction(clazz, offset, tableSwitchInstruction);
-
- // Otherwise try to simplify simple enum switches.
- if (!codeAttributeEditor.isModified(offset))
- {
- replaceSimpleEnumSwitchInstruction(clazz,
- codeAttribute,
- offset,
- tableSwitchInstruction);
-
- // Otherwise make sure all branch targets are valid.
- if (!codeAttributeEditor.isModified(offset))
- {
- cleanUpSwitchInstruction(clazz, offset, tableSwitchInstruction);
-
- trimSwitchInstruction(clazz, offset, tableSwitchInstruction);
- }
- }
- }
-
-
- public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
- {
- // First try to simplify it to a simple branch.
- replaceBranchInstruction(clazz, offset, lookUpSwitchInstruction);
-
- // Otherwise try to simplify simple enum switches.
- if (!codeAttributeEditor.isModified(offset))
- {
- replaceSimpleEnumSwitchInstruction(clazz,
- codeAttribute,
- offset,
- lookUpSwitchInstruction);
-
- // Otherwise make sure all branch targets are valid.
- if (!codeAttributeEditor.isModified(offset))
- {
- cleanUpSwitchInstruction(clazz, offset, lookUpSwitchInstruction);
-
- trimSwitchInstruction(clazz, offset, lookUpSwitchInstruction);
- }
- }
- }
-
-
- // Small utility methods.
-
- /**
- * Replaces the push instruction at the given offset by a simpler push
- * instruction, if possible.
- */
- private void replaceAnyPushInstruction(Clazz clazz,
- int offset,
- Instruction instruction)
- {
- Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0);
- if (pushedValue.isParticular())
- {
- switch (pushedValue.computationalType())
- {
- case Value.TYPE_INTEGER:
- replaceIntegerPushInstruction(clazz, offset, instruction);
- break;
- case Value.TYPE_LONG:
- replaceLongPushInstruction(clazz, offset, instruction);
- break;
- case Value.TYPE_FLOAT:
- replaceFloatPushInstruction(clazz, offset, instruction);
- break;
- case Value.TYPE_DOUBLE:
- replaceDoublePushInstruction(clazz, offset, instruction);
- break;
- case Value.TYPE_REFERENCE:
- replaceReferencePushInstruction(clazz, offset, instruction);
- break;
- }
- }
- }
-
-
- /**
- * Replaces the integer pushing instruction at the given offset by a simpler
- * push instruction, if possible.
- */
- private void replaceIntegerPushInstruction(Clazz clazz,
- int offset,
- Instruction instruction)
- {
- replaceIntegerPushInstruction(clazz,
- offset,
- instruction,
- partialEvaluator.getVariablesBefore(offset).size());
- }
-
-
- /**
- * Replaces the integer pushing instruction at the given offset by a simpler
- * push instruction, if possible.
- */
- private void replaceIntegerPushInstruction(Clazz clazz,
- int offset,
- Instruction instruction,
- int maxVariableIndex)
- {
- Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0);
- if (pushedValue.isParticular())
- {
- // Push a constant instead.
- int value = pushedValue.integerValue().value();
- if ((short)value == value)
- {
- replaceConstantPushInstruction(clazz,
- offset,
- instruction,
- InstructionConstants.OP_SIPUSH,
- value);
- }
- else
- {
- ConstantPoolEditor constantPoolEditor =
- new ConstantPoolEditor((ProgramClass)clazz);
-
- Instruction replacementInstruction =
- new ConstantInstruction(InstructionConstants.OP_LDC,
- constantPoolEditor.addIntegerConstant(value));
-
- replaceInstruction(clazz, offset, instruction, replacementInstruction);
- }
- }
- else if (pushedValue.isSpecific())
- {
- // Load an equivalent lower-numbered variable instead, if any.
- TracedVariables variables = partialEvaluator.getVariablesBefore(offset);
- for (int variableIndex = 0; variableIndex < maxVariableIndex; variableIndex++)
- {
- if (pushedValue.equals(variables.load(variableIndex)))
- {
- replaceVariablePushInstruction(clazz,
- offset,
- instruction,
- InstructionConstants.OP_ILOAD,
- variableIndex);
- break;
- }
- }
- }
- }
-
-
- /**
- * Replaces the long pushing instruction at the given offset by a simpler
- * push instruction, if possible.
- */
- private void replaceLongPushInstruction(Clazz clazz,
- int offset,
- Instruction instruction)
- {
- replaceLongPushInstruction(clazz,
- offset,
- instruction,
- partialEvaluator.getVariablesBefore(offset).size());
- }
-
-
- /**
- * Replaces the long pushing instruction at the given offset by a simpler
- * push instruction, if possible.
- */
- private void replaceLongPushInstruction(Clazz clazz,
- int offset,
- Instruction instruction,
- int maxVariableIndex)
- {
- Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0);
- if (pushedValue.isParticular())
- {
- // Push a constant instead.
- long value = pushedValue.longValue().value();
- if (value == 0L ||
- value == 1L)
- {
- replaceConstantPushInstruction(clazz,
- offset,
- instruction,
- InstructionConstants.OP_LCONST_0,
- (int)value);
- }
- else
- {
- ConstantPoolEditor constantPoolEditor =
- new ConstantPoolEditor((ProgramClass)clazz);
-
- Instruction replacementInstruction =
- new ConstantInstruction(InstructionConstants.OP_LDC2_W,
- constantPoolEditor.addLongConstant(value));
-
- replaceInstruction(clazz, offset, instruction, replacementInstruction);
- }
- }
- else if (pushedValue.isSpecific())
- {
- // Load an equivalent lower-numbered variable instead, if any.
- TracedVariables variables = partialEvaluator.getVariablesBefore(offset);
- for (int variableIndex = 0; variableIndex < maxVariableIndex; variableIndex++)
- {
- // Note that we have to check the second part as well.
- if (pushedValue.equals(variables.load(variableIndex)) &&
- variables.load(variableIndex + 1) != null &&
- variables.load(variableIndex + 1).computationalType() == Value.TYPE_TOP)
- {
- replaceVariablePushInstruction(clazz,
- offset,
- instruction,
- InstructionConstants.OP_LLOAD,
- variableIndex);
- }
- }
- }
- }
-
-
- /**
- * Replaces the float pushing instruction at the given offset by a simpler
- * push instruction, if possible.
- */
- private void replaceFloatPushInstruction(Clazz clazz,
- int offset,
- Instruction instruction)
- {
- replaceFloatPushInstruction(clazz,
- offset,
- instruction,
- partialEvaluator.getVariablesBefore(offset).size());
- }
-
-
- /**
- * Replaces the float pushing instruction at the given offset by a simpler
- * push instruction, if possible.
- */
- private void replaceFloatPushInstruction(Clazz clazz,
- int offset,
- Instruction instruction,
- int maxVariableIndex)
- {
- Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0);
- if (pushedValue.isParticular())
- {
- // Push a constant instead.
- // 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)
- {
- replaceConstantPushInstruction(clazz,
- offset,
- instruction,
- InstructionConstants.OP_FCONST_0,
- (int)value);
- }
- else
- {
- ConstantPoolEditor constantPoolEditor =
- new ConstantPoolEditor((ProgramClass)clazz);
-
- Instruction replacementInstruction =
- new ConstantInstruction(InstructionConstants.OP_LDC,
- constantPoolEditor.addFloatConstant(value));
-
- replaceInstruction(clazz, offset, instruction, replacementInstruction);
- }
- }
- else if (pushedValue.isSpecific())
- {
- // Load an equivalent lower-numbered variable instead, if any.
- TracedVariables variables = partialEvaluator.getVariablesBefore(offset);
- for (int variableIndex = 0; variableIndex < maxVariableIndex; variableIndex++)
- {
- if (pushedValue.equals(variables.load(variableIndex)))
- {
- replaceVariablePushInstruction(clazz,
- offset,
- instruction,
- InstructionConstants.OP_FLOAD,
- variableIndex);
- }
- }
- }
- }
-
-
- /**
- * Replaces the double pushing instruction at the given offset by a simpler
- * push instruction, if possible.
- */
- private void replaceDoublePushInstruction(Clazz clazz,
- int offset,
- Instruction instruction)
- {
- replaceDoublePushInstruction(clazz,
- offset,
- instruction,
- partialEvaluator.getVariablesBefore(offset).size());
- }
-
-
- /**
- * Replaces the double pushing instruction at the given offset by a simpler
- * push instruction, if possible.
- */
- private void replaceDoublePushInstruction(Clazz clazz,
- int offset,
- Instruction instruction,
- int maxVariableIndex)
- {
- Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0);
- if (pushedValue.isParticular())
- {
- // Push a constant instead.
- // 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 ||
- value == 1.0)
- {
- replaceConstantPushInstruction(clazz,
- offset,
- instruction,
- InstructionConstants.OP_DCONST_0,
- (int)value);
- }
- else
- {
- ConstantPoolEditor constantPoolEditor =
- new ConstantPoolEditor((ProgramClass)clazz);
-
- Instruction replacementInstruction =
- new ConstantInstruction(InstructionConstants.OP_LDC2_W,
- constantPoolEditor.addDoubleConstant(value));
-
- replaceInstruction(clazz, offset, instruction, replacementInstruction);
- }
- }
- else if (pushedValue.isSpecific())
- {
- // Load an equivalent lower-numbered variable instead, if any.
- TracedVariables variables = partialEvaluator.getVariablesBefore(offset);
- for (int variableIndex = 0; variableIndex < maxVariableIndex; variableIndex++)
- {
- // Note that we have to check the second part as well.
- if (pushedValue.equals(variables.load(variableIndex)) &&
- variables.load(variableIndex + 1) != null &&
- variables.load(variableIndex + 1).computationalType() == Value.TYPE_TOP)
- {
- replaceVariablePushInstruction(clazz,
- offset,
- instruction,
- InstructionConstants.OP_DLOAD,
- variableIndex);
- }
- }
- }
- }
-
-
- /**
- * Replaces the reference pushing instruction at the given offset by a
- * simpler push instruction, if possible.
- */
- private void replaceReferencePushInstruction(Clazz clazz,
- int offset,
- Instruction instruction)
- {
- Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0);
- if (pushedValue.isParticular())
- {
- // A reference value can only be specific if it is null.
- replaceConstantPushInstruction(clazz,
- offset,
- instruction,
- InstructionConstants.OP_ACONST_NULL,
- 0);
- }
- }
-
-
- /**
- * Replaces the instruction at a given offset by a given push instruction
- * of a constant.
- */
- private void replaceConstantPushInstruction(Clazz clazz,
- int offset,
- Instruction instruction,
- byte replacementOpcode,
- int value)
- {
- Instruction replacementInstruction =
- new SimpleInstruction(replacementOpcode, value);
-
- replaceInstruction(clazz, offset, instruction, replacementInstruction);
- }
-
-
- /**
- * Replaces the instruction at a given offset by a given push instruction
- * of a variable.
- */
- private void replaceVariablePushInstruction(Clazz clazz,
- int offset,
- Instruction instruction,
- byte replacementOpcode,
- int variableIndex)
- {
- Instruction replacementInstruction =
- new VariableInstruction(replacementOpcode, variableIndex);
-
- replaceInstruction(clazz, offset, instruction, replacementInstruction);
- }
-
-
- /**
- * Replaces the given 'jsr' instruction by a simpler branch instruction,
- * if it jumps to a subroutine that doesn't return or a subroutine that
- * is only called from one place.
- */
- private void replaceJsrInstruction(Clazz clazz,
- int offset,
- BranchInstruction branchInstruction)
- {
- // Is the subroutine ever returning?
- int subroutineStart = offset + branchInstruction.branchOffset;
- if (!partialEvaluator.isSubroutineReturning(subroutineStart) ||
- partialEvaluator.branchOrigins(subroutineStart).instructionOffsetCount() == 1)
- {
- // All 'jsr' instructions to this subroutine can be replaced
- // by unconditional branch instructions.
- replaceBranchInstruction(clazz, offset, branchInstruction);
- }
- else if (!partialEvaluator.isTraced(offset + branchInstruction.length(offset)))
- {
- // We have to make sure the instruction after this 'jsr'
- // instruction is valid, even if it is never reached.
- replaceByInfiniteLoop(clazz, offset + branchInstruction.length(offset), branchInstruction);
- }
- }
-
-
- /**
- * Deletes the reference popping instruction at the given offset, if
- * it is at the start of a subroutine that doesn't return or a subroutine
- * that is only called from one place.
- */
- private void deleteReferencePopInstruction(Clazz clazz,
- int offset,
- Instruction instruction)
- {
- if (partialEvaluator.isSubroutineStart(offset) &&
- (!partialEvaluator.isSubroutineReturning(offset) ||
- partialEvaluator.branchOrigins(offset).instructionOffsetCount() == 1))
- {
- if (DEBUG) System.out.println(" Deleting store of subroutine return address "+instruction.toString(offset));
-
- // A reference value can only be specific if it is null.
- codeAttributeEditor.deleteInstruction(offset);
- }
- }
-
-
- /**
- * Deletes the given branch instruction, or replaces it by a simpler branch
- * instruction, if possible.
- */
- private void replaceBranchInstruction(Clazz clazz,
- int offset,
- Instruction instruction)
- {
- InstructionOffsetValue branchTargets = partialEvaluator.branchTargets(offset);
-
- // Is there exactly one branch target (not from a goto or jsr)?
- if (branchTargets != null &&
- branchTargets.instructionOffsetCount() == 1)
- {
- // Is it branching to the next instruction?
- int branchOffset = branchTargets.instructionOffset(0) - offset;
- if (branchOffset == instruction.length(offset))
- {
- if (DEBUG) System.out.println(" Ignoring zero branch instruction at ["+offset+"]");
- }
- else
- {
- // Replace the branch instruction by a simple branch instruction.
- Instruction replacementInstruction =
- new BranchInstruction(InstructionConstants.OP_GOTO,
- branchOffset);
-
- replaceInstruction(clazz, offset, instruction, replacementInstruction);
- }
- }
- }
-
-
- /**
- * Replaces the given table switch instruction, if it is based on the value
- * of a fixed array. This is typical for switches on simple enums.
- */
- private void replaceSimpleEnumSwitchInstruction(Clazz clazz,
- CodeAttribute codeAttribute,
- int offset,
- TableSwitchInstruction tableSwitchInstruction)
- {
- // Check if the switch instruction is consuming a single value loaded
- // from a fully specified array.
- InstructionOffsetValue producerOffsets =
- partialEvaluator.getStackBefore(offset).getTopProducerValue(0).instructionOffsetValue();
-
- if (producerOffsets.instructionOffsetCount() == 1)
- {
- int producerOffset = producerOffsets.instructionOffset(0);
-
- if (codeAttribute.code[producerOffset] == InstructionConstants.OP_IALOAD &&
- !codeAttributeEditor.isModified(producerOffset))
- {
- ReferenceValue referenceValue =
- partialEvaluator.getStackBefore(producerOffset).getTop(1).referenceValue();
-
- if (referenceValue.isParticular())
- {
- // Simplify the entire construct.
- replaceSimpleEnumSwitchInstruction(clazz,
- codeAttribute,
- producerOffset,
- offset,
- tableSwitchInstruction,
- referenceValue);
- }
- }
- }
- }
-
-
- /**
- * Replaces the given table switch instruction that is based on a value of
- * the given fixed array.
- */
- private void replaceSimpleEnumSwitchInstruction(Clazz clazz,
- CodeAttribute codeAttribute,
- int loadOffset,
- int switchOffset,
- TableSwitchInstruction tableSwitchInstruction,
- ReferenceValue mappingValue)
- {
- ValueFactory valueFactory = new ParticularValueFactory();
-
- // Transform the jump offsets.
- int[] jumpOffsets = tableSwitchInstruction.jumpOffsets;
- int[] newJumpOffsets = new int[mappingValue.arrayLength(valueFactory).value()];
-
- for (int index = 0; index < newJumpOffsets.length; index++)
- {
- int switchCase =
- mappingValue.integerArrayLoad(valueFactory.createIntegerValue(
- index),
- valueFactory).value();
-
- newJumpOffsets[index] =
- switchCase >= tableSwitchInstruction.lowCase &&
- switchCase <= tableSwitchInstruction.highCase ?
- jumpOffsets[switchCase - tableSwitchInstruction.lowCase] :
- tableSwitchInstruction.defaultOffset;
- }
-
- // Update the instruction.
- tableSwitchInstruction.lowCase = 0;
- tableSwitchInstruction.highCase = newJumpOffsets.length - 1;
- tableSwitchInstruction.jumpOffsets = newJumpOffsets;
-
- // Replace the original one with the new version.
- replaceSimpleEnumSwitchInstruction(clazz,
- loadOffset,
- switchOffset,
- tableSwitchInstruction);
-
- cleanUpSwitchInstruction(clazz, switchOffset, tableSwitchInstruction);
-
- trimSwitchInstruction(clazz, switchOffset, tableSwitchInstruction);
- }
-
-
- /**
- * Replaces the given look up switch instruction, if it is based on the
- * value of a fixed array. This is typical for switches on simple enums.
- */
- private void replaceSimpleEnumSwitchInstruction(Clazz clazz,
- CodeAttribute codeAttribute,
- int offset,
- LookUpSwitchInstruction lookupSwitchInstruction)
- {
- // Check if the switch instruction is consuming a single value loaded
- // from a fully specified array.
- InstructionOffsetValue producerOffsets =
- partialEvaluator.getStackBefore(offset).getTopProducerValue(0).instructionOffsetValue();
-
- if (producerOffsets.instructionOffsetCount() == 1)
- {
- int producerOffset = producerOffsets.instructionOffset(0);
-
- if (codeAttribute.code[producerOffset] == InstructionConstants.OP_IALOAD &&
- !codeAttributeEditor.isModified(producerOffset))
- {
- ReferenceValue referenceValue =
- partialEvaluator.getStackBefore(producerOffset).getTop(1).referenceValue();
-
- if (referenceValue.isParticular())
- {
- // Simplify the entire construct.
- replaceSimpleEnumSwitchInstruction(clazz,
- codeAttribute,
- producerOffset,
- offset,
- lookupSwitchInstruction,
- referenceValue);
- }
- }
- }
- }
-
-
- /**
- * Replaces the given look up switch instruction that is based on a value of
- * the given fixed array. This is typical for switches on simple enums.
- */
- private void replaceSimpleEnumSwitchInstruction(Clazz clazz,
- CodeAttribute codeAttribute,
- int loadOffset,
- int switchOffset,
- LookUpSwitchInstruction lookupSwitchInstruction,
- ReferenceValue mappingValue)
- {
- ValueFactory valueFactory = new ParticularValueFactory();
-
- // Transform the jump offsets.
- int[] cases = lookupSwitchInstruction.cases;
- int[] jumpOffsets = lookupSwitchInstruction.jumpOffsets;
- int[] newJumpOffsets = new int[mappingValue.arrayLength(valueFactory).value()];
-
- for (int index = 0; index < newJumpOffsets.length; index++)
- {
- int switchCase =
- mappingValue.integerArrayLoad(valueFactory.createIntegerValue(index),
- valueFactory).value();
-
- int caseIndex = Arrays.binarySearch(cases, switchCase);
-
- newJumpOffsets[index] = caseIndex >= 0 ?
- jumpOffsets[caseIndex] :
- lookupSwitchInstruction.defaultOffset;
- }
-
- // Replace the original lookup switch with a table switch.
- TableSwitchInstruction replacementSwitchInstruction =
- new TableSwitchInstruction(InstructionConstants.OP_TABLESWITCH,
- lookupSwitchInstruction.defaultOffset,
- 0,
- newJumpOffsets.length - 1,
- newJumpOffsets);
-
- replaceSimpleEnumSwitchInstruction(clazz,
- loadOffset,
- switchOffset,
- replacementSwitchInstruction);
-
- cleanUpSwitchInstruction(clazz, switchOffset, replacementSwitchInstruction);
-
- trimSwitchInstruction(clazz, switchOffset, replacementSwitchInstruction);
- }
-
-
- /**
- * Makes sure all branch targets of the given switch instruction are valid.
- */
- private void cleanUpSwitchInstruction(Clazz clazz,
- int offset,
- SwitchInstruction switchInstruction)
- {
- // Get the actual branch targets.
- InstructionOffsetValue branchTargets = partialEvaluator.branchTargets(offset);
-
- // Get an offset that can serve as a valid default offset.
- int defaultOffset =
- branchTargets.instructionOffset(branchTargets.instructionOffsetCount()-1) -
- offset;
-
- Instruction replacementInstruction = null;
-
- // Check the jump offsets.
- int[] jumpOffsets = switchInstruction.jumpOffsets;
- for (int index = 0; index < jumpOffsets.length; index++)
- {
- if (!branchTargets.contains(offset + jumpOffsets[index]))
- {
- // Replace the unused offset.
- jumpOffsets[index] = defaultOffset;
-
- // Remember to replace the instruction.
- replacementInstruction = switchInstruction;
- }
- }
-
- // Check the default offset.
- if (!branchTargets.contains(offset + switchInstruction.defaultOffset))
- {
- // Replace the unused offset.
- switchInstruction.defaultOffset = defaultOffset;
-
- // Remember to replace the instruction.
- replacementInstruction = switchInstruction;
- }
-
- if (replacementInstruction != null)
- {
- replaceInstruction(clazz, offset, switchInstruction, replacementInstruction);
- }
- }
-
-
- /**
- * Trims redundant offsets from the given switch instruction.
- */
- private void trimSwitchInstruction(Clazz clazz,
- int offset,
- TableSwitchInstruction tableSwitchInstruction)
- {
- // Get an offset that can serve as a valid default offset.
- int defaultOffset = tableSwitchInstruction.defaultOffset;
- int[] jumpOffsets = tableSwitchInstruction.jumpOffsets;
- int length = jumpOffsets.length;
-
- // Find the lowest index with a non-default jump offset.
- int lowIndex = 0;
- while (lowIndex < length &&
- jumpOffsets[lowIndex] == defaultOffset)
- {
- lowIndex++;
- }
-
- // Find the highest index with a non-default jump offset.
- int highIndex = length - 1;
- while (highIndex >= 0 &&
- jumpOffsets[highIndex] == defaultOffset)
- {
- highIndex--;
- }
-
- // Can we use a shorter array?
- int newLength = highIndex - lowIndex + 1;
- if (newLength < length)
- {
- if (newLength <= 0)
- {
- // Replace the switch instruction by a simple branch instruction.
- Instruction replacementInstruction =
- new BranchInstruction(InstructionConstants.OP_GOTO,
- defaultOffset);
-
- replaceInstruction(clazz, offset, tableSwitchInstruction,
- replacementInstruction);
- }
- else
- {
- // Trim the array.
- int[] newJumpOffsets = new int[newLength];
-
- System.arraycopy(jumpOffsets, lowIndex, newJumpOffsets, 0, newLength);
-
- tableSwitchInstruction.jumpOffsets = newJumpOffsets;
- tableSwitchInstruction.lowCase += lowIndex;
- tableSwitchInstruction.highCase -= length - newLength - lowIndex;
-
- replaceInstruction(clazz, offset, tableSwitchInstruction,
- tableSwitchInstruction);
- }
- }
- }
-
-
- /**
- * Trims redundant offsets from the given switch instruction.
- */
- private void trimSwitchInstruction(Clazz clazz,
- int offset,
- LookUpSwitchInstruction lookUpSwitchInstruction)
- {
- // Get an offset that can serve as a valid default offset.
- int defaultOffset = lookUpSwitchInstruction.defaultOffset;
- int[] jumpOffsets = lookUpSwitchInstruction.jumpOffsets;
- int length = jumpOffsets.length;
- int newLength = length;
-
- // Count the default jump offsets.
- for (int index = 0; index < length; index++)
- {
- if (jumpOffsets[index] == defaultOffset)
- {
- newLength--;
- }
- }
-
- // Can we use shorter arrays?
- if (newLength < length)
- {
- if (newLength <= 0)
- {
- // Replace the switch instruction by a simple branch instruction.
- Instruction replacementInstruction =
- new BranchInstruction(InstructionConstants.OP_GOTO,
- defaultOffset);
-
- replaceInstruction(clazz, offset, lookUpSwitchInstruction,
- replacementInstruction);
- }
- else
- {
- // Remove redundant entries from the arrays.
- int[] cases = lookUpSwitchInstruction.cases;
- int[] newJumpOffsets = new int[newLength];
- int[] newCases = new int[newLength];
-
- int newIndex = 0;
-
- for (int index = 0; index < length; index++)
- {
- if (jumpOffsets[index] != defaultOffset)
- {
- newJumpOffsets[newIndex] = jumpOffsets[index];
- newCases[newIndex++] = cases[index];
- }
- }
-
- lookUpSwitchInstruction.jumpOffsets = newJumpOffsets;
- lookUpSwitchInstruction.cases = newCases;
-
- replaceInstruction(clazz, offset, lookUpSwitchInstruction,
- lookUpSwitchInstruction);
- }
- }
- }
-
-
- /**
- * Replaces the given instruction by an infinite loop.
- */
- private void replaceByInfiniteLoop(Clazz clazz,
- int offset,
- Instruction instruction)
- {
- // Replace the instruction by an infinite loop.
- Instruction replacementInstruction =
- new BranchInstruction(InstructionConstants.OP_GOTO, 0);
-
- if (DEBUG) System.out.println(" Replacing unreachable instruction by infinite loop "+replacementInstruction.toString(offset));
-
- codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
-
- // Visit the instruction, if required.
- if (extraInstructionVisitor != null)
- {
- // Note: we're not passing the right arguments for now, knowing that
- // they aren't used anyway.
- instruction.accept(clazz,
- null,
- null,
- offset,
- extraInstructionVisitor);
- }
- }
-
-
- /**
- * Replaces the instruction at a given offset by a given push instruction.
- */
- private void replaceInstruction(Clazz clazz,
- int offset,
- Instruction instruction,
- Instruction replacementInstruction)
- {
- // Pop unneeded stack entries if necessary.
- int popCount =
- instruction.stackPopCount(clazz) -
- replacementInstruction.stackPopCount(clazz);
-
- insertPopInstructions(offset, popCount);
-
- if (DEBUG) System.out.println(" Replacing instruction "+instruction.toString(offset)+" -> "+replacementInstruction.toString()+(popCount == 0 ? "" : " ("+popCount+" pops)"));
-
- codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
-
- // Visit the instruction, if required.
- if (extraInstructionVisitor != null)
- {
- // Note: we're not passing the right arguments for now, knowing that
- // they aren't used anyway.
- instruction.accept(clazz, null, null, offset, extraInstructionVisitor);
- }
- }
-
-
- /**
- * Pops the given number of stack entries before the instruction at the
- * given offset.
- */
- private void insertPopInstructions(int offset, int popCount)
- {
- switch (popCount)
- {
- case 0:
- {
- break;
- }
- case 1:
- {
- // Insert a single pop instruction.
- Instruction popInstruction =
- new SimpleInstruction(InstructionConstants.OP_POP);
-
- codeAttributeEditor.insertBeforeInstruction(offset,
- popInstruction);
- break;
- }
- case 2:
- {
- // Insert a single pop2 instruction.
- Instruction popInstruction =
- new SimpleInstruction(InstructionConstants.OP_POP2);
-
- codeAttributeEditor.insertBeforeInstruction(offset,
- popInstruction);
- break;
- }
- default:
- {
- // Insert the specified number of pop instructions.
- Instruction[] popInstructions =
- new Instruction[popCount / 2 + popCount % 2];
-
- Instruction popInstruction =
- new SimpleInstruction(InstructionConstants.OP_POP2);
-
- for (int index = 0; index < popCount / 2; index++)
- {
- popInstructions[index] = popInstruction;
- }
-
- if (popCount % 2 == 1)
- {
- popInstruction =
- new SimpleInstruction(InstructionConstants.OP_POP);
-
- popInstructions[popCount / 2] = popInstruction;
- }
-
- codeAttributeEditor.insertBeforeInstruction(offset,
- popInstructions);
- break;
- }
- }
- }
-
-
- /**
- * Replaces the simple enum switch instructions at a given offsets by a
- * given replacement instruction.
- */
- private void replaceSimpleEnumSwitchInstruction(Clazz clazz,
- int loadOffset,
- int switchOffset,
- SwitchInstruction replacementSwitchInstruction)
- {
- if (DEBUG) System.out.println(" Replacing switch instruction at ["+switchOffset+"] -> ["+loadOffset+"] swap + pop, "+replacementSwitchInstruction.toString(switchOffset)+")");
-
- // Remove the array load instruction.
- codeAttributeEditor.replaceInstruction(loadOffset, new Instruction[]
- {
- new SimpleInstruction(InstructionConstants.OP_SWAP),
- new SimpleInstruction(InstructionConstants.OP_POP),
- });
-
- // Replace the switch instruction.
- codeAttributeEditor.replaceInstruction(switchOffset, replacementSwitchInstruction);
-
- // Visit the instruction, if required.
- if (extraInstructionVisitor != null)
- {
- // Note: we're not passing the right arguments for now, knowing that
- // they aren't used anyway.
- replacementSwitchInstruction.accept(clazz,
- null,
- null,
- switchOffset,
- extraInstructionVisitor);
- }
- }
-}
diff --git a/src/proguard/optimize/evaluation/LivenessAnalyzer.java b/src/proguard/optimize/evaluation/LivenessAnalyzer.java
deleted file mode 100644
index 87bd4e5..0000000
--- a/src/proguard/optimize/evaluation/LivenessAnalyzer.java
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * 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
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.optimize.evaluation;
-
-import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.visitor.*;
-import proguard.classfile.instruction.*;
-import proguard.classfile.instruction.visitor.InstructionVisitor;
-import proguard.classfile.util.SimplifiedVisitor;
-import proguard.evaluation.value.*;
-
-/**
- * This AttributeVisitor analyzes the liveness of the variables in the code
- * attributes that it visits, based on partial evaluation.
- *
- * @author Eric Lafortune
- */
-public class LivenessAnalyzer
-extends SimplifiedVisitor
-implements AttributeVisitor,
- InstructionVisitor,
- ExceptionInfoVisitor
-{
- //*
- private static final boolean DEBUG = false;
- /*/
- private static boolean DEBUG = true;
- //*/
-
- private static final int MAX_VARIABLES_SIZE = 64;
-
- private final PartialEvaluator partialEvaluator;
-
- private long[] isAliveBefore = new long[ClassConstants.TYPICAL_CODE_LENGTH];
- private long[] isAliveAfter = new long[ClassConstants.TYPICAL_CODE_LENGTH];
- private long[] isCategory2 = new long[ClassConstants.TYPICAL_CODE_LENGTH];
-
- // Fields acting as global temporary variables.
- private boolean checkAgain;
- private long alive;
-
-
- /**
- * Creates a new LivenessAnalyzer.
- */
- public LivenessAnalyzer()
- {
- this(new PartialEvaluator());
- }
-
-
- /**
- * Creates a new LivenessAnalyzer that will use the given partial evaluator.
- * It will run this evaluator on every code attribute that it visits.
- */
- public LivenessAnalyzer(PartialEvaluator partialEvaluator)
- {
- this.partialEvaluator = partialEvaluator;
- }
-
-
- /**
- * 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.
- */
- public boolean isAliveBefore(int instructionOffset, int variableIndex)
- {
- return variableIndex >= MAX_VARIABLES_SIZE ||
- (isAliveBefore[instructionOffset] & (1L << variableIndex)) != 0;
- }
-
-
- /**
- * Sets whether the specified variable is alive before the instruction
- * at the given offset.
- */
- public void setAliveBefore(int instructionOffset, int variableIndex, boolean alive)
- {
- if (variableIndex < MAX_VARIABLES_SIZE)
- {
- if (alive)
- {
- isAliveBefore[instructionOffset] |= 1L << variableIndex;
- }
- else
- {
- isAliveBefore[instructionOffset] &= ~(1L << variableIndex);
- }
- }
- }
-
-
- /**
- * Returns whether the specified variable is alive after the instruction
- * at the given offset.
- */
- public boolean isAliveAfter(int instructionOffset, int variableIndex)
- {
- return variableIndex >= MAX_VARIABLES_SIZE ||
- (isAliveAfter[instructionOffset] & (1L << variableIndex)) != 0;
- }
-
-
- /**
- * Sets whether the specified variable is alive after the instruction
- * at the given offset.
- */
- public void setAliveAfter(int instructionOffset, int variableIndex, boolean alive)
- {
- if (variableIndex < MAX_VARIABLES_SIZE)
- {
- if (alive)
- {
- isAliveAfter[instructionOffset] |= 1L << variableIndex;
- }
- else
- {
- isAliveAfter[instructionOffset] &= ~(1L << variableIndex);
- }
- }
- }
-
-
- /**
- * Returns whether the specified variable takes up two entries after the
- * instruction at the given offset.
- */
- public boolean isCategory2(int instructionOffset, int variableIndex)
- {
- return variableIndex < MAX_VARIABLES_SIZE &&
- (isCategory2[instructionOffset] & (1L << variableIndex)) != 0;
- }
-
-
- /**
- * Sets whether the specified variable takes up two entries after the
- * instruction at the given offset.
- */
- public void setCategory2(int instructionOffset, int variableIndex, boolean category2)
- {
- if (variableIndex < MAX_VARIABLES_SIZE)
- {
- if (category2)
- {
- isCategory2[instructionOffset] |= 1L << variableIndex;
- }
- else
- {
- isCategory2[instructionOffset] &= ~(1L << variableIndex);
- }
- }
- }
-
-
- // Implementations for AttributeVisitor.
-
- public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
-
-
- public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
-// DEBUG =
-// clazz.getName().equals("abc/Def") &&
-// method.getName(clazz).equals("abc");
-
- if (DEBUG)
- {
- System.out.println();
- System.out.println("Liveness analysis: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
- }
-
- // Initialize the global arrays.
- initializeArrays(codeAttribute);
-
- // Evaluate the method.
- partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
-
- int codeLength = codeAttribute.u4codeLength;
- int variablesSize = codeAttribute.u2maxLocals;
-
- // We'll only really analyze the first 64 variables.
- if (variablesSize > MAX_VARIABLES_SIZE)
- {
- variablesSize = MAX_VARIABLES_SIZE;
- }
-
- // Mark liveness blocks, as many times as necessary.
- do
- {
- checkAgain = false;
- alive = 0L;
-
- // Loop over all traced instructions, backward.
- for (int offset = codeLength - 1; offset >= 0; offset--)
- {
- if (partialEvaluator.isTraced(offset))
- {
- // Update the liveness based on the branch targets.
- InstructionOffsetValue branchTargets = partialEvaluator.branchTargets(offset);
- if (branchTargets != null)
- {
- // Update the liveness right after the branch instruction.
- alive = combinedLiveness(branchTargets);
- }
-
- // Merge the current liveness.
- alive |= isAliveAfter[offset];
-
- // Update the liveness after the instruction.
- isAliveAfter[offset] = alive;
-
- // Update the current liveness based on the instruction.
- codeAttribute.instructionAccept(clazz, method, offset, this);
-
- // Merge the current liveness.
- alive |= isAliveBefore[offset];
-
- // Update the liveness before the instruction.
- if ((~isAliveBefore[offset] & alive) != 0L)
- {
- isAliveBefore[offset] = alive;
-
- // Do we have to check again after this loop?
- checkAgain |= offset < maxOffset(partialEvaluator.branchOrigins(offset));
- }
- }
- }
-
- // Account for the liveness at the start of the exception handlers.
- codeAttribute.exceptionsAccept(clazz, method, this);
- }
- while (checkAgain);
-
- // Loop over all instructions, to mark variables that take up two entries.
- for (int offset = 0; offset < codeLength; offset++)
- {
- if (partialEvaluator.isTraced(offset))
- {
- // Loop over all variables.
- for (int variableIndex = 0; variableIndex < variablesSize; variableIndex++)
- {
- // Is the variable alive and a category 2 type?
- if (isAliveBefore(offset, variableIndex))
- {
- Value value = partialEvaluator.getVariablesBefore(offset).getValue(variableIndex);
- if (value != null && value.isCategory2())
- {
- // Mark it as such.
- setCategory2(offset, variableIndex, true);
-
- // Mark the next variable as well.
- setAliveBefore(offset, variableIndex + 1, true);
- setCategory2( offset, variableIndex + 1, true);
- }
- }
-
- // Is the variable alive and a category 2 type?
- if (isAliveAfter(offset, variableIndex))
- {
- Value value = partialEvaluator.getVariablesAfter(offset).getValue(variableIndex);
- if (value != null && value.isCategory2())
- {
- // Mark it as such.
- setCategory2(offset, variableIndex, true);
-
- // Mark the next variable as well.
- setAliveAfter(offset, variableIndex + 1, true);
- setCategory2( offset, variableIndex + 1, true);
- }
- }
- }
- }
- }
-
- if (DEBUG)
- {
- // Loop over all instructions.
- for (int offset = 0; offset < codeLength; offset++)
- {
- if (partialEvaluator.isTraced(offset))
- {
- long aliveBefore = isAliveBefore[offset];
- long aliveAfter = isAliveAfter[offset];
- long category2 = isCategory2[offset];
-
- // Print out the liveness of all variables before the instruction.
- for (int variableIndex = 0; variableIndex < variablesSize; variableIndex++)
- {
- long variableMask = (1L << variableIndex);
- System.out.print((aliveBefore & variableMask) == 0L ? '.' :
- (category2 & variableMask) == 0L ? 'x' :
- '*');
- }
-
- // Print out the instruction itself.
- System.out.println(" "+ InstructionFactory.create(codeAttribute.code, offset).toString(offset));
-
- // Print out the liveness of all variables after the instruction.
- for (int variableIndex = 0; variableIndex < variablesSize; variableIndex++)
- {
- long variableMask = (1L << variableIndex);
- System.out.print((aliveAfter & variableMask) == 0L ? '.' :
- (category2 & variableMask) == 0L ? 'x' :
- '=');
- }
-
- System.out.println();
- }
- }
- }
- }
-
-
- // 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)
- {
- int variableIndex = variableInstruction.variableIndex;
- if (variableIndex < MAX_VARIABLES_SIZE)
- {
- long livenessMask = 1L << variableIndex;
-
- // Is it a load instruction or a store instruction?
- if (variableInstruction.isLoad())
- {
- // Start marking the variable before the load instruction.
- alive |= livenessMask;
- }
- else
- {
- // Stop marking the variable before the store instruction.
- alive &= ~livenessMask;
-
- // But do mark the variable right after the store instruction.
- isAliveAfter[offset] |= livenessMask;
- }
- }
- }
-
-
- public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
- {
- // Special case: variable 0 ('this') in an initializer has to be alive
- // as long as it hasn't been initialized.
- if (offset == partialEvaluator.superInitializationOffset())
- {
- alive |= 1L;
- }
- }
-
-
- // Implementations for ExceptionInfoVisitor.
-
- public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
- {
- // Are any variables alive at the start of the handler?
- long alive = isAliveBefore[exceptionInfo.u2handlerPC];
- if (alive != 0L)
- {
- // Set the same liveness flags for the entire try block.
- int startOffset = exceptionInfo.u2startPC;
- int endOffset = exceptionInfo.u2endPC;
-
- for (int offset = startOffset; offset < endOffset; offset++)
- {
- if (partialEvaluator.isTraced(offset))
- {
- if ((~(isAliveBefore[offset] & isAliveAfter[offset]) & alive) != 0L)
- {
- isAliveBefore[offset] |= alive;
- isAliveAfter[offset] |= alive;
-
- // Check again after having marked this try block.
- checkAgain = true;
- }
- }
- }
- }
- }
-
-
- // Small utility methods.
-
- /**
- * Initializes the global arrays.
- */
- private void initializeArrays(CodeAttribute codeAttribute)
- {
- int codeLength = codeAttribute.u4codeLength;
-
- // Create new arrays for storing information at each instruction offset.
- if (isAliveBefore.length < codeLength)
- {
- isAliveBefore = new long[codeLength];
- isAliveAfter = new long[codeLength];
- isCategory2 = new long[codeLength];
- }
- else
- {
- for (int index = 0; index < codeLength; index++)
- {
- isAliveBefore[index] = 0L;
- isAliveAfter[index] = 0L;
- isCategory2[index] = 0L;
- }
- }
- }
-
-
- /**
- * Returns the combined liveness mask of the variables right before the
- * specified instruction offsets.
- */
- private long combinedLiveness(InstructionOffsetValue instructionOffsetValue)
- {
- long alive = 0L;
-
- int count = instructionOffsetValue.instructionOffsetCount();
- for (int index = 0; index < count; index++)
- {
- alive |= isAliveBefore[instructionOffsetValue.instructionOffset(index)];
- }
-
- return alive;
- }
-
-
- /**
- * Returns the minimum offset from the given instruction offsets.
- */
- private int minOffset(Value instructionOffsets)
- {
- return minOffset(instructionOffsets, Integer.MAX_VALUE);
- }
-
-
- /**
- * Returns the minimum offset from the given instruction offsets.
- */
- private int minOffset(Value instructionOffsets, int minOffset)
- {
- if (instructionOffsets != null)
- {
- InstructionOffsetValue instructionOffsetValue =
- instructionOffsets.instructionOffsetValue();
-
- int count = instructionOffsetValue.instructionOffsetCount();
- for (int index = 0; index < count; index++)
- {
- int offset = instructionOffsetValue.instructionOffset(index);
- if (minOffset > offset)
- {
- minOffset = offset;
- }
- }
- }
-
- return minOffset;
- }
-
-
- /**
- * Returns the maximum offset from the given instruction offsets.
- */
- private int maxOffset(Value instructionOffsets)
- {
- return maxOffset(instructionOffsets, Integer.MIN_VALUE);
- }
-
-
- /**
- * Returns the maximum offset from the given instruction offsets.
- */
- private int maxOffset(Value instructionOffsets, int maxOffset)
- {
- if (instructionOffsets != null)
- {
- InstructionOffsetValue instructionOffsetValue =
- instructionOffsets.instructionOffsetValue();
-
- int count = instructionOffsetValue.instructionOffsetCount();
- for (int index = 0; index < count; index++)
- {
- int offset = instructionOffsetValue.instructionOffset(index);
- if (maxOffset < offset)
- {
- maxOffset = offset;
- }
- }
- }
-
- return maxOffset;
- }
-}
diff --git a/src/proguard/optimize/evaluation/LoadingInvocationUnit.java b/src/proguard/optimize/evaluation/LoadingInvocationUnit.java
deleted file mode 100644
index 80b4b84..0000000
--- a/src/proguard/optimize/evaluation/LoadingInvocationUnit.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * 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
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.optimize.evaluation;
-
-import proguard.classfile.*;
-import proguard.classfile.constant.RefConstant;
-import proguard.evaluation.BasicInvocationUnit;
-import proguard.evaluation.value.*;
-
-/**
- * This InvocationUnit loads parameter values and return values that were
- * previously stored with the methods that are invoked.
- *
- * @see StoringInvocationUnit
- * @author Eric Lafortune
- */
-public class LoadingInvocationUnit
-extends BasicInvocationUnit
-{
- private final boolean loadFieldValues;
- private final boolean loadMethodParameterValues;
- private final boolean loadMethodReturnValues;
-
-
- /**
- * Creates a new LoadingInvocationUnit with the given value factory.
- */
- public LoadingInvocationUnit(ValueFactory valueFactory)
- {
- this(valueFactory, true, true, true);
- }
-
-
- /**
- * Creates a new LoadingInvocationUnit with the given value factory, for
- * loading the specified values.
- */
- public LoadingInvocationUnit(ValueFactory valueFactory,
- boolean loadFieldValues,
- boolean loadMethodParameterValues,
- boolean loadMethodReturnValues)
- {
- super(valueFactory);
-
- this.loadFieldValues = loadFieldValues;
- this.loadMethodParameterValues = loadMethodParameterValues;
- this.loadMethodReturnValues = loadMethodReturnValues;
- }
-
-
- // Implementations for BasicInvocationUnit.
-
- protected Value getFieldClassValue(Clazz clazz,
- RefConstant refConstant,
- String type)
- {
- if (loadFieldValues)
- {
- // Do we know this field?
- Member referencedMember = refConstant.referencedMember;
- if (referencedMember != null)
- {
- // Retrieve the stored field class value.
- ReferenceValue value = StoringInvocationUnit.getFieldClassValue((Field)referencedMember);
- if (value != null)
- {
- return value;
- }
- }
- }
-
- return super.getFieldClassValue(clazz, refConstant, type);
- }
-
-
- protected Value getFieldValue(Clazz clazz,
- RefConstant refConstant,
- String type)
- {
- if (loadFieldValues)
- {
- // Do we know this field?
- Member referencedMember = refConstant.referencedMember;
- if (referencedMember != null)
- {
- // Retrieve the stored field value.
- Value value = StoringInvocationUnit.getFieldValue((Field)referencedMember);
- if (value != null)
- {
- return value;
- }
- }
- }
-
- return super.getFieldValue(clazz, refConstant, type);
- }
-
-
- protected Value getMethodParameterValue(Clazz clazz,
- Method method,
- int parameterIndex,
- String type,
- Clazz referencedClass)
- {
- if (loadMethodParameterValues)
- {
- // Retrieve the stored method parameter value.
- Value value = StoringInvocationUnit.getMethodParameterValue(method, parameterIndex);
- if (value != null)
- {
- return value;
- }
- }
-
- return super.getMethodParameterValue(clazz,
- method,
- parameterIndex,
- type,
- referencedClass);
- }
-
-
- protected Value getMethodReturnValue(Clazz clazz,
- RefConstant refConstant,
- String type)
- {
- if (loadMethodReturnValues)
- {
- // Do we know this method?
- Member referencedMember = refConstant.referencedMember;
- if (referencedMember != null)
- {
- // Retrieve the stored method return value.
- Value value = StoringInvocationUnit.getMethodReturnValue((Method)referencedMember);
- if (value != null)
- {
- return value;
- }
- }
- }
-
- return super.getMethodReturnValue(clazz,
- refConstant,
- type);
- }
-}
diff --git a/src/proguard/optimize/evaluation/PartialEvaluator.java b/src/proguard/optimize/evaluation/PartialEvaluator.java
deleted file mode 100644
index 0301f12..0000000
--- a/src/proguard/optimize/evaluation/PartialEvaluator.java
+++ /dev/null
@@ -1,1282 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * 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
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.optimize.evaluation;
-
-import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.visitor.*;
-import proguard.classfile.constant.ClassConstant;
-import proguard.classfile.instruction.*;
-import proguard.classfile.util.*;
-import proguard.classfile.visitor.*;
-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.
- *
- * @author Eric Lafortune
- */
-public class PartialEvaluator
-extends SimplifiedVisitor
-implements AttributeVisitor,
- ExceptionInfoVisitor
-{
- //*
- private static final boolean DEBUG = false;
- private static final boolean DEBUG_RESULTS = false;
- /*/
- private static boolean DEBUG = true;
- private static boolean DEBUG_RESULTS = true;
- //*/
-
- private static final int MAXIMUM_EVALUATION_COUNT = 5;
-
- public static final int NONE = -2;
- public static final int AT_METHOD_ENTRY = -1;
- public static final int AT_CATCH_ENTRY = -1;
-
- private final ValueFactory valueFactory;
- private final InvocationUnit invocationUnit;
- private final boolean evaluateAllCode;
-
- private InstructionOffsetValue[] branchOriginValues = new InstructionOffsetValue[ClassConstants.TYPICAL_CODE_LENGTH];
- private InstructionOffsetValue[] branchTargetValues = new InstructionOffsetValue[ClassConstants.TYPICAL_CODE_LENGTH];
- private TracedVariables[] variablesBefore = new TracedVariables[ClassConstants.TYPICAL_CODE_LENGTH];
- private TracedStack[] stacksBefore = new TracedStack[ClassConstants.TYPICAL_CODE_LENGTH];
- private TracedVariables[] variablesAfter = new TracedVariables[ClassConstants.TYPICAL_CODE_LENGTH];
- 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 boolean evaluateExceptions;
-
- private final BasicBranchUnit branchUnit;
- private final BranchTargetFinder branchTargetFinder;
-
- private final java.util.Stack callingInstructionBlockStack;
- private final java.util.Stack instructionBlockStack = new java.util.Stack();
-
-
- /**
- * Creates a simple PartialEvaluator.
- */
- public PartialEvaluator()
- {
- this(new ValueFactory(),
- new BasicInvocationUnit(new ValueFactory()),
- true);
- }
-
-
- /**
- * Creates a new PartialEvaluator.
- * @param valueFactory the value factory that will create all values
- * during evaluation.
- * @param invocationUnit the invocation unit that will handle all
- * communication with other fields and methods.
- * @param evaluateAllCode a flag that specifies whether all casts, branch
- * targets, and exception handlers should be
- * evaluated, even if they are unnecessary or
- * unreachable.
- */
- public PartialEvaluator(ValueFactory valueFactory,
- InvocationUnit invocationUnit,
- boolean evaluateAllCode)
- {
- this(valueFactory,
- invocationUnit,
- evaluateAllCode,
- evaluateAllCode ?
- new BasicBranchUnit() :
- new TracedBranchUnit(),
- new BranchTargetFinder(),
- null);
- }
-
-
- /**
- * Creates a new PartialEvaluator, based on an existing one.
- * @param partialEvaluator the subroutine calling partial evaluator.
- */
- private PartialEvaluator(PartialEvaluator partialEvaluator)
- {
- this(partialEvaluator.valueFactory,
- partialEvaluator.invocationUnit,
- partialEvaluator.evaluateAllCode,
- partialEvaluator.branchUnit,
- partialEvaluator.branchTargetFinder,
- partialEvaluator.instructionBlockStack);
- }
-
-
- /**
- * Creates a new PartialEvaluator.
- * @param valueFactory the value factory that will create
- * all values during evaluation.
- * @param invocationUnit the invocation unit that will handle
- * all communication with other fields
- * and methods.
- * @param evaluateAllCode a flag that specifies whether all
- * casts, branch targets, and exception
- * handlers should be evaluated, even
- * if they are unnecessary or
- * unreachable.
- * @param branchUnit the branch unit that will handle all
- * branches.
- * @param branchTargetFinder the utility class that will find all
- * branches.
- * @param callingInstructionBlockStack the stack of instruction blocks to
- * be evaluated
- */
- private PartialEvaluator(ValueFactory valueFactory,
- InvocationUnit invocationUnit,
- boolean evaluateAllCode,
- BasicBranchUnit branchUnit,
- BranchTargetFinder branchTargetFinder,
- java.util.Stack callingInstructionBlockStack)
- {
- this.valueFactory = valueFactory;
- this.invocationUnit = invocationUnit;
- this.evaluateAllCode = evaluateAllCode;
- this.branchUnit = branchUnit;
- this.branchTargetFinder = branchTargetFinder;
- this.callingInstructionBlockStack = callingInstructionBlockStack == null ?
- this.instructionBlockStack :
- callingInstructionBlockStack;
- }
-
-
- // Implementations for AttributeVisitor.
-
- public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
-
-
- public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
-// DEBUG = DEBUG_RESULTS =
-// clazz.getName().equals("abc/Def") &&
-// method.getName(clazz).equals("abc");
-
- // TODO: Remove this when the partial evaluator has stabilized.
- // Catch any unexpected exceptions from the actual visiting method.
- try
- {
- // Process the code.
- visitCodeAttribute0(clazz, method, codeAttribute);
- }
- catch (RuntimeException ex)
- {
- System.err.println("Unexpected error while performing partial evaluation:");
- System.err.println(" Class = ["+clazz.getName()+"]");
- System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]");
- System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")");
-
- 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;
- }
- }
-
-
- public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
- // Evaluate the instructions, starting at the entry point.
- if (DEBUG)
- {
- System.out.println();
- System.out.println("Partial evaluation: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
- System.out.println(" Max locals = "+codeAttribute.u2maxLocals);
- System.out.println(" Max stack = "+codeAttribute.u2maxStack);
- }
-
- // Reuse the existing variables and stack objects, ensuring the right size.
- TracedVariables variables = new TracedVariables(codeAttribute.u2maxLocals);
- TracedStack stack = new TracedStack(codeAttribute.u2maxStack);
-
- // Initialize the reusable arrays and variables.
- initializeArrays(codeAttribute);
- initializeParameters(clazz, method, codeAttribute, variables);
-
- // Find all instruction offsets,...
- codeAttribute.accept(clazz, method, branchTargetFinder);
-
- // Start executing the first instruction block.
- evaluateInstructionBlockAndExceptionHandlers(clazz,
- method,
- codeAttribute,
- variables,
- stack,
- 0,
- codeAttribute.u4codeLength);
-
- if (DEBUG_RESULTS)
- {
- 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 >= 0)
- {
- 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);
- }
- }
-
-
- /**
- * Returns whether a block of instructions is ever used.
- */
- public boolean isTraced(int startOffset, int endOffset)
- {
- for (int index = startOffset; index < endOffset; index++)
- {
- if (isTraced(index))
- {
- return true;
- }
- }
-
- return false;
- }
-
-
- /**
- * Returns whether the instruction at the given offset has ever been
- * executed during the partial evaluation.
- */
- public boolean isTraced(int instructionOffset)
- {
- return evaluationCounts[instructionOffset] > 0;
- }
-
-
- /**
- * Returns whether there is an instruction at the given offset.
- */
- public boolean isInstruction(int instructionOffset)
- {
- return branchTargetFinder.isInstruction(instructionOffset);
- }
-
-
- /**
- * Returns whether the instruction at the given offset is the target of a
- * branch instruction or an exception.
- */
- public boolean isBranchOrExceptionTarget(int instructionOffset)
- {
- return branchTargetFinder.isBranchTarget(instructionOffset) ||
- branchTargetFinder.isExceptionHandler(instructionOffset);
- }
-
-
- /**
- * Returns whether the instruction at the given offset is the start of a
- * subroutine.
- */
- public boolean isSubroutineStart(int instructionOffset)
- {
- return branchTargetFinder.isSubroutineStart(instructionOffset);
- }
-
-
- /**
- * Returns whether the instruction at the given offset is a subroutine
- * invocation.
- */
- public boolean isSubroutineInvocation(int instructionOffset)
- {
- return branchTargetFinder.isSubroutineInvocation(instructionOffset);
- }
-
-
- /**
- * Returns whether the instruction at the given offset is part of a
- * subroutine.
- */
- public boolean isSubroutine(int instructionOffset)
- {
- return branchTargetFinder.isSubroutine(instructionOffset);
- }
-
-
- /**
- * Returns whether the subroutine at the given offset is ever returning
- * by means of a regular 'ret' instruction.
- */
- public boolean isSubroutineReturning(int instructionOffset)
- {
- return branchTargetFinder.isSubroutineReturning(instructionOffset);
- }
-
-
- /**
- * Returns the offset after the subroutine that starts at the given
- * offset.
- */
- public int subroutineEnd(int instructionOffset)
- {
- return branchTargetFinder.subroutineEnd(instructionOffset);
- }
-
-
- /**
- * Returns the instruction offset at which the object instance that is
- * created at the given 'new' instruction offset is initialized, or
- * <code>NONE</code> if it is not being created.
- */
- public int initializationOffset(int instructionOffset)
- {
- return branchTargetFinder.initializationOffset(instructionOffset);
- }
-
-
- /**
- * Returns whether the method is an instance initializer.
- */
- public boolean isInitializer()
- {
- return branchTargetFinder.isInitializer();
- }
-
-
- /**
- * Returns the instruction offset at which this initializer is calling
- * the "super" or "this" initializer method, or <code>NONE</code> if it is
- * not an initializer.
- */
- public int superInitializationOffset()
- {
- return branchTargetFinder.superInitializationOffset();
- }
-
-
- /**
- * Returns the offset of the 'new' instruction that corresponds to the
- * invocation of the instance initializer at the given offset, or
- * <code>AT_METHOD_ENTRY</code> if the invocation is calling the "super" or
- * "this" initializer method, , or <code>NONE</code> if it is not a 'new'
- * instruction.
- */
- public int creationOffset(int offset)
- {
- return branchTargetFinder.creationOffset(offset);
- }
-
-
- /**
- * Returns the variables before execution of the instruction at the given
- * offset.
- */
- public TracedVariables getVariablesBefore(int instructionOffset)
- {
- return variablesBefore[instructionOffset];
- }
-
-
- /**
- * Returns the variables after execution of the instruction at the given
- * offset.
- */
- public TracedVariables getVariablesAfter(int instructionOffset)
- {
- return variablesAfter[instructionOffset];
- }
-
-
- /**
- * Returns the stack before execution of the instruction at the given
- * offset.
- */
- public TracedStack getStackBefore(int instructionOffset)
- {
- return stacksBefore[instructionOffset];
- }
-
-
- /**
- * Returns the stack after execution of the instruction at the given
- * offset.
- */
- public TracedStack getStackAfter(int instructionOffset)
- {
- return stacksAfter[instructionOffset];
- }
-
-
- /**
- * Returns the instruction offsets that branch to the given instruction
- * offset.
- */
- public InstructionOffsetValue branchOrigins(int instructionOffset)
- {
- return branchOriginValues[instructionOffset];
- }
-
-
- /**
- * Returns the instruction offsets to which the given instruction offset
- * branches.
- */
- public InstructionOffsetValue branchTargets(int instructionOffset)
- {
- return branchTargetValues[instructionOffset];
- }
-
-
- // Utility methods to evaluate instruction blocks.
-
- /**
- * Pushes block of instructions to be executed in the calling partial
- * evaluator.
- */
- private void pushCallingInstructionBlock(TracedVariables variables,
- TracedStack stack,
- int startOffset)
- {
- callingInstructionBlockStack.push(new MyInstructionBlock(variables,
- stack,
- startOffset));
- }
-
-
- /**
- * Pushes block of instructions to be executed in this partial evaluator.
- */
- private void pushInstructionBlock(TracedVariables variables,
- TracedStack stack,
- int startOffset)
- {
- instructionBlockStack.push(new MyInstructionBlock(variables,
- stack,
- startOffset));
- }
-
-
- /**
- * Evaluates the instruction block and the exception handlers covering the
- * given instruction range in the given code.
- */
- private void evaluateInstructionBlockAndExceptionHandlers(Clazz clazz,
- Method method,
- CodeAttribute codeAttribute,
- TracedVariables variables,
- TracedStack stack,
- int startOffset,
- int endOffset)
- {
- evaluateInstructionBlock(clazz,
- method,
- codeAttribute,
- variables,
- stack,
- startOffset);
-
- evaluateExceptionHandlers(clazz,
- method,
- codeAttribute,
- startOffset,
- endOffset);
- }
-
-
- /**
- * Evaluates a block of instructions, starting at the given offset and ending
- * at a branch instruction, a return instruction, or a throw instruction.
- */
- private void evaluateInstructionBlock(Clazz clazz,
- Method method,
- CodeAttribute codeAttribute,
- TracedVariables variables,
- TracedStack stack,
- int startOffset)
- {
- // Execute the initial instruction block.
- evaluateSingleInstructionBlock(clazz,
- method,
- codeAttribute,
- variables,
- stack,
- startOffset);
-
- // Execute all resulting instruction blocks on the execution stack.
- while (!instructionBlockStack.empty())
- {
- if (DEBUG) System.out.println("Popping alternative branch out of "+instructionBlockStack.size()+" blocks");
-
- MyInstructionBlock instructionBlock =
- (MyInstructionBlock)instructionBlockStack.pop();
-
- evaluateSingleInstructionBlock(clazz,
- method,
- codeAttribute,
- instructionBlock.variables,
- instructionBlock.stack,
- instructionBlock.startOffset);
- }
- }
-
-
- /**
- * Evaluates a block of instructions, starting at the given offset and ending
- * at a branch instruction, a return instruction, or a throw instruction.
- * Instruction blocks that are to be evaluated as a result are pushed on
- * the given stack.
- */
- private void evaluateSingleInstructionBlock(Clazz clazz,
- Method method,
- CodeAttribute codeAttribute,
- TracedVariables variables,
- TracedStack stack,
- int startOffset)
- {
- byte[] code = codeAttribute.code;
-
- if (DEBUG)
- {
- System.out.println("Instruction block starting at ["+startOffset+"] in "+
- ClassUtil.externalFullMethodDescription(clazz.getName(),
- 0,
- method.getName(clazz),
- method.getDescriptor(clazz)));
- System.out.println("Init vars: "+variables);
- System.out.println("Init stack: "+stack);
- }
-
- Processor processor = new Processor(variables,
- stack,
- valueFactory,
- branchUnit,
- invocationUnit,
- evaluateAllCode);
-
- int instructionOffset = startOffset;
-
- int maxOffset = startOffset;
-
- // Evaluate the subsequent instructions.
- while (true)
- {
- if (maxOffset < instructionOffset)
- {
- maxOffset = instructionOffset;
- }
-
- // Maintain a generalized local variable frame and stack at this
- // instruction offset, before execution.
- int evaluationCount = evaluationCounts[instructionOffset];
- if (evaluationCount == 0)
- {
- // First time we're passing by this instruction.
- if (variablesBefore[instructionOffset] == null)
- {
- // There's not even a context at this index yet.
- variablesBefore[instructionOffset] = new TracedVariables(variables);
- stacksBefore[instructionOffset] = new TracedStack(stack);
- }
- else
- {
- // Reuse the context objects at this index.
- variablesBefore[instructionOffset].initialize(variables);
- stacksBefore[instructionOffset].copy(stack);
- }
-
- // We'll execute in the generalized context, because it is
- // the same as the current context.
- generalizedContexts[instructionOffset] = true;
- }
- else
- {
- // Merge in the current context.
- boolean variablesChanged = variablesBefore[instructionOffset].generalize(variables, true);
- boolean stackChanged = stacksBefore[instructionOffset].generalize(stack);
-
- //System.out.println("GVars: "+variablesBefore[instructionOffset]);
- //System.out.println("GStack: "+stacksBefore[instructionOffset]);
-
- // Bail out if the current context is the same as last time.
- if (!variablesChanged &&
- !stackChanged &&
- generalizedContexts[instructionOffset])
- {
- if (DEBUG) System.out.println("Repeated variables, stack, and branch targets");
-
- break;
- }
-
- // See if this instruction has been evaluated an excessive number
- // of times.
- if (evaluationCount >= MAXIMUM_EVALUATION_COUNT)
- {
- if (DEBUG) System.out.println("Generalizing current context after "+evaluationCount+" evaluations");
-
- // Continue, but generalize the current context.
- // Note that the most recent variable values have to remain
- // last in the generalizations, for the sake of the ret
- // instruction.
- variables.generalize(variablesBefore[instructionOffset], false);
- stack.generalize(stacksBefore[instructionOffset]);
-
- // We'll execute in the generalized context.
- generalizedContexts[instructionOffset] = true;
- }
- else
- {
- // We'll execute in the current context.
- generalizedContexts[instructionOffset] = false;
- }
- }
-
- // We'll evaluate this instruction.
- evaluationCounts[instructionOffset]++;
-
- // Remember this instruction's offset with any stored value.
- Value storeValue = new InstructionOffsetValue(instructionOffset);
- variables.setProducerValue(storeValue);
- stack.setProducerValue(storeValue);
-
- // Reset the trace value.
- InstructionOffsetValue traceValue = InstructionOffsetValue.EMPTY_VALUE;
-
- // Note that the instruction is only volatile.
- Instruction instruction = InstructionFactory.create(code, instructionOffset);
-
- // By default, the next instruction will be the one after this
- // instruction.
- int nextInstructionOffset = instructionOffset +
- instruction.length(instructionOffset);
- InstructionOffsetValue nextInstructionOffsetValue = new InstructionOffsetValue(nextInstructionOffset);
- branchUnit.resetCalled();
- branchUnit.setTraceBranchTargets(nextInstructionOffsetValue);
-
- if (DEBUG)
- {
- System.out.println(instruction.toString(instructionOffset));
- }
-
- try
- {
- // Process the instruction. The processor may modify the
- // variables and the stack, and it may call the branch unit
- // and the invocation unit.
- instruction.accept(clazz,
- method,
- codeAttribute,
- instructionOffset,
- processor);
- }
- catch (RuntimeException ex)
- {
- System.err.println("Unexpected error while evaluating instruction:");
- System.err.println(" Class = ["+clazz.getName()+"]");
- System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]");
- System.err.println(" Instruction = "+instruction.toString(instructionOffset));
- System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")");
-
- throw ex;
- }
-
- // Collect the branch targets from the branch unit.
- InstructionOffsetValue branchTargets = branchUnit.getTraceBranchTargets();
- int branchTargetCount = branchTargets.instructionOffsetCount();
-
- // Stop tracing.
- branchUnit.setTraceBranchTargets(traceValue);
-
- if (DEBUG)
- {
- if (branchUnit.wasCalled())
- {
- System.out.println(" is branching to "+branchTargets);
- }
- if (branchTargetValues[instructionOffset] != null)
- {
- System.out.println(" has up till now been branching to "+branchTargetValues[instructionOffset]);
- }
-
- System.out.println(" Vars: "+variables);
- System.out.println(" Stack: "+stack);
- }
-
- // Maintain a generalized local variable frame and stack at this
- // instruction offset, after execution.
- if (evaluationCount == 0)
- {
- // First time we're passing by this instruction.
- if (variablesAfter[instructionOffset] == null)
- {
- // There's not even a context at this index yet.
- variablesAfter[instructionOffset] = new TracedVariables(variables);
- stacksAfter[instructionOffset] = new TracedStack(stack);
- }
- else
- {
- // Reuse the context objects at this index.
- variablesAfter[instructionOffset].initialize(variables);
- stacksAfter[instructionOffset].copy(stack);
- }
- }
- else
- {
- // Merge in the current context.
- variablesAfter[instructionOffset].generalize(variables, true);
- stacksAfter[instructionOffset].generalize(stack);
- }
-
- // Did the branch unit get called?
- if (branchUnit.wasCalled())
- {
- // Accumulate the branch targets at this offset.
- branchTargetValues[instructionOffset] = branchTargetValues[instructionOffset] == null ?
- branchTargets :
- branchTargetValues[instructionOffset].generalize(branchTargets).instructionOffsetValue();
-
- // Are there no branch targets at all?
- if (branchTargetCount == 0)
- {
- // Exit from this code block.
- break;
- }
-
- // Accumulate the branch origins at the branch target offsets.
- InstructionOffsetValue instructionOffsetValue = new InstructionOffsetValue(instructionOffset);
- for (int index = 0; index < branchTargetCount; index++)
- {
- int branchTarget = branchTargets.instructionOffset(index);
- branchOriginValues[branchTarget] = branchOriginValues[branchTarget] == null ?
- instructionOffsetValue:
- branchOriginValues[branchTarget].generalize(instructionOffsetValue).instructionOffsetValue();
- }
-
- // Are there multiple branch targets?
- if (branchTargetCount > 1)
- {
- // Push them on the execution stack and exit from this block.
- for (int index = 0; index < branchTargetCount; index++)
- {
- if (DEBUG) System.out.println("Pushing alternative branch #"+index+" out of "+branchTargetCount+", from ["+instructionOffset+"] to ["+branchTargets.instructionOffset(index)+"]");
-
- pushInstructionBlock(new TracedVariables(variables),
- new TracedStack(stack),
- branchTargets.instructionOffset(index));
- }
-
- break;
- }
-
- if (DEBUG) System.out.println("Definite branch from ["+instructionOffset+"] to ["+branchTargets.instructionOffset(0)+"]");
- }
-
- // Just continue with the next instruction.
- instructionOffset = branchTargets.instructionOffset(0);
-
- // Is this a subroutine invocation?
- if (instruction.opcode == InstructionConstants.OP_JSR ||
- instruction.opcode == InstructionConstants.OP_JSR_W)
- {
- // Evaluate the subroutine in another partial evaluator.
- evaluateSubroutine(clazz,
- method,
- codeAttribute,
- variables,
- stack,
- instructionOffset,
- instructionBlockStack);
-
- break;
- }
- else if (instruction.opcode == InstructionConstants.OP_RET)
- {
- // Let the partial evaluator that has called the subroutine
- // handle the evaluation after the return.
- pushCallingInstructionBlock(new TracedVariables(variables),
- new TracedStack(stack),
- instructionOffset);
- break;
- }
- }
-
- if (DEBUG) System.out.println("Ending processing of instruction block starting at ["+startOffset+"]");
- }
-
-
- /**
- * Evaluates a subroutine and its exception handlers, starting at the given
- * offset and ending at a subroutine return instruction.
- */
- private void evaluateSubroutine(Clazz clazz,
- Method method,
- CodeAttribute codeAttribute,
- TracedVariables variables,
- TracedStack stack,
- int subroutineStart,
- java.util.Stack instructionBlockStack)
- {
- int subroutineEnd = branchTargetFinder.subroutineEnd(subroutineStart);
-
- if (DEBUG) System.out.println("Evaluating subroutine from "+subroutineStart+" to "+subroutineEnd);
-
- // Create a temporary partial evaluator, so there are no conflicts
- // with variables that are alive across subroutine invocations, between
- // different invocations.
- PartialEvaluator subroutinePartialEvaluator =
- new PartialEvaluator(this);
-
- subroutinePartialEvaluator.initializeArrays(codeAttribute);
-
- // Evaluate the subroutine.
- subroutinePartialEvaluator.evaluateInstructionBlockAndExceptionHandlers(clazz,
- method,
- codeAttribute,
- variables,
- stack,
- subroutineStart,
- subroutineEnd);
-
- // Merge back the temporary partial evaluator. This way, we'll get
- // the lowest common denominator of stacks and variables.
- generalize(subroutinePartialEvaluator, 0, codeAttribute.u4codeLength);
-
- if (DEBUG) System.out.println("Ending subroutine from "+subroutineStart+" to "+subroutineEnd);
- }
-
-
- /**
- * Generalizes the results of this partial evaluator with those of another
- * given partial evaluator, over a given range of instructions.
- */
- private void generalize(PartialEvaluator other,
- int codeStart,
- int codeEnd)
- {
- if (DEBUG) System.out.println("Generalizing with temporary partial evaluation");
-
- for (int offset = codeStart; offset < codeEnd; offset++)
- {
- if (other.branchOriginValues[offset] != null)
- {
- branchOriginValues[offset] = branchOriginValues[offset] == null ?
- other.branchOriginValues[offset] :
- branchOriginValues[offset].generalize(other.branchOriginValues[offset]).instructionOffsetValue();
- }
-
- if (other.isTraced(offset))
- {
- if (other.branchTargetValues[offset] != null)
- {
- branchTargetValues[offset] = branchTargetValues[offset] == null ?
- other.branchTargetValues[offset] :
- branchTargetValues[offset].generalize(other.branchTargetValues[offset]).instructionOffsetValue();
- }
-
- 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];
- }
- else
- {
- variablesBefore[offset].generalize(other.variablesBefore[offset], false);
- stacksBefore[offset] .generalize(other.stacksBefore[offset]);
- variablesAfter[offset] .generalize(other.variablesAfter[offset], false);
- stacksAfter[offset] .generalize(other.stacksAfter[offset]);
- //generalizedContexts[offset]
- evaluationCounts[offset] += other.evaluationCounts[offset];
- }
- }
- }
- }
-
-
- /**
- * Evaluates the exception handlers covering and targeting the given
- * instruction range in the given code.
- */
- private void evaluateExceptionHandlers(Clazz clazz,
- Method method,
- CodeAttribute codeAttribute,
- int startOffset,
- int endOffset)
- {
- if (DEBUG) System.out.println("Evaluating exceptions covering ["+startOffset+" -> "+endOffset+"]:");
-
- ExceptionHandlerFilter exceptionEvaluator =
- new ExceptionHandlerFilter(startOffset,
- endOffset,
- this);
-
- // Evaluate the exception catch blocks, until their entry variables
- // have stabilized.
- do
- {
- // Reset the flag to stop evaluating.
- evaluateExceptions = false;
-
- // Evaluate all relevant exception catch blocks once.
- codeAttribute.exceptionsAccept(clazz,
- method,
- startOffset,
- endOffset,
- exceptionEvaluator);
- }
- while (evaluateExceptions);
- }
-
-
- // Implementations for ExceptionInfoVisitor.
-
- public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
- {
- int startPC = exceptionInfo.u2startPC;
- int endPC = exceptionInfo.u2endPC;
-
- // Do we have to evaluate this exception catch block?
- if (isTraced(startPC, endPC))
- {
- int handlerPC = exceptionInfo.u2handlerPC;
- int catchType = exceptionInfo.u2catchType;
-
- if (DEBUG) System.out.println("Evaluating exception ["+startPC +" -> "+endPC +": "+handlerPC+"]:");
-
- // Reuse the existing variables and stack objects, ensuring the
- // right size.
- TracedVariables variables = new TracedVariables(codeAttribute.u2maxLocals);
- TracedStack stack = new TracedStack(codeAttribute.u2maxStack);
-
- // Initialize the trace values.
- Value storeValue = new InstructionOffsetValue(AT_CATCH_ENTRY);
- variables.setProducerValue(storeValue);
- stack.setProducerValue(storeValue);
-
- // Initialize the variables by generalizing the variables of the
- // try block. Make sure to include the results of the last
- // instruction for preverification.
- generalizeVariables(startPC,
- endPC,
- evaluateAllCode,
- variables);
-
- // Initialize the the stack.
- //stack.push(valueFactory.createReference((ClassConstant)((ProgramClass)clazz).getConstant(exceptionInfo.u2catchType), false));
- String catchClassName = catchType != 0 ?
- clazz.getClassName(catchType) :
- ClassConstants.NAME_JAVA_LANG_THROWABLE;
-
- Clazz catchClass = catchType != 0 ?
- ((ClassConstant)((ProgramClass)clazz).getConstant(catchType)).referencedClass :
- null;
-
- stack.push(valueFactory.createReferenceValue(catchClassName,
- catchClass,
- false));
-
- int evaluationCount = evaluationCounts[handlerPC];
-
- // Evaluate the instructions, starting at the entry point.
- evaluateInstructionBlock(clazz,
- method,
- codeAttribute,
- variables,
- stack,
- handlerPC);
-
- // Remember to evaluate all exception handlers once more.
- if (!evaluateExceptions)
- {
- evaluateExceptions = evaluationCount < evaluationCounts[handlerPC];
- }
- }
-// else if (evaluateAllCode)
-// {
-// if (DEBUG) System.out.println("No information for partial evaluation of exception ["+startPC +" -> "+endPC +": "+exceptionInfo.u2handlerPC+"] yet");
-//
-// // We don't have any information on the try block yet, but we do
-// // have to evaluate the exception handler.
-// // Remember to evaluate all exception handlers once more.
-// evaluateExceptions = true;
-// }
- else
- {
- if (DEBUG) System.out.println("No information for partial evaluation of exception ["+startPC +" -> "+endPC +": "+exceptionInfo.u2handlerPC+"]");
- }
- }
-
-
- // Small utility methods.
-
- /**
- * Initializes the data structures for the variables, stack, etc.
- */
- private void initializeArrays(CodeAttribute codeAttribute)
- {
- int codeLength = codeAttribute.u4codeLength;
-
- // Create new arrays for storing information at each instruction offset.
- 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];
- }
- 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++)
- {
- if (variablesBefore[index] != null)
- {
- variablesBefore[index].reset(codeAttribute.u2maxLocals);
- }
-
- if (stacksBefore[index] != null)
- {
- stacksBefore[index].reset(codeAttribute.u2maxStack);
- }
-
- if (variablesAfter[index] != null)
- {
- variablesAfter[index].reset(codeAttribute.u2maxLocals);
- }
-
- if (stacksAfter[index] != null)
- {
- stacksAfter[index].reset(codeAttribute.u2maxStack);
- }
- }
- }
- }
-
-
- /**
- * 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);
-
- // Remember this instruction's offset with any stored value.
- Value storeValue = new InstructionOffsetValue(AT_METHOD_ENTRY);
- parameters.setProducerValue(storeValue);
-
- // Initialize the method parameters.
- invocationUnit.enterMethod(clazz, method, parameters);
-
- if (DEBUG)
- {
- System.out.println(" Params: "+parameters);
- }
-
- // Initialize the variables with the parameters.
- variables.initialize(parameters);
-
- // Set the store value of each parameter variable.
- InstructionOffsetValue atMethodEntry = new InstructionOffsetValue(AT_METHOD_ENTRY);
-
- for (int index = 0; index < parameters.size(); index++)
- {
- variables.setProducerValue(index, atMethodEntry);
- }
- }
-
-
- /**
- * Generalize the local variable frames of a block of instructions.
- */
- private void generalizeVariables(int startOffset,
- int endOffset,
- boolean includeAfterLastInstruction,
- TracedVariables generalizedVariables)
- {
- boolean first = true;
- int lastIndex = -1;
-
- // Generalize the variables before each of the instructions in the block.
- for (int index = startOffset; index < endOffset; index++)
- {
- if (isTraced(index))
- {
- TracedVariables tracedVariables = variablesBefore[index];
-
- if (first)
- {
- // Initialize the variables with the first traced local
- // variable frame.
- generalizedVariables.initialize(tracedVariables);
-
- first = false;
- }
- else
- {
- // Generalize the variables with the traced local variable
- // frame. We can't use the return value, because local
- // generalization can be different a couple of times,
- // with the global generalization being the same.
- generalizedVariables.generalize(tracedVariables, false);
- }
-
- lastIndex = index;
- }
- }
-
- // Generalize the variables after the last instruction in the block,
- // if required.
- if (includeAfterLastInstruction &&
- lastIndex >= 0)
- {
- TracedVariables tracedVariables = variablesAfter[lastIndex];
-
- if (first)
- {
- // Initialize the variables with the local variable frame.
- generalizedVariables.initialize(tracedVariables);
- }
- else
- {
- // Generalize the variables with the local variable frame.
- generalizedVariables.generalize(tracedVariables, false);
- }
- }
-
- // Just clear the variables if there aren't any traced instructions
- // in the block.
- if (first)
- {
- generalizedVariables.reset(generalizedVariables.size());
- }
- }
-
-
- private static class MyInstructionBlock
- {
- private TracedVariables variables;
- private TracedStack stack;
- private int startOffset;
-
-
- private MyInstructionBlock(TracedVariables variables,
- TracedStack stack,
- int startOffset)
- {
- this.variables = variables;
- this.stack = stack;
- this.startOffset = startOffset;
- }
- }
-}
diff --git a/src/proguard/optimize/evaluation/SimpleEnumArrayPropagator.java b/src/proguard/optimize/evaluation/SimpleEnumArrayPropagator.java
deleted file mode 100644
index d6aaf7d..0000000
--- a/src/proguard/optimize/evaluation/SimpleEnumArrayPropagator.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * 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
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.optimize.evaluation;
-
-import proguard.classfile.*;
-import proguard.classfile.util.SimplifiedVisitor;
-import proguard.classfile.visitor.*;
-import proguard.evaluation.value.*;
-import proguard.optimize.info.*;
-
-/**
- * This ClassVisitor propagates the value of the $VALUES field to the values()
- * method in the simple enum classes that it visits.
- *
- * @see SimpleEnumMarker
- * @author Eric Lafortune
- */
-public class SimpleEnumArrayPropagator
-extends SimplifiedVisitor
-implements ClassVisitor,
- MemberVisitor
-{
- private final ValueFactory valueFactory = new ParticularValueFactory();
-
- private Value array;
-
-
- // Implementations for ClassVisitor.
-
- public void visitProgramClass(ProgramClass programClass)
- {
- // Update the return value of the "int[] values()" method.
- programClass.methodsAccept(new MemberDescriptorFilter("()[I", this));
- }
-
-
- // Implementations for MemberVisitor.
-
- public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
- {
- // Find the array length of the "int[] $VALUES" field.
- programClass.fieldsAccept(new MemberDescriptorFilter("[I", this));
-
- if (array != null)
- {
- // Set the array value with the found array length. We can't use
- // the original array, because its elements might get overwritten.
- Value propagatedArray =
- valueFactory.createArrayReferenceValue("I",
- null,
- array.referenceValue().arrayLength(
- valueFactory));
-
- setMethodReturnValue(programMethod, propagatedArray);
-
- array = null;
- }
- }
-
- public void visitProgramField(ProgramClass programClass, ProgramField programField)
- {
- array = StoringInvocationUnit.getFieldValue(programField);
- }
-
-
- // Small utility methods.
-
- private static void setMethodReturnValue(Method method, Value value)
- {
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.setReturnValue(value);
- }
- }
-}
diff --git a/src/proguard/optimize/evaluation/SimpleEnumClassChecker.java b/src/proguard/optimize/evaluation/SimpleEnumClassChecker.java
deleted file mode 100644
index 1bd5008..0000000
--- a/src/proguard/optimize/evaluation/SimpleEnumClassChecker.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * 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
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.optimize.evaluation;
-
-import proguard.classfile.*;
-import proguard.classfile.visitor.*;
-import proguard.optimize.info.SimpleEnumMarker;
-
-/**
- * This ClassVisitor marks all program classes that it visits as simple enums,
- * if their methods qualify.
- *
- * @author Eric Lafortune
- */
-public class SimpleEnumClassChecker
-implements ClassVisitor
-{
- //*
- private static final boolean DEBUG = false;
- /*/
- private static boolean DEBUG = System.getProperty("enum") != null;
- //*/
-
-
- private final SimpleEnumMarker simpleEnumMarker = new SimpleEnumMarker(true);
- private final MemberVisitor virtualMethodChecker = new MemberAccessFilter(0,
- ClassConstants.ACC_PRIVATE |
- ClassConstants.ACC_STATIC,
- new MemberToClassVisitor(
- new SimpleEnumMarker(false)));
-
-
- // Implementations for ClassVisitor.
-
- public void visitLibraryClass(LibraryClass libraryClass) {}
-
- public void visitProgramClass(ProgramClass programClass)
- {
- // Does the class have the simple enum constructor?
- if (programClass.findMethod(ClassConstants.METHOD_NAME_INIT,
- ClassConstants.METHOD_TYPE_INIT_ENUM) != null)
- {
- if (DEBUG)
- {
- System.out.println("SimpleEnumClassChecker: ["+programClass.getName()+"] is a candidate simple enum, without extra fields");
- }
-
- // Mark it.
- simpleEnumMarker.visitProgramClass(programClass);
-
- // However, unmark it again if it has any non-private, non-static
- // methods.
- programClass.methodsAccept(virtualMethodChecker);
- }
- }
-} \ No newline at end of file
diff --git a/src/proguard/optimize/evaluation/SimpleEnumClassSimplifier.java b/src/proguard/optimize/evaluation/SimpleEnumClassSimplifier.java
deleted file mode 100644
index 33f775f..0000000
--- a/src/proguard/optimize/evaluation/SimpleEnumClassSimplifier.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * 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
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.optimize.evaluation;
-
-import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.visitor.*;
-import proguard.classfile.constant.*;
-import proguard.classfile.editor.*;
-import proguard.classfile.instruction.*;
-import proguard.classfile.instruction.visitor.InstructionVisitor;
-import proguard.classfile.util.SimplifiedVisitor;
-import proguard.classfile.visitor.*;
-import proguard.optimize.info.SimpleEnumMarker;
-import proguard.optimize.peephole.*;
-
-/**
- * This ClassVisitor simplifies the classes that it visits to simple enums.
- *
- * @see SimpleEnumMarker
- * @see MemberReferenceFixer
- * @author Eric Lafortune
- */
-public class SimpleEnumClassSimplifier
-extends SimplifiedVisitor
-implements ClassVisitor,
- AttributeVisitor,
- InstructionVisitor
-{
- //*
- private static final boolean DEBUG = false;
- /*/
- private static boolean DEBUG = System.getProperty("enum") != null;
- //*/
-
-
- private static final int ENUM_CLASS_NAME = InstructionSequenceReplacer.A;
- private static final int ENUM_TYPE_NAME = InstructionSequenceReplacer.B;
- private static final int ENUM_CONSTANT_NAME = InstructionSequenceReplacer.X;
- private static final int ENUM_CONSTANT_ORDINAL = InstructionSequenceReplacer.Y;
- private static final int ENUM_CONSTANT_FIELD_NAME = InstructionSequenceReplacer.Z;
-
- private static final int STRING_ENUM_CONSTANT_NAME = 0;
-
- private static final int METHOD_ENUM_INIT = 1;
- private static final int FIELD_ENUM_CONSTANT = 2;
-
- private static final int CLASS_ENUM = 3;
-
- private static final int NAME_AND_TYPE_ENUM_INIT = 4;
- private static final int NAME_AND_TYPE_ENUM_CONSTANT = 5;
-
- private static final int UTF8_INIT = 6;
- private static final int UTF8_STRING_I = 7;
-
-
- private static final Constant[] CONSTANTS = new Constant[]
- {
- new StringConstant(ENUM_CONSTANT_NAME, null, null),
-
- new MethodrefConstant(CLASS_ENUM, NAME_AND_TYPE_ENUM_INIT, null, null),
- new FieldrefConstant( CLASS_ENUM, NAME_AND_TYPE_ENUM_CONSTANT, null, null),
-
- new ClassConstant(ENUM_CLASS_NAME, null),
-
- new NameAndTypeConstant(UTF8_INIT, UTF8_STRING_I),
- new NameAndTypeConstant(ENUM_CONSTANT_FIELD_NAME, ENUM_TYPE_NAME),
-
- new Utf8Constant(ClassConstants.METHOD_NAME_INIT),
- new Utf8Constant(ClassConstants.METHOD_TYPE_INIT_ENUM),
- };
-
- private static final Instruction[] INSTRUCTIONS = new Instruction[]
- {
- new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_ENUM),
- new SimpleInstruction(InstructionConstants.OP_DUP),
- new ConstantInstruction(InstructionConstants.OP_LDC, STRING_ENUM_CONSTANT_NAME),
- new SimpleInstruction(InstructionConstants.OP_ICONST_0, ENUM_CONSTANT_ORDINAL),
- new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_ENUM_INIT),
- };
-
- private static final Instruction[] REPLACEMENT_INSTRUCTIONS = new Instruction[]
- {
- new SimpleInstruction(InstructionConstants.OP_SIPUSH, ENUM_CONSTANT_ORDINAL),
- new SimpleInstruction(InstructionConstants.OP_ICONST_1),
- new SimpleInstruction(InstructionConstants.OP_IADD),
- };
-
-
- private final CodeAttributeEditor codeAttributeEditor =
- new CodeAttributeEditor(true, true);
-
- private final InstructionSequenceReplacer instructionSequenceReplacer =
- new InstructionSequenceReplacer(CONSTANTS,
- INSTRUCTIONS,
- REPLACEMENT_INSTRUCTIONS,
- null,
- codeAttributeEditor);
-
- private final MemberVisitor initializerSimplifier = new AllAttributeVisitor(this);
-
-
- // Implementations for ClassVisitor.
-
- public void visitProgramClass(ProgramClass programClass)
- {
- if (DEBUG)
- {
- System.out.println("SimpleEnumClassSimplifier: ["+programClass.getName()+"]");
- }
-
- // Unmark the class as an enum.
- programClass.u2accessFlags &= ~ClassConstants.ACC_ENUM;
-
- // Remove the valueOf method, if present.
- Method valueOfMethod =
- programClass.findMethod(ClassConstants.METHOD_NAME_VALUEOF, null);
- if (valueOfMethod != null)
- {
- new ClassEditor(programClass).removeMethod(valueOfMethod);
- }
-
- // Simplify the static initializer.
- programClass.methodAccept(ClassConstants.METHOD_NAME_CLINIT,
- ClassConstants.METHOD_TYPE_CLINIT,
- initializerSimplifier);
- }
-
-
- // Implementations for AttributeVisitor.
-
- public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
-
-
- public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
- // Set up the code attribute editor.
- codeAttributeEditor.reset(codeAttribute.u4codeLength);
-
- // Find the peephole changes.
- codeAttribute.instructionsAccept(clazz, method, instructionSequenceReplacer);
-
- // Apply the peephole changes.
- codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
- }
-}
diff --git a/src/proguard/optimize/evaluation/SimpleEnumDescriptorSimplifier.java b/src/proguard/optimize/evaluation/SimpleEnumDescriptorSimplifier.java
deleted file mode 100644
index f1323ea..0000000
--- a/src/proguard/optimize/evaluation/SimpleEnumDescriptorSimplifier.java
+++ /dev/null
@@ -1,583 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * 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
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.optimize.evaluation;
-
-import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.visitor.*;
-import proguard.classfile.constant.*;
-import proguard.classfile.constant.visitor.ConstantVisitor;
-import proguard.classfile.editor.*;
-import proguard.classfile.instruction.visitor.InstructionVisitor;
-import proguard.classfile.util.*;
-import proguard.classfile.visitor.*;
-import proguard.optimize.info.*;
-
-/**
- * This ClassVisitor simplifies the descriptors that contain simple enums in
- * the program classes that it visits.
- *
- * @see SimpleEnumMarker
- * @see MemberReferenceFixer
- * @author Eric Lafortune
- */
-public class SimpleEnumDescriptorSimplifier
-extends SimplifiedVisitor
-implements ClassVisitor,
- ConstantVisitor,
- MemberVisitor,
- AttributeVisitor,
- LocalVariableInfoVisitor,
- LocalVariableTypeInfoVisitor
-{
- //*
- private static final boolean DEBUG = false;
- /*/
- private static boolean DEBUG = System.getProperty("enum") != null;
- //*/
-
-
- // Implementations for ClassVisitor.
-
- public void visitProgramClass(ProgramClass programClass)
- {
- if (DEBUG)
- {
- System.out.println("SimpleEnumDescriptorSimplifier: "+programClass.getName());
- }
-
- // Simplify the class members.
- programClass.fieldsAccept(this);
- programClass.methodsAccept(this);
-
- // Simplify the attributes.
- //programClass.attributesAccept(this);
-
- // Simplify the simple enum array constants.
- programClass.constantPoolEntriesAccept(this);
- }
-
-
- // Implementations for ConstantVisitor.
-
- public void visitAnyConstant(Clazz clazz, Constant constant) {}
-
-
- public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
- {
- // Does the constant refer to a simple enum type?
- Clazz referencedClass = stringConstant.referencedClass;
- if (isSimpleEnum(referencedClass))
- {
- // Is it an array type?
- String name = stringConstant.getString(clazz);
- if (ClassUtil.isInternalArrayType(name))
- {
- // Update the type.
- ConstantPoolEditor constantPoolEditor =
- new ConstantPoolEditor((ProgramClass)clazz);
-
- String newName = simplifyDescriptor(name, referencedClass);
-
- stringConstant.u2stringIndex =
- constantPoolEditor.addUtf8Constant(newName);
-
- // Clear the referenced class.
- stringConstant.referencedClass = null;
- }
- }
- }
-
-
- public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
- {
- // Update the descriptor if it has any simple enum classes.
- String descriptor = invokeDynamicConstant.getType(clazz);
- String newDescriptor = simplifyDescriptor(descriptor, invokeDynamicConstant.referencedClasses);
-
- if (!descriptor.equals(newDescriptor))
- {
- // Update the descriptor.
- ConstantPoolEditor constantPoolEditor =
- new ConstantPoolEditor((ProgramClass)clazz);
-
- invokeDynamicConstant.u2nameAndTypeIndex =
- constantPoolEditor.addNameAndTypeConstant(invokeDynamicConstant.getName(clazz),
- newDescriptor);
-
- // Update the referenced classes.
- invokeDynamicConstant.referencedClasses =
- simplifyReferencedClasses(descriptor, invokeDynamicConstant.referencedClasses);
- }
- }
-
-
- public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
- {
- // Does the constant refer to a simple enum type?
- Clazz referencedClass = classConstant.referencedClass;
- if (isSimpleEnum(referencedClass))
- {
- // Is it an array type?
- String name = classConstant.getName(clazz);
- if (ClassUtil.isInternalArrayType(name))
- {
- // Update the type.
- ConstantPoolEditor constantPoolEditor =
- new ConstantPoolEditor((ProgramClass)clazz);
-
- String newName = simplifyDescriptor(name, referencedClass);
-
- classConstant.u2nameIndex =
- constantPoolEditor.addUtf8Constant(newName);
-
- // Clear the referenced class.
- classConstant.referencedClass = null;
- }
- }
- }
-
-
- // Implementations for MemberVisitor.
-
- public void visitProgramField(ProgramClass programClass, ProgramField programField)
- {
- // Update the descriptor if it has a simple enum class.
- String descriptor = programField.getDescriptor(programClass);
- String newDescriptor = simplifyDescriptor(descriptor, programField.referencedClass);
-
- if (!descriptor.equals(newDescriptor))
- {
- String name = programField.getName(programClass);
- String newName = name + ClassConstants.SPECIAL_MEMBER_SEPARATOR + Long.toHexString(Math.abs((descriptor).hashCode()));
-
- if (DEBUG)
- {
- System.out.println("SimpleEnumDescriptorSimplifier: ["+programClass.getName()+"."+name+" "+descriptor + "] -> ["+newName+" "+newDescriptor+"]");
- }
-
- ConstantPoolEditor constantPoolEditor =
- new ConstantPoolEditor(programClass);
-
- // Update the name.
- programField.u2nameIndex =
- constantPoolEditor.addUtf8Constant(newName);
-
- // Update the descriptor itself.
- programField.u2descriptorIndex =
- constantPoolEditor.addUtf8Constant(newDescriptor);
-
- // Clear the referenced class.
- programField.referencedClass = null;
-
- // Clear the field value.
- FieldOptimizationInfo fieldOptimizationInfo =
- FieldOptimizationInfo.getFieldOptimizationInfo(programField);
- if (fieldOptimizationInfo != null)
- {
- fieldOptimizationInfo.resetValue(programClass, programField);
- }
-
- // Simplify the signature.
- programField.attributesAccept(programClass, this);
- }
- }
-
-
- public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
- {
-// // Skip the valueOf method.
-// if (programMethod.getName(programClass).equals(ClassConstants.METHOD_NAME_VALUEOF))
-// {
-// return;
-// }
-
- // Simplify the code, the signature, and the parameter annotations,
- // before simplifying the descriptor.
- programMethod.attributesAccept(programClass, this);
-
- // Update the descriptor if it has any simple enum classes.
- String descriptor = programMethod.getDescriptor(programClass);
- String newDescriptor = simplifyDescriptor(descriptor, programMethod.referencedClasses);
-
- if (!descriptor.equals(newDescriptor))
- {
- String name = programMethod.getName(programClass);
- String newName = name;
-
- // Append a code, if the method isn't a class instance initializer.
- if (!name.equals(ClassConstants.METHOD_NAME_INIT))
- {
- newName += ClassConstants.SPECIAL_MEMBER_SEPARATOR + Long.toHexString(Math.abs((descriptor).hashCode()));
- }
-
- if (DEBUG)
- {
- System.out.println("SimpleEnumDescriptorSimplifier: ["+programClass.getName()+"."+name+descriptor+"] -> ["+newName+newDescriptor+"]");
- }
-
- ConstantPoolEditor constantPoolEditor =
- new ConstantPoolEditor(programClass);
-
- // Update the name, if necessary.
- if (!newName.equals(name))
- {
- programMethod.u2nameIndex =
- constantPoolEditor.addUtf8Constant(newName);
- }
-
- // Update the descriptor itself.
- programMethod.u2descriptorIndex =
- constantPoolEditor.addUtf8Constant(newDescriptor);
-
- // Update the referenced classes.
- programMethod.referencedClasses =
- simplifyReferencedClasses(descriptor, programMethod.referencedClasses);
- }
- }
-
-
- // Implementations for AttributeVisitor.
-
- public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
-
-
- public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
- // Simplify the local variable descriptors.
- codeAttribute.attributesAccept(clazz, method, this);
- }
-
-
- public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
- {
- // Change the references of the local variables.
- localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
- }
-
-
- public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
- {
- // Change the references of the local variables.
- localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
- }
-
-
- public void visitSignatureAttribute(Clazz clazz, Field field, SignatureAttribute signatureAttribute)
- {
- // We're only looking at the base type for now.
- if (signatureAttribute.referencedClasses != null &&
- signatureAttribute.referencedClasses.length > 0)
- {
- // Update the signature if it has any simple enum classes.
- String signature = signatureAttribute.getSignature(clazz);
- String newSignature = simplifyDescriptor(signature,
- signatureAttribute.referencedClasses[0]);
-
- if (!signature.equals(newSignature))
- {
- // Update the signature.
- signatureAttribute.u2signatureIndex =
- new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSignature);
-
- // Clear the referenced class.
- signatureAttribute.referencedClasses[0] = null;
- }
- }
- }
-
-
- public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute signatureAttribute)
- {
- // Compute the new signature.
- String signature = signatureAttribute.getSignature(clazz);
- String newSignature = simplifyDescriptor(signature,
- signatureAttribute.referencedClasses);
-
- if (!signature.equals(newSignature))
- {
- // Update the signature.
- signatureAttribute.u2signatureIndex =
- new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSignature);
- }
- }
-
-
- // Implementations for LocalVariableInfoVisitor.
-
- public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
- {
- // Update the descriptor if it has a simple enum class.
- String descriptor = localVariableInfo.getDescriptor(clazz);
- String newDescriptor = simplifyDescriptor(descriptor, localVariableInfo.referencedClass);
-
- if (!descriptor.equals(newDescriptor))
- {
- // Update the descriptor.
- localVariableInfo.u2descriptorIndex =
- new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newDescriptor);
-
- // Clear the referenced class.
- localVariableInfo.referencedClass = null;
- }
- }
-
-
- // Implementations for LocalVariableTypeInfoVisitor.
-
- public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
- {
- // We're only looking at the base type for now.
- if (localVariableTypeInfo.referencedClasses != null &&
- localVariableTypeInfo.referencedClasses.length > 0)
- {
- // Update the signature if it has any simple enum classes.
- String signature = localVariableTypeInfo.getSignature(clazz);
- String newSignature = simplifyDescriptor(signature,
- localVariableTypeInfo.referencedClasses[0]);
-
- if (!signature.equals(newSignature))
- {
- // Update the signature.
- localVariableTypeInfo.u2signatureIndex =
- new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSignature);
-
- // Clear the referenced class.
- localVariableTypeInfo.referencedClasses[0] = null;
- }
- }
- }
-
-
- // Small utility methods.
-
- /**
- * Returns the descriptor with simplified enum type.
- */
- private String simplifyDescriptor(String descriptor,
- Clazz referencedClass)
- {
- return isSimpleEnum(referencedClass) ?
- descriptor.substring(0, ClassUtil.internalArrayTypeDimensionCount(descriptor)) + ClassConstants.TYPE_INT :
- descriptor;
- }
-
-
- /**
- * Returns the descriptor with simplified enum types.
- */
- private String simplifyDescriptor(String descriptor,
- Clazz[] referencedClasses)
- {
- if (referencedClasses != null)
- {
- InternalTypeEnumeration internalTypeEnumeration =
- new InternalTypeEnumeration(descriptor);
-
- int referencedClassIndex = 0;
-
- StringBuffer newDescriptorBuffer =
- new StringBuffer(descriptor.length());
-
- // Go over the formal type parameters.
- {
- // Consider the classes referenced by this formal type
- // parameter.
- String type = internalTypeEnumeration.formalTypeParameters();
- int count = new DescriptorClassEnumeration(type).classCount();
-
- // Replace simple enum types.
- for (int counter = 0; counter < count; counter++)
- {
- Clazz referencedClass =
- referencedClasses[referencedClassIndex++];
-
- if (isSimpleEnum(referencedClass))
- {
- // Let's replace the simple enum type by
- // java.lang.Integer.
- type =
- type.substring(0, ClassUtil.internalArrayTypeDimensionCount(type)) +
- ClassConstants.NAME_JAVA_LANG_INTEGER;
- }
- }
-
- newDescriptorBuffer.append(type);
- }
-
- newDescriptorBuffer.append(ClassConstants.METHOD_ARGUMENTS_OPEN);
-
- // Go over the parameters.
- while (internalTypeEnumeration.hasMoreTypes())
- {
- // Consider the classes referenced by this parameter type.
- String type = internalTypeEnumeration.nextType();
- int count = new DescriptorClassEnumeration(type).classCount();
-
- // Replace simple enum types.
- for (int counter = 0; counter < count; counter++)
- {
- Clazz referencedClass =
- referencedClasses[referencedClassIndex++];
-
- if (isSimpleEnum(referencedClass))
- {
- type =
- type.substring(0, ClassUtil.internalArrayTypeDimensionCount(type)) +
- ClassConstants.TYPE_INT;
- }
- }
-
- newDescriptorBuffer.append(type);
- }
-
- newDescriptorBuffer.append(ClassConstants.METHOD_ARGUMENTS_CLOSE);
-
- // Go over the return value.
- {
- String type = internalTypeEnumeration.returnType();
- int count = new DescriptorClassEnumeration(type).classCount();
-
- // Replace simple enum types.
- for (int counter = 0; counter < count; counter++)
- {
- Clazz referencedClass =
- referencedClasses[referencedClassIndex++];
-
- if (isSimpleEnum(referencedClass))
- {
- type =
- type.substring(0, ClassUtil.internalArrayTypeDimensionCount(type)) +
- ClassConstants.TYPE_INT;
- }
- }
-
- newDescriptorBuffer.append(type);
- }
-
- descriptor = newDescriptorBuffer.toString();
- }
-
- return descriptor;
- }
-
-
- /**
- * Returns the simplified and shrunk array of referenced classes for the
- * given descriptor.
- */
- private Clazz[] simplifyReferencedClasses(String descriptor,
- Clazz[] referencedClasses)
- {
- if (referencedClasses != null)
- {
- InternalTypeEnumeration internalTypeEnumeration =
- new InternalTypeEnumeration(descriptor);
-
- int referencedClassIndex = 0;
- int newReferencedClassIndex = 0;
-
- // Go over the formal type parameters.
- {
- String type = internalTypeEnumeration.formalTypeParameters();
- int count = new DescriptorClassEnumeration(type).classCount();
-
- // Clear all non-simple enum classes
- // (now java.lang.Integer).
- for (int counter = 0; counter < count; counter++)
- {
- Clazz referencedClass =
- referencedClasses[referencedClassIndex++];
-
- referencedClasses[newReferencedClassIndex++] =
- isSimpleEnum(referencedClass) ? null : referencedClass;
- }
- }
-
- // Go over the parameters.
- while (internalTypeEnumeration.hasMoreTypes())
- {
- // Consider the classes referenced by this parameter type.
- String type = internalTypeEnumeration.nextType();
- int count = new DescriptorClassEnumeration(type).classCount();
-
- // Copy all non-simple enum classes.
- for (int counter = 0; counter < count; counter++)
- {
- Clazz referencedClass =
- referencedClasses[referencedClassIndex++];
-
- if (!isSimpleEnum(referencedClass))
- {
- referencedClasses[newReferencedClassIndex++] =
- referencedClass;
- }
- }
- }
-
- // Go over the return type.
- {
- String type = internalTypeEnumeration.returnType();
- int count = new DescriptorClassEnumeration(type).classCount();
-
- // Copy all non-simple enum classes.
- for (int counter = 0; counter < count; counter++)
- {
- Clazz referencedClass =
- referencedClasses[referencedClassIndex++];
-
- if (!isSimpleEnum(referencedClass))
- {
- referencedClasses[newReferencedClassIndex++] =
- referencedClass;
- }
- }
- }
-
- // Shrink the array to the proper size.
- if (newReferencedClassIndex == 0)
- {
- referencedClasses = null;
- }
- else if (newReferencedClassIndex < referencedClassIndex)
- {
- Clazz[] newReferencedClasses = new Clazz[newReferencedClassIndex];
- System.arraycopy(referencedClasses, 0,
- newReferencedClasses, 0,
- newReferencedClassIndex);
-
- referencedClasses = newReferencedClasses;
- }
- }
-
- return referencedClasses;
- }
-
-
- /**
- * Returns whether the given class is not null and a simple enum class.
- */
- private boolean isSimpleEnum(Clazz clazz)
- {
- return clazz != null &&
- SimpleEnumMarker.isSimpleEnum(clazz);
- }
-}
diff --git a/src/proguard/optimize/evaluation/SimpleEnumUseChecker.java b/src/proguard/optimize/evaluation/SimpleEnumUseChecker.java
deleted file mode 100644
index b748c68..0000000
--- a/src/proguard/optimize/evaluation/SimpleEnumUseChecker.java
+++ /dev/null
@@ -1,760 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * 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
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.optimize.evaluation;
-
-import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.visitor.*;
-import proguard.classfile.constant.ClassConstant;
-import proguard.classfile.constant.visitor.ConstantVisitor;
-import proguard.classfile.instruction.*;
-import proguard.classfile.instruction.visitor.InstructionVisitor;
-import proguard.classfile.util.*;
-import proguard.classfile.visitor.*;
-import proguard.evaluation.*;
-import proguard.evaluation.value.*;
-import proguard.optimize.info.SimpleEnumMarker;
-
-/**
- * This ClassVisitor marks enums that can't be simplified due to the way they
- * are used in the classes that it visits.
- *
- * @see SimpleEnumMarker
- * @author Eric Lafortune
- */
-public class SimpleEnumUseChecker
-extends SimplifiedVisitor
-implements ClassVisitor,
- MemberVisitor,
- AttributeVisitor,
- InstructionVisitor,
- ConstantVisitor,
- ParameterVisitor
-{
- //*
- private static final boolean DEBUG = false;
- /*/
- private static boolean DEBUG = System.getProperty("enum") != null;
- //*/
-
- private final PartialEvaluator partialEvaluator;
- private final MemberVisitor methodCodeChecker = new AllAttributeVisitor(this);
- private final ConstantVisitor invokedMethodChecker = new ReferencedMemberVisitor(this);
- private final ConstantVisitor parameterChecker = new ReferencedMemberVisitor(new AllParameterVisitor(this));
- private final ClassVisitor complexEnumMarker = new SimpleEnumMarker(false);
- private final ReferencedClassVisitor referencedComplexEnumMarker = new ReferencedClassVisitor(complexEnumMarker);
-
-
- // Fields acting as parameters and return values for the visitor methods.
- private int invocationOffset;
-
-
- /**
- * Creates a new SimpleEnumUseSimplifier.
- */
- public SimpleEnumUseChecker()
- {
- this(new PartialEvaluator());
- }
-
-
- /**
- * Creates a new SimpleEnumUseChecker.
- * @param partialEvaluator the partial evaluator that will execute the code
- * and provide information about the results.
- */
- public SimpleEnumUseChecker(PartialEvaluator partialEvaluator)
- {
- this.partialEvaluator = partialEvaluator;
- }
-
-
- // Implementations for ClassVisitor.
-
- public void visitProgramClass(ProgramClass programClass)
- {
- if ((programClass.getAccessFlags() & ClassConstants.ACC_ANNOTATTION) != 0)
- {
- // Unmark the simple enum classes in annotations.
- programClass.methodsAccept(referencedComplexEnumMarker);
- }
- else
- {
- // Unmark the simple enum classes that are used in a complex way.
- programClass.methodsAccept(methodCodeChecker);
- }
- }
-
-
- // Implementations for AttributeVisitor.
-
- public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
-
-
- public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
- // Evaluate the method.
- partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
-
- int codeLength = codeAttribute.u4codeLength;
-
- // Check all traced instructions.
- for (int offset = 0; offset < codeLength; offset++)
- {
- if (partialEvaluator.isTraced(offset))
- {
- Instruction instruction = InstructionFactory.create(codeAttribute.code,
- offset);
-
- instruction.accept(clazz, method, codeAttribute, offset, this);
-
- // Check generalized stacks and variables at branch targets.
- if (partialEvaluator.isBranchOrExceptionTarget(offset))
- {
- checkMixedStackEntriesBefore(offset);
-
- checkMixedVariablesBefore(offset);
- }
- }
- }
- }
-
-
- // Implementations for InstructionVisitor.
-
- public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
- {
- switch (simpleInstruction.opcode)
- {
- case InstructionConstants.OP_AASTORE:
- {
- // Check if the instruction is storing a simple enum in a
- // more general array.
- if (!isPoppingSimpleEnumType(offset, 2))
- {
- if (DEBUG)
- {
- if (isPoppingSimpleEnumType(offset))
- {
- System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] stores enum ["+
- partialEvaluator.getStackBefore(offset).getTop(0).referenceValue().getType()+"] in more general array ["+
- partialEvaluator.getStackBefore(offset).getTop(2).referenceValue().getType()+"]");
- }
- }
-
- markPoppedComplexEnumType(offset);
- }
- break;
- }
- case InstructionConstants.OP_ARETURN:
- {
- // Check if the instruction is returning a simple enum as a
- // more general type.
- if (!isReturningSimpleEnumType(clazz, method))
- {
- if (DEBUG)
- {
- if (isPoppingSimpleEnumType(offset))
- {
- System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] returns enum [" +
- partialEvaluator.getStackBefore(offset).getTop(0).referenceValue().getType()+"] as more general type");
- }
- }
-
- markPoppedComplexEnumType(offset);
- }
- break;
- }
- case InstructionConstants.OP_MONITORENTER:
- case InstructionConstants.OP_MONITOREXIT:
- {
- // Make sure the popped type is not a simple enum type.
- if (DEBUG)
- {
- if (isPoppingSimpleEnumType(offset))
- {
- System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] uses enum ["+
- partialEvaluator.getStackBefore(offset).getTop(0).referenceValue().getType()+"] as monitor");
- }
- }
-
- markPoppedComplexEnumType(offset);
-
- break;
- }
- }
- }
-
-
- public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
- {
- }
-
-
- public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
- {
- switch (constantInstruction.opcode)
- {
- case InstructionConstants.OP_PUTSTATIC:
- case InstructionConstants.OP_PUTFIELD:
- {
- // Check if the instruction is generalizing a simple enum to a
- // different type.
- invocationOffset = offset;
- clazz.constantPoolEntryAccept(constantInstruction.constantIndex,
- parameterChecker);
- break;
- }
- case InstructionConstants.OP_INVOKEVIRTUAL:
- {
- // Check if the instruction is calling a simple enum.
- String invokedMethodName =
- clazz.getRefName(constantInstruction.constantIndex);
- String invokedMethodType =
- clazz.getRefType(constantInstruction.constantIndex);
- int stackEntryIndex =
- ClassUtil.internalMethodParameterSize(invokedMethodType);
- if (isPoppingSimpleEnumType(offset, stackEntryIndex) &&
- !isSupportedMethod(invokedMethodName,
- invokedMethodType))
- {
- if (DEBUG)
- {
- System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] calls ["+partialEvaluator.getStackBefore(offset).getTop(stackEntryIndex).referenceValue().getType()+"."+invokedMethodName+"]");
- }
-
- markPoppedComplexEnumType(offset, stackEntryIndex);
- }
-
- // Check if any of the parameters is generalizing a simple
- // enum to a different type.
- invocationOffset = offset;
- clazz.constantPoolEntryAccept(constantInstruction.constantIndex,
- parameterChecker);
- break;
- }
- case InstructionConstants.OP_INVOKESPECIAL:
- case InstructionConstants.OP_INVOKESTATIC:
- case InstructionConstants.OP_INVOKEINTERFACE:
- {
- // Check if it is calling a method that we can't simplify.
- clazz.constantPoolEntryAccept(constantInstruction.constantIndex,
- invokedMethodChecker);
-
- // Check if any of the parameters is generalizing a simple
- // enum to a different type.
- invocationOffset = offset;
- clazz.constantPoolEntryAccept(constantInstruction.constantIndex,
- parameterChecker);
- break;
- }
- case InstructionConstants.OP_CHECKCAST:
- case InstructionConstants.OP_INSTANCEOF:
- {
- // Check if the instruction is popping a different type.
- if (!isPoppingExpectedType(offset,
- clazz,
- constantInstruction.constantIndex))
- {
- if (DEBUG)
- {
- if (isPoppingSimpleEnumType(offset))
- {
- System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] is casting or checking ["+
- partialEvaluator.getStackBefore(offset).getTop(0).referenceValue().getType()+"] as ["+
- clazz.getClassName(constantInstruction.constantIndex)+"]");
- }
- }
-
- // Make sure the popped type is not a simple enum type.
- markPoppedComplexEnumType(offset);
-
- // Make sure the checked type is not a simple enum type.
- // We're somewhat arbitrarily skipping casts in static
- // methods of simple enum classes, because they do occur
- // in values() and valueOf(String), without obstructing
- // simplification.
- if (!isSimpleEnum(clazz) ||
- (method.getAccessFlags() & ClassConstants.ACC_STATIC) == 0 ||
- constantInstruction.opcode != InstructionConstants.OP_CHECKCAST)
- {
- if (DEBUG)
- {
- if (isSimpleEnum(((ClassConstant)((ProgramClass)clazz).getConstant(constantInstruction.constantIndex)).referencedClass))
- {
- System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] is casting or checking ["+
- partialEvaluator.getStackBefore(offset).getTop(0).referenceValue().getType()+"] as ["+
- clazz.getClassName(constantInstruction.constantIndex)+"]");
- }
- }
-
- markConstantComplexEnumType(clazz, constantInstruction.constantIndex);
- }
- }
- break;
- }
- }
- }
-
-
- public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
- {
- switch (branchInstruction.opcode)
- {
- case InstructionConstants.OP_IFACMPEQ:
- case InstructionConstants.OP_IFACMPNE:
- {
- // Check if the instruction is comparing different types.
- if (!isPoppingIdenticalTypes(offset, 0, 1))
- {
- if (DEBUG)
- {
- if (isPoppingSimpleEnumType(offset, 0))
- {
- System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] compares ["+partialEvaluator.getStackBefore(offset).getTop(0).referenceValue().getType()+"] to plain type");
- }
-
- if (isPoppingSimpleEnumType(offset, 1))
- {
- System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] compares ["+partialEvaluator.getStackBefore(offset).getTop(1).referenceValue().getType()+"] to plain type");
- }
- }
-
- // Make sure the first popped type is not a simple enum type.
- markPoppedComplexEnumType(offset, 0);
-
- // Make sure the second popped type is not a simple enum type.
- markPoppedComplexEnumType(offset, 1);
- }
- break;
- }
- }
- }
-
-
- public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction)
- {
- }
-
-
- // Implementations for MemberVisitor.
-
- public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) {}
-
-
- public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
- {
- if (isSimpleEnum(programClass) &&
- isUnsupportedMethod(programMethod.getName(programClass),
- programMethod.getDescriptor(programClass)))
- {
- if (DEBUG)
- {
- System.out.println("SimpleEnumUseChecker: invocation of ["+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"]");
- }
-
- complexEnumMarker.visitProgramClass(programClass);
- }
- }
-
-
- // Implementations for ParameterVisitor.
-
- public void visitParameter(Clazz clazz, Member member, int parameterIndex, int parameterCount, int parameterOffset, int parameterSize, String parameterType, Clazz referencedClass)
- {
- // Check if the parameter is passing a simple enum as a more general
- // type.
- int stackEntryIndex = parameterSize - parameterOffset - 1;
- if (ClassUtil.isInternalClassType(parameterType) &&
- !isPoppingExpectedType(invocationOffset, stackEntryIndex,
- ClassUtil.isInternalArrayType(parameterType) ?
- parameterType :
- ClassUtil.internalClassNameFromClassType(parameterType)))
- {
- if (DEBUG)
- {
- ReferenceValue poppedValue =
- partialEvaluator.getStackBefore(invocationOffset).getTop(stackEntryIndex).referenceValue();
- if (isSimpleEnumType(poppedValue))
- {
- System.out.println("SimpleEnumUseChecker: ["+poppedValue.getType()+"] "+
- (member instanceof Field ?
- ("is stored as more general type ["+parameterType+"] in field ["+clazz.getName()+"."+member.getName(clazz)+"]") :
- ("is passed as more general argument #"+parameterIndex+" ["+parameterType+"] to ["+clazz.getName()+"."+member.getName(clazz)+"]")));
- }
- }
-
- // Make sure the popped type is not a simple enum type.
- markPoppedComplexEnumType(invocationOffset, stackEntryIndex);
- }
- }
-
-
- // Small utility methods.
-
- /**
- * Returns whether the specified enum method is supported for simple enums.
- */
- private boolean isSupportedMethod(String name, String type)
- {
- return
- name.equals(ClassConstants.METHOD_NAME_ORDINAL) &&
- type.equals(ClassConstants.METHOD_TYPE_ORDINAL) ||
-
- name.equals(ClassConstants.METHOD_NAME_CLONE) &&
- type.equals(ClassConstants.METHOD_TYPE_CLONE);
- }
-
-
- /**
- * Returns whether the specified enum method is unsupported for simple enums.
- */
- private boolean isUnsupportedMethod(String name, String type)
- {
- return
- name.equals(ClassConstants.METHOD_NAME_VALUEOF);
- }
-
-
- /**
- * Unmarks simple enum classes that are mixed with incompatible reference
- * types in the stack before the given instruction offset.
- */
- private void checkMixedStackEntriesBefore(int offset)
- {
- TracedStack stackBefore = partialEvaluator.getStackBefore(offset);
-
- // Check all stack entries.
- int stackSize = stackBefore.size();
-
- for (int stackEntryIndex = 0; stackEntryIndex < stackSize; stackEntryIndex++)
- {
- // Check reference entries.
- Value stackEntry = stackBefore.getBottom(stackEntryIndex);
- if (stackEntry.computationalType() == Value.TYPE_REFERENCE)
- {
- // Check reference entries with multiple producers.
- InstructionOffsetValue producerOffsets =
- stackBefore.getBottomActualProducerValue(stackEntryIndex).instructionOffsetValue();
-
- int producerCount = producerOffsets.instructionOffsetCount();
- if (producerCount > 1)
- {
- // Is the consumed stack entry not a simple enum?
- ReferenceValue consumedStackEntry =
- stackEntry.referenceValue();
-
- if (!isSimpleEnumType(consumedStackEntry))
- {
- // Check all producers.
- for (int producerIndex = 0; producerIndex < producerCount; producerIndex++)
- {
- int producerOffset =
- producerOffsets.instructionOffset(producerIndex);
-
- if (producerOffset >= 0)
- {
- if (DEBUG)
- {
- ReferenceValue producedValue =
- partialEvaluator.getStackAfter(producerOffset).getTop(0).referenceValue();
- if (isSimpleEnumType(producedValue))
- {
- System.out.println("SimpleEnumUseChecker: ["+producedValue.getType()+"] mixed with general type on stack");
- }
- }
-
- // Make sure the produced stack entry isn't a
- // simple enum either.
- markPushedComplexEnumType(producerOffset);
- }
- }
- }
- }
- }
- }
- }
-
-
- /**
- * Unmarks simple enum classes that are mixed with incompatible reference
- * types in the variables before the given instruction offset.
- */
- private void checkMixedVariablesBefore(int offset)
- {
- TracedVariables variablesBefore =
- partialEvaluator.getVariablesBefore(offset);
-
- // Check all variables.
- int variablesSize = variablesBefore.size();
-
- for (int variableIndex = 0; variableIndex < variablesSize; variableIndex++)
- {
- // Check reference variables.
- Value variable = variablesBefore.getValue(variableIndex);
- if (variable != null &&
- variable.computationalType() == Value.TYPE_REFERENCE)
- {
- // Check reference variables with multiple producers.
- InstructionOffsetValue producerOffsets =
- variablesBefore.getProducerValue(variableIndex).instructionOffsetValue();
-
- int producerCount = producerOffsets.instructionOffsetCount();
- if (producerCount > 1)
- {
- // Is the consumed variable not a simple enum?
- ReferenceValue consumedVariable =
- variable.referenceValue();
-
- if (!isSimpleEnumType(consumedVariable))
- {
- // Check all producers.
- for (int producerIndex = 0; producerIndex < producerCount; producerIndex++)
- {
- int producerOffset =
- producerOffsets.instructionOffset(producerIndex);
-
- if (producerOffset >= 0)
- {
- if (DEBUG)
- {
- ReferenceValue producedValue =
- partialEvaluator.getVariablesAfter(producerOffset).getValue(variableIndex).referenceValue();
- if (isSimpleEnumType(producedValue))
- {
- System.out.println("SimpleEnumUseChecker: ["+producedValue.getType()+"] mixed with general type in variables");
- }
- }
-
- // Make sure the stored variable entry isn't a
- // simple enum either.
- markStoredComplexEnumType(producerOffset, variableIndex);
- }
- }
- }
- }
- }
- }
- }
-
-
- /**
- * Returns whether the instruction at the given offset is popping two
- * identical reference types.
- */
- private boolean isPoppingIdenticalTypes(int offset,
- int stackEntryIndex1,
- int stackEntryIndex2)
- {
- TracedStack stackBefore = partialEvaluator.getStackBefore(offset);
-
- String type1 =
- stackBefore.getTop(stackEntryIndex1).referenceValue().getType();
- String type2 =
- stackBefore.getTop(stackEntryIndex2).referenceValue().getType();
-
- return type1 == null ? type2 == null : type1.equals(type2);
- }
-
-
- /**
- * Returns whether the instruction at the given offset is popping exactly
- * the reference type of the specified class constant.
- */
- private boolean isPoppingExpectedType(int offset,
- Clazz clazz,
- int constantIndex)
- {
- return isPoppingExpectedType(offset, 0, clazz, constantIndex);
- }
-
-
- /**
- * Returns whether the instruction at the given offset is popping exactly
- * the reference type of the specified class constant.
- */
- private boolean isPoppingExpectedType(int offset,
- int stackEntryIndex,
- Clazz clazz,
- int constantIndex)
- {
- return isPoppingExpectedType(offset,
- stackEntryIndex,
- clazz.getClassName(constantIndex));
- }
-
-
- /**
- * Returns whether the instruction at the given offset is popping exactly
- * the given reference type.
- */
- private boolean isPoppingExpectedType(int offset,
- int stackEntryIndex,
- String expectedType)
- {
- TracedStack stackBefore = partialEvaluator.getStackBefore(offset);
-
- String poppedType =
- stackBefore.getTop(stackEntryIndex).referenceValue().getType();
-
- return expectedType.equals(poppedType);
- }
-
-
- /**
- * Returns whether the given method is returning a simple enum type.
- * This includes simple enum arrays.
- */
- private boolean isReturningSimpleEnumType(Clazz clazz, Method method)
- {
- String descriptor = method.getDescriptor(clazz);
- String returnType = ClassUtil.internalMethodReturnType(descriptor);
-
- if (ClassUtil.isInternalClassType(returnType))
- {
- Clazz[] referencedClasses =
- ((ProgramMethod)method).referencedClasses;
-
- if (referencedClasses != null)
- {
- int returnedClassIndex =
- new DescriptorClassEnumeration(descriptor).classCount() - 1;
-
- Clazz returnedClass = referencedClasses[returnedClassIndex];
-
- return isSimpleEnum(returnedClass);
- }
- }
-
- return false;
- }
-
-
- /**
- * Returns whether the instruction at the given offset is popping a type
- * with a simple enum class. This includes simple enum arrays.
- */
- private boolean isPoppingSimpleEnumType(int offset)
- {
- return isPoppingSimpleEnumType(offset, 0);
- }
-
-
- /**
- * Returns whether the instruction at the given offset is popping a type
- * with a simple enum class. This includes simple enum arrays.
- */
- private boolean isPoppingSimpleEnumType(int offset, int stackEntryIndex)
- {
- ReferenceValue referenceValue =
- partialEvaluator.getStackBefore(offset).getTop(stackEntryIndex).referenceValue();
-
- return isSimpleEnumType(referenceValue);
- }
-
-
- /**
- * Returns whether the given value is a simple enum type. This includes
- * simple enum arrays.
- */
- private boolean isSimpleEnumType(ReferenceValue referenceValue)
- {
- return isSimpleEnum(referenceValue.getReferencedClass());
- }
-
-
- /**
- * Returns whether the given class is not null and a simple enum class.
- */
- private boolean isSimpleEnum(Clazz clazz)
- {
- return clazz != null &&
- SimpleEnumMarker.isSimpleEnum(clazz);
- }
-
-
- /**
- * Marks the enum class of the popped type as complex.
- */
- private void markConstantComplexEnumType(Clazz clazz, int constantIndex)
- {
- clazz.constantPoolEntryAccept(constantIndex,
- referencedComplexEnumMarker);
- }
-
-
- /**
- * Marks the enum class of the popped type as complex.
- */
- private void markPoppedComplexEnumType(int offset)
- {
- markPoppedComplexEnumType(offset, 0);
- }
-
-
- /**
- * Marks the enum class of the specified popped type as complex.
- */
- private void markPoppedComplexEnumType(int offset, int stackEntryIndex)
- {
- ReferenceValue referenceValue =
- partialEvaluator.getStackBefore(offset).getTop(stackEntryIndex).referenceValue();
-
- markComplexEnumType(referenceValue);
- }
-
-
- /**
- * Marks the enum class of the specified pushed type as complex.
- */
- private void markPushedComplexEnumType(int offset)
- {
- ReferenceValue referenceValue =
- partialEvaluator.getStackAfter(offset).getTop(0).referenceValue();
-
- markComplexEnumType(referenceValue);
- }
-
-
- /**
- * Marks the enum class of the specified stored type as complex.
- */
- private void markStoredComplexEnumType(int offset, int variableIndex)
- {
- ReferenceValue referenceValue =
- partialEvaluator.getVariablesAfter(offset).getValue(variableIndex).referenceValue();
-
- markComplexEnumType(referenceValue);
- }
-
-
- /**
- * Marks the enum class of the specified value as complex.
- */
- private void markComplexEnumType(ReferenceValue referenceValue)
- {
- Clazz clazz = referenceValue.getReferencedClass();
- if (clazz != null)
- {
- clazz.accept(complexEnumMarker);
- }
- }
-}
diff --git a/src/proguard/optimize/evaluation/SimpleEnumUseSimplifier.java b/src/proguard/optimize/evaluation/SimpleEnumUseSimplifier.java
deleted file mode 100644
index b5a2396..0000000
--- a/src/proguard/optimize/evaluation/SimpleEnumUseSimplifier.java
+++ /dev/null
@@ -1,820 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * 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
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.optimize.evaluation;
-
-import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.visitor.AttributeVisitor;
-import proguard.classfile.constant.*;
-import proguard.classfile.constant.visitor.ConstantVisitor;
-import proguard.classfile.editor.*;
-import proguard.classfile.instruction.*;
-import proguard.classfile.instruction.visitor.InstructionVisitor;
-import proguard.classfile.util.*;
-import proguard.classfile.visitor.*;
-import proguard.evaluation.value.*;
-import proguard.optimize.info.SimpleEnumMarker;
-
-/**
- * This AttributeVisitor simplifies the use of enums in the code attributes that
- * it visits.
- *
- * @see SimpleEnumMarker
- * @see MemberReferenceFixer
- * @author Eric Lafortune
- */
-public class SimpleEnumUseSimplifier
-extends SimplifiedVisitor
-implements AttributeVisitor,
- InstructionVisitor,
- ConstantVisitor,
- ParameterVisitor
-{
- //*
- private static final boolean DEBUG = false;
- /*/
- private static boolean DEBUG = System.getProperty("enum") != null;
- //*/
-
- private final InstructionVisitor extraInstructionVisitor;
-
- private final PartialEvaluator partialEvaluator;
- private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(true, true);
- private final ConstantVisitor nullParameterFixer = new ReferencedMemberVisitor(new AllParameterVisitor(this));
-
- // Fields acting as parameters and return values for the visitor methods.
- private Clazz invocationClazz;
- private Method invocationMethod;
- private CodeAttribute invocationCodeAttribute;
- private int invocationOffset;
- private boolean isSimpleEnum;
-
-
- /**
- * Creates a new SimpleEnumUseSimplifier.
- */
- public SimpleEnumUseSimplifier()
- {
- this(new PartialEvaluator(), null);
- }
-
-
- /**
- * Creates a new SimpleEnumDescriptorSimplifier.
- * @param partialEvaluator the partial evaluator that will
- * execute the code and provide
- * information about the results.
- * @param extraInstructionVisitor an optional extra visitor for all
- * simplified instructions.
- */
- public SimpleEnumUseSimplifier(PartialEvaluator partialEvaluator,
- InstructionVisitor extraInstructionVisitor)
- {
- this.partialEvaluator = partialEvaluator;
- this.extraInstructionVisitor = extraInstructionVisitor;
- }
-
-
- // Implementations for AttributeVisitor.
-
- public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
-
-
- public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
- if (DEBUG)
- {
- System.out.println("SimpleEnumUseSimplifier: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
- }
-
- // Skip the non-static methods of simple enum classes.
- if (SimpleEnumMarker.isSimpleEnum(clazz) &&
- (method.getAccessFlags() & ClassConstants.ACC_STATIC) == 0)
- {
- return;
- }
-
- // Evaluate the method.
- partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
-
- int codeLength = codeAttribute.u4codeLength;
-
- // Reset the code changes.
- codeAttributeEditor.reset(codeLength);
-
- // Replace any instructions that can be simplified.
- for (int offset = 0; offset < codeLength; offset++)
- {
- if (partialEvaluator.isTraced(offset))
- {
- Instruction instruction = InstructionFactory.create(codeAttribute.code,
- offset);
-
- instruction.accept(clazz, method, codeAttribute, offset, this);
- }
- }
-
- // Apply all accumulated changes to the code.
- codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
- }
-
-
- // Implementations for InstructionVisitor.
-
- public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
- {
- switch (simpleInstruction.opcode)
- {
- case InstructionConstants.OP_AALOAD:
- {
- if (isPushingSimpleEnum(offset))
- {
- // Load a simple enum integer from an integer array.
- replaceInstruction(clazz,
- offset,
- simpleInstruction,
- new SimpleInstruction(
- InstructionConstants.OP_IALOAD));
- }
- break;
- }
- case InstructionConstants.OP_AASTORE:
- {
- if (isPoppingSimpleEnumArray(offset, 2))
- {
- // Store a simple enum integer in an integer array.
- replaceInstruction(clazz,
- offset,
- simpleInstruction,
- new SimpleInstruction(InstructionConstants.OP_IASTORE));
-
- // Replace any producers of null constants.
- replaceNullStackEntryProducers(clazz, method, codeAttribute, offset);
- }
- break;
- }
- case InstructionConstants.OP_ARETURN:
- {
- if (isReturningSimpleEnum(clazz, method))
- {
- // Return a simple enum integer instead of an enum.
- replaceInstruction(clazz,
- offset,
- simpleInstruction,
- new SimpleInstruction(InstructionConstants.OP_IRETURN));
-
- // Replace any producers of null constants.
- replaceNullStackEntryProducers(clazz, method, codeAttribute, offset);
- }
- break;
- }
- }
- }
-
-
- public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
- {
- int variableIndex = variableInstruction.variableIndex;
-
- switch (variableInstruction.opcode)
- {
- case InstructionConstants.OP_ALOAD:
- case InstructionConstants.OP_ALOAD_0:
- case InstructionConstants.OP_ALOAD_1:
- case InstructionConstants.OP_ALOAD_2:
- case InstructionConstants.OP_ALOAD_3:
- {
- if (isPushingSimpleEnum(offset))
- {
- // Load a simple enum integer instead of an enum.
- replaceInstruction(clazz,
- offset,
- variableInstruction,
- new VariableInstruction(InstructionConstants.OP_ILOAD,
- variableIndex));
-
- // Replace any producers of null constants.
- replaceNullVariableProducers(clazz,
- method,
- codeAttribute,
- offset,
- variableIndex);
- }
- break;
- }
- case InstructionConstants.OP_ASTORE:
- case InstructionConstants.OP_ASTORE_0:
- case InstructionConstants.OP_ASTORE_1:
- case InstructionConstants.OP_ASTORE_2:
- case InstructionConstants.OP_ASTORE_3:
- {
- if (!partialEvaluator.isSubroutineStart(offset) &&
- isPoppingSimpleEnum(offset))
- {
- // Store a simple enum integer instead of an enum.
- replaceInstruction(clazz,
- offset,
- variableInstruction,
- new VariableInstruction(InstructionConstants.OP_ISTORE,
- variableIndex));
-
- // Replace any producers of null constants.
- replaceNullStackEntryProducers(clazz, method, codeAttribute, offset);
- }
- break;
- }
- }
- }
-
-
- public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
- {
- switch (constantInstruction.opcode)
- {
- case InstructionConstants.OP_PUTSTATIC:
- case InstructionConstants.OP_PUTFIELD:
- {
- // Replace any producers of null constants.
- invocationClazz = clazz;
- invocationMethod = method;
- invocationCodeAttribute = codeAttribute;
- invocationOffset = offset;
- clazz.constantPoolEntryAccept(constantInstruction.constantIndex,
- nullParameterFixer);
- break;
- }
- case InstructionConstants.OP_INVOKEVIRTUAL:
- {
- // Check if the instruction is calling a simple enum.
- String invokedMethodName =
- clazz.getRefName(constantInstruction.constantIndex);
- String invokedMethodType =
- clazz.getRefType(constantInstruction.constantIndex);
- int stackEntryIndex =
- ClassUtil.internalMethodParameterSize(invokedMethodType);
- if (isPoppingSimpleEnum(offset, stackEntryIndex))
- {
- replaceSupportedMethod(clazz,
- offset,
- constantInstruction,
- invokedMethodName,
- invokedMethodType);
- }
-
- // Fall through to check the parameters.
- }
- case InstructionConstants.OP_INVOKESPECIAL:
- case InstructionConstants.OP_INVOKESTATIC:
- case InstructionConstants.OP_INVOKEINTERFACE:
- {
- // Replace any producers of null constants.
- invocationClazz = clazz;
- invocationMethod = method;
- invocationCodeAttribute = codeAttribute;
- invocationOffset = offset;
- clazz.constantPoolEntryAccept(constantInstruction.constantIndex,
- nullParameterFixer);
- break;
- }
- case InstructionConstants.OP_ANEWARRAY:
- {
- int constantIndex = constantInstruction.constantIndex;
-
- if (isReferencingSimpleEnum(clazz, constantIndex) &&
- !ClassUtil.isInternalArrayType(clazz.getClassName(constantIndex)))
- {
- // Create an integer array instead of an enum array.
- replaceInstruction(clazz,
- offset,
- constantInstruction,
- new SimpleInstruction(InstructionConstants.OP_NEWARRAY,
- InstructionConstants.ARRAY_T_INT));
- }
- break;
- }
- case InstructionConstants.OP_CHECKCAST:
- {
- if (isPoppingSimpleEnum(offset))
- {
- // Enum classes can only be simple if the checkcast
- // succeeds, so we can delete it.
- deleteInstruction(clazz,
- offset,
- constantInstruction);
-
- // Replace any producers of null constants.
- replaceNullStackEntryProducers(clazz, method, codeAttribute, offset);
- }
- break;
- }
- case InstructionConstants.OP_INSTANCEOF:
- {
- if (isPoppingSimpleEnum(offset))
- {
- // Enum classes can only be simple if the instanceof
- // succeeds, so we can push a constant result.
- replaceInstruction(clazz,
- offset,
- constantInstruction,
- new SimpleInstruction(InstructionConstants.OP_ICONST_1));
-
- // Replace any producers of null constants.
- replaceNullStackEntryProducers(clazz, method, codeAttribute, offset);
- }
- break;
- }
- }
- }
-
-
- public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
- {
- switch (branchInstruction.opcode)
- {
- case InstructionConstants.OP_IFACMPEQ:
- {
- if (isPoppingSimpleEnum(offset))
- {
- // Compare simple enum integers instead of enums.
- replaceInstruction(clazz,
- offset,
- branchInstruction,
- new BranchInstruction(InstructionConstants.OP_IFICMPEQ,
- branchInstruction.branchOffset));
- }
- break;
- }
- case InstructionConstants.OP_IFACMPNE:
- {
- if (isPoppingSimpleEnum(offset))
- {
- // Compare simple enum integers instead of enums.
- replaceInstruction(clazz,
- offset,
- branchInstruction,
- new BranchInstruction(InstructionConstants.OP_IFICMPNE,
- branchInstruction.branchOffset));
- }
- break;
- }
- case InstructionConstants.OP_IFNULL:
- {
- if (isPoppingSimpleEnum(offset))
- {
- // Compare with 0 instead of null.
- replaceInstruction(clazz,
- offset,
- branchInstruction,
- new BranchInstruction(
- InstructionConstants.OP_IFEQ,
- branchInstruction.branchOffset));
- }
- break;
- }
- case InstructionConstants.OP_IFNONNULL:
- {
- if (isPoppingSimpleEnum(offset))
- {
- // Compare with 0 instead of null.
- replaceInstruction(clazz,
- offset,
- branchInstruction,
- new BranchInstruction(InstructionConstants.OP_IFNE,
- branchInstruction.branchOffset));
- }
- break;
- }
- }
- }
-
-
- public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction)
- {
- }
-
-
- // Implementations for ConstantVisitor.
-
- public void visitAnyConstant(Clazz clazz, Constant constant) {}
-
-
- public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
- {
- // Does the constant refer to a simple enum type?
- isSimpleEnum = isSimpleEnum(stringConstant.referencedClass);
- }
-
-
- public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
- {
- // Does the constant refer to a simple enum type?
- isSimpleEnum = isSimpleEnum(classConstant.referencedClass);
- }
-
-
- // Implementations for ParameterVisitor.
-
- public void visitParameter(Clazz clazz, Member member, int parameterIndex, int parameterCount, int parameterOffset, int parameterSize, String parameterType, Clazz referencedClass)
- {
- // Check if the parameter is passing a simple enum as a more general
- // type.
- if (!ClassUtil.isInternalPrimitiveType(parameterType.charAt(0)) &&
- isSimpleEnum(referencedClass))
- {
- // Replace any producers of null constants for this parameter.
- int stackEntryIndex = parameterSize - parameterOffset - 1;
-
- replaceNullStackEntryProducers(invocationClazz,
- invocationMethod,
- invocationCodeAttribute,
- invocationOffset,
- stackEntryIndex);
- }
- }
-
-
- // Small utility methods.
-
- /**
- * Returns whether the constant at the given offset is referencing a
- * simple enum class.
- */
- private boolean isReferencingSimpleEnum(Clazz clazz, int constantIndex)
- {
- isSimpleEnum = false;
-
- clazz.constantPoolEntryAccept(constantIndex, this);
-
- return isSimpleEnum;
- }
-
-
- /**
- * Returns whether the given method is returning a simple enum class.
- */
- private boolean isReturningSimpleEnum(Clazz clazz, Method method)
- {
- String descriptor = method.getDescriptor(clazz);
- String returnType = ClassUtil.internalMethodReturnType(descriptor);
-
- if (ClassUtil.isInternalClassType(returnType) &&
- !ClassUtil.isInternalArrayType(returnType))
- {
- Clazz[] referencedClasses =
- ((ProgramMethod)method).referencedClasses;
-
- if (referencedClasses != null)
- {
- int returnedClassIndex =
- new DescriptorClassEnumeration(descriptor).classCount() - 1;
-
- Clazz returnedClass = referencedClasses[returnedClassIndex];
-
- return isSimpleEnum(returnedClass);
- }
- }
-
- return false;
- }
-
-
- /**
- * Returns whether the instruction at the given offset is pushing a simple
- * enum class.
- */
- private boolean isPushingSimpleEnum(int offset)
- {
- ReferenceValue referenceValue =
- partialEvaluator.getStackAfter(offset).getTop(0).referenceValue();
-
- Clazz referencedClass = referenceValue.getReferencedClass();
-
- return isSimpleEnum(referencedClass) &&
- !ClassUtil.isInternalArrayType(referenceValue.getType());
- }
-
-
- /**
- * Returns whether the instruction at the given offset is popping a simple
- * enum class.
- */
- private boolean isPoppingSimpleEnum(int offset)
- {
- return isPoppingSimpleEnum(offset, 0);
- }
-
-
- /**
- * Returns whether the instruction at the given offset is popping a simple
- * enum class.
- */
- private boolean isPoppingSimpleEnum(int offset, int stackEntryIndex)
- {
- ReferenceValue referenceValue =
- partialEvaluator.getStackBefore(offset).getTop(stackEntryIndex).referenceValue();
-
- return isSimpleEnum(referenceValue.getReferencedClass()) &&
- !ClassUtil.isInternalArrayType(referenceValue.getType());
- }
-
-
- /**
- * Returns whether the instruction at the given offset is popping a simple
- * enum type. This includes simple enum arrays.
- */
- private boolean isPoppingSimpleEnumType(int offset, int stackEntryIndex)
- {
- ReferenceValue referenceValue =
- partialEvaluator.getStackBefore(offset).getTop(stackEntryIndex).referenceValue();
-
- return isSimpleEnum(referenceValue.getReferencedClass());
- }
-
-
- /**
- * Returns whether the instruction at the given offset is popping a
- * one-dimensional simple enum array.
- */
- private boolean isPoppingSimpleEnumArray(int offset, int stackEntryIndex)
- {
- ReferenceValue referenceValue =
- partialEvaluator.getStackBefore(offset).getTop(stackEntryIndex).referenceValue();
-
- return isSimpleEnum(referenceValue.getReferencedClass()) &&
- ClassUtil.internalArrayTypeDimensionCount(referenceValue.getType()) == 1;
- }
-
-
- /**
- * Returns whether the given class is not null and a simple enum class.
- */
- private boolean isSimpleEnum(Clazz clazz)
- {
- return clazz != null &&
- SimpleEnumMarker.isSimpleEnum(clazz);
- }
-
-
- /**
- * Returns whether the specified enum method is supported for simple enums.
- */
- private void replaceSupportedMethod(Clazz clazz,
- int offset,
- Instruction instruction,
- String name,
- String type)
- {
- if (name.equals(ClassConstants.METHOD_NAME_ORDINAL) &&
- type.equals(ClassConstants.METHOD_TYPE_ORDINAL))
- {
- Instruction[] replacementInstructions = new Instruction[]
- {
- new SimpleInstruction(InstructionConstants.OP_ICONST_1),
- new SimpleInstruction(InstructionConstants.OP_ISUB),
- };
-
- replaceInstructions(clazz,
- offset,
- instruction,
- replacementInstructions);
- }
- }
-
-
- /**
- * Replaces the instruction at the given offset by the given instructions.
- */
- private void replaceInstructions(Clazz clazz,
- int offset,
- Instruction instruction,
- Instruction[] replacementInstructions)
- {
- if (DEBUG) System.out.println(" Replacing instruction "+instruction.toString(offset)+" -> "+replacementInstructions.length+" instructions");
-
- codeAttributeEditor.replaceInstruction(offset, replacementInstructions);
-
- // Visit the instruction, if required.
- if (extraInstructionVisitor != null)
- {
- // Note: we're not passing the right arguments for now, knowing that
- // they aren't used anyway.
- instruction.accept(clazz, null, null, offset, extraInstructionVisitor);
- }
- }
-
-
- /**
- * Replaces the instruction at the given offset by the given instruction,
- * popping any now unused stack entries.
- */
- private void replaceInstruction(Clazz clazz,
- int offset,
- Instruction instruction,
- Instruction replacementInstruction)
- {
- // Pop unneeded stack entries if necessary.
- int popCount =
- instruction.stackPopCount(clazz) -
- replacementInstruction.stackPopCount(clazz);
-
- insertPopInstructions(offset, popCount);
-
- if (DEBUG) System.out.println(" Replacing instruction "+instruction.toString(offset)+" -> "+replacementInstruction.toString()+(popCount == 0 ? "" : " ("+popCount+" pops)"));
-
- codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
-
- // Visit the instruction, if required.
- if (extraInstructionVisitor != null)
- {
- // Note: we're not passing the right arguments for now, knowing that
- // they aren't used anyway.
- instruction.accept(clazz, null, null, offset, extraInstructionVisitor);
- }
- }
-
-
- /**
- * Deletes the instruction at the given offset, popping any now unused
- * stack entries.
- */
- private void deleteInstruction(Clazz clazz,
- int offset,
- Instruction instruction)
- {
- // Pop unneeded stack entries if necessary.
- //int popCount = instruction.stackPopCount(clazz);
- //
- //insertPopInstructions(offset, popCount);
- //
- //if (DEBUG) System.out.println(" Deleting instruction "+instruction.toString(offset)+(popCount == 0 ? "" : " ("+popCount+" pops)"));
-
- if (DEBUG) System.out.println(" Deleting instruction "+instruction.toString(offset));
-
- codeAttributeEditor.deleteInstruction(offset);
-
- // Visit the instruction, if required.
- if (extraInstructionVisitor != null)
- {
- // Note: we're not passing the right arguments for now, knowing that
- // they aren't used anyway.
- instruction.accept(clazz, null, null, offset, extraInstructionVisitor);
- }
- }
-
-
- /**
- * Pops the given number of stack entries before the instruction at the
- * given offset.
- */
- private void insertPopInstructions(int offset, int popCount)
- {
- switch (popCount)
- {
- case 0:
- {
- break;
- }
- case 1:
- {
- // Insert a single pop instruction.
- Instruction popInstruction =
- new SimpleInstruction(InstructionConstants.OP_POP);
-
- codeAttributeEditor.insertBeforeInstruction(offset,
- popInstruction);
- break;
- }
- case 2:
- {
- // Insert a single pop2 instruction.
- Instruction popInstruction =
- new SimpleInstruction(InstructionConstants.OP_POP2);
-
- codeAttributeEditor.insertBeforeInstruction(offset,
- popInstruction);
- break;
- }
- default:
- {
- // Insert the specified number of pop instructions.
- Instruction[] popInstructions =
- new Instruction[popCount / 2 + popCount % 2];
-
- Instruction popInstruction =
- new SimpleInstruction(InstructionConstants.OP_POP2);
-
- for (int index = 0; index < popCount / 2; index++)
- {
- popInstructions[index] = popInstruction;
- }
-
- if (popCount % 2 == 1)
- {
- popInstruction =
- new SimpleInstruction(InstructionConstants.OP_POP);
-
- popInstructions[popCount / 2] = popInstruction;
- }
-
- codeAttributeEditor.insertBeforeInstruction(offset,
- popInstructions);
- break;
- }
- }
- }
-
-
- /**
- * Replaces aconst_null producers of the consumer of the top stack entry
- * at the given offset by iconst_0.
- */
- private void replaceNullStackEntryProducers(Clazz clazz,
- Method method,
- CodeAttribute codeAttribute,
- int consumerOffset)
- {
- replaceNullStackEntryProducers(clazz, method, codeAttribute, consumerOffset, 0);
- }
-
-
- /**
- * Replaces aconst_null producers of the specified stack entry by
- * iconst_0.
- */
- private void replaceNullStackEntryProducers(Clazz clazz,
- Method method,
- CodeAttribute codeAttribute,
- int consumerOffset,
- int stackEntryIndex)
- {
- InstructionOffsetValue producerOffsets =
- partialEvaluator.getStackBefore(consumerOffset).getTopActualProducerValue(stackEntryIndex).instructionOffsetValue();
-
- for (int index = 0; index < producerOffsets.instructionOffsetCount(); index++)
- {
- int producerOffset = producerOffsets.instructionOffset(index);
-
- // TODO: A method might be pushing the null constant.
- if (producerOffset >= 0 &&
- codeAttribute.code[producerOffset] == InstructionConstants.OP_ACONST_NULL)
- {
- // Replace pushing null by pushing 0.
- replaceInstruction(clazz,
- producerOffset,
- new SimpleInstruction(InstructionConstants.OP_ACONST_NULL),
- new SimpleInstruction(InstructionConstants.OP_ICONST_0));
- }
- }
- }
-
-
- /**
- * Replaces aconst_null/astore producers of the specified reference variable by
- * iconst_0/istore.
- */
- private void replaceNullVariableProducers(Clazz clazz,
- Method method,
- CodeAttribute codeAttribute,
- int consumerOffset,
- int variableIndex)
- {
- InstructionOffsetValue producerOffsets =
- partialEvaluator.getVariablesBefore(consumerOffset).getProducerValue(variableIndex).instructionOffsetValue();
-
- for (int index = 0; index < producerOffsets.instructionOffsetCount(); index++)
- {
- int producerOffset = producerOffsets.instructionOffset(index);
-
- if (producerOffset >= 0 &&
- partialEvaluator.getVariablesAfter(producerOffset).getValue(variableIndex).referenceValue().isNull() == Value.ALWAYS)
- {
- // Replace loading null by loading 0.
- replaceInstruction(clazz,
- producerOffset,
- new VariableInstruction(InstructionConstants.OP_ASTORE, variableIndex),
- new VariableInstruction(InstructionConstants.OP_ISTORE, variableIndex));
-
- // Replace pushing null by pushing 0.
- replaceNullStackEntryProducers(clazz, method, codeAttribute, producerOffset);
- }
- }
- }
-}
diff --git a/src/proguard/optimize/evaluation/StoringInvocationUnit.java b/src/proguard/optimize/evaluation/StoringInvocationUnit.java
deleted file mode 100644
index 271b654..0000000
--- a/src/proguard/optimize/evaluation/StoringInvocationUnit.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * 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
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.optimize.evaluation;
-
-import proguard.classfile.*;
-import proguard.classfile.constant.RefConstant;
-import proguard.evaluation.BasicInvocationUnit;
-import proguard.evaluation.value.*;
-import proguard.optimize.info.*;
-
-/**
- * This InvocationUnit stores parameter values and return values with the
- * methods that are invoked.
- *
- * @see LoadingInvocationUnit
- * @author Eric Lafortune
- */
-public class StoringInvocationUnit
-extends BasicInvocationUnit
-{
- private boolean storeFieldValues;
- private boolean storeMethodParameterValues;
- private boolean storeMethodReturnValues;
-
-
- /**
- * Creates a new StoringInvocationUnit with the given value factory.
- */
- public StoringInvocationUnit(ValueFactory valueFactory)
- {
- this(valueFactory, true, true, true);
- }
-
-
- /**
- * Creates a new StoringInvocationUnit with the given value factory, for
- * storing the specified values.
- */
- public StoringInvocationUnit(ValueFactory valueFactory,
- boolean storeFieldValues,
- boolean storeMethodParameterValues,
- boolean storeMethodReturnValues)
- {
- super(valueFactory);
-
- this.storeFieldValues = storeFieldValues;
- this.storeMethodParameterValues = storeMethodParameterValues;
- this.storeMethodReturnValues = storeMethodReturnValues;
- }
-
-
- // Implementations for BasicInvocationUnit.
-
- protected void setFieldClassValue(Clazz clazz,
- RefConstant refConstant,
- ReferenceValue value)
- {
- if (storeFieldValues)
- {
- Member referencedMember = refConstant.referencedMember;
- if (referencedMember != null)
- {
- generalizeFieldClassValue((Field)referencedMember, value);
- }
- }
- }
-
-
- protected void setFieldValue(Clazz clazz,
- RefConstant refConstant,
- Value value)
- {
- if (storeFieldValues)
- {
- Member referencedMember = refConstant.referencedMember;
- if (referencedMember != null)
- {
- generalizeFieldValue((Field)referencedMember, value);
- }
- }
- }
-
-
- protected void setMethodParameterValue(Clazz clazz,
- RefConstant refConstant,
- int parameterIndex,
- Value value)
- {
- if (storeMethodParameterValues)
- {
- Member referencedMember = refConstant.referencedMember;
- if (referencedMember != null)
- {
- generalizeMethodParameterValue((Method)referencedMember,
- parameterIndex,
- value);
- }
- }
- }
-
-
- protected void setMethodReturnValue(Clazz clazz,
- Method method,
- Value value)
- {
- if (storeMethodReturnValues)
- {
- generalizeMethodReturnValue(method, value);
- }
- }
-
-
- // Small utility methods.
-
- private static void generalizeFieldClassValue(Field field, ReferenceValue value)
- {
- FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
- if (info != null)
- {
- info.generalizeReferencedClass(value);
- }
- }
-
-
- public static ReferenceValue getFieldClassValue(Field field)
- {
- FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
- return info != null ?
- info.getReferencedClass() :
- null;
- }
-
-
- private static void generalizeFieldValue(Field field, Value value)
- {
- FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
- if (info != null)
- {
- info.generalizeValue(value);
- }
- }
-
-
- public static Value getFieldValue(Field field)
- {
- FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
- return info != null ?
- info.getValue() :
- null;
- }
-
-
- private static void generalizeMethodParameterValue(Method method, int parameterIndex, Value value)
- {
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.generalizeParameter(parameterIndex, value);
- }
- }
-
-
- public static Value getMethodParameterValue(Method method, int parameterIndex)
- {
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info != null ?
- info.getParameter(parameterIndex) :
- null;
- }
-
-
- private static void generalizeMethodReturnValue(Method method, Value value)
- {
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.generalizeReturnValue(value);
- }
- }
-
-
- public static Value getMethodReturnValue(Method method)
- {
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info != null ?
- info.getReturnValue() :
- null;
- }
-}
diff --git a/src/proguard/optimize/evaluation/TracedBranchUnit.java b/src/proguard/optimize/evaluation/TracedBranchUnit.java
deleted file mode 100644
index 9e55275..0000000
--- a/src/proguard/optimize/evaluation/TracedBranchUnit.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * 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
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.optimize.evaluation;
-
-import proguard.classfile.Clazz;
-import proguard.classfile.attribute.CodeAttribute;
-import proguard.evaluation.BasicBranchUnit;
-import proguard.evaluation.value.Value;
-
-/**
- * This BranchUnit remembers the branch unit commands that are invoked on it.
- *
- * @author Eric Lafortune
- */
-class TracedBranchUnit
-extends BasicBranchUnit
-{
- // Implementations for BranchUnit.
-
- public void branchConditionally(Clazz clazz,
- CodeAttribute codeAttribute,
- int offset,
- int branchTarget,
- int conditional)
- {
- if (conditional == Value.ALWAYS)
- {
- // Always branch.
- super.branch(clazz, codeAttribute, offset, branchTarget);
- }
- else if (conditional != Value.NEVER)
- {
- // Maybe branch.
- super.branchConditionally(clazz, codeAttribute, offset, branchTarget, conditional);
- }
- else
- {
- super.setCalled();
- }
- }
-}
diff --git a/src/proguard/optimize/evaluation/VariableOptimizer.java b/src/proguard/optimize/evaluation/VariableOptimizer.java
deleted file mode 100644
index bef1445..0000000
--- a/src/proguard/optimize/evaluation/VariableOptimizer.java
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * 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
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.optimize.evaluation;
-
-import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.visitor.*;
-import proguard.classfile.editor.*;
-import proguard.classfile.util.*;
-import proguard.classfile.visitor.MemberVisitor;
-
-/**
- * This AttributeVisitor optimizes variable allocation based on their the liveness,
- * in the code attributes that it visits.
- *
- * @author Eric Lafortune
- */
-public class VariableOptimizer
-extends SimplifiedVisitor
-implements AttributeVisitor,
- LocalVariableInfoVisitor,
- LocalVariableTypeInfoVisitor
-{
- //*
- private static final boolean DEBUG = false;
- /*/
- private static boolean DEBUG = true;
- //*/
-
- private static final int MAX_VARIABLES_SIZE = 64;
-
-
- private final boolean reuseThis;
- private final MemberVisitor extraVariableMemberVisitor;
-
- 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];
-
-
- /**
- * Creates a new VariableOptimizer.
- * @param reuseThis specifies whether the 'this' variable can be reused.
- * Many JVMs for JME and IBM's JVMs for JSE can't handle
- * such reuse.
- */
- public VariableOptimizer(boolean reuseThis)
- {
- this(reuseThis, null);
- }
-
-
- /**
- * Creates a new VariableOptimizer with an extra visitor.
- * @param reuseThis specifies whether the 'this' variable
- * can be reused. Many JVMs for JME and
- * IBM's JVMs for JSE can't handle such
- * reuse.
- * @param extraVariableMemberVisitor an optional extra visitor for all
- * removed variables.
- */
- public VariableOptimizer(boolean reuseThis,
- MemberVisitor extraVariableMemberVisitor)
- {
- this.reuseThis = reuseThis;
- this.extraVariableMemberVisitor = extraVariableMemberVisitor;
- }
-
-
- // Implementations for AttributeVisitor.
-
- public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
-
-
- public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
-// DEBUG =
-// clazz.getName().equals("abc/Def") &&
-// method.getName(clazz).equals("abc");
-
- // Initialize the global arrays.
- initializeArrays(codeAttribute);
-
- // 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.ACC_STATIC) != 0 ||
- reuseThis ? 0 : 1;
-
- int parameterSize =
- ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz),
- method.getAccessFlags());
-
- int variableSize = codeAttribute.u2maxLocals;
- int codeLength = codeAttribute.u4codeLength;
-
- boolean remapping = false;
-
- // Loop over all variables.
- for (int oldIndex = 0; oldIndex < variableSize; oldIndex++)
- {
- // By default, the variable will be mapped onto itself.
- variableMap[oldIndex] = oldIndex;
-
- // Only try remapping the variable if it's not a parameter.
- if (oldIndex >= parameterSize &&
- oldIndex < MAX_VARIABLES_SIZE)
- {
- // Try to remap the variable to a variable with a smaller index.
- for (int newIndex = startIndex; newIndex < oldIndex; newIndex++)
- {
- if (areNonOverlapping(oldIndex, newIndex, codeLength))
- {
- variableMap[oldIndex] = newIndex;
-
- updateLiveness(oldIndex, newIndex, codeLength);
-
- remapping = true;
-
- // This variable has been remapped. Go to the next one.
- break;
- }
- }
- }
- }
-
- // Have we been able to remap any 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(" v"+index+" -> "+variableMap[index]);
- }
- }
-
- // Remap the variables.
- variableRemapper.setVariableMap(variableMap);
- variableRemapper.visitCodeAttribute(clazz, method, codeAttribute);
-
- // Visit the method, if required.
- if (extraVariableMemberVisitor != null)
- {
- 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);
-
- // Leave the start address of unused variables unchanged.
- int length = endPC - startPC;
- if (length > 0)
- {
- localVariableInfo.u2startPC = startPC;
- }
-
- localVariableInfo.u2length = length;
- }
-
-
- // 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);
-
- // Leave the start address of unused variables unchanged.
- int length = endPC - startPC;
- if (length > 0)
- {
- localVariableTypeInfo.u2startPC = startPC;
- }
-
- localVariableTypeInfo.u2length = length;
- }
-
-
- // Small utility methods.
-
- /**
- * Initializes the global arrays.
- */
- private void initializeArrays(CodeAttribute codeAttribute)
- {
- int codeLength = codeAttribute.u4codeLength;
-
- // Create new arrays for storing information at each instruction offset.
- if (variableMap.length < codeLength)
- {
- variableMap = new int[codeLength];
- }
- }
-
-
- /**
- * Returns whether the given variables are never alive at the same time.
- */
- private boolean areNonOverlapping(int variableIndex1,
- int variableIndex2,
- int codeLength)
- {
- // Loop over all instructions.
- for (int offset = 0; offset < codeLength; offset++)
- {
- if ((livenessAnalyzer.isAliveBefore(offset, variableIndex1) &&
- livenessAnalyzer.isAliveBefore(offset, variableIndex2)) ||
-
- (livenessAnalyzer.isAliveAfter(offset, variableIndex1) &&
- livenessAnalyzer.isAliveAfter(offset, variableIndex2)) ||
-
- // For now, exclude Category 2 variables.
- livenessAnalyzer.isCategory2(offset, variableIndex1))
- {
- return false;
- }
- }
-
- return true;
- }
-
-
- /**
- * Updates the liveness resulting from mapping the given old variable on
- * the given new variable.
- */
- private void updateLiveness(int oldVariableIndex,
- int newVariableIndex,
- int codeLength)
- {
- // Loop over all instructions.
- for (int offset = 0; offset < codeLength; offset++)
- {
- // Update the liveness before the instruction.
- if (livenessAnalyzer.isAliveBefore(offset, oldVariableIndex))
- {
- livenessAnalyzer.setAliveBefore(offset, oldVariableIndex, false);
- livenessAnalyzer.setAliveBefore(offset, newVariableIndex, true);
- }
-
- // Update the liveness after the instruction.
- if (livenessAnalyzer.isAliveAfter(offset, oldVariableIndex))
- {
- livenessAnalyzer.setAliveAfter(offset, oldVariableIndex, false);
- livenessAnalyzer.setAliveAfter(offset, newVariableIndex, true);
- }
- }
- }
-
-
- /**
- * 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;
- }
-}
diff --git a/src/proguard/optimize/evaluation/package.html b/src/proguard/optimize/evaluation/package.html
deleted file mode 100644
index 5341f9f..0000000
--- a/src/proguard/optimize/evaluation/package.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<body>
-This package contains visitors that perform partial evaluation and subsequent
-optimizations on byte code.
-</body>