< 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 >