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

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

/*
* $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.x86.X86Assembler;
import org.jnode.assembler.x86.X86Register;
import org.jnode.assembler.x86.X86Register.GPR;
import org.jnode.assembler.x86.X86Register.GPR32;
import org.jnode.assembler.x86.X86Register.GPR64;
import org.jnode.vm.JvmType;
import org.jnode.vm.bytecode.StackException;
import org.jnode.vm.facade.VmUtils;
import org.jnode.vm.x86.compiler.X86CompilerHelper;

/**
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
public abstract class WordItem extends Item {

    private X86Register.GPR gpr;

    protected WordItem(ItemFactory factory) {
        super(factory);
    }

    protected final void initialize(EmitterContext ec, byte kind, X86Register reg, short local) {
        super.initialize(kind, local,
            ((reg instanceof X86Register.XMM) ? (X86Register.XMM) reg
                : null));
        this.gpr = (reg instanceof X86Register.GPR) ? (X86Register.GPR) reg
            : null;
        if (VmUtils.verifyAssertions()) {
            switch (kind) {
                case Kind.GPR:
                    VmUtils._assert((this.gpr != null),
                        "kind == register implies that reg != null");
                    break;
            }
            verifyState(ec);
        }
    }

    /**
     * @see org.jnode.vm.x86.compiler.l1a.Item#clone()
     */
    protected Item clone(EmitterContext ec) {
        final WordItem res;
        final X86Assembler os = ec.getStream();

        switch (getKind()) {
            case Kind.GPR:
                res = L1AHelper.requestWordRegister(ec, getType(), false);
                final GPR r = res.getRegister();
                os.writeMOV(gpr.getSize(), r, gpr);
                break;

            case Kind.LOCAL:
                res = (WordItem) factory.createLocal(getType(), getOffsetToFP(ec));
                break;

            case Kind.CONSTANT:
                res = cloneConstant(ec);
                break;

            case Kind.FPUSTACK:
                // TODO
                notImplemented();
                res = null;
                break;

            case Kind.STACK:
                os.writePUSH(X86Register.ESP, 0);
                res = (WordItem) factory.createStack(getType());
                if (VirtualStack.checkOperandStack) {
                    final ItemStack operandStack = ec.getVStack().operandStack;
                    operandStack.pop(this);
                    operandStack.push(this);
                    operandStack.push(res);
                }
                break;

            default:
                throw new IllegalArgumentException("Invalid item kind");
        }
        return res;
    }

    /**
     * Create a clone of this item, which must be a constant.
     *
     * @param ec
     * @return The cloned item
     */
    protected abstract WordItem cloneConstant(EmitterContext ec);

    /**
     * Gets the register the is used by this item.
     *
     * @return The register that contains this item
     */
    final X86Register.GPR getRegister() {
        if (VmUtils.verifyAssertions())
            VmUtils._assert(isGPR(), "Must be register");
        return gpr;
    }

    /**
     * @see org.jnode.vm.x86.compiler.l1a.Item#load(EmitterContext)
     */
    final void load(EmitterContext ec) {
        if (!isGPR()) {
            final X86RegisterPool pool = ec.getGPRPool();
            X86Register r = pool.request(getType(), this);
            if (r == null) {
                final VirtualStack vstack = ec.getVStack();
                vstack.push(ec);
                r = pool.request(getType(), this);
            }
            if (VmUtils.verifyAssertions())
                VmUtils._assert(r != null, "r != null");
            loadTo(ec, (X86Register.GPR) r);
        }
        if (VmUtils.verifyAssertions()) {
            verifyState(ec);
        }
    }

    /**
     * load item with register reg. Assumes that reg is properly allocated
     *
     * @param ec  current emitter context
     * @param reg register to load the item to
     */
    final void loadTo(EmitterContext ec, X86Register.GPR reg) {
        if (VmUtils.verifyAssertions())
            VmUtils._assert(reg != null, "Reg != null");
        final X86Assembler os = ec.getStream();
        final X86RegisterPool pool = ec.getGPRPool();
        final VirtualStack stack = ec.getVStack();
        final X86CompilerHelper helper = ec.getHelper();
        if (VmUtils.verifyAssertions()) {
            VmUtils._assert(!pool.isFree(reg), "reg not free");
        }

        switch (getKind()) {
            case Kind.GPR:
                if (this.gpr != reg) {
                    os.writeMOV(reg.getSize(), reg, this.gpr);
                    cleanup(ec);
                }
                break;

            case Kind.LOCAL:
                os.writeMOV(reg.getSize(), reg, helper.BP, getOffsetToFP(ec));
                break;

            case Kind.CONSTANT:
                loadToConstant(ec, os, reg);
                break;

            case Kind.FPUSTACK:
                // Make sure this item is on top of the FPU stack
                FPUHelper.fxch(os, stack.fpuStack, this);
                stack.fpuStack.pop(this);
                // Convert & move to new space on normal stack
                os.writeLEA(helper.SP, helper.SP, -helper.SLOTSIZE);
                popFromFPU(os, helper.SP, 0);
                os.writePOP(reg);
                break;

            case Kind.STACK:
                // TODO: make sure 'this' is on top of stack
                // TODO: implemen it for 64 bits
                if (!stack.operandStack.isTos(this)) {

                    int stack_loc = stack.operandStack.stackLocation(this);
                    if (stack_loc < 0)
                        throw new StackException("Item not found on stack");

                    stack.operandStack.makeTop(stack_loc);

                    //todo test it
                    os.writeMOV(org.jnode.vm.x86.compiler.X86CompilerConstants.BITS32, reg, helper.SP, helper.SLOTSIZE);
                    os.writeXCHG(helper.SP, org.jnode.vm.x86.compiler.X86CompilerConstants.BITS32 * stack_loc, reg);
                    os.writeMOV(org.jnode.vm.x86.compiler.X86CompilerConstants.BITS32, helper.SP, helper.SLOTSIZE, reg);
                }

                if (VirtualStack.checkOperandStack) {
                    stack.operandStack.pop(this);
                }
                os.writePOP(reg);
                break;

            default:
                throw new IllegalArgumentException("Invalid item kind");
        }
        setKind(Kind.GPR);
        this.gpr = reg;
    }

    /**
     * Load my constant to the given os.
     *
     * @param ec
     * @param os
     * @param reg
     */
    protected abstract void loadToConstant(EmitterContext ec, X86Assembler os,
                                           GPR reg);

    /**
     * Load this item to a general purpose register.
     *
     * @param ec
     */
    final void loadToGPR(EmitterContext ec) {
        if (!isGPR()) {
            X86Register r = ec.getGPRPool().request(JvmType.INT);
            if (r == null) {
                ec.getVStack().push(ec);
                r = ec.getGPRPool().request(JvmType.INT);
            }
            if (VmUtils.verifyAssertions())
                VmUtils._assert(r != null, "r != null");
            loadTo(ec, (X86Register.GPR) r);
        }
    }

    /**
     * Load this item to an XMM register.
     *
     * @param ec
     */
    final void loadToXMM(EmitterContext ec) {
        throw new Error("Not implemented yet");
    }

    /**
     * Load this item into a register that is suitable for BITS8 mode.
     *
     * @param ec
     */
    final void loadToBITS8GPR(EmitterContext ec) {
        if (!isGPR() || !gpr.isSuitableForBits8()) {
            final X86RegisterPool pool = ec.getGPRPool();
            X86Register r = pool.request(JvmType.INT, this, true);
            if (r == null) {
                ec.getVStack().push(ec);
                r = ec.getGPRPool().request(JvmType.INT, this, true);
            }
            if (VmUtils.verifyAssertions())
                VmUtils._assert(r != null, "r != null");
            loadTo(ec, (X86Register.GPR) r);
        }
    }

    /**
     * Load item into the given register (only for Category 1 items), if its
     * kind matches the mask.
     *
     * @param ec
     * @param mask
     * @param t0   the destination register
     */
    final void loadToIf(EmitterContext ec, int mask, X86Register.GPR t0) {
        if ((getKind() & mask) > 0)
            loadTo(ec, t0);
    }

    /**
     * Pop the top of the FPU stack into the given memory location.
     *
     * @param os
     * @param reg
     * @param disp
     */
    protected abstract void popFromFPU(X86Assembler os, GPR reg, int disp);

    /**
     * @see org.jnode.vm.x86.compiler.l1a.Item#push(EmitterContext)
     */
    final void push(EmitterContext ec) {
        final X86Assembler os = ec.getStream();
        final VirtualStack stack = ec.getVStack();
        final X86CompilerHelper helper = ec.getHelper();

        switch (getKind()) {
            case Kind.GPR:
                os.writePUSH(gpr);
                break;

            case Kind.LOCAL:
                os.writePUSH(helper.BP, getOffsetToFP(ec));
                break;

            case Kind.CONSTANT:
                pushConstant(ec, os);
                break;

            case Kind.FPUSTACK:
                // Make sure this item is on top of the FPU stack
                final FPUStack fpuStack = stack.fpuStack;
                FPUHelper.fxch(os, fpuStack, this);
                stack.fpuStack.pop(this);
                // Convert & move to new space on normal stack
                os.writeLEA(helper.SP, helper.SP, -helper.SLOTSIZE);
                popFromFPU(os, helper.SP, 0);
                break;

            case Kind.STACK:
                // nothing to do
                if (VirtualStack.checkOperandStack) {
                    // the item is not really pushed and popped
                    // but this checks that it is really the top
                    // element
                    stack.operandStack.pop(this);
                }
                break;

            default:
                throw new IllegalArgumentException("Invalid item kind");
        }
        cleanup(ec);
        setKind(Kind.STACK);

        if (VirtualStack.checkOperandStack) {
            stack.operandStack.push(this);
        }
    }

    /**
     * Push my constant on the stack using the given os.
     *
     * @param ec
     * @param os
     */
    protected abstract void pushConstant(EmitterContext ec, X86Assembler os);

    /**
     * Push the value at the given memory location on the FPU stack.
     *
     * @param os
     * @param reg
     * @param disp
     */
    protected abstract void pushToFPU(X86Assembler os, GPR reg, int disp);

    /**
     * @see org.jnode.vm.x86.compiler.l1a.Item#pushToFPU(EmitterContext)
     */
    final void pushToFPU(EmitterContext ec) {
        final X86Assembler os = ec.getStream();
        final VirtualStack stack = ec.getVStack();
        final X86CompilerHelper helper = ec.getHelper();

        switch (getKind()) {
            case Kind.GPR:
                os.writePUSH(gpr);
                pushToFPU(os, helper.SP, 0);
                os.writeLEA(helper.SP, helper.SP, helper.SLOTSIZE);
                break;

            case Kind.LOCAL:
                pushToFPU(os, helper.BP, getOffsetToFP(ec));
                break;

            case Kind.CONSTANT:
                pushConstant(ec, os);
                pushToFPU(os, helper.SP, 0);
                os.writeLEA(helper.SP, helper.SP, helper.SLOTSIZE);
                break;

            case Kind.FPUSTACK:
                // Assert this item is at the top of the stack
                stack.fpuStack.pop(this);
                stack.fpuStack.push(this);
                return;
            // break;

            case Kind.STACK:
                if (VirtualStack.checkOperandStack) {
                    stack.operandStack.pop(this);
                }
                pushToFPU(os, helper.SP, 0);
                os.writeLEA(helper.SP, helper.SP, helper.SLOTSIZE);
                break;

            default:
                throw new IllegalArgumentException("Invalid item kind");
        }

        cleanup(ec);
        setKind(Kind.FPUSTACK);
        stack.fpuStack.push(this);
    }

    /**
     * @see org.jnode.vm.x86.compiler.l1a.Item#release(EmitterContext)
     */
    final void release(EmitterContext ec) {
        cleanup(ec);
        ec.getItemFactory().release(this);
    }

    /**
     * @param ec
     * @see org.jnode.vm.x86.compiler.l1a.Item#release(EmitterContext)
     */
    private void cleanup(EmitterContext ec) {
        // assertCondition(!ec.getVStack().contains(this), "Cannot release while
        // on vstack");
        final X86RegisterPool pool = ec.getGPRPool();

        switch (getKind()) {
            case Kind.GPR:
                pool.release(gpr);
                if (VmUtils.verifyAssertions())
                    VmUtils._assert(pool.isFree(gpr), "reg is free");
                break;

            case Kind.LOCAL:
                // nothing to do
                break;

            case Kind.CONSTANT:
                // nothing to do
                break;

            case Kind.FPUSTACK:
                // nothing to do
                break;

            case Kind.STACK:
                // nothing to do
                break;

            default:
                throw new IllegalArgumentException("Invalid item kind");
        }

        this.gpr = null;
        setKind((byte) 0);
    }

    /**
     * @see org.jnode.vm.x86.compiler.l1a.Item#spill(EmitterContext, org.jnode.assembler.x86.X86Register)
     */
    final void spill(EmitterContext ec, X86Register reg) {
        if (VmUtils.verifyAssertions()) {
            VmUtils._assert(isGPR() && (this.gpr.getNr() == reg.getNr()), "spill1 gpr=" + gpr + ", reg=" + reg);
        }
        final X86RegisterPool pool = ec.getGPRPool();
        X86Register r = pool.request(getType());
        if (r == null) {
            ec.getVStack().push(ec);
            if (getKind() == Kind.STACK) {
                return;
            }
            r = pool.request(getType());
            if (VmUtils.verifyAssertions())
                VmUtils._assert(r != null, "r != null");
        }
        loadTo(ec, (X86Register.GPR) r);
        pool.transferOwnerTo(r, this);
        if (VmUtils.verifyAssertions()) {
            verifyState(ec);
        }
    }

    /**
     * @see org.jnode.vm.x86.compiler.l1a.Item#uses(org.jnode.assembler.x86.X86Register)
     */
    final boolean uses(X86Register reg) {
        return (isGPR() && this.gpr.equals(reg));
    }

    /**
     * enquire whether the item uses a volatile register
     *
     * @return true, when this item uses a volatile register.
     */
    final boolean usesVolatileRegister(X86RegisterPool pool) {
        return (isGPR() && !pool.isCallerSaved(gpr));
    }

    /**
     * Verify the consistency of the state of this item.
     * Throw an exception is the state is inconsistent.
     */
    protected void verifyState(EmitterContext ec) {
        switch (getKind()) {
            case Kind.GPR:
                if (gpr == null) {
                    throw new IllegalStateException("gpr cannot not be null");
                }
                if (ec.getStream().isCode32()) {
                    if (!(gpr instanceof GPR32)) {
                        throw new IllegalStateException("gpr must be GPR32");
                    }
                } else {
                    if (getType() == JvmType.REFERENCE) {
                        if (!(gpr instanceof GPR64)) {
                            throw new IllegalStateException("gpr must be GPR64");
                        }
                    } else {
                        if (!(gpr instanceof GPR32)) {
                            throw new IllegalStateException("gpr must be GPR32");
                        }
                    }
                }
                break;
        }
    }
}
TOP

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

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.