< prev index next >
src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java
Print this page
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2020, 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.
@@ -35,10 +35,11 @@
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Formatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.ServiceLoader;
@@ -209,10 +210,19 @@
static String callToString(Object o) {
return o.toString();
}
/**
+ * Set of recognized {@code "jvmci.*"} system properties. Entries not associated with an
+ * {@link Option} have this object as their value.
+ */
+ static final Map<String, Object> options = new HashMap<>();
+ static {
+ options.put("jvmci.class.path.append", options);
+ }
+
+ /**
* A list of all supported JVMCI options.
*/
public enum Option {
// @formatter:off
Compiler(String.class, null, "Selects the system compiler. This must match the getCompilerName() value returned " +
@@ -243,24 +253,25 @@
private static final String NULL_VALUE = "NULL";
private final Class<?> type;
@NativeImageReinitialize private Object value;
private final Object defaultValue;
- private boolean isDefault;
+ private boolean isDefault = true;
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.defaultValue = defaultValue;
this.helpLines = helpLines;
+ Object existing = options.put(getPropertyName(), this);
+ assert existing == null : getPropertyName();
}
@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 == null) {
- String propertyValue = Services.getSavedProperty(getPropertyName());
+ private void init(String propertyValue) {
+ assert value == null : "cannot re-initialize " + name();
if (propertyValue == null) {
this.value = defaultValue == null ? NULL_VALUE : defaultValue;
this.isDefault = true;
} else {
if (type == Boolean.class) {
@@ -271,11 +282,20 @@
throw new JVMCIError("Unexpected option type " + type);
}
this.isDefault = false;
}
}
- return value == NULL_VALUE ? null : value;
+
+ @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 == NULL_VALUE) {
+ return null;
+ }
+ if (value == null) {
+ return defaultValue;
+ }
+ return value;
}
/**
* Gets the name of system property from which this option gets its value.
*/
@@ -332,10 +352,65 @@
for (String line : option.helpLines) {
out.printf("%" + PROPERTY_HELP_INDENT + "s%s%n", "", line);
}
}
}
+
+ /**
+ * Compute string similarity based on Dice's coefficient.
+ *
+ * Ported from str_similar() in globals.cpp.
+ */
+ static float stringSimiliarity(String str1, String str2) {
+ int hit = 0;
+ for (int i = 0; i < str1.length() - 1; ++i) {
+ for (int j = 0; j < str2.length() - 1; ++j) {
+ if ((str1.charAt(i) == str2.charAt(j)) && (str1.charAt(i + 1) == str2.charAt(j + 1))) {
+ ++hit;
+ break;
+ }
+ }
+ }
+ return 2.0f * hit / (str1.length() + str2.length());
+ }
+
+ private static final float FUZZY_MATCH_THRESHOLD = 0.7F;
+
+ /**
+ * Parses all system properties starting with {@value #JVMCI_OPTION_PROPERTY_PREFIX} and
+ * initializes the options based on their values.
+ */
+ static void parse() {
+ Map<String, String> savedProps = jdk.vm.ci.services.Services.getSavedProperties();
+ for (Map.Entry<String, String> e : savedProps.entrySet()) {
+ String name = e.getKey();
+ if (name.startsWith(Option.JVMCI_OPTION_PROPERTY_PREFIX)) {
+ Object value = options.get(name);
+ if (value == null) {
+ List<String> matches = new ArrayList<>();
+ for (String pn : options.keySet()) {
+ float score = stringSimiliarity(pn, name);
+ if (score >= FUZZY_MATCH_THRESHOLD) {
+ matches.add(pn);
+ }
+ }
+ Formatter msg = new Formatter();
+ msg.format("Could not find option %s", name);
+ if (!matches.isEmpty()) {
+ msg.format("%nDid you mean one of the following?");
+ for (String match : matches) {
+ msg.format("%n %s=<value>", match);
+ }
+ }
+ throw new IllegalArgumentException(msg.toString());
+ } else if (value instanceof Option) {
+ Option option = (Option) value;
+ option.init(e.getValue());
+ }
+ }
+ }
+ }
}
private static HotSpotJVMCIBackendFactory findFactory(String architecture) {
Iterable<HotSpotJVMCIBackendFactory> factories = getHotSpotJVMCIBackendFactories();
assert factories != null : "sanity";
@@ -452,10 +527,13 @@
vmLogStream = new PrintStream(getLogStream());
System.setOut(vmLogStream);
System.setErr(vmLogStream);
}
+ // Initialize the Option values.
+ Option.parse();
+
String hostArchitecture = config.getHostArchitectureName();
HotSpotJVMCIBackendFactory factory;
try (InitTimer t = timer("find factory:", hostArchitecture)) {
factory = findFactory(hostArchitecture);
@@ -711,22 +789,30 @@
}
return hsResult;
}
/**
+ * Guard to ensure shut down actions are performed at most once.
+ */
+ private boolean isShutdown;
+
+ /**
* Shuts down the runtime.
*/
@VMEntryPoint
- private void shutdown() throws Exception {
+ private synchronized void shutdown() throws Exception {
+ if (!isShutdown) {
+ isShutdown = true;
// 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.
*/
@VMEntryPoint
@@ -913,25 +999,34 @@
* private static char[] convertToCharArray(String[] a) { ... }
* }
* </pre>
*
* 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:
+ * shared library that contains the JVMCI compiler. The {@code JCompile.compile0} implementation
+ * must be exported as the following JNI-compatible symbol:
*
* <pre>
* Java_com_jcompile_JCompile_compile0
* </pre>
*
* @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"
*
*
- * @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})
+ * @return info about the Java VM in the JVMCI shared library {@code JavaVM*}. The info is
+ * encoded in a long array as follows:
+ *
+ * <pre>
+ * long[] info = {
+ * javaVM, // the {@code JavaVM*} value
+ * javaVM->functions->reserved0,
+ * javaVM->functions->reserved1,
+ * javaVM->functions->reserved2
+ * }
+ * </pre>
+ *
* @throws NullPointerException if {@code clazz == null}
* @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
* {@code -XX:-UseJVMCINativeLibrary})
* @throws IllegalStateException if the current execution context is the JVMCI shared library
* @throws IllegalArgumentException if {@code clazz} is {@link Class#isPrimitive()}
@@ -1016,10 +1111,12 @@
* thread was already attached
* @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
* {@code -XX:-UseJVMCINativeLibrary})
* @throws IllegalStateException if the peer runtime has not been initialized or there is an
* error while trying to attach the thread
+ * @throws ArrayIndexOutOfBoundsException if {@code javaVMInfo} is non-null and is shorter than
+ * the length of the array returned by {@link #registerNativeMethods}
*/
public boolean attachCurrentThread(boolean asDaemon) {
return compilerToVm.attachCurrentThread(asDaemon);
}
< prev index next >