--- 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));
}
/**