Package org.jnode.vm.x86.compiler

Source Code of org.jnode.vm.x86.compiler.X86CompilerHelper

/*
* $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;

import java.util.HashMap;
import java.util.Map;
import org.jnode.annotation.PrivilegedActionPragma;
import org.jnode.assembler.Label;
import org.jnode.assembler.x86.X86Assembler;
import org.jnode.assembler.x86.X86Constants;
import org.jnode.assembler.x86.X86Register;
import org.jnode.assembler.x86.X86Register.GPR;
import org.jnode.assembler.x86.X86Register.GPR64;
import org.jnode.vm.JvmType;
import org.jnode.vm.classmgr.VmArray;
import org.jnode.vm.classmgr.VmInstanceField;
import org.jnode.vm.classmgr.VmIsolatedStaticsEntry;
import org.jnode.vm.classmgr.VmMethod;
import org.jnode.vm.classmgr.VmSharedStaticsEntry;
import org.jnode.vm.classmgr.VmStaticField;
import org.jnode.vm.classmgr.VmType;
import org.jnode.vm.classmgr.VmTypeState;
import org.jnode.vm.compiler.EntryPoints;
import org.jnode.vm.facade.VmUtils;
import org.jnode.vm.facade.VmWriteBarrier;
import org.jnode.vm.scheduler.VmProcessor;
import org.jnode.vm.x86.X86CpuID;

import static org.jnode.vm.x86.compiler.X86CompilerConstants.BITS32;
import static org.jnode.vm.x86.compiler.X86CompilerConstants.BITS64;
import static org.jnode.vm.x86.compiler.X86CompilerConstants.INTSIZE;
import static org.jnode.vm.x86.compiler.X86CompilerConstants.PROCESSOR64;

/**
* Helpers class used by the X86 compilers.
*
* @author epr
* @author patrik_reali
*/
public class X86CompilerHelper {

    /**
     * Address size ax register (EAX/RAX)
     */
    public final GPR AAX;

    /**
     * Address size bx register (EBX/RBX)
     */
    public final GPR ABX;

    /**
     * Address size cx register (ECX/RCX)
     */
    public final GPR ACX;

    /**
     * Address size dx register (EDX/RDX)
     */
    public final GPR ADX;

    /**
     * The stack pointer (ESP/RSP)
     */
    public final GPR SP;

    /**
     * The stack frame pointer (EBP/RBP)
     */
    public final GPR BP;

    /**
     * The statics table pointer (EDI/RDI)
     */
    public final GPR STATICS;

    /**
     * The size of an address (BITS32/BITS64)
     */
    public final int ADDRSIZE;

    /**
     * The size of stack slot in bytes (4/8)
     */
    public final int SLOTSIZE;

    private EntryPoints entryPoints;

    private VmMethod method;

    private String labelPrefix;

    private String instrLabelPrefix;

    private final boolean haveCMOV;

    private final Map<Integer, Label> addressLabels = new HashMap<Integer, Label>();

    private final boolean debug = VmUtils.getVm().isDebugMode();

    private final AbstractX86StackManager stackMgr;

    private X86Assembler os;

    private final Map<VmType<?>, Label> classInitLabels = new HashMap<VmType<?>, Label>();

    /**
     * Create a new instance
     *
     * @param entryPoints
     */
    @PrivilegedActionPragma
    public X86CompilerHelper(X86Assembler os, AbstractX86StackManager stackMgr,
                             EntryPoints entryPoints, boolean isBootstrap) {
        this.os = os;
        if (os.isCode32()) {
            this.AAX = X86Register.EAX;
            this.ABX = X86Register.EBX;
            this.ACX = X86Register.ECX;
            this.ADX = X86Register.EDX;
            this.SP = X86Register.ESP;
            this.BP = X86Register.EBP;
            this.STATICS = X86CompilerConstants.STATICS32;
            this.ADDRSIZE = X86Constants.BITS32;
            this.SLOTSIZE = 4;
        } else {
            this.AAX = X86Register.RAX;
            this.ABX = X86Register.RBX;
            this.ACX = X86Register.RCX;
            this.ADX = X86Register.RDX;
            this.SP = X86Register.RSP;
            this.BP = X86Register.RBP;
            this.STATICS = X86CompilerConstants.STATICS64;
            this.ADDRSIZE = X86Constants.BITS64;
            this.SLOTSIZE = 8;
        }
        this.entryPoints = entryPoints;
        this.stackMgr = stackMgr;
        final X86CpuID cpuId = (X86CpuID) os.getCPUID();
        haveCMOV = cpuId.hasFeature(X86CpuID.FEAT_CMOV);
    }

    public void reset(X86Assembler x86Assembler, EntryPoints entryPoints) {
        this.os = x86Assembler;
        this.entryPoints = entryPoints;
    }

    /**
     * Reset the state of this helper.
     */
    public final void reset() {
        classInitLabels.clear();
    }

    /**
     * Gets the method that is currently being compiled.
     *
     * @return method
     */
    public final VmMethod getMethod() {
        return method;
    }

    /**
     * Sets the method that is currently being compiled.
     *
     * @param method
     */
    public final void setMethod(VmMethod method) {
        this.method = method;
        setLabelPrefix(method.toString() + '_');
    }

    /**
     * Sets the current label prefix.
     *
     * @param prefix
     */
    public final void setLabelPrefix(String prefix) {
        this.labelPrefix = prefix;
        this.instrLabelPrefix = labelPrefix + "_bci_";
        this.addressLabels.clear();
    }

    public final String getLabelPrefix() {
        return labelPrefix;
    }

    /**
     */
    public void startInlinedMethod(VmMethod inlinedMethod, Label curInstrLabel) {
        setLabelPrefix(curInstrLabel + "_" + inlinedMethod.getName() + '_');
    }

    /**
     * Create a method relative label to a given bytecode address.
     *
     * @param address
     * @return The created label
     */
    public final Label getInstrLabel(int address) {
        Label l = addressLabels.get(address);
        if (l == null) {
            l = new Label(instrLabelPrefix + address);
            addressLabels.put(address, l);
        }
        return l;
    }

    /**
     * Create a method relative label
     *
     * @param postFix
     * @return The created label
     */
    public final Label genLabel(String postFix) {
        return new Label(labelPrefix + postFix);
    }

    /**
     * Write code to call the address found at the given index in the system
     * jumptable.
     *
     * @param index
     * @see X86JumpTable
     */
    public final void writeJumpTableCALL(int index) {
        if (os.isCode64()) {
            index *= 2;
        }
        final int offset = (VmArray.DATA_OFFSET * SLOTSIZE) + (index << 2);
        os.writeCALL(STATICS, offset);
    }

    /**
     * Write code to jump to the address found at the given index in the system
     * jumptable.
     *
     * @param index
     * @see X86JumpTable
     */
    public final void writeJumpTableJMP(int index) {
        if (os.isCode64()) {
            index *= 2;
        }
        final int offset = (VmArray.DATA_OFFSET * SLOTSIZE) + (index << 2);
        os.writeJMP(STATICS, offset);
    }

    /**
     * Emit code to push the returncode of the given method signature.
     *
     * @param signature
     */
    public final void pushReturnValue(String signature) {
        final int returnType = JvmType.getReturnType(signature);
        assertCondition(
            signature.endsWith("V") == (returnType == JvmType.VOID),
            "Return type");
        // System.out.println("Return type: " + returnType + "\t" + signature);
        switch (returnType) {
            case JvmType.VOID:
                // No return value
                break;
            case JvmType.DOUBLE:
            case JvmType.LONG:
                // Wide return value
                if (os.isCode32()) {
                    stackMgr.writePUSH64(returnType, X86Register.EAX,
                        X86Register.EDX);
                } else {
                    stackMgr.writePUSH64(returnType, X86Register.RAX);
                }
                break;
            case JvmType.REFERENCE:
                stackMgr.writePUSH(returnType, AAX);
                break;
            default:
                // int/float return value
                stackMgr.writePUSH(returnType, X86Register.EAX);
        }
    }

    /**
     * Emit code to invoke a java method
     *
     * @param method
     */
    public final void invokeJavaMethod(VmMethod method) {
        final int offset = getSharedStaticsOffset(method);
        os.writeCALL(STATICS, offset);
        pushReturnValue(method.getSignature());
    }

    /**
     * Insert a yieldpoint into the code
     */
    public final void writeYieldPoint(Object curInstrLabel) {
        if (!method.isUninterruptible()) {
            final Label doneLabel = new Label(curInstrLabel + "noYP");
            final Label ypLabel = new Label(curInstrLabel + "$$yp");
            final int offset = entryPoints.getVmThreadSwitchIndicatorOffset();
            final int flag = VmProcessor.TSI_SWITCH_REQUESTED;
            if (os.isCode32()) {
                os.writePrefix(X86Constants.FS_PREFIX);
                os.writeCMP_MEM(BITS32, offset, flag);
            } else {
                os.writeCMP_Const(BITS32, PROCESSOR64, offset, flag);
            }
            // Jump to the yieldpoint interrupt, when flags are set
            // We do NOT predict this to happen (in most cases),
            // so we optimize for that (wrt. branch prediction)
            os.writeJCC(ypLabel, X86Constants.JE);
            // Jump over INT is most cases
            os.writeJMP(doneLabel);
            // Trigger yieldpoint
            os.setObjectRef(ypLabel);
            os.writeINT(X86CompilerConstants.YIELDPOINT_INTNO);
            // Done
            os.setObjectRef(doneLabel);
        }
    }

    /**
     * Write class initialization code
     *
     * @param method the method reference
     * @return true if code was written, false otherwise
     */
    public final boolean writeClassInitialize(VmMethod method) {
        // Only for static methods (non <clinit>)
        if (method.isStatic() && !method.isInitializer()) {
            // Only when class is not initialize
            final VmType<?> cls = method.getDeclaringClass();
            if (!cls.isAlwaysInitialized()) {
                final GPR aax = this.AAX;
                final Label label = genLabel("$$class-init");

                // Save eax
                os.writePUSH(aax);
                // Get class into aax
                if (os.isCode32()) {
                    writeGetStaticsEntry(label, aax, cls);
                } else {
                    writeGetStaticsEntry64(label, (GPR64) aax,
                        (VmSharedStaticsEntry) cls);
                }
                // Write code to initialize
                writeClassInitialize(label, aax, aax, cls);
                // Restore eax
                os.writePOP(aax);
                return true;
            }
        }
        return false;
    }

    /**
     * Emit code to test the initialized state of a class and if required, call
     * the class initializer.
     *
     * @param curInstrLabel
     * @param classReg
     * @param tmpReg        A temporary reference type register. This may be the same as
     *                      classReg, but this register is not preserved.
     * @param cls
     */
    public final void writeClassInitialize(Label curInstrLabel, GPR classReg,
                                           GPR tmpReg, VmType<?> cls) {
        if (!cls.isAlwaysInitialized()) {
            // Create jump labels
            final Label testIsolated = new Label(curInstrLabel + "$$testiso-cinit");
            final Label doInit = new Label(curInstrLabel + "$$do-cinit-ex");
            final Label done = new Label(curInstrLabel + "$$done-cinit-ex");

            // Test declaringClass.modifiers (mostly true)
            os.writeTEST(BITS32, classReg, entryPoints.getVmTypeState()
                .getOffset(), VmTypeState.ST_ALWAYS_INITIALIZED);
            if (!cls.isSharedStatics()) {
                // Jump when not initialized to isolated state test
                // Branch predication expects this forward jump NOT
                // to be taken.
                os.writeJCC(testIsolated, X86Constants.JZ);
                // We don't have to initialize, so jump over the init-code.
                os.writeJMP(done);

                // Test isolated class state
                os.setObjectRef(testIsolated);
                writeLoadIsolatedStatics(curInstrLabel, "$$ld-is-stat", tmpReg);
                final int offset = getIsolatedStaticsOffset(cls);
                os.writeTEST(BITS32, tmpReg, offset, VmTypeState.IST_INITIALIZED);
            }
            // Jump when not initialized to doInit.
            // Branch predication expects this forward jump NOT
            // to be taken.
            os.writeJCC(doInit, X86Constants.JZ);

            // We don't have to initialize, so jump over the init-code.
            os.writeJMP(done);

            // Start initialize code
            os.setObjectRef(doInit);

            // Get label for class initialize code
            Label initializer = classInitLabels.get(cls);
            if (initializer == null) {
                // create one
                initializer = genLabel("$$init-" + cls.getName());
                classInitLabels.put(cls, initializer);
            }
            // Setup call to class initializer code
            os.writeCALL(initializer);
            os.writeJMP(done);

            // Set the done label
            os.setObjectRef(done);
        }
    }

    /**
     * Write the class initializer code.
     */
    public final void writeClassInitializers() {
        for (Map.Entry<VmType<?>, Label> entry : classInitLabels.entrySet()) {
            final Label label = entry.getValue();
            // Set label
            os.setObjectRef(label);
            // Save registers
            if (os.isCode32()) {
                os.writePUSHA();
            } else {
                os.writePUSH(X86Register.RAX);
                os.writePUSH(X86Register.RBX);
                os.writePUSH(X86Register.RCX);
                os.writePUSH(X86Register.RDX);
                os.writePUSH(X86Register.RSI);
                os.writePUSH(X86Register.R8);
                os.writePUSH(X86Register.R9);
                os.writePUSH(X86Register.R10);
                os.writePUSH(X86Register.R11);
                // R12 contains processor and is preserved
                os.writePUSH(X86Register.R13);
                os.writePUSH(X86Register.R14);
                os.writePUSH(X86Register.R15);
            }
            // Load cls
            if (os.isCode32()) {
                writeGetStaticsEntry(label, AAX, entry.getKey());
            } else {
                writeGetStaticsEntry64(label, (GPR64) AAX,
                    (VmSharedStaticsEntry) entry.getKey());
            }
            // Call cls.initialize
            os.writePUSH(AAX); // cls
            invokeJavaMethod(entryPoints.getVmTypeInitialize());
            if (os.isCode32()) {
                os.writePOPA();
            } else {
                os.writePOP(X86Register.R15);
                os.writePOP(X86Register.R14);
                os.writePOP(X86Register.R13);
                // R12 contains processor and is preserved
                os.writePOP(X86Register.R11);
                os.writePOP(X86Register.R10);
                os.writePOP(X86Register.R9);
                os.writePOP(X86Register.R8);
                os.writePOP(X86Register.RSI);
                os.writePOP(X86Register.RDX);
                os.writePOP(X86Register.RCX);
                os.writePOP(X86Register.RBX);
                os.writePOP(X86Register.RAX);
            }
            // Return
            os.writeRET();
        }
    }

    /**
     * Write stack overflow test code.
     *
     * @param method
     */
    public final void writeStackOverflowTest(VmMethod method) {
        // cmp esp,STACKEND
        // jg vm_invoke_testStackOverflowDone
        // vm_invoke_testStackOverflow:
        // int 0x31
        // vm_invoke_testStackOverflowDone:
        final int offset = entryPoints.getVmProcessorStackEnd().getOffset();
        final Label doneLabel = new Label(labelPrefix + "$$stackof-done");
        final Label intLabel = new Label(labelPrefix + "$$stovf");
        if (os.isCode32()) {
            os.writePrefix(X86Constants.FS_PREFIX);
            os.writeCMP_MEM(X86Register.ESP, offset);
        } else {
            os.writeCMP(X86Register.RSP, PROCESSOR64, offset);
        }
        // We expect no stack overflow, so optimize jumps for static
        // branch prediction.
        os.writeJCC(intLabel, X86Constants.JNG);
        os.writeJMP(doneLabel);
        os.setObjectRef(intLabel);
        os.writeINT(0x31);
        os.setObjectRef(doneLabel);
    }

    /**
     * Write staticTable load code. After the code (generated by this method) is
     * executed, the STATICS register contains the reference to the statics
     * table.
     */
    public final void writeLoadSTATICS(Label curInstrLabel, String labelPrefix,
                                       boolean isTestOnly) {
        final int offset = entryPoints.getVmProcessorSharedStaticsTable()
            .getOffset();
        if (isTestOnly) {
            if (debug) {
                final Label ok = new Label(curInstrLabel + labelPrefix
                    + "$$ediok");
                if (os.isCode32()) {
                    os.writePrefix(X86Constants.FS_PREFIX);
                    os.writeCMP_MEM(this.STATICS, offset);
                } else {
                    os.writeCMP(this.STATICS, PROCESSOR64, offset);
                }
                os.writeJCC(ok, X86Constants.JE);
                os.writeINT(0x88);
                os.setObjectRef(ok);
            }
        } else {
            if (os.isCode32()) {
                os.writeXOR(this.STATICS, this.STATICS);
                os.writePrefix(X86Constants.FS_PREFIX);
                os.writeMOV(INTSIZE, this.STATICS, this.STATICS, offset);
            } else {
                os.writeMOV(BITS64, this.STATICS, PROCESSOR64, offset);
            }
        }
    }

    /**
     * Write isolatedStaticTable load code. After the code (generated by this
     * method) is executed, the given destination register contains the
     * reference to the isolated statics table of the current isolate.
     */
    public final void writeLoadIsolatedStatics(Label curInstrLabel,
                                               String labelPrefix, GPR dst) {
        final int offset = entryPoints.getVmProcessorIsolatedStaticsTable()
            .getOffset();
        if (os.isCode32()) {
            VmUtils.getVm().getCounter("### load " + dst.getName()).inc();
            // os.writeXOR(dst, dst);
            os.writePrefix(X86Constants.FS_PREFIX);
            // os.writeMOV(INTSIZE, dst, dst, offset);
            os.writeMOV(dst, offset);
        } else {
            os.writeMOV(BITS64, dst, PROCESSOR64, offset);
        }
    }

    /**
     * Is class initialization code needed for the given method.
     *
     * @param method
     * @return true if class init code is needed, false otherwise.
     */
    public static boolean isClassInitializeNeeded(VmMethod method) {
        // Only for static methods (non <clinit>)
        if (method.isStatic() && !method.isInitializer()) {
            // Only when class is not initialize
            final VmType<?> cls = method.getDeclaringClass();
            if (!cls.isAlwaysInitialized()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Do we need a write barrier
     *
     * @return True/false
     */
    public final boolean needsWriteBarrier() {
        return (entryPoints.getWriteBarrier() != null);
    }

    /**
     * Write code to call the arrayStoreWriteBarrier.
     *
     * @param refReg
     * @param indexReg
     * @param valueReg
     */
    public final void writeArrayStoreWriteBarrier(GPR refReg, GPR indexReg,
                                                  GPR valueReg, GPR scratchReg) {
        final VmWriteBarrier wb = entryPoints.getWriteBarrier();
        if (wb != null) {
            os.writeMOV_Const(scratchReg, wb);
            os.writePUSH(scratchReg);
            os.writePUSH(refReg);
            os.writePUSH(indexReg);
            os.writePUSH(valueReg);
            invokeJavaMethod(entryPoints.getArrayStoreWriteBarrier());
        }
    }

    /**
     * Write code to call the putfieldWriteBarrier.
     *
     * @param field
     * @param refReg
     * @param valueReg
     */
    public final void writePutfieldWriteBarrier(VmInstanceField field,
                                                GPR refReg, GPR valueReg, GPR scratchReg) {
        if (field.isObjectRef()) {
            final VmWriteBarrier wb = entryPoints.getWriteBarrier();
            if (wb != null) {
                os.writeMOV_Const(scratchReg, wb);
                os.writePUSH(scratchReg);
                os.writePUSH(refReg);
                os.writePUSH(field.getOffset());
                os.writePUSH(valueReg);
                invokeJavaMethod(entryPoints.getPutfieldWriteBarrier());
            }
        }
    }

    /**
     * Write code to call the putstaticWriteBarrier.
     *
     * @param field
     * @param valueReg
     */
    public final void writePutstaticWriteBarrier(VmStaticField field,
                                                 GPR valueReg, GPR scratchReg) {
        if (VmUtils.verifyAssertions()) {
            VmUtils._assert(scratchReg.getSize() == this.ADDRSIZE,
                "scratchReg wrong size");
            VmUtils._assert(valueReg.getSize() == this.ADDRSIZE,
                "valueReg wrong size");
        }
        if (field.isObjectRef()) {
            final VmWriteBarrier wb = entryPoints.getWriteBarrier();
            if (wb != null) {
                os.writeMOV_Const(scratchReg, wb);
                os.writePUSH(scratchReg);
                if (field.isShared()) {
                    os.writePUSH(1); // shared = true
                    os.writePUSH(field.getSharedStaticsIndex());
                } else {
                    os.writePUSH(0); // shared = false
                    os.writePUSH(field.getIsolatedStaticsIndex());
                }
                os.writePUSH(valueReg);
                invokeJavaMethod(entryPoints.getPutstaticWriteBarrier());
            }
        }
    }

    /**
     * Is CMOVxx support bu the current cpu.
     *
     * @return Returns the haveCMOV.
     */
    public final boolean haveCMOV() {
        return this.haveCMOV;
    }

    /**
     * Write code to load the given 32-bit shared statics table entry into the
     * given register.
     *
     * @param curInstrLabel
     * @param dst
     * @param entry
     */
    public final void writeGetStaticsEntry(Label curInstrLabel, GPR dst,
                                           VmSharedStaticsEntry entry) {
        if (VmUtils.verifyAssertions()) {
            VmUtils._assert(dst.getSize() == BITS32, "dst wrong size");
        }
        writeLoadSTATICS(curInstrLabel, "gs", true);
        os.writeMOV(INTSIZE, dst, this.STATICS, getSharedStaticsOffset(entry));
    }

    /**
     * Write code to load the given 32-bit isolated statics table entry into the
     * given register.
     *
     * @param curInstrLabel
     * @param dst
     * @param entry
     * @param tmp           A temporary REFERENCE register
     */
    public final void writeGetStaticsEntry(Label curInstrLabel, GPR dst,
                                           VmIsolatedStaticsEntry entry, GPR tmp) {
        if (VmUtils.verifyAssertions()) {
            VmUtils._assert(dst.getSize() == BITS32, "dst wrong size");
        }
        writeLoadIsolatedStatics(curInstrLabel, "gs", tmp);
        os.writeMOV(INTSIZE, dst, tmp, getIsolatedStaticsOffset(entry));
    }

    /**
     * Write code to load the given statics table entry onto the FPU stack.
     *
     * @param curInstrLabel
     * @param entry
     * @param is32bit       If true, a 32-bit load is performed, otherwise a 64-bit load.
     */
    public final void writeGetStaticsEntryToFPU(Label curInstrLabel,
                                                VmSharedStaticsEntry entry, boolean is32bit) {
        writeLoadSTATICS(curInstrLabel, "gs", true);
        final int staticsIdx = getSharedStaticsOffset(entry);
        if (is32bit) {
            os.writeFLD32(this.STATICS, staticsIdx);
        } else {
            os.writeFLD64(this.STATICS, staticsIdx);
        }
    }

    /**
     * Write code to load the given statics table entry onto the FPU stack.
     *
     * @param curInstrLabel
     * @param entry
     * @param is32bit       If true, a 32-bit load is performed, otherwise a 64-bit load.
     * @param tmp           A temporary register of the REFERENCE kind
     */
    public final void writeGetStaticsEntryToFPU(Label curInstrLabel,
                                                VmIsolatedStaticsEntry entry, boolean is32bit, GPR tmp) {
        writeLoadIsolatedStatics(curInstrLabel, "gs", tmp);
        final int staticsIdx = getIsolatedStaticsOffset(entry);
        if (is32bit) {
            os.writeFLD32(tmp, staticsIdx);
        } else {
            os.writeFLD64(tmp, staticsIdx);
        }
    }

    /**
     * Write code to push the given statics table entry to the stack
     *
     * @param curInstrLabel
     * @param entry
     */
    /* Patrik, added to push without requiring allocation of a register */
    public final void writePushStaticsEntry(Label curInstrLabel,
                                            VmSharedStaticsEntry entry) {
        writeLoadSTATICS(curInstrLabel, "gs", true);
        os.writePUSH(this.STATICS, getSharedStaticsOffset(entry));
    }

    /**
     * Write code to load the given 64-bit shared statics table entry into the
     * given 32-bit registers.
     *
     * @param curInstrLabel
     * @param lsbDst
     * @param msbReg
     * @param entry
     */
    public final void writeGetStaticsEntry64(Label curInstrLabel, GPR lsbDst,
                                             GPR msbReg, VmSharedStaticsEntry entry) {
        writeLoadSTATICS(curInstrLabel, "gs64", true);
        final int staticsOfs = getSharedStaticsOffset(entry);
        os.writeMOV(INTSIZE, msbReg, this.STATICS, staticsOfs + 4); // MSB
        os.writeMOV(INTSIZE, lsbDst, this.STATICS, staticsOfs + 0); // LSB
    }

    /**
     * Write code to load the given 64-bit isolated statics table entry into the
     * given 32-bit registers.
     *
     * @param curInstrLabel
     * @param lsbDst
     * @param msbReg
     * @param entry
     */
    public final void writeGetStaticsEntry64(Label curInstrLabel, GPR lsbDst,
                                             GPR msbReg, VmIsolatedStaticsEntry entry) {
        writeLoadIsolatedStatics(curInstrLabel, "gs64", lsbDst);
        final int staticsOfs = getIsolatedStaticsOffset(entry);
        os.writeMOV(INTSIZE, msbReg, lsbDst, staticsOfs + 4); // MSB
        os.writeMOV(INTSIZE, lsbDst, lsbDst, staticsOfs + 0); // LSB
    }

    /**
     * Write code to load the given 64-bit shared statics table entry into the
     * given 64-bit register.
     *
     * @param curInstrLabel
     * @param dstReg
     * @param entry
     */
    public final void writeGetStaticsEntry64(Label curInstrLabel, GPR64 dstReg,
                                             VmSharedStaticsEntry entry) {
        writeLoadSTATICS(curInstrLabel, "gs64", true);
        os
            .writeMOV(BITS64, dstReg, this.STATICS,
                getSharedStaticsOffset(entry));
    }

    /**
     * Write code to load the given 64-bit shared statics table entry into the
     * given 64-bit register.
     *
     * @param curInstrLabel
     * @param dstReg
     * @param entry
     */
    public final void writeGetStaticsEntry64(Label curInstrLabel, GPR64 dstReg,
                                             VmIsolatedStaticsEntry entry) {
        writeLoadIsolatedStatics(curInstrLabel, "gs64", dstReg);
        os.writeMOV(BITS64, dstReg, dstReg, getIsolatedStaticsOffset(entry));
    }

    /**
     * Write code to store the given statics table entry into the given
     * register.
     *
     * @param curInstrLabel
     * @param src
     * @param entry
     */
    public final void writePutStaticsEntry(Label curInstrLabel, GPR src,
                                           VmSharedStaticsEntry entry) {
        writeLoadSTATICS(curInstrLabel, "ps", true);
        os.writeMOV(INTSIZE, this.STATICS, getSharedStaticsOffset(entry), src);
    }

    /**
     * Write code to store the given isolated statics table entry into the given
     * register.
     *
     * @param curInstrLabel
     * @param src
     * @param entry
     */
    public final void writePutStaticsEntry(Label curInstrLabel, GPR src,
                                           VmIsolatedStaticsEntry entry, GPR tmp) {
        writeLoadIsolatedStatics(curInstrLabel, "ps", tmp);
        os.writeMOV(INTSIZE, tmp, getIsolatedStaticsOffset(entry), src);
    }

    /**
     * Write code to store the given 64-bit shared statics table entry into the
     * given 32-bit registers.
     *
     * @param curInstrLabel
     * @param lsbSrc
     * @param msbSrc
     * @param entry
     */
    public final void writePutStaticsEntry64(Label curInstrLabel, GPR lsbSrc,
                                             GPR msbSrc, VmSharedStaticsEntry entry) {
        writeLoadSTATICS(curInstrLabel, "ps64", true);
        final int staticsOfs = getSharedStaticsOffset(entry);
        os.writeMOV(BITS32, this.STATICS, staticsOfs + 4, msbSrc); // MSB
        os.writeMOV(BITS32, this.STATICS, staticsOfs + 0, lsbSrc); // LSB
    }

    /**
     * Write code to store the given 64-bit shared statics table entry into the
     * given 32-bit registers.
     *
     * @param curInstrLabel
     * @param lsbSrc
     * @param msbSrc
     * @param entry
     */
    public final void writePutStaticsEntry64(Label curInstrLabel, GPR lsbSrc,
                                             GPR msbSrc, VmIsolatedStaticsEntry entry, GPR tmp) {
        writeLoadIsolatedStatics(curInstrLabel, "ps64", tmp);
        final int staticsOfs = getIsolatedStaticsOffset(entry);
        os.writeMOV(BITS32, tmp, staticsOfs + 4, msbSrc); // MSB
        os.writeMOV(BITS32, tmp, staticsOfs + 0, lsbSrc); // LSB
    }

    /**
     * Write code to store the given 64-bit shared statics table entry into the
     * given 64-bit register.
     *
     * @param curInstrLabel
     * @param srcReg
     * @param entry
     */
    public final void writePutStaticsEntry64(Label curInstrLabel, GPR64 srcReg,
                                             VmSharedStaticsEntry entry) {
        writeLoadSTATICS(curInstrLabel, "ps64", true);
        os
            .writeMOV(BITS64, this.STATICS, getSharedStaticsOffset(entry),
                srcReg);
    }

    /**
     * Write code to store the given 64-bit isolated statics table entry into
     * the given 64-bit register.
     *
     * @param curInstrLabel
     * @param srcReg
     * @param entry
     */
    public final void writePutStaticsEntry64(Label curInstrLabel, GPR64 srcReg,
                                             VmIsolatedStaticsEntry entry, GPR tmp) {
        writeLoadIsolatedStatics(curInstrLabel, "ps64", tmp);
        os.writeMOV(BITS64, tmp, getIsolatedStaticsOffset(entry), srcReg);
    }

    /**
     * Gets the offset from the beginning of the shared statics table
     * (this.STATICS) to the given entry.
     *
     * @param entry
     * @return The byte offset from this.STATICS to the entry.
     */
    public final int getSharedStaticsOffset(VmSharedStaticsEntry entry) {
        if (os.isCode32()) {
            return (VmArray.DATA_OFFSET * 4)
                + (entry.getSharedStaticsIndex() << 2);
        } else {
            return (VmArray.DATA_OFFSET * 8)
                + (entry.getSharedStaticsIndex() << 2);
        }
    }

    /**
     * Gets the offset from the beginning of the isolated statics table to the
     * given entry.
     *
     * @param entry
     * @return The byte offset from the isolated statics table to the entry.
     */
    public final int getIsolatedStaticsOffset(VmIsolatedStaticsEntry entry) {
        if (os.isCode32()) {
            return (VmArray.DATA_OFFSET * 4)
                + (entry.getIsolatedStaticsIndex() << 2);
        } else {
            return (VmArray.DATA_OFFSET * 8)
                + (entry.getIsolatedStaticsIndex() << 2);
        }
    }

    public static void assertCondition(boolean condition, String msg) {
        if (!condition) {
            throw new InternalError("Assertion failed: " + msg);
        }
    }
}
TOP

Related Classes of org.jnode.vm.x86.compiler.X86CompilerHelper

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.