changeset 18614:c307546c7b0a

made initialization of the Graal class loader and well known Graal classes lazy
author Doug Simon <doug.simon@oracle.com>
date Thu, 04 Dec 2014 13:42:56 +0100
parents 8c3a85077f84
children c2da0aa9e675
files graal/com.oracle.graal.hotspot.loader/src/com/oracle/graal/hotspot/loader/Factory.java src/share/vm/classfile/systemDictionary.cpp src/share/vm/classfile/systemDictionary.hpp src/share/vm/graal/graalCompiler.cpp src/share/vm/graal/graalRuntime.cpp src/share/vm/graal/graalRuntime.hpp src/share/vm/prims/nativeLookup.cpp src/share/vm/runtime/thread.cpp
diffstat 8 files changed, 80 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot.loader/src/com/oracle/graal/hotspot/loader/Factory.java	Thu Dec 04 13:41:59 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.loader/src/com/oracle/graal/hotspot/loader/Factory.java	Thu Dec 04 13:42:56 2014 +0100
@@ -26,19 +26,31 @@
 import java.net.*;
 
 /**
- * Utility to create a separate class loader for loading classes in {@code graal.jar} and
- * {@code graal-truffle.jar}.
+ * Utility to create and register a separate class loader for loading Graal classes (i.e., those in
+ * {@code graal.jar} and {@code graal-truffle.jar}).
  */
 public class Factory {
 
     /**
+     * Copy of the {@code UseGraalClassLoader} VM option. Set by the VM before the static
+     * initializer is called.
+     */
+    private static boolean useGraalClassLoader;
+
+    /**
+     * Registers the Graal class loader in the VM.
+     */
+    private static native void init(ClassLoader loader);
+
+    static {
+        init(useGraalClassLoader ? newClassLoader() : null);
+    }
+
+    /**
      * Creates a new class loader for loading classes in {@code graal.jar} and
-     * {@code graal-truffle.jar}
-     *
-     * Called from the VM.
+     * {@code graal-truffle.jar}.
      */
-    @SuppressWarnings("unused")
-    private static ClassLoader newClassLoader() throws MalformedURLException {
+    private static ClassLoader newClassLoader() {
         URL[] urls = {getGraalJarUrl("graal"), getGraalJarUrl("graal-truffle")};
         ClassLoader parent = null;
         return URLClassLoader.newInstance(urls, parent);
@@ -47,7 +59,7 @@
     /**
      * Gets the URL for {@code base.jar}.
      */
-    private static URL getGraalJarUrl(String base) throws MalformedURLException {
+    private static URL getGraalJarUrl(String base) {
         File file = new File(System.getProperty("java.home"));
         for (String name : new String[]{"lib", base + ".jar"}) {
             file = new File(file, name);
@@ -57,6 +69,10 @@
             throw new InternalError(file + " does not exist");
         }
 
-        return file.toURI().toURL();
+        try {
+            return file.toURI().toURL();
+        } catch (MalformedURLException e) {
+            throw new InternalError(e);
+        }
     }
 }
--- a/src/share/vm/classfile/systemDictionary.cpp	Thu Dec 04 13:41:59 2014 +0100
+++ b/src/share/vm/classfile/systemDictionary.cpp	Thu Dec 04 13:42:56 2014 +0100
@@ -96,6 +96,10 @@
 oop SystemDictionary::graal_loader() {
   return _graal_loader;
 }
+void SystemDictionary::init_graal_loader(oop loader) {
+  assert(UseGraalClassLoader == (loader != NULL), "must be");
+  _graal_loader = loader;
+}
 #endif
 
 // lazily initialized klass variables
@@ -1931,18 +1935,6 @@
   }
 }
 
-#ifdef GRAAL
-void SystemDictionary::initialize_preloaded_graal_classes(TRAPS) {
-  assert(WK_KLASS(Node_klass) == NULL, "preloaded Graal classes should only be initialized once");
-  if (UseGraalClassLoader) {
-    _graal_loader = GraalRuntime::compute_graal_class_loader(CHECK);
-  }
-
-  WKID scan = FIRST_GRAAL_WKID;
-  initialize_wk_klasses_through(LAST_GRAAL_WKID, scan, CHECK);
-}
-#endif
-
 // Tells if a given klass is a box (wrapper class, such as java.lang.Integer).
 // If so, returns the basic type it holds.  If not, returns T_OBJECT.
 BasicType SystemDictionary::box_klass_type(Klass* k) {
--- a/src/share/vm/classfile/systemDictionary.hpp	Thu Dec 04 13:41:59 2014 +0100
+++ b/src/share/vm/classfile/systemDictionary.hpp	Thu Dec 04 13:42:56 2014 +0100
@@ -185,7 +185,7 @@
                                                                                                                          \
   /* Support for Graal */                                                                                                \
   do_klass(BitSet_klass,                                java_util_BitSet,                          Opt                 ) \
-  /* Graal classes */                                                                                                    \
+  /* Graal classes. These are loaded on-demand. */                                                                                 \
   GRAAL_ONLY(do_klass(Node_klass,                            com_oracle_graal_graph_Node,                                  Graal)) \
   GRAAL_ONLY(do_klass(NodeClass_klass,                       com_oracle_graal_graph_NodeClass,                             Graal)) \
   GRAAL_ONLY(do_klass(HotSpotCompiledCode_klass,             com_oracle_graal_hotspot_HotSpotCompiledCode,                 Graal)) \
@@ -537,6 +537,8 @@
   // Returns the Graal loader. This will be NULL if !UseGraalClassLoader
   // in which case it's equivalent to the boot loader
   static oop graal_loader();
+  // Sets the Graal loader. This is called at most once.
+  static void init_graal_loader(oop loader);
 #endif
 
   // Compute the default system loader
@@ -704,10 +706,6 @@
 public:
   static bool is_ext_class_loader(Handle class_loader);
 
-#ifdef GRAAL
-  static void initialize_preloaded_graal_classes(TRAPS);
-#endif
-
 private:
   static Klass* find_shared_class(Symbol* class_name);
 
--- a/src/share/vm/graal/graalCompiler.cpp	Thu Dec 04 13:41:59 2014 +0100
+++ b/src/share/vm/graal/graalCompiler.cpp	Thu Dec 04 13:42:56 2014 +0100
@@ -115,6 +115,7 @@
       return;
   }
 
+  GraalRuntime::ensure_graal_class_loader_is_initialized();
   HandleMark hm;
   ResourceMark rm;
   JavaValue result(T_VOID);
--- a/src/share/vm/graal/graalRuntime.cpp	Thu Dec 04 13:41:59 2014 +0100
+++ b/src/share/vm/graal/graalRuntime.cpp	Thu Dec 04 13:42:56 2014 +0100
@@ -49,6 +49,8 @@
   AMD64_ONLY(guarantee(heap_end < allocation_end, "heap end too close to end of address space (might lead to erroneous TLAB allocations)"));
   NOT_LP64(error("check TLAB allocation code for address space conflicts"));
 
+  ensure_graal_class_loader_is_initialized();
+
   JavaThread* THREAD = JavaThread::current();
   {
     ThreadToNativeFromVM trans(THREAD);
@@ -656,6 +658,13 @@
   return value;
 JRT_END
 
+// private static void Factory.init()
+JVM_ENTRY(void, JVM_InitGraalClassLoader(JNIEnv *env, jclass c, jobject loader_handle))
+  SystemDictionary::init_graal_loader(JNIHandles::resolve(loader_handle));
+  SystemDictionary::WKID scan = SystemDictionary::FIRST_GRAAL_WKID;
+  SystemDictionary::initialize_wk_klasses_through(SystemDictionary::LAST_GRAAL_WKID, scan, CHECK);
+JVM_END
+
 // private static GraalRuntime Graal.initializeRuntime()
 JVM_ENTRY(jobject, JVM_GetGraalRuntime(JNIEnv *env, jclass c))
   return GraalRuntime::get_HotSpotGraalRuntime_jobject();
@@ -748,6 +757,36 @@
   return result;
 JVM_END
 
+
+void GraalRuntime::ensure_graal_class_loader_is_initialized() {
+  // This initialization code is guarded by a static pointer to the Factory class.
+  // Once it is non-null, the Graal class loader and well know Graal classes are
+  // guaranteed to have been initialized. By going through the static
+  // initializer of Factory, we can rely on class initialization semantics to
+  // synchronize threads racing to do the initialization.
+  static Klass* _FactoryKlass = NULL;
+  if (_FactoryKlass == NULL) {
+    Thread* THREAD = Thread::current();
+    TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/loader/Factory", CHECK_ABORT);
+    KlassHandle klass = SystemDictionary::resolve_or_fail(name, true, THREAD);
+    if (HAS_PENDING_EXCEPTION) {
+      abort_on_pending_exception(PENDING_EXCEPTION, "Graal classes are not available");
+    }
+    TempNewSymbol field_name = SymbolTable::new_symbol("useGraalClassLoader", CHECK_ABORT);
+
+    fieldDescriptor field_desc;
+    if (klass->find_field(field_name, vmSymbols::bool_signature(), &field_desc) == NULL) {
+      ResourceMark rm;
+      fatal(err_msg("Invalid layout of %s at %s", field_name->as_C_string(), klass->external_name()));
+    }
+    InstanceKlass* ik = InstanceKlass::cast(klass());
+    address addr = ik->static_field_addr(field_desc.offset() - InstanceMirrorKlass::offset_of_static_fields());
+    *((jboolean *) addr) = (jboolean) UseGraalClassLoader;
+    klass->initialize(CHECK_ABORT);
+    _FactoryKlass = klass();
+  }
+}
+
 jint GraalRuntime::check_arguments(TRAPS) {
   KlassHandle nullHandle;
   parse_arguments(nullHandle, THREAD);
@@ -800,6 +839,7 @@
 }
 
 void GraalRuntime::parse_argument(KlassHandle hotSpotOptionsClass, char* arg, TRAPS) {
+  ensure_graal_class_loader_is_initialized();
   char first = arg[0];
   char* name;
   size_t name_len;
@@ -1017,17 +1057,6 @@
                           thread);
 }
 
-oop GraalRuntime::compute_graal_class_loader(TRAPS) {
-  assert(UseGraalClassLoader, "must be");
-  TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/loader/Factory", CHECK_NULL);
-  KlassHandle klass = SystemDictionary::resolve_or_fail(name, true, CHECK_NULL);
-
-  TempNewSymbol getClassLoader = SymbolTable::new_symbol("newClassLoader", CHECK_NULL);
-  JavaValue result(T_OBJECT);
-  JavaCalls::call_static(&result, klass, getClassLoader, vmSymbols::void_classloader_signature(), CHECK_NULL);
-  return (oop) result.get_jobject();
-}
-
 void GraalRuntime::abort_on_pending_exception(Handle exception, const char* message, bool dump_core) {
   Thread* THREAD = Thread::current();
   CLEAR_PENDING_EXCEPTION;
--- a/src/share/vm/graal/graalRuntime.hpp	Thu Dec 04 13:41:59 2014 +0100
+++ b/src/share/vm/graal/graalRuntime.hpp	Thu Dec 04 13:42:56 2014 +0100
@@ -127,6 +127,11 @@
 
  public:
 
+  /**
+   * Ensures that the Graal class loader is initialized and the well known Graal classes are loaded.
+   */
+  static void ensure_graal_class_loader_is_initialized();
+
   static void initialize_natives(JNIEnv *env, jclass c2vmClass);
 
   static bool is_HotSpotGraalRuntime_initialized() { return _HotSpotGraalRuntime_initialized; }
@@ -200,11 +205,6 @@
    */
   static Klass* load_required_class(Symbol* name);
 
-  /**
-   * Creates a separate class loader for classes in graal.jar and graal-truffle.jar.
-   */
-  static oop compute_graal_class_loader(TRAPS);
-
   static BufferBlob* initialize_buffer_blob();
 
   /**
--- a/src/share/vm/prims/nativeLookup.cpp	Thu Dec 04 13:41:59 2014 +0100
+++ b/src/share/vm/prims/nativeLookup.cpp	Thu Dec 04 13:42:56 2014 +0100
@@ -127,6 +127,7 @@
   void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
   void JNICALL JVM_RegisterWhiteBoxMethods(JNIEnv *env, jclass wbclass);
 #ifdef GRAAL
+  void     JNICALL JVM_InitGraalClassLoader(JNIEnv *env, jclass c, jobject loader);
   void     JNICALL JVM_InitializeGraalNatives(JNIEnv *env, jclass compilerToVMClass);
   jobject  JNICALL JVM_GetGraalRuntime(JNIEnv *env, jclass c);
   jobject  JNICALL JVM_GetGraalServiceImpls(JNIEnv *env, jclass c);
@@ -148,6 +149,7 @@
   { CC"Java_sun_misc_Perf_registerNatives",                        NULL, FN_PTR(JVM_RegisterPerfMethods)         },
   { CC"Java_sun_hotspot_WhiteBox_registerNatives",                 NULL, FN_PTR(JVM_RegisterWhiteBoxMethods)     },
 #ifdef GRAAL
+  { CC"Java_com_oracle_graal_hotspot_loader_Factory_init",                                                NULL, FN_PTR(JVM_InitGraalClassLoader)               },
   { CC"Java_com_oracle_graal_api_runtime_Graal_initializeRuntime",                                        NULL, FN_PTR(JVM_GetGraalRuntime)                    },
   { CC"Java_com_oracle_graal_api_runtime_Services_getServiceImpls",                                       NULL, FN_PTR(JVM_GetGraalServiceImpls)               },
   { CC"Java_com_oracle_truffle_api_Truffle_createRuntime",                                                NULL, FN_PTR(JVM_CreateTruffleRuntime)               },
--- a/src/share/vm/runtime/thread.cpp	Thu Dec 04 13:41:59 2014 +0100
+++ b/src/share/vm/runtime/thread.cpp	Thu Dec 04 13:42:56 2014 +0100
@@ -3686,11 +3686,6 @@
   // set_init_completed has just been called, causing exceptions not to be shortcut
   // anymore. We call vm_exit_during_initialization directly instead.
   SystemDictionary::compute_java_system_loader(THREAD);
-#ifdef GRAAL
-  if (!HAS_PENDING_EXCEPTION) {
-    SystemDictionary::initialize_preloaded_graal_classes(THREAD);
-  }
-#endif
   if (HAS_PENDING_EXCEPTION) {
     vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION));
   }