bytecodemodifier.java
来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 428 行
JAVA
428 行
/*
* $Id: BytecodeModifier.java,v 1.1 2003/11/25 11:42:13 epr Exp $
*/
package org.jnode.vm.bytecode;
import java.util.List;
import org.jnode.vm.classmgr.VmByteCode;
import org.jnode.vm.classmgr.VmInterpretedExceptionHandler;
import org.jnode.vm.classmgr.VmLineNumberMap;
/**
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
public class BytecodeModifier {
private final VmByteCode byteCode;
private VmInterpretedExceptionHandler[] eTable;
private char[] lnTable;
private byte[] newBc;
/**
* @return The new code
*/
public final byte[] getNewCode() {
return this.newBc;
}
/**
* Create a new instance
* @param byteCode
*/
public BytecodeModifier(VmByteCode byteCode) {
this.byteCode = byteCode;
this.newBc = byteCode.getBytecode();
final List eTableList = byteCode.getExceptionHandlers();
if (eTableList.isEmpty()) {
this.eTable = null;
} else {
eTable = (VmInterpretedExceptionHandler[]) eTableList.toArray(new VmInterpretedExceptionHandler[eTableList.size()]);
}
final VmLineNumberMap lnMap = byteCode.getLineNrs();
if (lnMap == null) {
this.lnTable = null;
} else {
final int len = lnMap.getLength();
this.lnTable = new char[len * 2];
for (int i = 0; i < len; i++) {
lnTable[i * 2 + 0] = (char) lnMap.getStartPCAt(i);
lnTable[i * 2 + 1] = (char) lnMap.getLineNrAt(i);
}
}
}
/**
* Insert the given src bytes into a clone of the given byteCode
* at offset bcOfs, leave a portion of the original bytecode out
* and return the cloned bytecode.
* @param bcOfs The offset (in byteCode) from where to insert the new bytecode
* @param skipLen The number of bytes to leave out starting from bcOfs
* @param src The new bytes
* @param srcOfs The offset in src from where to start copying
* @param len The length of src
* @param newNoLocals
* @param newMaxStack
*/
public void insert(int bcOfs, int skipLen, byte[] src, int srcOfs, int len, int newNoLocals, int newMaxStack) {
final byte[] curBc = this.newBc;
final byte[] newBc = new byte[curBc.length - skipLen + len];
// Copy the first part
System.arraycopy(curBc, 0, newBc, 0, bcOfs);
// Copy/Insert the new part
if (src != null) {
System.arraycopy(src, srcOfs, newBc, bcOfs, len);
}
// Copy the second part
System.arraycopy(curBc, bcOfs + skipLen, newBc, bcOfs + len, curBc.length - (bcOfs + skipLen));
final int delta = len - skipLen;
// Create the new exception table
adjustExceptionTable(bcOfs, delta);
// Create the new line number table
adjustLineNrTable(bcOfs, delta);
// Create the new VmByteCode
final VmByteCode newByteCode = new VmByteCode(byteCode.getMethod(), newBc, newNoLocals, newMaxStack, eTable, new VmLineNumberMap(lnTable));
// Adjust all jump addresses after bcOfs
final BytecodeJumpModifier modifier = new BytecodeJumpModifier(newBc, bcOfs, delta);
BytecodeParser.parse(newByteCode, modifier);
// And we're done
this.newBc = newBc;
}
/**
* Remove a number of code bytes from the given bcOfs offset.
*
* @param bcOfs The offset (in byteCode) from where to remove the bytecode
* @param len The number of bytes to remove
* @param newNoLocals
* @param newMaxStack
*/
public void remove(int bcOfs, int len, int newNoLocals, int newMaxStack) {
insert(bcOfs, len, null, 0, 0, newNoLocals, newMaxStack);
}
/**
* Create the modified bytecode structure
* @param newNoLocals
* @param newMaxStack
* @return The bytecode
*/
public VmByteCode toByteCode(int newNoLocals, int newMaxStack) {
return new VmByteCode(byteCode.getMethod(), newBc, newNoLocals, newMaxStack, eTable, new VmLineNumberMap(lnTable));
}
/**
* Create a new exception table with modified pointers.
* All pointers that are >= bcOfs are incremented by delta.
* @param bcOfs
* @param delta
*/
private void adjustExceptionTable(int bcOfs, int delta) {
if (eTable != null) {
final int len = eTable.length;
for (int i = 0; i < len; i++) {
final VmInterpretedExceptionHandler h = eTable[i];
if ((h.getStartPC() >= bcOfs) || (h.getEndPC() >= bcOfs) || (h.getHandlerPC() >= bcOfs)) {
eTable[i] =
new VmInterpretedExceptionHandler(
h.getCatchType(),
adjust(h.getStartPC(), bcOfs, delta),
adjust(h.getEndPC(), bcOfs, delta),
adjust(h.getHandlerPC(), bcOfs, delta));
}
}
}
}
/**
* Create a new line number table with modified start pc pointers.
* All pointers that are >= bcOfs are incremented by delta.
* @param bcOfs
* @param delta
*/
private void adjustLineNrTable(int bcOfs, int delta) {
if (lnTable != null) {
final int len = lnTable.length;
for (int i = 0; i < len; i += 2) {
lnTable[i] = (char) adjust(lnTable[i], bcOfs, delta);
}
}
}
private final int adjust(int ofs, int bcOfs, int delta) {
if (ofs >= bcOfs) {
return ofs + delta;
} else {
return ofs;
}
}
static class BytecodeJumpModifier extends BytecodeVisitorSupport {
private final int bcOfs;
private final int delta;
private final byte[] bytecode;
private BytecodeParser parser;
public BytecodeJumpModifier(byte[] bytecode, int bcOfs, int delta) {
this.bcOfs = bcOfs;
this.delta = delta;
this.bytecode = bytecode;
}
/**
* Adjust a 16-bit address at the given offset from the start of
* the current instruction.
* @param address
* @param offset
*/
private void adjustBranch16(int address, int offset) {
final int newAddress = getNewBranchAddress(address);
if (newAddress != address) {
final int curAddress = getParser().getAddress();
final int target = newAddress - curAddress;
bytecode[curAddress + offset + 0] = (byte) ((target >> 8) & 0xFF);
bytecode[curAddress + offset + 1] = (byte) (target & 0xFF);
}
}
/**
* Adjust a 32-bit address at the given offset from the start of
* the current instruction.
* @param address
* @param offset
*/
private void adjustBranch32(int address, int offset) {
final int newAddress = getNewBranchAddress(address);
if (newAddress != address) {
final int curAddress = getParser().getAddress();
final int target = newAddress - curAddress;
bytecode[curAddress + offset + 0] = (byte) ((target >> 24) & 0xFF);
bytecode[curAddress + offset + 1] = (byte) ((target >> 16) & 0xFF);
bytecode[curAddress + offset + 2] = (byte) ((target >> 8) & 0xFF);
bytecode[curAddress + offset + 3] = (byte) (target & 0xFF);
}
}
/**
* Calculate the new address
* the current instruction.
* @param address
* @return int
*/
private int getNewBranchAddress(int address) {
final int curAddress = getParser().getAddress();
final int target = curAddress + address;
final int newAddress;
if ((curAddress < bcOfs) && (target >= bcOfs)) {
// Jump over the inserted area
newAddress = address + delta;
} else if ((curAddress >= bcOfs) && (target < bcOfs)) {
// Jump back over the insert data
newAddress = address - delta;
} else {
newAddress = address;
}
return newAddress;
}
/**
* @param parser
* @see org.jnode.vm.bytecode.BytecodeVisitor#setParser(org.jnode.vm.bytecode.BytecodeParser)
*/
public void setParser(BytecodeParser parser) {
this.parser = parser;
super.setParser(parser);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_goto(int)
*/
public void visit_goto(int address) {
final int opcode = parser.getOpcode();
if (opcode == 0xA7) {
adjustBranch16(address, 1);
} else if (opcode == 0xC8) {
adjustBranch32(address, 1);
}
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_acmpeq(int)
*/
public void visit_if_acmpeq(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_acmpne(int)
*/
public void visit_if_acmpne(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_icmpeq(int)
*/
public void visit_if_icmpeq(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_icmpge(int)
*/
public void visit_if_icmpge(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_icmpgt(int)
*/
public void visit_if_icmpgt(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_icmple(int)
*/
public void visit_if_icmple(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_icmplt(int)
*/
public void visit_if_icmplt(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_icmpne(int)
*/
public void visit_if_icmpne(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ifeq(int)
*/
public void visit_ifeq(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ifge(int)
*/
public void visit_ifge(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ifgt(int)
*/
public void visit_ifgt(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ifle(int)
*/
public void visit_ifle(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_iflt(int)
*/
public void visit_iflt(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ifne(int)
*/
public void visit_ifne(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ifnonnull(int)
*/
public void visit_ifnonnull(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ifnull(int)
*/
public void visit_ifnull(int address) {
adjustBranch16(address, 1);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_jsr(int)
*/
public void visit_jsr(int address) {
final int opcode = parser.getOpcode();
if (opcode == 0xA8) {
adjustBranch16(address, 1);
} else if (opcode == 0xC9) {
adjustBranch32(address, 1);
}
}
/**
* @param defValue
* @param matchValues
* @param addresses
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lookupswitch(int, int[], int[])
*/
public void visit_lookupswitch(int defValue, int[] matchValues, int[] addresses) {
final int offset = 9 + (parser.getPaddedAddress() - parser.getAddress());
for (int i = 0; i < matchValues.length; i++) {
adjustBranch32(addresses[i], offset + (i * 8) + 4);
}
}
/**
* @param defValue
* @param lowValue
* @param highValue
* @param addresses
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_tableswitch(int, int, int, int[])
*/
public void visit_tableswitch(int defValue, int lowValue, int highValue, int[] addresses) {
final int offset = 13 + (parser.getPaddedAddress() - parser.getAddress());
for (int i = 0; i < addresses.length; i++) {
adjustBranch32(addresses[i], offset + (i * 4));
}
}
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?