Package org.jnode.vm.compiler

Source Code of org.jnode.vm.compiler.NativeCodeCompiler

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

import java.io.Writer;

import org.jnode.assembler.Label;
import org.jnode.assembler.NativeStream;
import org.jnode.assembler.ObjectResolver;
import org.jnode.assembler.UnresolvedObjectRefException;
import org.jnode.vm.VmAddress;
import org.jnode.vm.VmMagic;
import org.jnode.annotation.MagicPermission;
import org.jnode.vm.bytecode.BasicBlock;
import org.jnode.vm.bytecode.ControlFlowGraph;
import org.jnode.vm.classmgr.VmAddressMap;
import org.jnode.vm.classmgr.VmByteCode;
import org.jnode.vm.classmgr.VmClassLoader;
import org.jnode.vm.classmgr.VmCompiledExceptionHandler;
import org.jnode.vm.classmgr.VmConstClass;
import org.jnode.vm.classmgr.VmMethod;
import org.jnode.vm.facade.VmUtils;
import org.jnode.vm.objects.VmSystemObject;
import org.vmmagic.unboxed.Address;

/**
* Abstract native code compiler.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
@MagicPermission
public abstract class NativeCodeCompiler extends VmSystemObject {

    /**
     * Compile the given method during bootstrapping
     *
     * @param method
     * @param os
     * @param level  Optimization level
     */
    public final void compileBootstrap(VmMethod method, NativeStream os,
                                       int level) {
        int start = os.getLength();
        final CompiledMethod cm;
        final boolean abstractM = method.isAbstract();
        if (abstractM) {
            if (method.isStatic()) {
                throw new Error("Abstract & static");
            }
            if (method.isNative()) {
                throw new Error("Abstract & native");
            }
            cm = doCompileAbstract(method, os, level, true);
            if (cm == null) {
                return;
            }
        } else {
            cm = doCompile(method, os, level, true);
        }
        int end = os.getLength();

        final VmAddress nativeCode = (VmAddress) cm.getCodeStart().getObject();
        final VmCompiledExceptionHandler[] eTable;
        final VmAddress defExHandler;
        final VmByteCode bc;
        final VmAddressMap aTable = cm.getAddressTable();

        if (!(method.isNative() || abstractM)) {
            final NativeStream.ObjectRef defExHRef = cm
                .getDefExceptionHandler();
            if (defExHRef != null) {
                defExHandler = (VmAddress) defExHRef.getObject();
            } else {
                defExHandler = null;
            }
            bc = method.getBytecode();
            final CompiledExceptionHandler[] ceh = cm.getExceptionHandlers();
            if (ceh != null) {
                eTable = new VmCompiledExceptionHandler[ceh.length];
                for (int i = 0; i < ceh.length; i++) {

                    final VmConstClass catchType = bc.getExceptionHandler(i)
                        .getCatchType();
                    final VmAddress startPtr = (VmAddress) ceh[i].getStartPc()
                        .getObject();
                    final VmAddress endPtr = (VmAddress) ceh[i].getEndPc()
                        .getObject();
                    final VmAddress handler = (VmAddress) ceh[i].getHandler()
                        .getObject();
                    eTable[i] = new VmCompiledExceptionHandler(catchType,
                        startPtr, endPtr, handler);
                }
            } else {
                eTable = null;
            }
        } else {
            eTable = null;
            defExHandler = null;
            bc = null;
        }

        method.addCompiledCode(VmUtils.getVm().getCompiledMethods().createCompiledCode(cm,
            method, this, bc, nativeCode, null, end - start, eTable,
            defExHandler, aTable), level);
    }

    /**
     * Compile the given method during runtime.
     *
     * @param method
     * @param resolver
     * @param level    Optimization level
     * @param os       The native stream, can be null
     */
    public void compileRuntime(VmMethod method, ObjectResolver resolver,
                               int level, NativeStream os) {

        if (method.isNative()) {
            throw new IllegalArgumentException("Cannot compile native methods");
        }

        // long start = System.currentTimeMillis();

        // System.out.println("Compiling " + method);

        if (os == null) {
            os = createNativeStream(resolver);
        }
        final CompiledMethod cm;
        if (method.isAbstract()) {
            cm = doCompileAbstract(method, os, level, false);
            if (cm == null) {
                return;
            }
        } else {
            cm = doCompile(method, os, level, false);
        }

        try {
            final int startOffset = cm.getCodeStart().getOffset();
            final int size = cm.getCodeEnd().getOffset() - startOffset;
            final byte[] code = new byte[size];
            System.arraycopy(os.getBytes(), startOffset, code, 0, size);
            final Address codePtr = VmMagic.getArrayData(code);

            final NativeStream.ObjectRef defExHRef = cm
                .getDefExceptionHandler();
            final Address defExHandler;
            if (defExHRef != null) {
                defExHandler = codePtr.add(cm.getDefExceptionHandler()
                    .getOffset()
                    - startOffset);
            } else {
                defExHandler = Address.zero();
            }
            final VmCompiledExceptionHandler[] eTable;
            final VmAddressMap aTable = cm.getAddressTable();

            final VmByteCode bc = method.getBytecode();
            final CompiledExceptionHandler[] ceh = cm.getExceptionHandlers();
            if (ceh != null) {
                eTable = new VmCompiledExceptionHandler[ceh.length];
                for (int i = 0; i < ceh.length; i++) {

                    final VmConstClass catchType = bc.getExceptionHandler(i)
                        .getCatchType();
                    final Address startPtr = codePtr.add(ceh[i].getStartPc()
                        .getOffset()
                        - startOffset);
                    final Address endPtr = codePtr.add(ceh[i].getEndPc()
                        .getOffset()
                        - startOffset);
                    final Address handler = codePtr.add(ceh[i].getHandler()
                        .getOffset()
                        - startOffset);

                    eTable[i] = new VmCompiledExceptionHandler(catchType,
                        startPtr.toAddress(), endPtr.toAddress(), handler
                        .toAddress());
                }
            } else {
                eTable = null;
            }

            method.addCompiledCode(VmUtils.getVm().getCompiledMethods().createCompiledCode(
                cm, method, this, bc, codePtr.toAddress(), code, size,
                eTable, defExHandler.toAddress(), aTable), level);

            // For debugging only
            // System.out.println("Code: " + NumberUtils.hex(code));
            // System.out.println();
            // End of debugging only
        } catch (UnresolvedObjectRefException ex) {
            throw new CompileError(ex);
        }

        if (os.hasUnresolvedObjectRefs()) {
            throw new CompileError("Unresolved labels after compile!");
        }
    }

    public abstract void disassemble(VmMethod method, ObjectResolver resolver,
                                     int level, Writer writer);

    /**
     * Create a native stream for the current architecture.
     *
     * @param resolver
     * @return NativeStream
     */
    public abstract NativeStream createNativeStream(ObjectResolver resolver);

    /**
     * Compile the given method into the given stream.
     *
     * @param method
     * @param os
     * @param level       Optimization level
     * @param isBootstrap
     * @return The compiled method
     */
    protected CompiledMethod doCompile(VmMethod method, NativeStream os,
                                       int level, boolean isBootstrap) {
        final CompiledMethod cm = new CompiledMethod(level);
        try {
            if (method.isNative()) {
                Object label = new Label(method.getMangledName());
                cm.setCodeStart(os.getObjectRef(label));
            } else {
                // Create the visitor
                CompilerBytecodeVisitor bcv = getBytecodeVisitor(method, cm, os, level, isBootstrap);

                try {
                    // Wrap in verifier if needed
                    if (!(bcv instanceof VerifyingCompilerBytecodeVisitor)) {
                        bcv = new VerifyingCompilerBytecodeVisitor<CompilerBytecodeVisitor>(bcv);
                    }
                    // Get the bytecode
                    final VmByteCode bc = method.getBytecode();
                    // Create the control flow graph
                    ControlFlowGraph cfg = (ControlFlowGraph) bc.getCompilerData();
                    if (cfg == null) {
                        cfg = new ControlFlowGraph(bc);
                        bc.setCompilerData(cfg);
                    }
                    // Compile the code 1 basic block at a time
                    final CompilerBytecodeParser parser = new CompilerBytecodeParser(bc, cfg, bcv);
                    bcv.startMethod(method);
                    for (BasicBlock bb : cfg) {
                        bcv.startBasicBlock(bb);
                        parser.parse(bb.getStartPC(), bb.getEndPC(), false);
                        bcv.endBasicBlock();
                    }
                    bcv.endMethod();

                    //remove the compiler data to save memory, will be regenerated if needed
                    bc.setCompilerData(null);
                } finally {
                    releaseBytecodeVisitor(bcv);
                }
            }
        } catch (RuntimeException x) {
            System.err.println("ERROR in compilation of " + method.getFullName());
            throw x;
        } catch (Error x) {
            System.err.println("ERROR in compilation of " + method.getFullName());
            throw x;
        }

        return cm;
    }

    /**
     * Compile the given abstract method into the given stream.
     *
     * @param method
     * @param os
     * @param level       Optimization level
     * @param isBootstrap
     * @return The compiled method
     */
    protected abstract CompiledMethod doCompileAbstract(VmMethod method, NativeStream os, int level,
                                                        boolean isBootstrap);

    /**
     * Create the visitor that converts bytecodes into native code.
     *
     * @param method
     * @param cm
     * @param os
     * @param level      Optimization level
     * @param isBootstrap
     * @return The new bytecode visitor.
     */
    protected abstract CompilerBytecodeVisitor createBytecodeVisitor(VmMethod method, CompiledMethod cm,
                                                                     NativeStream os, int level, boolean isBootstrap);

    /**
     * Returns an unused or newly created byte code visitor.
     * @see #createBytecodeVisitor(org.jnode.vm.classmgr.VmMethod, CompiledMethod, org.jnode.assembler.NativeStream,
     * int, boolean)
     */
    protected CompilerBytecodeVisitor getBytecodeVisitor(VmMethod method, CompiledMethod cm, NativeStream os,
                                                         int level, boolean isBootstrap) {
        return createBytecodeVisitor(method, cm, os, level, isBootstrap);
    }

    /**
     * Call this method when the specified bytecode visitor finished working.
     *
     * @param visitor a bytecode visitor
     */
    protected void releaseBytecodeVisitor(CompilerBytecodeVisitor visitor) {

    }
    /**
     * Initialize this compiler
     *
     * @param loader
     */
    public abstract void initialize(VmClassLoader loader);

    /**
     * Dump compiler statistics to System.out
     */
    public abstract void dumpStatistics();

    /**
     * Gets the magic value of this compiler.
     *
     * @return the magic value
     * @see org.jnode.vm.VmStackFrame#MAGIC_COMPILED
     * @see org.jnode.vm.VmStackFrame#MAGIC_MASK
     */
    public abstract int getMagic();

    /**
     * Gets the name of this compiler.
     *
     * @return the compiler name
     */
    public abstract String getName();

    /**
     * Create an iterator that can iterator of GCMaps generated by this compiler.
     *
     * @return the iterator
     */
    public abstract GCMapIterator createGCMapIterator();

    /**
     * Gets the names of the packages that are required by this compiler.
     *
     * @return the names
     */
    public abstract String[] getCompilerPackages();
}
TOP

Related Classes of org.jnode.vm.compiler.NativeCodeCompiler

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.