diff options
Diffstat (limited to 'src/proguard/optimize/evaluation/EvaluationShrinker.java')
-rw-r--r-- | src/proguard/optimize/evaluation/EvaluationShrinker.java | 2298 |
1 files changed, 0 insertions, 2298 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]; - } -} |