📄 partialevaluator.java
字号:
int lowestNecessaryIndex) { return branchOrigin <= lowestNecessaryIndex ^ branchTarget <= lowestNecessaryIndex; } /** * Inserts pop instructions where necessary, in order to make sure the * stack is consistent at the given index. * @param classFile the class file that is being checked. * @param codeAttrInfo the code that is being checked. * @param index the offset of the dependent instruction. */ private void fixStackConsistency(ClassFile classFile, CodeAttrInfo codeAttrInfo, int index) { // Is the unnecessary instruction popping values (but not a dup/swap // instruction)? Instruction popInstruction = InstructionFactory.create(codeAttrInfo.code, index); byte popOpcode = popInstruction.opcode; int popCount = popInstruction.stackPopCount(classFile); if (popCount > 0) // && //popOpcode != InstructionConstants.OP_DUP && //popOpcode != InstructionConstants.OP_DUP_X1 && //popOpcode != InstructionConstants.OP_DUP_X2 && //popOpcode != InstructionConstants.OP_DUP2 && //popOpcode != InstructionConstants.OP_DUP2_X1 && //popOpcode != InstructionConstants.OP_DUP2_X2 && //popOpcode != InstructionConstants.OP_SWAP) { // Check the instructions on which it depends. InstructionOffsetValue traceOffsetValue = stackTraceValues[index]; int traceOffsetCount = traceOffsetValue.instructionOffsetCount(); if (popCount <= 4 && isAllNecessary(traceOffsetValue)) { if (popOpcode == InstructionConstants.OP_POP || popOpcode == InstructionConstants.OP_POP2) { if (DEBUG_ANALYSIS) System.out.println(" Popping value again at "+popInstruction.toString(index)+" (pushed at all "+traceOffsetValue.instructionOffsetCount()+" offsets)"); // Simply mark pop and pop2 instructions. isNecessary[index] = true; } else { if (DEBUG_ANALYSIS) System.out.println(" Popping value instead of "+popInstruction.toString(index)+" (pushed at all "+traceOffsetValue.instructionOffsetCount()+" offsets)"); // Make sure the pushed value is popped again, // right before this instruction. decreaseStackSize(index, popCount, true, true); } } //else if (popCount == (popInstruction.isCategory2() ? 4 : 2) && // traceOffsetCount == 2 && // isAnyNecessary(traceOffsetValue)) //{ // if (DEBUG_ANALYSIS) System.out.println(" Popping single value instead of "+popInstruction.toString(index)+" (pushed at some of "+traceOffsetValue.instructionOffsetCount()+" offsets)"); // // // Make sure the single pushed value is popped again, // // right before this instruction. // decreaseStackSize(index, popCount / 2, true, true); //} else if (isAnyNecessary(traceOffsetValue)) { if (DEBUG_ANALYSIS) System.out.println(" Popping value somewhere before "+index+" (pushed at some of "+traceOffsetValue.instructionOffsetCount()+" offsets):"); // Go over all stack pushing instructions. for (int traceOffsetIndex = 0; traceOffsetIndex < traceOffsetCount; traceOffsetIndex++) { // Has the push instruction been marked? int pushInstructionOffset = traceOffsetValue.instructionOffset(traceOffsetIndex); if (isNecessary[pushInstructionOffset]) { Instruction pushInstruction = InstructionFactory.create(codeAttrInfo.code, pushInstructionOffset); int lastOffset = lastPopInstructionOffset(pushInstructionOffset, index, pushInstructionOffset); if (DEBUG_ANALYSIS) System.out.println(" Popping value right after "+lastOffset+", due to push at "+pushInstructionOffset); // Make sure the pushed value is popped again, // right after the instruction that pushes it // (or after the dup instruction that still uses it). decreaseStackSize(lastOffset, pushInstruction.stackPushCount(classFile), false, false); } } } } } /** * Returns the last offset of the necessary instruction that depends on the * stack result of the instruction at the given index. * @param startOffset the start offset in the search. * @param endOffset the end offset in the search. * @param pushInstructionOffset the offset of the instruction that pushes * a result onto the stack. * @return the last offset of the necessary instruction that uses the * above result. */ private int lastPopInstructionOffset(int startOffset, int endOffset, int pushInstructionOffset) { int lastOffset = startOffset; for (int index = startOffset; index < endOffset; index++) { if (isNecessary[index] && stackTraceValues[index].contains(pushInstructionOffset)) { lastOffset = index; } } return lastOffset; } /** * Puts the required push instruction before the given index. The * instruction is marked as necessary. * @param index the offset of the instruction. * @param computationalType the computational type on the stack, for * push instructions. * @param delete specifies whether the instruction should be * deleted. */ private void increaseStackSize(int index, int computationalType, boolean delete) { // Mark this instruction. isNecessary[index] = true; // Create a simple push instrucion. byte replacementOpcode = computationalType == Value.TYPE_INTEGER ? InstructionConstants.OP_ICONST_0 : computationalType == Value.TYPE_LONG ? InstructionConstants.OP_LCONST_0 : computationalType == Value.TYPE_FLOAT ? InstructionConstants.OP_FCONST_0 : computationalType == Value.TYPE_DOUBLE ? InstructionConstants.OP_DCONST_0 : computationalType == Value.TYPE_REFERENCE ? InstructionConstants.OP_ACONST_NULL : InstructionConstants.OP_NOP; Instruction replacementInstruction = new SimpleInstruction(replacementOpcode); // Insert the pop or push instruction. codeAttrInfoEditor.insertBeforeInstruction(index, replacementInstruction); // Delete the original instruction if necessary. if (delete) { codeAttrInfoEditor.deleteInstruction(index); } } /** * Puts the required pop instruction at the given index. The * instruction is marked as necessary. * @param offset the offset of the instruction. * @param popCount the required reduction of the stack size. * @param before specifies whether the pop instruction should be inserted * before or after the present instruction. * @param delete specifies whether the instruction should be deleted. */ private void decreaseStackSize(int offset, int popCount, boolean before, boolean delete) { boolean after = !before; // Special case: we may replace the instruction by two pop instructions. if (delete && popCount > 2) { before = true; after = true; } if (popCount < 1 || popCount > 4) { throw new IllegalArgumentException("Unsupported stack size reduction ["+popCount+"]"); } // Mark this instruction. isNecessary[offset] = true; if (before) { // Create a simple pop instrucion. byte replacementOpcode = popCount == 1 || popCount == 3 ? InstructionConstants.OP_POP : InstructionConstants.OP_POP2; Instruction replacementInstruction = new SimpleInstruction(replacementOpcode); // Insert the pop instruction. codeAttrInfoEditor.insertBeforeInstruction(offset, replacementInstruction); } if (after) { // Create a simple pop instrucion. byte replacementOpcode = popCount == 1 ? InstructionConstants.OP_POP : InstructionConstants.OP_POP2; Instruction replacementInstruction = new SimpleInstruction(replacementOpcode); if (DEBUG_ANALYSIS) System.out.println(" Pop instruction after ["+offset+"]: "+replacementInstruction); // Insert the pop instruction. codeAttrInfoEditor.insertAfterInstruction(offset, replacementInstruction); } // Delete the original instruction if necessary. if (delete) { codeAttrInfoEditor.deleteInstruction(offset); } } /** * Replaces the specified instruction by the proper dup/swap variant, * if necessary, depending on the state of the stack. * @param codeAttrInfo the code that is being checked. * @param offset the offset of the instruction. */ private void fixDupInstruction(CodeAttrInfo codeAttrInfo, int offset) { byte replacementOpcode = 0; // Simplify the popping instruction if possible. switch (codeAttrInfo.code[offset]) { case InstructionConstants.OP_DUP_X1: if (!isStackEntryPresent(offset, 1)) { replacementOpcode = InstructionConstants.OP_DUP; } break; case InstructionConstants.OP_DUP_X2: if (!isStackEntryPresent(offset, 1) || !isStackEntryPresent(offset, 2)) { if (isStackEntryPresent(offset, 1) || isStackEntryPresent(offset, 2)) { replacementOpcode = InstructionConstants.OP_DUP_X1; } else { replacementOpcode = InstructionConstants.OP_DUP; } } break; case InstructionConstants.OP_DUP2_X1: if (!isStackEntryPresent(offset, 2)) { replacementOpcode = InstructionConstants.OP_DUP2; } break; case InstructionConstants.OP_DUP2_X2: if (!isStackEntryPresent(offset, 2) || !isStackEntryPresent(offset, 3)) { if (isStackEntryPresent(offset, 2) || isStackEntryPresent(offset, 3)) { replacementOpcode = InstructionConstants.OP_DUP2_X1; } else { replacementOpcode = InstructionConstants.OP_DUP2; } } break; case InstructionConstants.OP_SWAP: if (!isStackEntryPresent(offset, 0)) { isNecessary[offset] = false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -