x86bytecodevisitor.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 2,035 行 · 第 1/5 页

JAVA
2,035
字号
/*
 * $Id: X86BytecodeVisitor.java,v 1.29 2004/02/24 08:05:27 epr Exp $
 */
package org.jnode.vm.x86.compiler.l1;

import org.jnode.assembler.Label;
import org.jnode.assembler.NativeStream;
import org.jnode.assembler.UnresolvedObjectRefException;
import org.jnode.assembler.x86.AbstractX86Stream;
import org.jnode.assembler.x86.Register;
import org.jnode.assembler.x86.X86Constants;
import org.jnode.vm.SoftByteCodes;
import org.jnode.vm.bytecode.BasicBlock;
import org.jnode.vm.bytecode.BytecodeParser;
import org.jnode.vm.classmgr.ObjectLayout;
import org.jnode.vm.classmgr.Signature;
import org.jnode.vm.classmgr.TIBLayout;
import org.jnode.vm.classmgr.VmArray;
import org.jnode.vm.classmgr.VmClassLoader;
import org.jnode.vm.classmgr.VmConstClass;
import org.jnode.vm.classmgr.VmConstFieldRef;
import org.jnode.vm.classmgr.VmConstIMethodRef;
import org.jnode.vm.classmgr.VmConstMethodRef;
import org.jnode.vm.classmgr.VmConstString;
import org.jnode.vm.classmgr.VmField;
import org.jnode.vm.classmgr.VmInstanceField;
import org.jnode.vm.classmgr.VmInstanceMethod;
import org.jnode.vm.classmgr.VmMethod;
import org.jnode.vm.classmgr.VmStaticField;
import org.jnode.vm.classmgr.VmStaticMethod;
import org.jnode.vm.classmgr.VmType;
import org.jnode.vm.classmgr.VmTypeState;
import org.jnode.vm.compiler.CompileError;
import org.jnode.vm.compiler.CompiledMethod;
import org.jnode.vm.compiler.InlineBytecodeVisitor;
import org.jnode.vm.x86.VmX86Architecture;
import org.jnode.vm.x86.compiler.X86CompilerConstants;
import org.jnode.vm.x86.compiler.X86CompilerContext;
import org.jnode.vm.x86.compiler.X86CompilerHelper;
import org.jnode.vm.x86.compiler.X86JumpTable;

/**
 * Actual converter from bytecodes to X86 native code.
 * 
 * @author Ewout Prangsma (epr@users.sourceforge.net)
 */
class X86BytecodeVisitor extends InlineBytecodeVisitor implements
        X86CompilerConstants {

    /** The output stream */
    private final AbstractX86Stream os;

    /** Helper class */
    private final X86CompilerHelper helper;

    /** The destination compiled method */
    private final CompiledMethod cm;

    /** Label of current instruction */
    private Label curInstrLabel;

    /** Length of os at start of method */
    private int startOffset;

    /** Stackframe utility */
    private X86StackFrame stackFrame;

    /** Size of an object reference */
    private final int slotSize;

    /** Current context */
    private final X86CompilerContext context;

    /** Emit logging info */
    private final boolean log;

    /** Class loader */
    private VmClassLoader loader;

    private boolean startOfBB;

    private Label endOfInlineLabel;

    private int maxLocals;

    /**
     * Create a new instance
     * 
     * @param outputStream
     * @param cm
     * @param isBootstrap
     * @param context
     */
    public X86BytecodeVisitor(NativeStream outputStream, CompiledMethod cm,
            boolean isBootstrap, X86CompilerContext context) {
        this.os = (AbstractX86Stream) outputStream;
        this.context = context;
        this.helper = new X86CompilerHelper(os, context, isBootstrap);
        this.cm = cm;
        this.slotSize = VmX86Architecture.SLOT_SIZE;
        this.log = os.isLogEnabled();
    }

    /**
     * @param method
     * @see org.jnode.vm.bytecode.BytecodeVisitor#startMethod(org.jnode.vm.classmgr.VmMethod)
     */
    public void startMethod(VmMethod method) {
        this.maxLocals = method.getBytecode().getNoLocals();
        this.loader = method.getDeclaringClass().getLoader();
        helper.setMethod(method);
        this.startOffset = os.getLength();
        this.stackFrame = new X86StackFrame(os, helper, method, context, cm);
        stackFrame.emitHeader();
    }

    /**
     * The given basic block is about to start.
     */
    public void startBasicBlock(BasicBlock bb) {
        if (log) {
            os.log("Start of basic block " + bb);
        }
        helper.reset();
        startOfBB = true;
    }

    /**
     * @param address
     * @see org.jnode.vm.bytecode.BytecodeVisitor#startInstruction(int)
     */
    public void startInstruction(int address) {
        this.curInstrLabel = helper.getInstrLabel(address);
        if (startOfBB) {
            os.setObjectRef(curInstrLabel);
            startOfBB = false;
        }
        final int offset = os.getLength() - startOffset;
        cm.add(address, offset);
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#endInstruction()
     */
    public void endInstruction() {
        // Nothing to do here
    }

    /**
     * The started basic block has finished.
     */
    public void endBasicBlock() {
        if (log) {
            os.log("End of basic block");
        }
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#endMethod()
     */
    public void endMethod() {
        stackFrame.emitTrailer(maxLocals);
    }

    /**
     * @param parser
     * @see org.jnode.vm.bytecode.BytecodeVisitor#setParser(org.jnode.vm.bytecode.BytecodeParser)
     */
    public void setParser(BytecodeParser parser) {
        // Nothing to do here
    }

    /**
     * @see org.jnode.vm.compiler.InlineBytecodeVisitor#endInlinedMethod(org.jnode.vm.classmgr.VmMethod)
     */
    public void endInlinedMethod(VmMethod previousMethod) {
        helper.setMethod(previousMethod);
        os.setObjectRef(endOfInlineLabel);
    }

    /**
     * @see org.jnode.vm.compiler.InlineBytecodeVisitor#startInlinedMethod(org.jnode.vm.classmgr.VmMethod,
     *      int)
     */
    public void startInlinedMethod(VmMethod inlinedMethod, int newMaxLocals) {
        maxLocals = newMaxLocals;
        endOfInlineLabel = new Label(curInstrLabel + "_end_of_inline");
        helper.startInlinedMethod(inlinedMethod, curInstrLabel);
    }

    /**
     * @see org.jnode.vm.compiler.InlineBytecodeVisitor#visit_inlinedReturn()
     */
    public void visit_inlinedReturn() {
        os.writeJMP(endOfInlineLabel);
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_aaload()
     */
    public final void visit_aaload() {
        helper.writePOP(T0); // Index
        helper.writePOP(S0); // Arrayref
        checkBounds(S0, T0);
        os.writePUSH(S0, T0, 4, VmArray.DATA_OFFSET * 4);
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_aastore()
     */
    public final void visit_aastore() {
        helper.writePOP(T1); // Value
        helper.writePOP(T0); // Index
        helper.writePOP(S0); // Arrayref
        checkBounds(S0, T0);
        os.writeMOV(INTSIZE, S0, T0, 4, VmArray.DATA_OFFSET * 4, T1);
        helper.writeArrayStoreWriteBarrier(S0, T0, T1, S1);
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_aconst_null()
     */
    public final void visit_aconst_null() {
        os.writeMOV_Const(T0, 0);
        helper.writePUSH(T0);
    }

    /**
     * @param index
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_aload(int)
     */
    public final void visit_aload(int index) {
        final int ebpOfs = stackFrame.getEbpOffset(index);
        os.writeMOV(INTSIZE, T0, FP, ebpOfs);
        helper.writePUSH(T0);
    }

    /**
     * @param classRef
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_anewarray(org.jnode.vm.classmgr.VmConstClass)
     */
    public final void visit_anewarray(VmConstClass classRef) {
        writeResolveAndLoadClassToEAX(classRef, S0);
        helper.writePOP(S0); /* Count */

        stackFrame.writePushMethodRef();
        helper.writePUSH(EAX); /* Class */
        helper.writePUSH(S0); /* Count */
        helper.invokeJavaMethod(context.getAnewarrayMethod());
        /* Result is already push on the stack */
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_areturn()
     */
    public final void visit_areturn() {
        helper.writePOP(T0);
        visit_return();
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_arraylength()
     */
    public final void visit_arraylength() {
        helper.writePOP(T0); // Arrayref
        os.writeMOV(INTSIZE, T1, T0, VmArray.LENGTH_OFFSET * slotSize);
        helper.writePUSH(T1);
    }

    /**
     * @param index
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_astore(int)
     */
    public final void visit_astore(int index) {
        final int ebpOfs = stackFrame.getEbpOffset(index);
        helper.writePOP(FP, ebpOfs);
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_athrow()
     */
    public final void visit_athrow() {
        helper.writePOP(T0); // Exception
        helper.writeJumpTableCALL(X86JumpTable.VM_ATHROW_OFS);
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_baload()
     */
    public final void visit_baload() {
        helper.writePOP(T1); // Index
        helper.writePOP(S0); // Arrayref
        checkBounds(S0, T1);
        os.writeMOV(BYTESIZE, T0, S0, T1, 1, VmArray.DATA_OFFSET * 4);
        os.writeMOVSX(T0, T0, BYTESIZE);
        helper.writePUSH(T0);
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_bastore()
     */
    public final void visit_bastore() {
        helper.writePOP(T1); // Value
        helper.writePOP(T0); // Index
        helper.writePOP(S0); // Arrayref
        checkBounds(S0, T0);
        os.writeMOV(BYTESIZE, S0, T0, 1, VmArray.DATA_OFFSET * 4, T1);
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_caload()
     */
    public final void visit_caload() {
        helper.writePOP(T1); // Index
        helper.writePOP(S0); // Arrayref
        checkBounds(S0, T1);
        os.writeMOV(WORDSIZE, T0, S0, T1, 2, VmArray.DATA_OFFSET * 4);
        os.writeMOVZX(T0, T0, WORDSIZE);
        helper.writePUSH(T0);
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_castore()
     */
    public final void visit_castore() {
        helper.writePOP(T1); // Value
        helper.writePOP(T0); // Index
        helper.writePOP(S0); // Arrayref
        checkBounds(S0, T0);
        os.writeMOV(WORDSIZE, S0, T0, 2, VmArray.DATA_OFFSET * 4, T1);
    }

    /**
     * @param classRef
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_checkcast(org.jnode.vm.classmgr.VmConstClass)
     */
    public final void visit_checkcast(VmConstClass classRef) {
        writeResolveAndLoadClassToEAX(classRef, S0);

        final Label okLabel = new Label(this.curInstrLabel + "cc-ok");

        /* objectref -> ECX (also leave in on the stack */
        os.writeMOV(INTSIZE, ECX, SP, 0);
        /* Is objectref null? */
        os.writeTEST(ECX, ECX);
        os.writeJCC(okLabel, X86Constants.JZ);
        /* Is instanceof? */
        instanceOf(okLabel);
        /* Not instanceof */

        // Call SoftByteCodes.systemException
        helper.writePUSH(SoftByteCodes.EX_CLASSCAST);
        helper.writePUSH(0);
        helper.invokeJavaMethod(context.getSystemExceptionMethod());

        /* Exception in EAX, throw it */
        helper.writeJumpTableCALL(X86JumpTable.VM_ATHROW_OFS);

        /* Normal exit */
        os.setObjectRef(okLabel);
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_d2f()
     */
    public final void visit_d2f() {
        os.writeFLD64(SP, 0);
        os.writeLEA(SP, SP, 4);
        os.writeFSTP32(SP, 0);
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_d2i()
     */
    public final void visit_d2i() {
        os.writeFLD64(SP, 0);
        os.writeLEA(SP, SP, 4);
        os.writeFISTP32(SP, 0);
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_d2l()
     */
    public final void visit_d2l() {
        os.writeFLD64(SP, 0);
        os.writeFISTP64(SP, 0);
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dadd()
     */
    public final void visit_dadd() {
        os.writeFLD64(SP, 8);
        os.writeFADD64(SP, 0);
        os.writeLEA(SP, SP, 8);
        os.writeFSTP64(SP, 0);
    }

    /**
     * @see org.jnode.vm.bytecode.BytecodeVisitor#visit_daload()
     */
    public final void visit_daload() {
        helper.writePOP(T0); // Index
        helper.writePOP(S0); // Arrayref
        checkBounds(S0, T0);
        os.writeLEA(S0, S0, T0, 8, VmArray.DATA_OFFSET * 4);
        os.writeMOV(INTSIZE, T0, S0, 0);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?