methodinliner.java
来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 511 行
JAVA
511 行
/*
* $Id: MethodInliner.java,v 1.2 2004/01/02 08:42:00 epr Exp $
*/
package org.jnode.vm.bytecode;
import org.jnode.vm.classmgr.VmClassLoader;
import org.jnode.vm.classmgr.VmByteCode;
import org.jnode.vm.classmgr.VmConstMethodRef;
import org.jnode.vm.classmgr.VmMethod;
import org.jnode.vm.classmgr.VmType;
/**
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
public class MethodInliner {
private final VmByteCode dst;
int noLocals;
int maxStack;
private final BytecodeModifier modifier;
/**
* Create a new instance
* @param dst
*/
public MethodInliner(VmByteCode dst) {
this.dst = dst;
this.noLocals = dst.getNoLocals();
this.maxStack = dst.getMaxStack();
this.modifier = new BytecodeModifier(dst);
}
/**
* Go through the bytecode and inline all method calls for which
* the oracle has decided that the method call should be inlined.
* @param oracle
* @param classLoader
* @return The number of inlined method calls
*/
public int inline(InlineOracle oracle, VmClassLoader classLoader) {
final InlineMethodVisitor visitor = new InlineMethodVisitor(oracle, classLoader, dst.getMethod());
BytecodeParser.parse(toByteCode(), visitor);
return visitor.getInlineCount();
}
/**
* Create the modified bytecode structure
* @return The bytecode
*/
public VmByteCode toByteCode() {
return modifier.toByteCode(noLocals, maxStack);
}
/**
* Inline bytecode src into bytecode dst at offset dstOfs.
* @param dstOfs
* @param src
* @param skipLen
*/
void inline(int dstOfs, VmByteCode src, int skipLen) {
final int localDelta = dst.getNoLocals();
noLocals = Math.max(noLocals, dst.getNoExceptionHandlers() + src.getNoLocals());
maxStack = Math.max(maxStack, dst.getMaxStack() + src.getMaxStack());
final VmMethod srcMethod = src.getMethod();
final BytecodeWriter writer = new BytecodeWriter();
// Create the inline header
createHeader(writer, srcMethod, localDelta);
// Insert the header code
final byte[] header = writer.toByteArray();
final int headerLen;
if (header != null) {
headerLen = header.length;
modifier.insert(dstOfs, skipLen, header, 0, headerLen, noLocals, maxStack);
} else {
headerLen = 0;
}
writer.clear();
// Insert the new method
final int insOfs = dstOfs + headerLen;
final byte[] srcBytes = src.getBytecode();
modifier.insert(insOfs, 0, srcBytes, 0, srcBytes.length, noLocals, maxStack);
// Create the footer code
createFooter(writer, srcMethod, localDelta);
// Insert the footer code
final byte[] footer = writer.toByteArray();
final int footerOfs = insOfs + srcBytes.length;
if (footer != null) {
modifier.insert(footerOfs, 0, footer, 0, footer.length, noLocals, maxStack);
}
// Modify the insert method code (between insOfs and footerOfs)
final InlinedMethodModifier imModifier = new InlinedMethodModifier(modifier, localDelta);
final VmByteCode newBc = modifier.toByteCode(noLocals, maxStack);
BytecodeParser.parse(newBc, imModifier, insOfs, footerOfs, false);
}
/**
* Create an inline header for a given method to inline
* @param writer
* @param srcMethod
* @param localDelta
*/
private void createHeader(BytecodeWriter writer, VmMethod srcMethod, int localDelta) {
// Pop all arguments into locals
popArgumentsToLocals(writer, localDelta, srcMethod);
// Insert a nullpointer check for non-static src methods
// For synchronized methods, the nullcheck is done automatically
// in the following monitorenter
if (!srcMethod.isStatic() && !srcMethod.isSynchronized()) {
insertNullCheck(writer, localDelta);
}
// Insert a monitor if the src method is synchronized
if (srcMethod.isSynchronized()) {
insertMonitor(writer, localDelta, true, srcMethod);
}
}
/**
* Create an inline footer for a given method to inline
* @param writer
* @param srcMethod
* @param localDelta
*/
private void createFooter(BytecodeWriter writer, VmMethod srcMethod, int localDelta) {
// Insert a monitor if the src method is synchronized
if (srcMethod.isSynchronized()) {
insertMonitor(writer, localDelta, false, srcMethod);
}
}
private void popArgumentsToLocals(BytecodeWriter writer, int localDelta, VmMethod method) {
final int cnt = method.getNoArguments();
final int[] locals = new int[cnt];
// Calculate the load indexes
int ofs = localDelta;
for (int i = 0; i < cnt; i++) {
locals[i] = ofs;
final VmType argType = method.getArgumentType(i);
final int size;
if (argType.isPrimitive()) {
if (argType.equals(VmType.getPrimitiveClass('J'))) {
size = 2;
} else if (argType.equals(VmType.getPrimitiveClass('D'))) {
size = 2;
} else {
size = 1;
}
} else {
size = 1;
}
ofs += size;
}
// Now pop and store in locals, (note in reverse argument order)
for (int i = cnt - 1; i >= 0; i--) {
final VmType argType = method.getArgumentType(i);
final int index = locals[i];
if (argType.isPrimitive()) {
final String typeName = argType.getName();
if (typeName.equals("boolean")) {
writer.istore(index);
} else if (typeName.equals("byte")) {
writer.istore(index);
} else if (typeName.equals("char")) {
writer.istore(index);
} else if (typeName.equals("short")) {
writer.istore(index);
} else if (typeName.equals("int")) {
writer.istore(index);
} else if (typeName.equals("float")) {
writer.fstore(index);
} else if (typeName.equals("long")) {
writer.lstore(index);
} else if (typeName.equals("double")) {
writer.dstore(index);
}
} else {
writer.astore(index);
}
}
// If non-static, pop the object ref
if (!method.isStatic()) {
writer.astore(ofs);
}
}
private void insertNullCheck(BytecodeWriter writer, int localDelta) {
//writer.aload(localDelta); // object-ref of srcMethod
// TODO Implement me
}
private void insertMonitor(BytecodeWriter writer, int localDelta, boolean entry, VmMethod method) {
if (method.isStatic()) {
// TODO Implement me
throw new RuntimeException("Cannot inline static synchronized methods yet");
} else {
writer.aload(localDelta); // object-ref of srcMethod
}
if (entry) {
writer.monitorenter();
} else {
writer.monitorexit();
}
}
final BytecodeModifier getModifier() {
return modifier;
}
/**
* This class calls the inline decider on all method calls
* and inlines the called methods if the decider has decided
* so.
*
* For now, interface method invocations are never inlined.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
class InlineMethodVisitor extends BytecodeVisitorSupport {
private final InlineOracle oracle;
private final VmClassLoader classLoader;
private int count;
private final VmMethod dstMethod;
public InlineMethodVisitor(InlineOracle oracle, VmClassLoader classLoader, VmMethod dstMethod) {
this.oracle = oracle;
this.classLoader = classLoader;
this.dstMethod = dstMethod;
}
private void adjustInvoke(VmConstMethodRef methodRef, int invokeType, int invokeLength) {
methodRef.resolve(classLoader);
final VmMethod callee = methodRef.getResolvedVmMethod();
if ((callee.getBytecode() != null) && (callee.getDeclaringClass() == dstMethod.getDeclaringClass())) {
if (oracle.shouldInline(toByteCode(), callee, invokeType)) {
final BytecodeParser parser = getParser();
final int start = parser.getAddress();
inline(start, callee.getBytecode(), invokeLength);
final byte[] newCode = getModifier().getNewCode();
parser.setCode(newCode);
parser.setContinueAt(start);
parser.setEndPC(newCode.length);
count++;
}
}
}
public int getInlineCount() {
return count;
}
/**
* @param methodRef
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_invokespecial(org.jnode.vm.classmgr.VmConstMethodRef)
*/
public void visit_invokespecial(VmConstMethodRef methodRef) {
adjustInvoke(methodRef, InlineOracle.INVOKE_SPECIAL, 3);
}
/**
* @param methodRef
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_invokestatic(org.jnode.vm.classmgr.VmConstMethodRef)
*/
public void visit_invokestatic(VmConstMethodRef methodRef) {
adjustInvoke(methodRef, InlineOracle.INVOKE_STATIC, 3);
}
/**
* @param methodRef
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_invokevirtual(org.jnode.vm.classmgr.VmConstMethodRef)
*/
public void visit_invokevirtual(VmConstMethodRef methodRef) {
adjustInvoke(methodRef, InlineOracle.INVOKE_VIRTUAL, 3);
}
}
/**
* This class modifies all indexes to local variables and replaced
* all returns with goto's.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
class InlinedMethodModifier extends ModifiableBytecodeVisitor {
private final int localDelta;
public InlinedMethodModifier(BytecodeModifier modifier, int localDelta) {
super(modifier, noLocals, maxStack);
this.localDelta = localDelta;
}
private final void adjustLoadStore(int index, int singleByteOpcode, int twoByteOpcode) {
final int start = getParser().getAddress();
final int newIndex = index + localDelta;
final byte[] code = getNewCode();
final int curOpcode = BytecodeWriter.get8(code, start);
if (curOpcode == singleByteOpcode + index) {
// It is a single byte opcode
if (newIndex > 255) {
// Upgrade to wide opcode
final byte[] opcode = new byte[4];
opcode[0] = (byte) 0xc4; // wide
opcode[1] = (byte) twoByteOpcode;
BytecodeWriter.set16(opcode, 2, newIndex);
insert(start, 1, opcode);
getParser().setContinueAt(start + 4);
} else if (newIndex > 3) {
// Upgrade to 2-byte opcode
final byte[] opcode = new byte[2];
opcode[0] = (byte) twoByteOpcode;
opcode[1] = (byte) newIndex;
insert(start, 1, opcode);
getParser().setContinueAt(start + 2);
} else {
// Keep 1-byte opcode
BytecodeWriter.set8(code, start, singleByteOpcode + newIndex);
}
} else if (curOpcode == 0xC4) {
// It is a wide opcode
BytecodeWriter.set16(code, start + 2, newIndex);
} else {
// It is a 2-byte opcode
if (newIndex > 255) {
// Upgrade to wide opcode
final byte[] opcode = new byte[4];
opcode[0] = (byte) 0xc4; // wide
opcode[1] = (byte) twoByteOpcode;
BytecodeWriter.set16(opcode, 2, newIndex);
insert(start, 2, opcode);
getParser().setContinueAt(start + 4);
} else {
BytecodeWriter.set8(code, start + 1, newIndex);
}
}
}
private final void adjustReturn() {
final BytecodeParser parser = getParser();
final int start = parser.getAddress();
if (start + 1 == parser.getEndPC()) {
// We're at the end, just remove the return
remove(start, 1);
} else {
// We're somewhere in the middle, replace the return with goto
final byte[] opcode = new byte[3];
opcode[0] = (byte) 0xa7; // goto
BytecodeWriter.set16(opcode, 1, parser.getEndPC() - start + 2);
insert(start, 1, opcode);
}
}
/**
* @param index
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_aload(int)
*/
public void visit_aload(int index) {
adjustLoadStore(index, 0x2a, 0x19);
}
/**
* @param index
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_astore(int)
*/
public void visit_astore(int index) {
adjustLoadStore(index, 0x4b, 0x3a);
}
/**
* @param index
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dload(int)
*/
public void visit_dload(int index) {
adjustLoadStore(index, 0x26, 0x18);
}
/**
* @param index
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dstore(int)
*/
public void visit_dstore(int index) {
adjustLoadStore(index, 0x47, 0x39);
}
/**
* @param index
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_fload(int)
*/
public void visit_fload(int index) {
adjustLoadStore(index, 0x22, 0x17);
}
/**
* @param index
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_fstore(int)
*/
public void visit_fstore(int index) {
adjustLoadStore(index, 0x43, 0x38);
}
/**
* @param index
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_iload(int)
*/
public void visit_iload(int index) {
adjustLoadStore(index, 0x1a, 0x15);
}
/**
* @param index
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_istore(int)
*/
public void visit_istore(int index) {
adjustLoadStore(index, 0x3b, 0x36);
}
/**
* @param index
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lload(int)
*/
public void visit_lload(int index) {
adjustLoadStore(index, 0x1e, 0x16);
}
/**
* @param index
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lstore(int)
*/
public void visit_lstore(int index) {
adjustLoadStore(index, 0x3f, 0x37);
}
/**
* @param index
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ret(int)
*/
public void visit_ret(int index) {
final int start = getParser().getAddress();
final int newIndex = index + localDelta;
final byte[] code = getNewCode();
final int curOpcode = BytecodeWriter.get8(code, start);
if (curOpcode == 0xC4) {
// It is a wide opcode
BytecodeWriter.set16(code, start + 2, newIndex);
} else {
// It is a ret opcode
if (newIndex > 255) {
// Upgrade to wide opcode
final byte[] opcode = new byte[4];
opcode[0] = (byte) 0xc4; // wide
opcode[1] = (byte) 0xA9; // ret
BytecodeWriter.set16(opcode, 2, newIndex);
insert(start, 2, opcode);
getParser().setContinueAt(start + 4);
} else {
BytecodeWriter.set8(code, start + 1, newIndex);
}
}
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_areturn()
*/
public void visit_areturn() {
adjustReturn();
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dreturn()
*/
public void visit_dreturn() {
adjustReturn();
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_freturn()
*/
public void visit_freturn() {
adjustReturn();
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ireturn()
*/
public void visit_ireturn() {
adjustReturn();
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lreturn()
*/
public void visit_lreturn() {
adjustReturn();
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_return()
*/
public void visit_return() {
adjustReturn();
}
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?