Mercurial > hg > truffle
diff graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HotSpotJVMCIRuntime.java @ 21551:5324104ac4f3
moved com.oracle.graal.hotspot.jvmci classes to com.oracle.jvmci.hotspot module (JBS:GRAAL-53)
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Tue, 26 May 2015 17:13:37 +0200 |
parents | |
children | b1530a6cce8c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HotSpotJVMCIRuntime.java Tue May 26 17:13:37 2015 +0200 @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.jvmci.hotspot; + +import static com.oracle.jvmci.common.UnsafeAccess.*; +import static com.oracle.jvmci.hotspot.InitTimer.*; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.options.*; +import com.oracle.jvmci.common.*; +import com.oracle.jvmci.hotspot.logging.*; +import com.oracle.jvmci.runtime.*; + +//JaCoCo Exclude + +public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider, HotSpotProxified { + + private static final HotSpotJVMCIRuntime instance; + + static { + try (InitTimer t0 = timer("HotSpotJVMCIRuntime.<clinit>")) { + try (InitTimer t = timer("initialize HotSpotOptions")) { + HotSpotOptions.initialize(); + } + + try (InitTimer t = timer("HotSpotJVMCIRuntime.<init>")) { + instance = new HotSpotJVMCIRuntime(); + } + + try (InitTimer t = timer("HotSpotJVMCIRuntime.completeInitialization")) { + // Why deferred initialization? See comment in completeInitialization(). + instance.completeInitialization(); + } + } + } + + /** + * Gets the singleton {@link HotSpotJVMCIRuntime} object. + */ + public static HotSpotJVMCIRuntime runtime() { + assert instance != null; + return instance; + } + + /** + * Do deferred initialization. + */ + public void completeInitialization() { + TTY.initialize(Options.LogFile.getStream(compilerToVm)); + + // Proxies for the VM/Compiler interfaces cannot be initialized + // in the constructor as proxy creation causes static + // initializers to be executed for all the types involved in the + // proxied methods. Some of these static initializers (e.g. in + // HotSpotMethodData) rely on the static 'instance' field being set + // to retrieve configuration details. + CompilerToVM toVM = this.compilerToVm; + + if (CountingProxy.ENABLED) { + toVM = CountingProxy.getProxy(CompilerToVM.class, toVM); + } + if (Logger.ENABLED) { + toVM = LoggingProxy.getProxy(CompilerToVM.class, toVM); + } + + this.compilerToVm = toVM; + } + + public static class Options { + + // @formatter:off + @Option(help = "The JVMCI runtime configuration to use", type = OptionType.Expert) + public static final OptionValue<String> JVMCIRuntime = new OptionValue<>(""); + + @Option(help = "File to which logging is sent. A %p in the name will be replaced with a string identifying the process, usually the process id.", type = OptionType.Expert) + public static final PrintStreamOption LogFile = new PrintStreamOption(); + // @formatter:on + } + + public static HotSpotJVMCIBackendFactory findFactory(String architecture) { + HotSpotJVMCIBackendFactory basic = null; + HotSpotJVMCIBackendFactory selected = null; + HotSpotJVMCIBackendFactory nonBasic = null; + int nonBasicCount = 0; + + for (HotSpotJVMCIBackendFactory factory : Services.load(HotSpotJVMCIBackendFactory.class)) { + if (factory.getArchitecture().equalsIgnoreCase(architecture)) { + if (factory.getJVMCIRuntimeName().equals(Options.JVMCIRuntime.getValue())) { + assert selected == null || checkFactoryOverriding(selected, factory); + selected = factory; + } + if (factory.getJVMCIRuntimeName().equals("basic")) { + assert basic == null || checkFactoryOverriding(basic, factory); + basic = factory; + } else { + nonBasic = factory; + nonBasicCount++; + } + } + } + + if (selected != null) { + return selected; + } else { + if (!Options.JVMCIRuntime.getValue().equals("")) { + // Fail fast if a non-default value for JVMCIRuntime was specified + // and the corresponding factory is not available + throw new JVMCIError("Specified runtime \"%s\" not available for the %s architecture", Options.JVMCIRuntime.getValue(), architecture); + } else if (nonBasicCount == 1) { + // If there is exactly one non-basic runtime, select this one. + return nonBasic; + } else { + return basic; + } + } + } + + /** + * Checks that a factory overriding is valid. A factory B can only override/replace a factory A + * if the B.getClass() is a subclass of A.getClass(). This models the assumption that B is + * extends the behavior of A and has therefore understood the behavior expected of A. + * + * @param baseFactory + * @param overridingFactory + */ + private static boolean checkFactoryOverriding(HotSpotJVMCIBackendFactory baseFactory, HotSpotJVMCIBackendFactory overridingFactory) { + return baseFactory.getClass().isAssignableFrom(overridingFactory.getClass()); + } + + /** + * Gets the kind of a word value on the {@linkplain #getHostJVMCIBackend() host} backend. + */ + public static Kind getHostWordKind() { + return instance.getHostJVMCIBackend().getCodeCache().getTarget().wordKind; + } + + /** + * Reads a klass pointer from a constant object. + */ + public static long unsafeReadKlassPointer(Object object) { + return instance.getCompilerToVM().readUnsafeKlassPointer(object); + } + + /** + * Reads a word value from a given object. + */ + public static long unsafeReadWord(Object object, long offset) { + if (getHostWordKind() == Kind.Long) { + return unsafe.getLong(object, offset); + } + return unsafe.getInt(object, offset) & 0xFFFFFFFFL; + } + + protected/* final */CompilerToVM compilerToVm; + + protected final HotSpotVMConfig config; + private final JVMCIBackend hostBackend; + + /** + * Graal mirrors are stored as a {@link ClassValue} associated with the {@link Class} of the + * type. This data structure stores both {@link HotSpotResolvedObjectType} and + * {@link HotSpotResolvedPrimitiveType} types. + */ + private final ClassValue<ResolvedJavaType> graalMirrors = new ClassValue<ResolvedJavaType>() { + @Override + protected ResolvedJavaType computeValue(Class<?> javaClass) { + if (javaClass.isPrimitive()) { + Kind kind = Kind.fromJavaClass(javaClass); + return new HotSpotResolvedPrimitiveType(kind); + } else { + return new HotSpotResolvedObjectTypeImpl(javaClass); + } + } + }; + + private final Map<Class<? extends Architecture>, JVMCIBackend> backends = new HashMap<>(); + + private HotSpotJVMCIRuntime() { + CompilerToVM toVM = new CompilerToVMImpl(); + compilerToVm = toVM; + try (InitTimer t = timer("HotSpotVMConfig<init>")) { + config = new HotSpotVMConfig(compilerToVm); + } + + if (Boolean.valueOf(System.getProperty("graal.printconfig"))) { + printConfig(config); + } + + String hostArchitecture = config.getHostArchitectureName(); + + HotSpotJVMCIBackendFactory factory; + try (InitTimer t = timer("find factory:", hostArchitecture)) { + factory = findFactory(hostArchitecture); + } + try (InitTimer t = timer("create JVMCI backend:", hostArchitecture)) { + hostBackend = registerBackend(factory.createJVMCIBackend(this, null)); + } + } + + private JVMCIBackend registerBackend(JVMCIBackend backend) { + Class<? extends Architecture> arch = backend.getCodeCache().getTarget().arch.getClass(); + JVMCIBackend oldValue = backends.put(arch, backend); + assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName(); + return backend; + } + + public ResolvedJavaType fromClass(Class<?> javaClass) { + return graalMirrors.get(javaClass); + } + + private static void printConfig(HotSpotVMConfig config) { + Field[] fields = config.getClass().getDeclaredFields(); + Map<String, Field> sortedFields = new TreeMap<>(); + for (Field f : fields) { + f.setAccessible(true); + sortedFields.put(f.getName(), f); + } + for (Field f : sortedFields.values()) { + try { + Logger.info(String.format("%9s %-40s = %s", f.getType().getSimpleName(), f.getName(), Logger.pretty(f.get(config)))); + } catch (Exception e) { + } + } + } + + public HotSpotVMConfig getConfig() { + return config; + } + + public CompilerToVM getCompilerToVM() { + return compilerToVm; + } + + public JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve) { + Objects.requireNonNull(accessingType, "cannot resolve type without an accessing class"); + // If the name represents a primitive type we can short-circuit the lookup. + if (name.length() == 1) { + Kind kind = Kind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); + return fromClass(kind.toJavaClass()); + } + + // Resolve non-primitive types in the VM. + HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType; + final long metaspaceKlass = compilerToVm.lookupType(name, hsAccessingType.mirror(), resolve); + + if (metaspaceKlass == 0L) { + assert resolve == false; + return HotSpotUnresolvedJavaType.create(this, name); + } + return HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(metaspaceKlass); + } + + public JVMCIBackend getHostJVMCIBackend() { + return hostBackend; + } + + public <T extends Architecture> JVMCIBackend getJVMCIBackend(Class<T> arch) { + assert arch != Architecture.class; + return backends.get(arch); + } + + public Map<Class<? extends Architecture>, JVMCIBackend> getBackends() { + return Collections.unmodifiableMap(backends); + } + + /** + * Called from the VM. + */ + @SuppressWarnings({"unused", "static-method"}) + private void compileTheWorld() throws Throwable { + for (HotSpotVMEventListener l : Services.load(HotSpotVMEventListener.class)) { + l.notifyCompileTheWorld(); + } + } + + /** + * Shuts down the runtime. + * + * Called from the VM. + */ + @SuppressWarnings({"unused", "static-method"}) + private void shutdown() throws Exception { + for (HotSpotVMEventListener l : Services.load(HotSpotVMEventListener.class)) { + l.notifyShutdown(); + } + } +}