📄 partialevaluator.java
字号:
/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 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.classfile.attribute.*;import proguard.classfile.attribute.visitor.*;import proguard.classfile.instruction.*;import proguard.classfile.util.*;import proguard.evaluation.*;import proguard.evaluation.value.*;import proguard.optimize.peephole.BranchTargetFinder;/** * This AttributeVisitor performs partial evaluation on the code attributes * that it visits. * * @author Eric Lafortune */public class PartialEvaluatorextends SimplifiedVisitorimplements 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 ValueFactory valueFactory; private InvocationUnit invocationUnit; private boolean evaluateAllCode; private InstructionOffsetValue[] varProducerValues = new InstructionOffsetValue[ClassConstants.TYPICAL_CODE_LENGTH]; private InstructionOffsetValue[] stackProducerValues = new InstructionOffsetValue[ClassConstants.TYPICAL_CODE_LENGTH]; 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 int[] initializedVariables = new int[ClassConstants.TYPICAL_CODE_LENGTH]; private boolean evaluateExceptions; private BasicBranchUnit branchUnit; private BranchTargetFinder branchTargetFinder = new BranchTargetFinder();// private ClassCleaner classCleaner = new ClassCleaner(); /** * Creates a new PartialEvaluator. */ public PartialEvaluator() { this(new ValueFactory(), new BasicInvocationUnit(), 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 branch targets * and exception 'catch' blocks should be evaluated, * even if they are unreachable. */ public PartialEvaluator(ValueFactory valueFactory, InvocationUnit invocationUnit, boolean evaluateAllCode) { this.valueFactory = valueFactory; this.invocationUnit = invocationUnit; this.evaluateAllCode = evaluateAllCode; this.branchUnit = evaluateAllCode ? new BasicBranchUnit() : new TracedBranchUnit(); } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // 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()); } throw ex; } } public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) {// DEBUG = DEBUG_RESULTS =// clazz.getName().equals("abc/Def") &&// method.getName(clazz).equals("abc"); // 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. initializeVariables(clazz, method, codeAttribute, variables, stack); // Find all instruction offsets,... codeAttribute.accept(clazz, method, branchTargetFinder); evaluateInstructionBlock(clazz, method, codeAttribute, variables, stack, 0); // 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, this); } while (evaluateExceptions); int codeLength = codeAttribute.u4codeLength; if (DEBUG_RESULTS) { System.out.println("Evaluation results:"); int offset = 0; do { if (isBranchOrExceptionTarget(offset)) { System.out.println("Branch target:"); 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)) { InstructionOffsetValue varProducerOffsets = varProducerOffsets(offset); if (varProducerOffsets.instructionOffsetCount() > 0) { System.out.println(" has overall been using information from instructions setting vars: "+varProducerOffsets); } InstructionOffsetValue stackProducerOffsets = stackProducerOffsets(offset); if (stackProducerOffsets.instructionOffsetCount() > 0) { System.out.println(" has overall been using information from instructions setting stack: "+stackProducerOffsets); } 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 < codeLength); } } /** * 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 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 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(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -