📄 codeinsertion.java
字号:
int[] transformedIndices)
throws InvalidByteCodeException
{
int instructionCount = instructions.size();
for (int sourceIndex = 0; sourceIndex < instructionCount; sourceIndex++) {
AbstractInstruction currentInstruction = (AbstractInstruction)instructions.get(sourceIndex);
int branchOffset = getBranchOffset(currentInstruction);
if (branchOffset == 0) {
continue;
}
if (currentInstruction instanceof TableSwitchInstruction) {
int[] jumpOffsets = ((TableSwitchInstruction)currentInstruction).getJumpOffsets();
for (int i = 0; i < jumpOffsets.length; i++) {
int targetIndex = getBranchTargetIndex(instructions, sourceIndex, jumpOffsets[i]);
jumpOffsets[i] =
calculateNewBranchOffset(newInstructions, sourceIndex, targetIndex, transformedIndices, newOffsets);
}
} else if (currentInstruction instanceof LookupSwitchInstruction) {
List matchOffsetPairs = ((LookupSwitchInstruction)currentInstruction).getMatchOffsetPairs();
for (int i = 0; i < matchOffsetPairs.size(); i++) {
MatchOffsetPair matchOffsetPair =
(MatchOffsetPair)matchOffsetPairs.get(i);
int targetIndex = getBranchTargetIndex(instructions, sourceIndex, matchOffsetPair.getOffset());
matchOffsetPair.setOffset(
calculateNewBranchOffset(newInstructions, sourceIndex, targetIndex, transformedIndices, newOffsets)
);
}
}
int targetIndex = getBranchTargetIndex(instructions, sourceIndex, branchOffset);
setBranchOffset(
currentInstruction,
calculateNewBranchOffset(newInstructions, sourceIndex, targetIndex, transformedIndices, newOffsets)
);
}
}
private static int calculateNewBranchOffset(List newInstructions,
int sourceIndex,
int targetIndex,
int[] transformedIndices,
int[] newOffsets)
{
int transformedSourceIndex = transformedIndices[sourceIndex];
int transformedTargetIndex = transformedIndices[targetIndex];
int newBranchOffset = newOffsets[transformedTargetIndex] - newOffsets[transformedSourceIndex];
return newBranchOffset;
}
private static int getBranchOffset(AbstractInstruction instruction) {
int branchOffset = 0;
if (instruction.getOpcode() == Opcodes.OPCODE_GOTO_W) {
branchOffset = ((ImmediateIntInstruction)instruction).getImmediateInt();
} else if (instruction instanceof TableSwitchInstruction) {
branchOffset = ((TableSwitchInstruction)instruction).getDefaultOffset();
} else if (instruction instanceof LookupSwitchInstruction) {
branchOffset = ((LookupSwitchInstruction)instruction).getDefaultOffset();
} else if (instruction instanceof BranchInstruction) {
branchOffset = ((BranchInstruction)instruction).getBranchOffset();
}
return branchOffset;
}
private static void setBranchOffset(AbstractInstruction instruction,
int branchOffset)
{
if (instruction.getOpcode() == Opcodes.OPCODE_GOTO_W) {
((ImmediateIntInstruction)instruction).setImmediateInt(branchOffset);
} else if (instruction instanceof TableSwitchInstruction) {
((TableSwitchInstruction)instruction).setDefaultOffset(branchOffset);
} else if (instruction instanceof LookupSwitchInstruction) {
((LookupSwitchInstruction)instruction).setDefaultOffset(branchOffset);
} else if (instruction instanceof BranchInstruction) {
((BranchInstruction)instruction).setBranchOffset(branchOffset);
}
}
private static int getBranchTargetIndex(List instructions,
int sourceIndex,
int branchOffset)
throws InvalidByteCodeException
{
int instructionsCount = instructions.size();
int startOffset = ((AbstractInstruction)instructions.get(sourceIndex)).getOffset();
int step = branchOffset > 0 ? 1 : -1;
for (int i = sourceIndex + step; i >= 0 && i < instructionsCount; i += step) {
int targetOffset = ((AbstractInstruction)instructions.get(i)).getOffset();
if (targetOffset - startOffset == branchOffset) {
return i;
}
}
throw new InvalidByteCodeException("Invalid branch target");
}
private static void adjustExceptionTable(int[] oldOffsets,
int[] newOffsets,
int[] transformedIndices,
CodeAttribute codeAttribute)
throws InvalidByteCodeException
{
ExceptionTableEntry[] exceptionTable = codeAttribute.getExceptionTable();
if (exceptionTable == null) {
return;
}
for (int i = 0; i < exceptionTable.length; i++) {
ExceptionTableEntry currentEntry = exceptionTable[i];
int startPcIndex = Arrays.binarySearch(oldOffsets, currentEntry.getStartPc());
int endPcIndex = Arrays.binarySearch(oldOffsets, currentEntry.getEndPc());
int handlerPcIndex = Arrays.binarySearch(oldOffsets, currentEntry.getHandlerPc());
if (startPcIndex < 0 || endPcIndex < 0 || handlerPcIndex < 0 ||
startPcIndex == oldOffsets.length ||
endPcIndex == oldOffsets.length ||
handlerPcIndex == oldOffsets.length)
{
throw new InvalidByteCodeException("Invalid exception table");
}
currentEntry.setStartPc(newOffsets[transformedIndices[startPcIndex]]);
currentEntry.setEndPc(newOffsets[transformedIndices[endPcIndex]]);
currentEntry.setHandlerPc(newOffsets[transformedIndices[handlerPcIndex]]);
}
}
private static void adjustLineNumberTable(int[] oldOffsets,
int[] newOffsets,
int[] transformedIndices,
CodeAttribute codeAttribute)
throws InvalidByteCodeException
{
LineNumberTableAttribute lineNumberTableAttribute =
(LineNumberTableAttribute)codeAttribute.findAttribute(LineNumberTableAttribute.class);
if (lineNumberTableAttribute == null) {
return;
}
LineNumberTableEntry[] lineNumberTable = lineNumberTableAttribute.getLineNumberTable();
for (int i = 0; i < lineNumberTable.length; i++) {
LineNumberTableEntry currentEntry = lineNumberTable[i];
int startPcIndex = Arrays.binarySearch(oldOffsets, currentEntry.getStartPc());
if (startPcIndex < 0 || startPcIndex == oldOffsets.length) {
throw new InvalidByteCodeException("Invalid line number table " + currentEntry.getStartPc());
}
currentEntry.setStartPc(newOffsets[transformedIndices[startPcIndex]]);
}
}
private int position;
private AbstractInstruction[] preInstructions;
private AbstractInstruction[] postInstructions;
private boolean shiftTarget;
/**
Create a code insertion.
@param position the instruction number to which this <tt>CodeInsertion</tt>
is to be applied. Corresponds to the index in the list
of instructions such as the one returned by a
<tt>ByteCodeReader</tt>.
@param preInstructions the instructions to be inserted <b>before</b>
the insertion point.
@param postInstructions the instructions to be inserted <b>after</b>
the insertion point.
@param shiftTarget should offsets of branch instructions pointing to
the position of this code insertion
be shifted or point to the beginning of the
code inserted via the <tt>preInstructions</tt>
parameters.
*/
public CodeInsertion(int position,
AbstractInstruction[] preInstructions,
AbstractInstruction[] postInstructions,
boolean shiftTarget)
{
this.position = position;
this.preInstructions = preInstructions;
this.postInstructions = postInstructions;
this.shiftTarget = shiftTarget;
}
/**
Get the insertion position, i.e the instruction number to which
this <tt>CodeInsertion</tt> is to be applied. Corresponds to the
index in the list of instructions such as the one returned by a
<tt>ByteCodeReader</tt>.
@return the insertion position
*/
public int getPosition() {
return position;
}
/**
Set the insertion position, i.e the instruction number to which
this <tt>CodeInsertion</tt> is to be applied. Corresponds to the
index in the list of instructions such as the one returned by a
<tt>ByteCodeReader</tt>.
@param position the insertion position
*/
public void setPosition(int position) {
this.position = position;
}
/**
Get the instructions to be inserted <b>before</b> the insertion point.
@return array of instructions
*/
public AbstractInstruction[] getPreInstructions() {
return preInstructions;
}
/**
Set the instructions to be inserted <b>before</b> the insertion point.
@param preInstructions array of instructions
*/
public void setPreInstructions(AbstractInstruction[] preInstructions) {
this.preInstructions = preInstructions;
}
/**
Get the instructions to be inserted <b>after</b> the insertion point.
@return array of instructions
*/
public AbstractInstruction[] getPostInstructions() {
return postInstructions;
}
/**
Set the instructions to be inserted <b>after</b> the insertion point.
@param postInstructions array of instructions
*/
public void setPostInstructions(AbstractInstruction[] postInstructions) {
this.postInstructions = postInstructions;
}
/**
Get whether offsets of branch instructions pointing to the position of
the resulting code insertion should be shifted to the first pre-instruction
or continue to point at the original instruction.
@return the boolean value
*/
public boolean isShiftTarget() {
return shiftTarget;
}
/**
Set whether offsets of branch instructions pointing to the position of
the resulting code insertion should be shifted to the first pre-instruction
or continue to point at the original instruction.
@param shiftTarget the boolean value.
*/
public void setShiftTarget(boolean shiftTarget) {
this.shiftTarget = shiftTarget;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -