📄 partialevaluator.java
字号:
/** * 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 instruction offsets that set the variable that is being * used at the given instruction offset. */ public InstructionOffsetValue varProducerOffsets(int instructionOffset) { return varProducerValues[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 set the stack entries that are being * used at the given instruction offset. */ public InstructionOffsetValue stackProducerOffsets(int instructionOffset) { return stackProducerValues[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]; } /** * Returns the variable that is initialized at the given instruction offset, * or <code>NONE</code> if no variable was initialized. */ public int initializedVariable(int instructionOffset) { return initializedVariables[instructionOffset]; } // 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; if (DEBUG) System.out.println("Partial evaluation of 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 ? 1 : 0), variables); // Initialize the the stack. //stack.push(valueFactory.createReference((ClassConstant)((ProgramClass)clazz).getConstant(exceptionInfo.u2catchType), false)); String catchType = exceptionInfo.u2catchType != 0 ? clazz.getClassName(exceptionInfo.u2catchType) : ClassConstants.INTERNAL_NAME_JAVA_LANG_THROWABLE; // TODO: Get catch type class from class constant pool entry. stack.push(valueFactory.createReferenceValue(catchType, null, 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+"]"); } } // Utility methods to evaluate instruction blocks. /** * 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) { 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); 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); // 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; variables.setCollectedProducerValue(traceValue); stack.setCollectedProducerValue(traceValue); // Reset the initialization flag. variables.resetInitialization(); // 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -