x86stackframe.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 302 行

JAVA
302
字号
/*
 * $Id: X86StackFrame.java,v 1.15 2004/02/26 10:33:40 epr Exp $
 */
package org.jnode.vm.x86.compiler.l1;

import org.jnode.assembler.Label;
import org.jnode.assembler.NativeStream.ObjectRef;
import org.jnode.assembler.x86.AbstractX86Stream;
import org.jnode.assembler.x86.Register;
import org.jnode.assembler.x86.X86Stream;
import org.jnode.vm.PragmaLoadStatics;
import org.jnode.vm.classmgr.VmByteCode;
import org.jnode.vm.classmgr.VmInterpretedExceptionHandler;
import org.jnode.vm.classmgr.VmMethod;
import org.jnode.vm.classmgr.VmMethodCode;
import org.jnode.vm.compiler.CompiledExceptionHandler;
import org.jnode.vm.compiler.CompiledMethod;
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;

/**
 * Utility class for generating the X86 method stack frame
 * 
 * @author epr
 */
class X86StackFrame implements X86CompilerConstants {

    private final VmMethod method;

    private final AbstractX86Stream os;

    private final X86CompilerHelper helper;

    private final X86CompilerContext context;

    private final CompiledMethod cm;

    private final VmByteCode bc;

    /** Label of the footer */
    private final Label footerLabel;

    /** Label of the create locals code */
    private final Label createLocalsLabel;

    /** Label of the create locals return address */
    private final Label createLocalsRetLabel;

    private X86Stream.ObjectInfo codeObject;

    private static final int EbpFrameRefOffset = 8;

    private static final int EbpMethodRefOffset = 0;

    /** Number of byte on the stack occupied by saved registers. See {@link #saveRegisters()} */
    private static final int SAVED_REGISTERSPACE = 0 * 4;

    /**
     * Create a new instance
     * 
     * @param os
     * @param method
     * @param context
     * @param cm
     */
    public X86StackFrame(AbstractX86Stream os, X86CompilerHelper helper,
            VmMethod method, X86CompilerContext context, CompiledMethod cm) {
        this.os = os;
        this.helper = helper;
        this.method = method;
        this.context = context;
        this.cm = cm;
        this.bc = method.getBytecode();
        this.createLocalsLabel = helper.genLabel("$$gen-locals");
        this.createLocalsRetLabel = helper.genLabel("$$gen-locals-ret");
        this.footerLabel = helper.genLabel("$$footer");
    }

    /**
     * Emit code to create the stack frame
     */
    public void emitHeader() {

        final VmMethodCode code = new VmMethodCode();
        final Label startLabel = helper.genLabel("$$start");
        codeObject = os.startObject(context.getVmMethodCodeClass());
        os.setObjectRef(code);
        cm.setCodeStart(os.setObjectRef(startLabel));

        // Test for stack overflow
        helper.writeStackOverflowTest(method);

        // Create class initialization code (if needed)
        helper.writeClassInitialize(method, EAX, ECX);

        // Increment the invocation count
        helper.writeIncInvocationCount(EAX);

        // Fixed framelayout
        saveRegisters();
        os.writePUSH(Register.EBP);
        os.writePUSH(context.getMagic());
        //os.writePUSH(0); // PC, which is only used in interpreted methods
        /** EAX MUST contain the VmMethod structure upon entry of the method */
        os.writePUSH(Register.EAX);
        os.writeMOV(INTSIZE, Register.EBP, Register.ESP);

        //final int noArgs = method.getNoArgs();
        //final int noLocals = bc.getNoLocals();
        //final int noLocalVars = noLocals - noArgs;

        // Create and clear all local variables
        os.writeJMP(createLocalsLabel);
        os.setObjectRef(createLocalsRetLabel);
        /*
         * if (noLocalVars > 0) { os.writeXOR(Register.EAX, Register.EAX); for
         * (int i = 0; i < noLocalVars; i++) { os.writePUSH(Register.EAX); }
         */

        // Load the statics table reference
        if (method.canThrow(PragmaLoadStatics.class)) {
            helper.writeLoadSTATICS(helper.genLabel("$$edi"), "init", false);
        }

        /* Create the synchronization enter code */
        emitSynchronizationCode(context.getMonitorEnterMethod());
    }

    /**
     * Emit code to end the stack frame
     */
    public void emitTrailer(int maxLocals) {
        final int argSlotCount = method.getArgSlotCount();

        // Emit the code to create the locals
        os.setObjectRef(createLocalsLabel);
        final int noLocalVars = maxLocals - argSlotCount;
        // Create and clear all local variables
        if (noLocalVars > 0) {
            os.writeXOR(Register.EAX, Register.EAX);
            for (int i = 0; i < noLocalVars; i++) {
                os.writePUSH(Register.EAX);
            }
        }
        os.writeJMP(createLocalsRetLabel);

        // Now start the actual footer
        os.setObjectRef(footerLabel);

        /* Go restore the previous current frame */
        emitSynchronizationCode(context.getMonitorExitMethod());
        os.writeLEA(Register.ESP, Register.EBP, EbpFrameRefOffset);
        os.writePOP(Register.EBP);
        restoreRegisters();
        // Return
        if (argSlotCount > 0) {
            os.writeRET(argSlotCount * 4);
        } else {
            os.writeRET();
        }

        // No set the exception start&endPtr's
        //final int noLocals = bc.getNoLocals();
        //final int noLocalVars = noLocals - noArgs;
        final int count = bc.getNoExceptionHandlers();
        CompiledExceptionHandler[] ceh = new CompiledExceptionHandler[ count];
        for (int i = 0; i < count; i++) {
            final VmInterpretedExceptionHandler eh = bc.getExceptionHandler(i);
            final Label handlerLabel = helper.genLabel("$$ex-handler" + i);

            final ObjectRef handlerRef = os.setObjectRef(handlerLabel);

            /** Clear the calculation stack (only locals are left) */
            os.writeLEA(Register.ESP, Register.EBP, -(noLocalVars * 4));
            /** Push the exception in EAX */
            os.writePUSH(Register.EAX);
            /** Goto the real handler */
            os.writeJMP(helper.getInstrLabel(eh.getHandlerPC()));

            ceh[ i] = new CompiledExceptionHandler();
            ceh[ i].setStartPc(os.getObjectRef(helper.getInstrLabel(eh
                    .getStartPC())));
            ceh[ i].setEndPc(os.getObjectRef(helper
                    .getInstrLabel(eh.getEndPC())));
            ceh[ i].setHandler(handlerRef);

        }
        cm.setExceptionHandlers(ceh);

        // Now create the default exception handler
        Label handlerLabel = helper.genLabel("$$def-ex-handler");
        cm.setDefExceptionHandler(os.setObjectRef(handlerLabel));
        emitSynchronizationCode(context.getMonitorExitMethod());
        os.writeLEA(Register.ESP, Register.EBP, EbpFrameRefOffset);
        os.writePOP(Register.EBP);
        restoreRegisters();
        /**
         * Do not do a ret here, this way the return address will be used by
         * vm_athrow as its return address
         */
        helper.writeJumpTableJMP(X86JumpTable.VM_ATHROW_NOTRACE_OFS);
        //os.writeJMP(helper.VM_ATHROW_NOTRACE);

        codeObject.markEnd();
        cm.setCodeEnd(os.setObjectRef(helper.genLabel("$$end-code-object")));
    }

    /**
     * Emit a jump to the exit code
     */
    public void emitReturn() {
        os.writeJMP(footerLabel);
    }

    /**
     * Gets the offset to EBP (current stack frame) for the local with the
     * given index.
     * 
     * @param index
     * @return int
     */
    public final int getEbpOffset(int index) {
        int noArgs = method.getArgSlotCount();
        if (index < noArgs) {
            // Index refers to a method argument
            return ((noArgs - index + 1) * 4) + EbpFrameRefOffset
                    + SAVED_REGISTERSPACE;
        } else {
            // Index refers to a local variable
            return (index - noArgs + 1) * -4;
        }
    }

    /**
     * Gets the offset to EBP (current stack frame) for the wide local with the
     * given index.
     * 
     * @param index
     * @return int
     */
    public final int getWideEbpOffset(int index) {
        return getEbpOffset(index + 1);
    }

    private void emitSynchronizationCode(VmMethod monitorMethod) {
        if (method.isSynchronized()) {
            os.writePUSH(Register.EAX);
            //System.out.println("synchr. " + method);
            if (method.isStatic()) {
                // Get declaring class
                final int declaringClassOffset = context
                        .getVmMemberDeclaringClassField().getOffset();
                writeGetMethodRef(Register.EAX);
                os.writePUSH(Register.EAX, declaringClassOffset);
                //os.writePUSH(method.getDeclaringClass());
            } else {
                os.writePUSH(Register.EBP, getEbpOffset(0));
            }
            helper.invokeJavaMethod(monitorMethod);
            os.writePOP(Register.EAX);
        }
    }

    /**
     * Push the method reference in the current stackframe onto the stack
     */
    public final void writePushMethodRef() {
        os.writePUSH(Register.EBP, EbpMethodRefOffset);
    }

    /**
     * Write code to copy the method reference into the dst register.
     */
    public final void writeGetMethodRef(Register dst) {
        os.writeMOV(INTSIZE, dst, Register.EBP, EbpMethodRefOffset);
    }

    /**
     * Write code to save the callee saved registers.
     * @see #SAVED_REGISTERSPACE
     * @see org.jnode.vm.x86.VmX86StackReader
     */
    private final void saveRegisters() {
        //os.writePUSH(Register.EBX);
        //os.writePUSH(Register.EDI);
        //os.writePUSH(Register.ESI);
    }

    /**
     * Write code to restore the callee saved registers.
     * @see #SAVED_REGISTERSPACE
     * @see org.jnode.vm.x86.VmX86StackReader
     */
    private final void restoreRegisters() {
        //os.writePOP(Register.ESI);
        //os.writePOP(Register.EDI);
        //os.writePOP(Register.EBX);
    }
}

⌨️ 快捷键说明

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