src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java
changeset 54669 ad45b3802d4e
parent 54647 c0d9bc9b4e1f
child 54732 2d012a75d35c
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Wed May 01 12:41:26 2019 -0400
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Wed May 01 12:31:29 2019 -0700
@@ -23,11 +23,22 @@
 package jdk.vm.ci.hotspot;
 
 import static jdk.vm.ci.common.InitTimer.timer;
+import static jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory.CompilationLevelAdjustment.None;
+import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE;
+import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
 
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.PrintStream;
+import java.io.Serializable;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.ConstantCallSite;
+import java.lang.invoke.MethodHandle;
 import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.ref.WeakReference;
+
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -35,11 +46,11 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.ServiceLoader;
-import java.util.Set;
+import java.util.TreeMap;
 import java.util.function.Predicate;
 
-import jdk.internal.misc.VM;
 import jdk.internal.misc.Unsafe;
+
 import jdk.vm.ci.code.Architecture;
 import jdk.vm.ci.code.CompilationRequestResult;
 import jdk.vm.ci.code.CompiledCode;
@@ -57,44 +68,144 @@
 import jdk.vm.ci.runtime.JVMCICompilerFactory;
 import jdk.vm.ci.runtime.JVMCIRuntime;
 import jdk.vm.ci.services.JVMCIServiceLocator;
-
-import static jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory.CompilationLevelAdjustment.None;
+import jdk.vm.ci.services.Services;
 
 /**
  * HotSpot implementation of a JVMCI runtime.
- *
- * The initialization of this class is very fragile since it's initialized both through
- * {@link JVMCI#initialize()} or through calling {@link HotSpotJVMCIRuntime#runtime()} and
- * {@link HotSpotJVMCIRuntime#runtime()} is also called by {@link JVMCI#initialize()}. So this class
- * can't have a static initializer and any required initialization must be done as part of
- * {@link #runtime()}. This allows the initialization to funnel back through
- * {@link JVMCI#initialize()} without deadlocking.
  */
 public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
 
-    @SuppressWarnings("try")
-    static class DelayedInit {
-        private static final HotSpotJVMCIRuntime instance;
+    /**
+     * Singleton instance lazily initialized via double-checked locking.
+     */
+    @NativeImageReinitialize private static volatile HotSpotJVMCIRuntime instance;
+
+    private HotSpotResolvedObjectTypeImpl javaLangObject;
+    private HotSpotResolvedObjectTypeImpl javaLangInvokeMethodHandle;
+    private HotSpotResolvedObjectTypeImpl constantCallSiteType;
+    private HotSpotResolvedObjectTypeImpl callSiteType;
+    private HotSpotResolvedObjectTypeImpl javaLangString;
+    private HotSpotResolvedObjectTypeImpl javaLangClass;
+    private HotSpotResolvedObjectTypeImpl throwableType;
+    private HotSpotResolvedObjectTypeImpl serializableType;
+    private HotSpotResolvedObjectTypeImpl cloneableType;
+    private HotSpotResolvedObjectTypeImpl enumType;
 
-        static {
-            try (InitTimer t = timer("HotSpotJVMCIRuntime.<init>")) {
-                instance = new HotSpotJVMCIRuntime();
+    HotSpotResolvedObjectTypeImpl getJavaLangObject() {
+        if (javaLangObject == null) {
+            javaLangObject = (HotSpotResolvedObjectTypeImpl) fromClass(Object.class);
+        }
+        return javaLangObject;
+    }
+
+    HotSpotResolvedObjectTypeImpl getJavaLangString() {
+        if (javaLangString == null) {
+            javaLangString = (HotSpotResolvedObjectTypeImpl) fromClass(String.class);
+        }
+        return javaLangString;
+    }
+
+    HotSpotResolvedObjectTypeImpl getJavaLangClass() {
+        if (javaLangClass == null) {
+            javaLangClass = (HotSpotResolvedObjectTypeImpl) fromClass(Class.class);
+        }
+        return javaLangClass;
+    }
 
-                // Can only do eager initialization of the JVMCI compiler
-                // once the singleton instance is available.
-                if (instance.config.getFlag("EagerJVMCI", Boolean.class)) {
-                    instance.getCompiler();
-                }
-            }
+    HotSpotResolvedObjectTypeImpl getJavaLangCloneable() {
+        if (cloneableType == null) {
+            cloneableType = (HotSpotResolvedObjectTypeImpl) fromClass(Cloneable.class);
+        }
+        return cloneableType;
+    }
+
+    HotSpotResolvedObjectTypeImpl getJavaLangSerializable() {
+        if (serializableType == null) {
+            serializableType = (HotSpotResolvedObjectTypeImpl) fromClass(Serializable.class);
+        }
+        return serializableType;
+    }
+
+    HotSpotResolvedObjectTypeImpl getJavaLangThrowable() {
+        if (throwableType == null) {
+            throwableType = (HotSpotResolvedObjectTypeImpl) fromClass(Throwable.class);
         }
+        return throwableType;
+    }
+
+    HotSpotResolvedObjectTypeImpl getJavaLangEnum() {
+        if (enumType == null) {
+            enumType = (HotSpotResolvedObjectTypeImpl) fromClass(Enum.class);
+        }
+        return enumType;
+    }
+
+    HotSpotResolvedObjectTypeImpl getConstantCallSite() {
+        if (constantCallSiteType == null) {
+            constantCallSiteType = (HotSpotResolvedObjectTypeImpl) fromClass(ConstantCallSite.class);
+        }
+        return constantCallSiteType;
+    }
+
+    HotSpotResolvedObjectTypeImpl getCallSite() {
+        if (callSiteType == null) {
+            callSiteType = (HotSpotResolvedObjectTypeImpl) fromClass(CallSite.class);
+        }
+        return callSiteType;
+    }
+
+    HotSpotResolvedObjectType getMethodHandleClass() {
+        if (javaLangInvokeMethodHandle == null) {
+            javaLangInvokeMethodHandle = (HotSpotResolvedObjectTypeImpl) fromClass(MethodHandle.class);
+        }
+        return javaLangInvokeMethodHandle;
     }
 
     /**
      * Gets the singleton {@link HotSpotJVMCIRuntime} object.
      */
+    @VMEntryPoint
+    @SuppressWarnings("try")
     public static HotSpotJVMCIRuntime runtime() {
-        JVMCI.initialize();
-        return DelayedInit.instance;
+        HotSpotJVMCIRuntime result = instance;
+        if (result == null) {
+            // Synchronize on JVMCI.class to avoid deadlock
+            // between the two JVMCI initialization paths:
+            // HotSpotJVMCIRuntime.runtime() and JVMCI.getRuntime().
+            synchronized (JVMCI.class) {
+                result = instance;
+                if (result == null) {
+                    try (InitTimer t = timer("HotSpotJVMCIRuntime.<init>")) {
+                        instance = result = new HotSpotJVMCIRuntime();
+
+                        // Can only do eager initialization of the JVMCI compiler
+                        // once the singleton instance is available.
+                        if (instance.config.getFlag("EagerJVMCI", Boolean.class)) {
+                            instance.getCompiler();
+                        }
+                    }
+                    // Ensures JVMCIRuntime::_HotSpotJVMCIRuntime_instance is
+                    // initialized.
+                    JVMCI.getRuntime();
+                }
+            }
+        }
+        return result;
+    }
+
+    @VMEntryPoint
+    static Throwable decodeThrowable(String encodedThrowable) throws Throwable {
+        return TranslatedException.decodeThrowable(encodedThrowable);
+    }
+
+    @VMEntryPoint
+    static String encodeThrowable(Throwable throwable) throws Throwable {
+        return TranslatedException.encodeThrowable(throwable);
+    }
+
+    @VMEntryPoint
+    static String callToString(Object o) {
+        return o.toString();
     }
 
     /**
@@ -103,17 +214,17 @@
     public enum Option {
         // @formatter:off
         Compiler(String.class, null, "Selects the system compiler. This must match the getCompilerName() value returned " +
-                                     "by a jdk.vm.ci.runtime.JVMCICompilerFactory provider. " +
-                                     "An empty string or the value \"null\" selects a compiler " +
-                                     "that will raise an exception upon receiving a compilation request."),
+                "by a jdk.vm.ci.runtime.JVMCICompilerFactory provider. " +
+                "An empty string or the value \"null\" selects a compiler " +
+                "that will raise an exception upon receiving a compilation request."),
         // Note: The following one is not used (see InitTimer.ENABLED). It is added here
         // so that -XX:+JVMCIPrintProperties shows the option.
         InitTimer(Boolean.class, false, "Specifies if initialization timing is enabled."),
         PrintConfig(Boolean.class, false, "Prints VM configuration available via JVMCI."),
         TraceMethodDataFilter(String.class, null,
-                        "Enables tracing of profiling info when read by JVMCI.",
-                        "Empty value: trace all methods",
-                        "Non-empty value: trace methods whose fully qualified name contains the value."),
+                "Enables tracing of profiling info when read by JVMCI.",
+                "Empty value: trace all methods",
+                "Non-empty value: trace methods whose fully qualified name contains the value."),
         UseProfilingInformation(Boolean.class, true, "");
         // @formatter:on
 
@@ -123,12 +234,12 @@
         private static final String JVMCI_OPTION_PROPERTY_PREFIX = "jvmci.";
 
         /**
-         * Marker for uninitialized flags.
+         * Sentinel for value initialized to {@code null} since {@code null} means uninitialized.
          */
-        private static final String UNINITIALIZED = "UNINITIALIZED";
+        private static final String NULL_VALUE = "NULL";
 
         private final Class<?> type;
-        private Object value;
+        @NativeImageReinitialize private Object value;
         private final Object defaultValue;
         private boolean isDefault;
         private final String[] helpLines;
@@ -136,17 +247,16 @@
         Option(Class<?> type, Object defaultValue, String... helpLines) {
             assert Character.isUpperCase(name().charAt(0)) : "Option name must start with upper-case letter: " + name();
             this.type = type;
-            this.value = UNINITIALIZED;
             this.defaultValue = defaultValue;
             this.helpLines = helpLines;
         }
 
         @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "sentinel must be String since it's a static final in an enum")
         private Object getValue() {
-            if (value == UNINITIALIZED) {
-                String propertyValue = VM.getSavedProperty(getPropertyName());
+            if (value == null) {
+                String propertyValue = Services.getSavedProperty(getPropertyName());
                 if (propertyValue == null) {
-                    this.value = defaultValue;
+                    this.value = defaultValue == null ? NULL_VALUE : defaultValue;
                     this.isDefault = true;
                 } else {
                     if (type == Boolean.class) {
@@ -158,10 +268,8 @@
                     }
                     this.isDefault = false;
                 }
-                // Saved properties should not be interned - let's be sure
-                assert value != UNINITIALIZED;
             }
-            return value;
+            return value == NULL_VALUE ? null : value;
         }
 
         /**
@@ -224,8 +332,10 @@
         }
     }
 
-    static HotSpotJVMCIBackendFactory findFactory(String architecture) {
-        for (HotSpotJVMCIBackendFactory factory : ServiceLoader.load(HotSpotJVMCIBackendFactory.class, ClassLoader.getSystemClassLoader())) {
+    private static HotSpotJVMCIBackendFactory findFactory(String architecture) {
+        Iterable<HotSpotJVMCIBackendFactory> factories = getHotSpotJVMCIBackendFactories();
+assert factories != null : "sanity";
+        for (HotSpotJVMCIBackendFactory factory : factories) {
             if (factory.getArchitecture().equalsIgnoreCase(architecture)) {
                 return factory;
             }
@@ -234,6 +344,23 @@
         throw new JVMCIError("No JVMCI runtime available for the %s architecture", architecture);
     }
 
+    private static volatile List<HotSpotJVMCIBackendFactory> cachedHotSpotJVMCIBackendFactories;
+
+    @SuppressFBWarnings(value = "LI_LAZY_INIT_UPDATE_STATIC", justification = "not sure about this")
+    private static Iterable<HotSpotJVMCIBackendFactory> getHotSpotJVMCIBackendFactories() {
+        if (IS_IN_NATIVE_IMAGE || cachedHotSpotJVMCIBackendFactories != null) {
+            return cachedHotSpotJVMCIBackendFactories;
+        }
+        Iterable<HotSpotJVMCIBackendFactory> result = ServiceLoader.load(HotSpotJVMCIBackendFactory.class, ClassLoader.getSystemClassLoader());
+        if (IS_BUILDING_NATIVE_IMAGE) {
+            cachedHotSpotJVMCIBackendFactories = new ArrayList<>();
+            for (HotSpotJVMCIBackendFactory factory : result) {
+                cachedHotSpotJVMCIBackendFactories.add(factory);
+            }
+        }
+        return result;
+    }
+
     /**
      * Gets the kind of a word value on the {@linkplain #getHostJVMCIBackend() host} backend.
      */
@@ -241,22 +368,32 @@
         return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordJavaKind;
     }
 
-    final CompilerToVM compilerToVm;
+    protected final CompilerToVM compilerToVm;
 
     protected final HotSpotVMConfigStore configStore;
-    private final HotSpotVMConfig config;
+    protected final HotSpotVMConfig config;
     private final JVMCIBackend hostBackend;
 
     private final JVMCICompilerFactory compilerFactory;
     private final HotSpotJVMCICompilerFactory hsCompilerFactory;
     private volatile JVMCICompiler compiler;
-    final HotSpotJVMCIMetaAccessContext metaAccessContext;
+    protected final HotSpotJVMCIReflection reflection;
+
+    @NativeImageReinitialize private volatile boolean creatingCompiler;
+
+    /**
+     * Cache for speeding up {@link #fromClass(Class)}.
+     */
+    @NativeImageReinitialize private volatile ClassValue<WeakReference<HotSpotResolvedJavaType>> resolvedJavaType;
+
+    @NativeImageReinitialize private HashMap<Long, WeakReference<ResolvedJavaType>> resolvedJavaTypes;
 
     /**
      * Stores the value set by {@link #excludeFromJVMCICompilation(Module...)} so that it can
      * be read from the VM.
      */
-    @SuppressWarnings("unused") @NativeImageReinitialize private Module[] excludeFromJVMCICompilation;
+    @SuppressWarnings("unused")//
+    @NativeImageReinitialize private Module[] excludeFromJVMCICompilation;
 
 
     private final Map<Class<? extends Architecture>, JVMCIBackend> backends = new HashMap<>();
@@ -283,6 +420,16 @@
             config = new HotSpotVMConfig(configStore);
         }
 
+        reflection = IS_IN_NATIVE_IMAGE ? new SharedLibraryJVMCIReflection() : new HotSpotJDKReflection();
+
+        PrintStream vmLogStream = null;
+        if (IS_IN_NATIVE_IMAGE) {
+            // Redirect System.out and System.err to HotSpot's TTY stream
+            vmLogStream = new PrintStream(getLogStream());
+            System.setOut(vmLogStream);
+            System.setErr(vmLogStream);
+        }
+
         String hostArchitecture = config.getHostArchitectureName();
 
         HotSpotJVMCIBackendFactory factory;
@@ -294,8 +441,6 @@
             hostBackend = registerBackend(factory.createJVMCIBackend(this, null));
         }
 
-        metaAccessContext = new HotSpotJVMCIMetaAccessContext();
-
         compilerFactory = HotSpotJVMCICompilerConfig.getCompilerFactory();
         if (compilerFactory instanceof HotSpotJVMCICompilerFactory) {
             hsCompilerFactory = (HotSpotJVMCICompilerFactory) compilerFactory;
@@ -310,15 +455,89 @@
         }
 
         if (config.getFlag("JVMCIPrintProperties", Boolean.class)) {
-            PrintStream out = new PrintStream(getLogStream());
-            Option.printProperties(out);
-            compilerFactory.printProperties(out);
+            if (vmLogStream == null) {
+                vmLogStream = new PrintStream(getLogStream());
+            }
+            Option.printProperties(vmLogStream);
+            compilerFactory.printProperties(vmLogStream);
             System.exit(0);
         }
 
         if (Option.PrintConfig.getBoolean()) {
-            configStore.printConfig();
+            printConfig(configStore, compilerToVm);
+        }
+    }
+
+    HotSpotResolvedJavaType createClass(Class<?> javaClass) {
+        if (javaClass.isPrimitive()) {
+            return HotSpotResolvedPrimitiveType.forKind(JavaKind.fromJavaClass(javaClass));
+        }
+        if (IS_IN_NATIVE_IMAGE) {
+            try {
+                return compilerToVm.lookupType(javaClass.getName().replace('.', '/'), null, true);
+            } catch (ClassNotFoundException e) {
+                throw new JVMCIError(e);
+            }
+        }
+        return compilerToVm.lookupClass(javaClass);
+    }
+
+    private HotSpotResolvedJavaType fromClass0(Class<?> javaClass) {
+        if (resolvedJavaType == null) {
+            synchronized (this) {
+                if (resolvedJavaType == null) {
+                    resolvedJavaType = new ClassValue<WeakReference<HotSpotResolvedJavaType>>() {
+                        @Override
+                        protected WeakReference<HotSpotResolvedJavaType> computeValue(Class<?> type) {
+                            return new WeakReference<>(createClass(type));
+                        }
+                    };
+                }
+            }
         }
+        HotSpotResolvedJavaType javaType = null;
+        while (javaType == null) {
+            WeakReference<HotSpotResolvedJavaType> type = resolvedJavaType.get(javaClass);
+            javaType = type.get();
+            if (javaType == null) {
+                /*
+                 * If the referent has become null, clear out the current value and let computeValue
+                 * above create a new value. Reload the value in a loop because in theory the
+                 * WeakReference referent can be reclaimed at any point.
+                 */
+                resolvedJavaType.remove(javaClass);
+            }
+        }
+        return javaType;
+    }
+
+    /**
+     * Gets the JVMCI mirror for a {@link Class} object.
+     *
+     * @return the {@link ResolvedJavaType} corresponding to {@code javaClass}
+     */
+    HotSpotResolvedJavaType fromClass(Class<?> javaClass) {
+        if (javaClass == null) {
+            return null;
+        }
+        return fromClass0(javaClass);
+    }
+
+    synchronized HotSpotResolvedObjectTypeImpl fromMetaspace(long klassPointer, String signature) {
+        if (resolvedJavaTypes == null) {
+            resolvedJavaTypes = new HashMap<>();
+        }
+        assert klassPointer != 0;
+        WeakReference<ResolvedJavaType> klassReference = resolvedJavaTypes.get(klassPointer);
+        HotSpotResolvedObjectTypeImpl javaType = null;
+        if (klassReference != null) {
+            javaType = (HotSpotResolvedObjectTypeImpl) klassReference.get();
+        }
+        if (javaType == null) {
+            javaType = new HotSpotResolvedObjectTypeImpl(klassPointer, signature);
+            resolvedJavaTypes.put(klassPointer, new WeakReference<>(javaType));
+        }
+        return javaType;
     }
 
     private JVMCIBackend registerBackend(JVMCIBackend backend) {
@@ -328,24 +547,21 @@
         return backend;
     }
 
-    ResolvedJavaType fromClass(Class<?> javaClass) {
-        return metaAccessContext.fromClass(javaClass);
-    }
-
     public HotSpotVMConfigStore getConfigStore() {
         return configStore;
     }
 
-    HotSpotVMConfig getConfig() {
+    public HotSpotVMConfig getConfig() {
         return config;
     }
 
-    CompilerToVM getCompilerToVM() {
+    public CompilerToVM getCompilerToVM() {
         return compilerToVm;
     }
 
-    // Non-volatile since multi-initialization is harmless
-    private Predicate<ResolvedJavaType> intrinsificationTrustPredicate;
+    HotSpotJVMCIReflection getReflection() {
+        return reflection;
+    }
 
     /**
      * Gets a predicate that determines if a given type can be considered trusted for the purpose of
@@ -355,47 +571,17 @@
      *            compiler.
      */
     public Predicate<ResolvedJavaType> getIntrinsificationTrustPredicate(Class<?>... compilerLeafClasses) {
-        if (intrinsificationTrustPredicate == null) {
-            intrinsificationTrustPredicate = new Predicate<>() {
-                @Override
-                public boolean test(ResolvedJavaType type) {
-                    if (type instanceof HotSpotResolvedJavaType) {
-                        Class<?> mirror = getMirror(type);
-                        Module module = mirror.getModule();
-                        return getTrustedModules().contains(module);
-                    } else {
-                        return false;
-                    }
+        return new Predicate<ResolvedJavaType>() {
+            @Override
+            public boolean test(ResolvedJavaType type) {
+                if (type instanceof HotSpotResolvedObjectTypeImpl) {
+                    HotSpotResolvedObjectTypeImpl hsType = (HotSpotResolvedObjectTypeImpl) type;
+                    return compilerToVm.isTrustedForIntrinsics(hsType);
+                } else {
+                    return false;
                 }
-
-                private volatile Set<Module> trustedModules;
-
-                private Set<Module> getTrustedModules() {
-                    Set<Module> modules = trustedModules;
-                    if (modules == null) {
-                        modules = new HashSet<>();
-                        for (Class<?> compilerConfiguration : compilerLeafClasses) {
-                            Module compilerConfigurationModule = compilerConfiguration.getModule();
-                            if (compilerConfigurationModule.getDescriptor().isAutomatic()) {
-                                throw new IllegalArgumentException(String.format("The module '%s' defining the Graal compiler configuration class '%s' must not be an automatic module",
-                                                compilerConfigurationModule.getName(), compilerConfiguration.getClass().getName()));
-                            }
-                            modules.add(compilerConfigurationModule);
-                            for (Requires require : compilerConfigurationModule.getDescriptor().requires()) {
-                                for (Module module : compilerConfigurationModule.getLayer().modules()) {
-                                    if (module.getName().equals(require.name())) {
-                                        modules.add(module);
-                                    }
-                                }
-                            }
-                        }
-                        trustedModules = modules;
-                    }
-                    return modules;
-                }
-            };
-        }
-        return intrinsificationTrustPredicate;
+            }
+        };
     }
 
     /**
@@ -406,9 +592,11 @@
      *         does not support mapping {@link ResolvedJavaType} instances to {@link Class}
      *         instances
      */
-    @SuppressWarnings("static-method")
     public Class<?> getMirror(ResolvedJavaType type) {
-        return ((HotSpotResolvedJavaType) type).mirror();
+        if (type instanceof HotSpotResolvedJavaType && reflection instanceof HotSpotJDKReflection) {
+            return ((HotSpotJDKReflection) reflection).getMirror((HotSpotResolvedJavaType) type);
+        }
+        return null;
     }
 
     @Override
@@ -416,7 +604,10 @@
         if (compiler == null) {
             synchronized (this) {
                 if (compiler == null) {
+                    assert !creatingCompiler : "recursive compiler creation";
+                    creatingCompiler = true;
                     compiler = compilerFactory.createCompiler(this);
+                    creatingCompiler = false;
                 }
             }
         }
@@ -438,19 +629,23 @@
      */
     public JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve) {
         Objects.requireNonNull(accessingType, "cannot resolve type without an accessing class");
+        return lookupTypeInternal(name, accessingType, resolve);
+    }
+
+    JavaType lookupTypeInternal(String name, HotSpotResolvedObjectType accessingType, boolean resolve) {
         // If the name represents a primitive type we can short-circuit the lookup.
         if (name.length() == 1) {
             JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0));
-            return fromClass(kind.toJavaClass());
+            return HotSpotResolvedPrimitiveType.forKind(kind);
         }
 
         // Resolve non-primitive types in the VM.
         HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType;
         try {
-            final HotSpotResolvedObjectTypeImpl klass = compilerToVm.lookupType(name, hsAccessingType.mirror(), resolve);
+            final HotSpotResolvedJavaType klass = compilerToVm.lookupType(name, hsAccessingType, resolve);
 
             if (klass == null) {
-                assert resolve == false;
+                assert resolve == false : name;
                 return UnresolvedJavaType.create(name);
             }
             return klass;
@@ -474,12 +669,9 @@
         return Collections.unmodifiableMap(backends);
     }
 
-    /**
-     * Called from the VM.
-     */
-    @SuppressWarnings({"unused"})
-    private HotSpotCompilationRequestResult compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id) {
-        CompilationRequestResult result = getCompiler().compileMethod(new HotSpotCompilationRequest(method, entryBCI, jvmciEnv, id));
+    @VMEntryPoint
+    private HotSpotCompilationRequestResult compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long compileState, int id) {
+        CompilationRequestResult result = getCompiler().compileMethod(new HotSpotCompilationRequest(method, entryBCI, compileState, id));
         assert result != null : "compileMethod must always return something";
         HotSpotCompilationRequestResult hsResult;
         if (result instanceof HotSpotCompilationRequestResult) {
@@ -500,11 +692,13 @@
 
     /**
      * Shuts down the runtime.
-     *
-     * Called from the VM.
      */
-    @SuppressWarnings({"unused"})
+    @VMEntryPoint
     private void shutdown() throws Exception {
+        // Cleaners are normally only processed when a new Cleaner is
+        // instantiated so process all remaining cleaners now.
+        Cleaner.clean();
+
         for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) {
             vmEventListener.notifyShutdown();
         }
@@ -512,10 +706,8 @@
 
     /**
      * Notify on completion of a bootstrap.
-     *
-     * Called from the VM.
      */
-    @SuppressWarnings({"unused"})
+    @VMEntryPoint
     private void bootstrapFinished() throws Exception {
         for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) {
             vmEventListener.notifyBootstrapFinished();
@@ -535,6 +727,41 @@
         }
     }
 
+    @SuppressFBWarnings(value = "DM_DEFAULT_ENCODING", justification = "no localization here please!")
+    private static void printConfigLine(CompilerToVM vm, String format, Object... args) {
+        String line = String.format(format, args);
+        byte[] lineBytes = line.getBytes();
+        vm.writeDebugOutput(lineBytes, 0, lineBytes.length);
+        vm.flushDebugOutput();
+    }
+
+    private static void printConfig(HotSpotVMConfigStore store, CompilerToVM vm) {
+        TreeMap<String, VMField> fields = new TreeMap<>(store.getFields());
+        for (VMField field : fields.values()) {
+            if (!field.isStatic()) {
+                printConfigLine(vm, "[vmconfig:instance field] %s %s {offset=%d[0x%x]}%n", field.type, field.name, field.offset, field.offset);
+            } else {
+                String value = field.value == null ? "null" : field.value instanceof Boolean ? field.value.toString() : String.format("%d[0x%x]", field.value, field.value);
+                printConfigLine(vm, "[vmconfig:static field] %s %s = %s {address=0x%x}%n", field.type, field.name, value, field.address);
+            }
+        }
+        TreeMap<String, VMFlag> flags = new TreeMap<>(store.getFlags());
+        for (VMFlag flag : flags.values()) {
+            printConfigLine(vm, "[vmconfig:flag] %s %s = %s%n", flag.type, flag.name, flag.value);
+        }
+        TreeMap<String, Long> addresses = new TreeMap<>(store.getAddresses());
+        for (Map.Entry<String, Long> e : addresses.entrySet()) {
+            printConfigLine(vm, "[vmconfig:address] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue());
+        }
+        TreeMap<String, Long> constants = new TreeMap<>(store.getConstants());
+        for (Map.Entry<String, Long> e : constants.entrySet()) {
+            printConfigLine(vm, "[vmconfig:constant] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue());
+        }
+        for (VMIntrinsicMethod e : store.getIntrinsics()) {
+            printConfigLine(vm, "[vmconfig:intrinsic] %d = %s.%s %s%n", e.id, e.declaringClass, e.name, e.descriptor);
+        }
+    }
+
     /**
      * Gets an output stream that writes to HotSpot's {@code tty} stream.
      */
@@ -577,27 +804,26 @@
      *
      * @return the offset in bytes
      */
-    @SuppressWarnings("static-method")
     public int getArrayBaseOffset(JavaKind kind) {
         switch (kind) {
             case Boolean:
-                return Unsafe.ARRAY_BOOLEAN_BASE_OFFSET;
+                return compilerToVm.ARRAY_BOOLEAN_BASE_OFFSET;
             case Byte:
-                return Unsafe.ARRAY_BYTE_BASE_OFFSET;
+                return compilerToVm.ARRAY_BYTE_BASE_OFFSET;
             case Char:
-                return Unsafe.ARRAY_CHAR_BASE_OFFSET;
+                return compilerToVm.ARRAY_CHAR_BASE_OFFSET;
             case Short:
-                return Unsafe.ARRAY_SHORT_BASE_OFFSET;
+                return compilerToVm.ARRAY_SHORT_BASE_OFFSET;
             case Int:
-                return Unsafe.ARRAY_INT_BASE_OFFSET;
+                return compilerToVm.ARRAY_INT_BASE_OFFSET;
             case Long:
-                return Unsafe.ARRAY_LONG_BASE_OFFSET;
+                return compilerToVm.ARRAY_LONG_BASE_OFFSET;
             case Float:
-                return Unsafe.ARRAY_FLOAT_BASE_OFFSET;
+                return compilerToVm.ARRAY_FLOAT_BASE_OFFSET;
             case Double:
-                return Unsafe.ARRAY_DOUBLE_BASE_OFFSET;
+                return compilerToVm.ARRAY_DOUBLE_BASE_OFFSET;
             case Object:
-                return Unsafe.ARRAY_OBJECT_BASE_OFFSET;
+                return compilerToVm.ARRAY_OBJECT_BASE_OFFSET;
             default:
                 throw new JVMCIError("%s", kind);
         }
@@ -609,27 +835,26 @@
      *
      * @return the scale in order to convert the index into a byte offset
      */
-    @SuppressWarnings("static-method")
     public int getArrayIndexScale(JavaKind kind) {
         switch (kind) {
             case Boolean:
-                return Unsafe.ARRAY_BOOLEAN_INDEX_SCALE;
+                return compilerToVm.ARRAY_BOOLEAN_INDEX_SCALE;
             case Byte:
-                return Unsafe.ARRAY_BYTE_INDEX_SCALE;
+                return compilerToVm.ARRAY_BYTE_INDEX_SCALE;
             case Char:
-                return Unsafe.ARRAY_CHAR_INDEX_SCALE;
+                return compilerToVm.ARRAY_CHAR_INDEX_SCALE;
             case Short:
-                return Unsafe.ARRAY_SHORT_INDEX_SCALE;
+                return compilerToVm.ARRAY_SHORT_INDEX_SCALE;
             case Int:
-                return Unsafe.ARRAY_INT_INDEX_SCALE;
+                return compilerToVm.ARRAY_INT_INDEX_SCALE;
             case Long:
-                return Unsafe.ARRAY_LONG_INDEX_SCALE;
+                return compilerToVm.ARRAY_LONG_INDEX_SCALE;
             case Float:
-                return Unsafe.ARRAY_FLOAT_INDEX_SCALE;
+                return compilerToVm.ARRAY_FLOAT_INDEX_SCALE;
             case Double:
-                return Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
+                return compilerToVm.ARRAY_DOUBLE_INDEX_SCALE;
             case Object:
-                return Unsafe.ARRAY_OBJECT_INDEX_SCALE;
+                return compilerToVm.ARRAY_OBJECT_INDEX_SCALE;
             default:
                 throw new JVMCIError("%s", kind);
 
@@ -637,10 +862,10 @@
     }
 
     /**
-     * Links each native method in {@code clazz} to an implementation in the JVMCI SVM library.
+     * Links each native method in {@code clazz} to an implementation in the JVMCI shared library.
      * <p>
      * A use case for this is a JVMCI compiler implementation that offers an API to Java code
-     * executing in HotSpot to exercise functionality (mostly) in the JVMCI SVM library. For
+     * executing in HotSpot to exercise functionality (mostly) in the JVMCI shared library. For
      * example:
      *
      * <pre>
@@ -665,28 +890,73 @@
      * }
      * </pre>
      *
-     * The implementation of the native {@code JCompile.compile0} method would be in the SVM library
-     * that contains the bulk of the JVMCI compiler. The {@code JCompile.compile0} implementation
-     * will be exported as the following JNI-compliant symbol:
+     * The implementation of the native {@code JCompile.compile0} method would be in the JVMCI
+     * shared library that contains the bulk of the JVMCI compiler. The {@code JCompile.compile0}
+     * implementation will be exported as the following JNI-compatible symbol:
      *
      * <pre>
      * Java_com_jcompile_JCompile_compile0
      * </pre>
      *
-     * How the JVMCI compiler SVM library is built is outside the scope of this document.
+     * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names"
+     * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#creating_the_vm"
+     * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#invocation_api_functions"
      *
-     * @see "https://docs.oracle.com/javase/10/docs/specs/jni/design.html#resolving-native-method-names"
      *
+     * @return an array of 4 longs where the first value is the {@code JavaVM*} value representing
+     *         the Java VM in the JVMCI shared library, and the remaining values are the first 3
+     *         pointers in the Invocation API function table (i.e., {@code JNIInvokeInterface})
      * @throws NullPointerException if {@code clazz == null}
-     * @throws IllegalArgumentException if the current execution context is SVM or if {@code clazz}
-     *             is {@link Class#isPrimitive()}
-     * @throws UnsatisfiedLinkError if the JVMCI SVM library is not available, a native method in
-     *             {@code clazz} is already linked or the SVM JVMCI library does not contain a
-     *             JNI-compliant symbol for a native method in {@code clazz}
+     * @throws IllegalArgumentException if the current execution context is the JVMCI shared library
+     *             or if {@code clazz} is {@link Class#isPrimitive()}
+     * @throws UnsatisfiedLinkError if the JVMCI shared library is not available, a native method in
+     *             {@code clazz} is already linked or the JVMCI shared library does not contain a
+     *             JNI-compatible symbol for a native method in {@code clazz}
      */
-    @SuppressWarnings({"static-method", "unused"})
-    public void registerNativeMethods(Class<?> clazz) {
-        throw new UnsatisfiedLinkError("SVM library is not available");
+    public long[] registerNativeMethods(Class<?> clazz) {
+        return compilerToVm.registerNativeMethods(clazz);
+    }
+
+    /**
+     * Creates or retrieves an object in the peer runtime that mirrors {@code obj}. The types whose
+     * objects can be translated are:
+     * <ul>
+     * <li>{@link HotSpotResolvedJavaMethodImpl},</li>
+     * <li>{@link HotSpotResolvedObjectTypeImpl},</li>
+     * <li>{@link HotSpotResolvedPrimitiveType},</li>
+     * <li>{@link IndirectHotSpotObjectConstantImpl},</li>
+     * <li>{@link DirectHotSpotObjectConstantImpl} and</li>
+     * <li>{@link HotSpotNmethod}</li>
+     * </ul>
+     *
+     * This mechanism can be used to pass and return values between the HotSpot and JVMCI shared
+     * library runtimes. In the receiving runtime, the value can be converted back to an object with
+     * {@link #unhand(Class, long)}.
+     *
+     * @param obj an object for which an equivalent instance in the peer runtime is requested
+     * @return a JNI global reference to the mirror of {@code obj} in the peer runtime
+     * @throws IllegalArgumentException if {@code obj} is not of a translatable type
+     *
+     * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references"
+     */
+    public long translate(Object obj) {
+        return compilerToVm.translate(obj);
+    }
+
+    /**
+     * Dereferences and returns the object referred to by the JNI global reference {@code handle}.
+     * The global reference is deleted prior to returning. Any further use of {@code handle} is
+     * invalid.
+     *
+     * @param handle a JNI global reference to an object in the current runtime
+     * @return the object referred to by {@code handle}
+     * @throws ClassCastException if the returned object cannot be case to {@code type}
+     *
+     * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references"
+     *
+     */
+    public <T> T unhand(Class<T> type, long handle) {
+        return type.cast(compilerToVm.unhand(handle));
     }
 
     /**