src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java
Index Unified diffs Context diffs Sdiffs Frames Patch New Old Previous File Next File
*** old/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Thu Mar 28 11:23:52 2019
--- new/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Thu Mar 28 11:23:52 2019

*** 1,7 **** --- 1,7 ---- /* ! * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ! * Copyright (c) 2015, 2019, 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.
*** 21,53 **** --- 21,64 ---- * questions. */ package jdk.vm.ci.hotspot; import static jdk.vm.ci.common.InitTimer.timer; + 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; import java.util.List; 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; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.common.InitTimer; import jdk.vm.ci.common.JVMCIError; + import jdk.vm.ci.common.NativeImageReinitialize; import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory.CompilationLevel; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.UnresolvedJavaType;
*** 55,100 **** --- 66,213 ---- import jdk.vm.ci.runtime.JVMCIBackend; import jdk.vm.ci.runtime.JVMCICompiler; import jdk.vm.ci.runtime.JVMCICompilerFactory; import jdk.vm.ci.runtime.JVMCIRuntime; import jdk.vm.ci.services.JVMCIServiceLocator; + 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; + + 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; + } + + 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; + } static { + /** + * Gets the singleton {@link HotSpotJVMCIRuntime} object. + */ + @VMEntryPoint + @SuppressWarnings("try") + public static HotSpotJVMCIRuntime runtime() { + 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; } /** * Gets the singleton {@link HotSpotJVMCIRuntime} object. */ public static HotSpotJVMCIRuntime runtime() { JVMCI.initialize(); return DelayedInit.instance; + @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(); } /** * A list of all supported JVMCI options. */
*** 119,152 **** --- 232,264 ---- * The prefix for system properties that are JVMCI options. */ 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; ! @NativeImageReinitialize private Object value; private final Object defaultValue; private boolean isDefault; private final String[] helpLines; 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 == null ? NULL_VALUE : defaultValue; this.isDefault = true; } else { if (type == Boolean.class) { this.value = Boolean.parseBoolean(propertyValue); } else if (type == String.class) {
*** 154,167 **** --- 266,277 ---- } else { throw new JVMCIError("Unexpected option type " + type); } this.isDefault = false; } // Saved properties should not be interned - let's be sure assert value != UNINITIALIZED; } ! return value == NULL_VALUE ? null : value; } /** * Gets the name of system property from which this option gets its value. */
*** 220,256 **** --- 330,394 ---- } } } } ! private static HotSpotJVMCIBackendFactory findFactory(String architecture) { for (HotSpotJVMCIBackendFactory factory : ServiceLoader.load(HotSpotJVMCIBackendFactory.class, ClassLoader.getSystemClassLoader())) { + Iterable<HotSpotJVMCIBackendFactory> factories = getHotSpotJVMCIBackendFactories(); + assert factories != null : "sanity"; + for (HotSpotJVMCIBackendFactory factory : factories) { if (factory.getArchitecture().equalsIgnoreCase(architecture)) { return factory; } } 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 = Services.load(HotSpotJVMCIBackendFactory.class); + 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. */ public static JavaKind getHostWordKind() { return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordJavaKind; } ! 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 result of {@link HotSpotJVMCICompilerFactory#getCompilationLevelAdjustment} so * that it can be read from the VM. */
*** 278,287 **** --- 416,435 ---- try (InitTimer t = timer("HotSpotVMConfig<init>")) { configStore = new HotSpotVMConfigStore(compilerToVm); 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; try (InitTimer t = timer("find factory:", hostArchitecture)) { factory = findFactory(hostArchitecture);
*** 289,300 **** --- 437,446 ---- try (InitTimer t = timer("create JVMCI backend:", hostArchitecture)) { hostBackend = registerBackend(factory.createJVMCIBackend(this, null)); } metaAccessContext = new HotSpotJVMCIMetaAccessContext(); compilerFactory = HotSpotJVMCICompilerConfig.getCompilerFactory(); if (compilerFactory instanceof HotSpotJVMCICompilerFactory) { hsCompilerFactory = (HotSpotJVMCICompilerFactory) compilerFactory; switch (hsCompilerFactory.getCompilationLevelAdjustment()) { case None:
*** 314,430 **** --- 460,622 ---- hsCompilerFactory = null; compilationLevelAdjustment = config.compLevelAdjustmentNone; } 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) { 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; } ResolvedJavaType fromClass(Class<?> javaClass) { return metaAccessContext.fromClass(javaClass); } public HotSpotVMConfigStore getConfigStore() { return configStore; } ! public HotSpotVMConfig getConfig() { return config; } ! 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 * intrinsifying methods it declares. * * @param compilerLeafClasses classes in the leaves of the module graph comprising the JVMCI * compiler. */ public Predicate<ResolvedJavaType> getIntrinsificationTrustPredicate(Class<?>... compilerLeafClasses) { ! if (intrinsificationTrustPredicate == null) { intrinsificationTrustPredicate = new Predicate<>() { ! return new Predicate<ResolvedJavaType>() { @Override public boolean test(ResolvedJavaType type) { ! if (type instanceof HotSpotResolvedJavaType) { ! Class<?> mirror = getMirror(type); ! Module module = mirror.getModule(); return getTrustedModules().contains(module); ! 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; } /** * Get the {@link Class} corresponding to {@code type}. * * @param type the type for which a {@link Class} is requested * @return the original Java class corresponding to {@code type} or {@code null} if this runtime * 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 public JVMCICompiler getCompiler() { if (compiler == null) { synchronized (this) { if (compiler == null) { + assert !creatingCompiler : "recursive compiler creation"; + creatingCompiler = true; compiler = compilerFactory.createCompiler(this); + creatingCompiler = false; } } } return compiler; }
*** 442,464 **** --- 634,660 ---- * @throws LinkageError if {@code resolve == true} and the resolution failed * @throws NullPointerException if {@code accessingClass} is {@code null} */ 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 : name; return UnresolvedJavaType.create(name); } return klass; } catch (ClassNotFoundException e) { throw (NoClassDefFoundError) new NoClassDefFoundError().initCause(e);
*** 478,492 **** --- 674,685 ---- public Map<Class<? extends Architecture>, JVMCIBackend> getJVMCIBackends() { return Collections.unmodifiableMap(backends); } /** * Called from the VM. */ @SuppressWarnings({"unused"}) private int adjustCompilationLevel(Class<?> declaringClass, String name, String signature, boolean isOsr, int level) { + @VMEntryPoint + private int adjustCompilationLevel(Object declaringClass, String name, String signature, boolean isOsr, int level) { CompilationLevel curLevel; if (level == config.compilationLevelNone) { curLevel = CompilationLevel.None; } else if (level == config.compilationLevelSimple) { curLevel = CompilationLevel.Simple;
*** 514,529 **** --- 707,719 ---- default: return level; } } /** * 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) { hsResult = (HotSpotCompilationRequestResult) result; } else {
*** 540,565 **** --- 730,755 ---- return hsResult; } /** * 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(); } } /** * Notify on completion of a bootstrap. * * Called from the VM. */ @SuppressWarnings({"unused"}) + @VMEntryPoint private void bootstrapFinished() throws Exception { for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) { vmEventListener.notifyBootstrapFinished(); } }
*** 575,584 **** --- 765,809 ---- for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) { vmEventListener.notifyInstall(hotSpotCodeCacheProvider, installedCode, compiledCode); } } + @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. */ public OutputStream getLogStream() { return new OutputStream() {
*** 617,647 **** --- 842,871 ---- /** * The offset from the origin of an array to the first element. * * @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); } }
*** 649,690 **** --- 873,913 ---- /** * The scale used for the index when accessing elements of an array of this kind. * * @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); } } /** ! * 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> * package com.jcompile; *
*** 705,733 **** --- 928,1001 ---- * private static long getHandle(Method method) { ... } * private static char[] convertToCharArray(String[] a) { ... } * } * </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} */ @SuppressWarnings({"static-method", "unused"}) public void registerNativeMethods(Class<?> clazz) { throw new UnsatisfiedLinkError("SVM library is not available"); ! * @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} + */ + 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)); } }

src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java
Index Unified diffs Context diffs Sdiffs Frames Patch New Old Previous File Next File