Package org.jnode.vm

Source Code of org.jnode.vm.LoadCompileService$LoadRequest

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

import java.nio.ByteBuffer;
import java.security.ProtectionDomain;
import java.util.ArrayList;

import org.jnode.assembler.ObjectResolver;
import org.jnode.annotation.Inline;
import org.jnode.annotation.Internal;
import org.jnode.annotation.KernelSpace;
import org.jnode.annotation.MagicPermission;
import org.jnode.annotation.SharedStatics;
import org.jnode.vm.classmgr.ClassDecoder;
import org.jnode.vm.classmgr.VmClassLoader;
import org.jnode.vm.classmgr.VmMethod;
import org.jnode.vm.classmgr.VmType;
import org.jnode.vm.compiler.NativeCodeCompiler;

/**
* Service used to load classes and compile methods.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
@MagicPermission
@SharedStatics
public final class LoadCompileService {

    private static LoadCompileService service;

    private final ArrayList<Request> requestQueue = new ArrayList<Request>();

    private final ObjectResolver resolver;

    private final NativeCodeCompiler[] compilers;

    private final NativeCodeCompiler[] testCompilers;

    private static boolean started = false;

    private static final int threadCount = 2; //4

    /**
     * Default ctor
     */
    public LoadCompileService(ObjectResolver resolver) {
        this.resolver = resolver;
        final BaseVmArchitecture arch = VmMagic.currentProcessor()
            .getArchitecture();
        this.compilers = arch.getCompilers();
        this.testCompilers = arch.getTestCompilers();
    }

    /**
     * Recompile the given method with the given optimization level
     *
     * @param method
     * @param optLevel
     * @param enableTestCompilers
     */
    public static final void compile(VmMethod method, int optLevel,
                                     boolean enableTestCompilers) {
        if (service == null) {
            service = new LoadCompileService(new Unsafe.UnsafeObjectResolver());
        }

        if ((!started) || (Thread.currentThread() instanceof LoadCompileThread)) {
            // Compile now
            service.doCompile(method, optLevel, enableTestCompilers);
        } else {
            // Put request in queue
            service.enqueAndWait(new CompileRequest(method, optLevel,
                enableTestCompilers));
        }
    }

    /**
     * Get the highest supported optimization level for the regular or test compilers.
     */
    public static int getHighestOptimizationLevel(boolean test) {
        if (test) {
            return service.testCompilers == null ? -1 : service.testCompilers.length - 1;
        } else {
            return service.compilers == null ? -1 : service.compilers.length - 1;
        }
    }

    /**
     * @see org.jnode.vm.classmgr.VmClassLoader#defineClass(java.lang.String,
     *      ByteBuffer, java.security.ProtectionDomain)
     */
    public static final VmType<?> defineClass(String name, ByteBuffer data,
                                              ProtectionDomain protDomain, VmClassLoader loader) {
        initService();
        /* TODO review it: if(true || ... disables class definition on the load-compile thread.*/
        if (true || (!started) || (Thread.currentThread() instanceof LoadCompileThread)) {
            // Load now
            return service.doDefineClass(name, data, protDomain, loader);
        } else {
            // Put request in queue
            LoadRequest request = new LoadRequest(name, data, protDomain,
                loader);
            service.enqueAndWait(request);
            return request.getDefinedType();
        }
    }

    /**
     * Start this service.
     */
    static final void start() {
        initService();
        /*
        Disabled the startup of the LoadCompile thread service because multithreaded
        class loading creates deadlock in URLClassLoader and subclasses.
        Loading and compilation will happen onthe caller thread.
        - load-compile thread are enabled again but only used for compilation
        TODO review this: investigate class loading in dedicated threads (probably will not work)
        TODO and method compilation on dedicated threads (probably will work)
        */
        if (!started) {
            started = true;
            for (int i = 0; i < threadCount; i++) {
                LoadCompileThread thread = new LoadCompileThread(service,
                    "LoadCompile-" + i);
                thread.start();
            }
        }

    }

    @KernelSpace
    @Internal
    public static final void showInfo() {
        Unsafe.debug(" #loadcompile requests: ");
        Unsafe.debug((service != null) ? service.requestQueue.size() : 0);
    }

    /**
     * Initialize the service if needed.
     */
    @Inline
    private static void initService() {
        if (service == null) {
            service = new LoadCompileService(new Unsafe.UnsafeObjectResolver());
        }
    }

    /**
     * Put request in queue and wait for request to finish.
     *
     * @param request
     */
    private void enqueAndWait(Request request) {
        // Put request in queue
        synchronized (requestQueue) {
            requestQueue.add(request);
            requestQueue.notify();
        }
        // Wait for request to finish
        request.waitUntilFinished();
    }

    /**
     * Wait for a request in the queue and process it.
     */
    final void processNextRequest() {
        // Get the first request
        final Request request;
        synchronized (requestQueue) {
            while (requestQueue.isEmpty()) {
                try {
                    requestQueue.wait();
                } catch (InterruptedException ex) {
                    // Ignore
                }
            }
            request = requestQueue.get(0);
            requestQueue.remove(0);
        }
        try {
            // Process request
            request.execute();
        } finally {
            // Notify waiting threads
            request.setFinished();
        }
    }

    /**
     * Compile the given method
     *
     * @param vmMethod The method to compile
     * @param optLevel The optimization level
     */
    private void doCompile(VmMethod vmMethod, int optLevel,
                           boolean enableTestCompilers) {
        final NativeCodeCompiler cmps[];
        int index;
        if (enableTestCompilers) {
            index = optLevel;
            optLevel += compilers.length;
            cmps = testCompilers;
        } else {
            index = optLevel;
            cmps = compilers;
        }

        final NativeCodeCompiler cmp;
        if (index < 0) {
            index = 0;
        } else if (index >= cmps.length) {
            index = cmps.length - 1;
        }
        if (vmMethod.getNativeCodeOptLevel() < optLevel) {
            cmp = cmps[index];
            cmp.compileRuntime(vmMethod, resolver, optLevel, null);
        }
    }

    /**
     * @see org.jnode.vm.classmgr.VmClassLoader#defineClass(java.lang.String,
     *      ByteBuffer, java.security.ProtectionDomain)
     */
    final VmType<?> doDefineClass(String name, ByteBuffer data,
                                  ProtectionDomain protDomain, VmClassLoader loader) {
        return ClassDecoder.defineClass(name, data, true, loader, protDomain);
    }

    private abstract static class Request {

        private boolean finished = false;
        private Throwable exception;

        /**
         * Wait until this request is finished.
         */
        final synchronized void waitUntilFinished() {
            while (!finished) {
                try {
                    wait(5000);
                } catch (InterruptedException ex) {
                    // Ignore
                }
            }
            if (exception != null) {
                //todo debug
                exception.printStackTrace();
                throw new RuntimeException(errorMessage(), exception);
            }
        }

        final synchronized void setFinished() {
            finished = true;
            notifyAll();
        }

        final void execute() {
            try {
                doExecute();
            } catch (Throwable ex) {
                this.exception = ex;
            }
        }

        /**
         * Execute this request.
         */
        abstract void doExecute();

        /**
         * Gets request specific error message.
         *
         * @return
         */
        abstract String errorMessage();
    }

    static final class CompileRequest extends Request {

        private final VmMethod method;

        private final int optLevel;

        private final boolean enableTestCompilers;

        /**
         * @param method
         * @param optLevel
         * @param enableTestCompilers
         */
        CompileRequest(final VmMethod method, final int optLevel,
                       final boolean enableTestCompilers) {
            this.method = method;
            this.optLevel = optLevel;
            this.enableTestCompilers = enableTestCompilers;
        }

        /**
         * Execute this request.
         *
         * @see org.jnode.vm.LoadCompileService.Request#execute()
         */
        void doExecute() {
            service.doCompile(method, optLevel, enableTestCompilers);
        }

        /**
         * @see org.jnode.vm.LoadCompileService.Request#errorMessage()
         */
        @Override
        String errorMessage() {
            return "Error in compilation: ";
        }
    }

    static final class LoadRequest extends Request {
        private final String name;

        private final ByteBuffer data;

        private final ProtectionDomain protDomain;

        private final VmClassLoader loader;

        private VmType<?> definedType;

        /**
         * @param name
         * @param data
         * @param protDomain
         * @param loader
         */
        LoadRequest(final String name, final ByteBuffer data,
                    final ProtectionDomain protDomain, final VmClassLoader loader) {
            this.name = name;
            this.data = data;
            this.protDomain = protDomain;
            this.loader = loader;
        }

        /**
         * Execute this request.
         *
         * @see org.jnode.vm.LoadCompileService.Request#execute()
         */
        void doExecute() {
            definedType = service.doDefineClass(name, data, protDomain, loader);
        }

        /**
         * @return the definedType
         */
        final VmType<?> getDefinedType() {
            return definedType;
        }

        /**
         * @see org.jnode.vm.LoadCompileService.Request#errorMessage()
         */
        @Override
        String errorMessage() {
            return "Error in class loading: ";
        }
    }
}
TOP

Related Classes of org.jnode.vm.LoadCompileService$LoadRequest

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.