Package org.jnode.vm.x86.compiler.l1a

Source Code of org.jnode.vm.x86.compiler.l1a.X86StackFrame

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.vm.x86.compiler.l1a;

import org.jnode.assembler.Label;
import org.jnode.assembler.NativeStream.ObjectRef;
import org.jnode.assembler.x86.X86Assembler;
import org.jnode.assembler.x86.X86BinaryAssembler;
import org.jnode.assembler.x86.X86Constants;
import org.jnode.assembler.x86.X86Register;
import org.jnode.assembler.x86.X86Register.GPR;
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.compiler.EntryPoints;
import org.jnode.vm.facade.TypeSizeInfo;
import org.jnode.vm.x86.compiler.X86CompilerHelper;
import org.jnode.vm.x86.compiler.X86JumpTable;

import static org.jnode.vm.x86.compiler.X86CompilerConstants.PROCESSOR64;

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

    private final VmMethod method;

    private final X86Assembler os;

    private final X86CompilerHelper helper;

    private final EntryPoints entryPoints;

    private final CompiledMethod cm;

    private final VmByteCode bc;

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

    /**
     * Label at start of method init code
     */
    private final Label initLabel;

    /**
     * Label at start of actual method code
     */
    private final Label startCodeLabel;

    private X86BinaryAssembler.ObjectInfo codeObject;

    /**
     * Offset from EBP/RBP to the save EBP/RBP
     */
    private final int EbpFrameRefOffset;

    /**
     * Size of an address
     */
    private final int slotSize;

    /**
     * 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 helper
     * @param method
     * @param context
     * @param cm
     */
    public X86StackFrame(X86Assembler os, X86CompilerHelper helper,
                         VmMethod method, EntryPoints context, CompiledMethod cm) {
        this.os = os;
        this.helper = helper;
        this.method = method;
        this.entryPoints = context;
        this.cm = cm;
        this.bc = method.getBytecode();
        this.initLabel = helper.genLabel("$$init");
        this.startCodeLabel = helper.genLabel("$$code");
        this.footerLabel = helper.genLabel("$$footer");
        this.slotSize = os.isCode32() ? 4 : 8;
        this.EbpFrameRefOffset = 1 * slotSize;
    }

    /**
     * Emit code to create the stack frame
     *
     * @return The length of os at the start of the method code.
     */
    public int emitHeader() {

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

        if (false) {
            // Debug only
            os.writeBreakPoint();
        }

        // Jump to init code
        os.writeJMP(initLabel);
        // Set startCode label
        os.setObjectRef(startCodeLabel);

        return rc;
    }

    /**
     * Write code to test the alignment of the stack pointer.
     *
     * @param curInstrLabel
     */
    public void writeStackAlignmentTest(Label curInstrLabel) {
        if (false && os.isCode64()) {
            final int idx = os.getLength();
            final Label test = new Label(curInstrLabel + "$$stackAlignTest" + idx);
            final Label failed = new Label(curInstrLabel + "$$stackAlign" + idx);
            os.writeJMP(test);
            os.setObjectRef(failed);
            os.writeINT(0x41);
            os.setObjectRef(test);
            os.writeTEST(X86Register.RSP, 7);
            os.writeJCC(failed, X86Constants.JNZ);
        }
    }

    /**
     * Emit code to end the stack frame
     *
     * @param typeSizeInfo
     * @param maxLocals
     */
    public void emitTrailer(TypeSizeInfo typeSizeInfo, int maxLocals) {
        final int argSlotCount = method.getArgSlotCount();
        final Label stackOverflowLabel = helper.genLabel("$$stack-overflow");
        final GPR asp = helper.SP;
        final GPR abp = helper.BP;
        final GPR aax = helper.AAX;
        final int size = helper.ADDRSIZE;

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

        /* Go restore the previous current frame */
        emitSynchronizationCode(typeSizeInfo, entryPoints.getMonitorExitMethod());
        os.writeLEA(asp, abp, EbpFrameRefOffset);
        os.writePOP(abp);
        restoreRegisters();
        // Return
        if (argSlotCount > 0) {
            os.writeRET(argSlotCount * slotSize);
        } else {
            os.writeRET();
        }
        // End footer

        // Begin header
        // Init starts here
        os.setObjectRef(initLabel);

        // Test stack overflow       
        final int stackEndOffset = entryPoints.getVmProcessorStackEnd().getOffset();
        if (os.isCode32()) {
            os.writePrefix(X86Constants.FS_PREFIX);
            os.writeCMP_MEM(X86Register.ESP, stackEndOffset);
        } else {
            os.writeCMP(X86Register.RSP, PROCESSOR64, stackEndOffset);
        }
        // This forward jump is not predicted by branch prediction.
        // Which is good, because we do not predict a stack overflow
        os.writeJCC(stackOverflowLabel, X86Constants.JLE);

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

        // Test stack alignment
        writeStackAlignmentTest(helper.genLabel("$$stackAlignment"));

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

        // Increment the invocation count
        //helper.writeIncInvocationCount(aax); (NOT USED for now, aax is also invalid now)

        // Fixed framelayout
        saveRegisters();
        os.writePUSH(abp);
        os.writePUSH(cm.getCompiledCodeId());
        os.writeMOV(size, abp, asp);

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

        // Create the synchronization enter code
        emitSynchronizationCode(typeSizeInfo, entryPoints.getMonitorEnterMethod());

        // And jump back to the actual code start
        os.writeJMP(startCodeLabel);

        // Write stack overflow code
        os.setObjectRef(stackOverflowLabel);
        os.writeINT(0x31);

        // Write class initializers
        helper.writeClassInitializers();

        // End header      

        // 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) */
            if (noLocalVars < 0) {
                System.out.println("@#@#@#@# noLocalVars = " + noLocalVars);
            }
            final int ofs = Math.max(0, noLocalVars) * slotSize;
            os.writeLEA(asp, abp, -ofs);
            /** Push the exception in EAX */
            os.writePUSH(aax);
            /** 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(typeSizeInfo, entryPoints.getMonitorExitMethod());
        os.writeLEA(asp, abp, EbpFrameRefOffset);
        os.writePOP(abp);
        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_IDX);
        //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 typeSizeInfo
     * @param index
     * @return int
     */
    public final short getEbpOffset(TypeSizeInfo typeSizeInfo, int index) {
        final int noArgs = method.getArgSlotCount();
        final int stackSlot = index;
//        final int stackSlot = Signature.getStackSlotForJavaArgNumber(typeSizeInfo, method, index);
        if (stackSlot < noArgs) {
            // Index refers to a method argument
            return toShort(((noArgs - stackSlot + 1) * slotSize) + EbpFrameRefOffset + SAVED_REGISTERSPACE);
        } else {
            // Index refers to a local variable
            return toShort((stackSlot - noArgs + 1) * -slotSize);
        }
    }

    private short toShort(int v) {
        if ((v >= Short.MIN_VALUE) && (v <= Short.MAX_VALUE)) {
            return (short) v;
        } else {
            throw new IllegalArgumentException("Given value does not fit in a short " + v);
        }
    }

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

    private void emitSynchronizationCode(TypeSizeInfo typeSizeInfo, VmMethod monitorMethod) {
        if (method.isSynchronized()) {
            final GPR aax = os.isCode32() ? (GPR) X86Register.EAX : X86Register.RAX;
            final GPR adx = os.isCode32() ? (GPR) X86Register.EDX : X86Register.RDX;

            os.writePUSH(aax);
            os.writePUSH(adx);
            //System.out.println("synchr. " + method);
            if (method.isStatic()) {
                // Get declaring class
                final int typeOfs = helper.getSharedStaticsOffset(method.getDeclaringClass());
                os.writePUSH(helper.STATICS, typeOfs);
            } else {
                os.writePUSH(helper.BP, getEbpOffset(typeSizeInfo, 0));
            }
            helper.invokeJavaMethod(monitorMethod);
            os.writePOP(adx);
            os.writePOP(aax);
        }
    }

    /**
     * Write code to save the callee saved registers.
     *
     * @see #SAVED_REGISTERSPACE
     * @see org.jnode.vm.x86.VmX86StackReader
     */
    private 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 void restoreRegisters() {
        //os.writePOP(Register.ESI);
        //os.writePOP(Register.EDI);
        //os.writePOP(Register.EBX);
    }
}
TOP

Related Classes of org.jnode.vm.x86.compiler.l1a.X86StackFrame

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.