Package org.jnode.vm.x86.compiler

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

/*
* $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 org.jnode.assembler.ObjectResolver;
import org.jnode.assembler.x86.X86Assembler;
import org.jnode.assembler.x86.X86Register;
import org.jnode.util.LittleEndian;
import org.jnode.vm.classmgr.ObjectLayout;
import org.jnode.vm.classmgr.TIBLayout;
import org.jnode.vm.classmgr.VmArray;
import org.jnode.vm.classmgr.VmClassLoader;
import org.jnode.vm.classmgr.VmMethod;
import org.jnode.vm.compiler.CompiledIMT;
import org.jnode.vm.compiler.IMTCompiler;

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

/**
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
public final class X86IMTCompiler32 extends IMTCompiler {

    /**
     * Register that holds the selector
     */
    public static final X86Register SELECTOR_REG = X86Register.EDX;

    /**
     * Size in bytes of an entry in the IMT jump table generated by this method.
     */
    private static final int IMT_ENTRY_SIZE = 6;

    /**
     * Initialize this instance.
     */
    public X86IMTCompiler32() {
    }

    /**
     * Generate the actual invocation code of an interface method. Inputs: EDI
     * statics table (EDI is preserved) EAX object to invoke method on (EAX is
     * destroyed)
     *
     * @param os
     * @param method
     */
    public static void emitInvokeInterface(X86Assembler os, VmMethod method) {
        final int selector = method.getSelector();
        final int index = selector % ObjectLayout.IMT_LENGTH;
        final int offset = (VmArray.DATA_OFFSET * 4) + (index * IMT_ENTRY_SIZE);

        // For debugging only
        // os.writeMOV_Const(Register.ESI, offset);

        // Get tib into EAX
        os.writeMOV(BITS32, X86Register.EAX, X86Register.EAX,
            ObjectLayout.TIB_SLOT * 4);
        // Get selector into EDX
        os.writeMOV_Const(X86Register.EDX, selector);
        // Get compiled IMT into EAX
        os.writeMOV(BITS32, X86Register.EAX, X86Register.EAX,
            (TIBLayout.COMPILED_IMT_INDEX + VmArray.DATA_OFFSET) * 4);
        // Call to offset within compiled IMT
        os.writeLEA(X86Register.EAX, X86Register.EAX, offset);
        os.writeCALL(X86Register.EAX);
    }

    /**
     * Initialize this compiler
     *
     * @param loader
     */
    public void initialize(VmClassLoader loader) {
        // Nothing to do
    }

    /**
     * @see org.jnode.vm.compiler.IMTCompiler#compile(ObjectResolver, Object[],
     *      boolean[])
     */
    public CompiledIMT compile(ObjectResolver resolver__, Object[] imt, boolean[] imtCollisions) {
        final int imtLength = imt.length;

        // Calculate size of code array
        int size = imtLength * IMT_ENTRY_SIZE;
        for (int i = 0; i < imtLength; i++) {
            if (imtCollisions[i]) {
                final Object[] arr = (Object[]) imt[i];
                size += arr.length * 15;
            }
        }

        final byte[] code = new byte[size];
        // Create the jump table
        int extraIndex = imtLength * IMT_ENTRY_SIZE;
        for (int i = 0; i < imtLength; i++) {
            final int ofsStart = i * IMT_ENTRY_SIZE;
            int ofs = ofsStart;

            if (imtCollisions[i]) {
                // Complex route
                final Object[] arr = (Object[]) imt[i];
                final int arrLength = arr.length;
                final int jmpEaxCodeOfs;

                // JMP extraIndex
                code[ofs++] = (byte) 0xE9;
                LittleEndian.setInt32(code, ofs, (extraIndex - ofs) - 4);
                ofs += 4;

                // Create extra field
                for (int k = 0; k < arrLength; k++) {
                    final VmMethod method = (VmMethod) arr[k];

                    if (k + 1 == arrLength) {
                        // Last entry, jump directly
                        // JMP [statics+method_statics_index]
                        extraIndex = genJmpStaticsCodeOfs(code, extraIndex,
                            method.getSharedStaticsIndex());
                    } else {
                        // Non-last entry, compare and jump of select match

                        // CMP selectorReg, imm32_selector
                        code[extraIndex++] = (byte) 0x81;
                        code[extraIndex++] = (byte) 0xFA;
                        LittleEndian.setInt32(code, extraIndex, method
                            .getSelector());
                        extraIndex += 4;

                        // JNE labelAfterJump
                        code[extraIndex++] = (byte) 0x75;
                        code[extraIndex++] = (byte) 0x06;

                        // JMP [statics+method_statics_index]
                        extraIndex = genJmpStaticsCodeOfs(code, extraIndex,
                            method.getSharedStaticsIndex());
                    }
                }
            } else if (imt[i] != null) {
                // Simple route

                // JMP [STATICS+staticsOfs]
                final VmMethod method = (VmMethod) imt[i];
                ofs = genJmpStaticsCodeOfs(code, ofs, method.getSharedStaticsIndex());
            } else {
                // Empty IMT slot
                // INT ABSTRACT_METHOD
                code[ofs++] = (byte) 0xCD;
                code[ofs++] = (byte) X86CompilerConstants.ABSTRACT_METHOD_INTNO;
                // Fill with NOP's
                code[ofs++] = (byte) 0x90;
                code[ofs++] = (byte) 0x90;
                code[ofs++] = (byte) 0x90;
                code[ofs++] = (byte) 0x90;
            }

            if (ofs > ofsStart + IMT_ENTRY_SIZE) {
                throw new InternalError("Adjust IMT_ENTRY_SIZE to "
                    + (ofs - ofsStart));
            }
        }

        return new X86CompiledIMT(code);
    }

    /**
     * Generate: JMP [STATICS+method.staticsOffset]
     *
     * @param code
     * @param ofs
     * @param staticsIndex
     * @return the new offset
     */
    private int genJmpStaticsCodeOfs(byte[] code, int ofs, int staticsIndex) {
        final int offset = (staticsIndex + VmArray.DATA_OFFSET) * 4;
        // JMP [EDI+codeOfs]
        code[ofs++] = (byte) 0xFF;
        code[ofs++] = (byte) 0xA7;
        LittleEndian.setInt32(code, ofs, offset);
        return ofs + 4;
    }
}
TOP

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

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.