# HG changeset patch # User Doug Simon # Date 1497356574 -7200 # Node ID d4858e92c9b158550a52c6deaeba90b1c0373ad1 # Parent 0c5304ad61bdc44bd1bc8e64557c739ffb1db9cd [GR-4077] support Graal.SDK on the boot class path and Truffle on a class path invisible to apps but visible to JVMCI diff -r 0c5304ad61bd -r d4858e92c9b1 jvmci/jdk.vm.ci.services/src/jdk/vm/ci/services/JVMCIClassLoaderFactory.java --- a/jvmci/jdk.vm.ci.services/src/jdk/vm/ci/services/JVMCIClassLoaderFactory.java Mon Jun 12 16:03:24 2017 +0200 +++ b/jvmci/jdk.vm.ci.services/src/jdk/vm/ci/services/JVMCIClassLoaderFactory.java Tue Jun 13 14:22:54 2017 +0200 @@ -23,9 +23,13 @@ package jdk.vm.ci.services; import java.io.File; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -33,8 +37,10 @@ /** * Utility called from the VM to create and register a separate class loader for loading JVMCI - * classes (i.e., those in found in lib/jvmci/*.jar) as well as those available on the class path in - * the {@code "jvmci.class.path.append"} system property. + * classes (i.e., those in found in {@code /lib/jvmci/*.jar)} as well as those available + * on the class path in the {@code "jvmci.class.path.append"} system property. The JVMCI class + * loader can optionally be given a parent other than the boot class loader as specified by + * {@link #getJVMCIParentClassLoader(Path)}. */ class JVMCIClassLoaderFactory { @@ -57,46 +63,77 @@ * Creates a new class loader for loading JVMCI classes. */ private static ClassLoader newClassLoader() { - URL[] urls = getJVMCIJarsUrls(); - ClassLoader parent = null; + Path jvmciDir = Paths.get(VM.getSavedProperty("java.home"), "lib", "jvmci"); + if (!Files.isDirectory(jvmciDir)) { + throw new InternalError(jvmciDir + " does not exist or is not a directory"); + } + URL[] urls = getJVMCIJarsUrls(jvmciDir); + ClassLoader parent = getJVMCIParentClassLoader(jvmciDir); return URLClassLoader.newInstance(urls, parent); } /** - * Gets the URLs for lib/jvmci/*.jar. + * Creates a parent class loader for the JVMCI class loader. The class path for the loader is + * specified in the optional file {@code /lib/jvmci/parentClassLoader.classpath}. If + * the file exists, its contents must be a well formed class path. Relative entries in the class + * path are resolved against {@code /lib/jvmci}. + * + * @return {@code null} if {@code /lib/jvmci/parentClassLoader.classpath} does not + * exist otherwise a {@link URLClassLoader} constructed from the class path in the file */ - private static URL[] getJVMCIJarsUrls() { - File javaHome = new File(VM.getSavedProperty("java.home")); - File lib = new File(javaHome, "lib"); - File jvmci = new File(lib, "jvmci"); - if (!jvmci.isDirectory()) { - throw new InternalError(jvmci + " does not exist or is not a directory"); + private static ClassLoader getJVMCIParentClassLoader(Path jvmciDir) { + Path parentFile = jvmciDir.resolve("parentClassLoader.classpath"); + if (Files.exists(parentFile)) { + String[] entries; + try { + entries = new String(Files.readAllBytes(parentFile)).trim().split(File.pathSeparator); + } catch (IOException e) { + throw new InternalError("Error reading " + parentFile.toAbsolutePath(), e); + } + URL[] urls = new URL[entries.length]; + for (int i = 0; i < entries.length; i++) { + try { + // If entries[i] is already absolute, it will remain unchanged + urls[i] = jvmciDir.resolve(entries[i]).toFile().toURI().toURL(); + } catch (MalformedURLException e) { + throw new InternalError(e); + } + } + ClassLoader parent = null; + return URLClassLoader.newInstance(urls, parent); } + return null; + } - List urls = new ArrayList<>(); - for (String fileName : jvmci.list()) { + /** + * Gets the URLs for all jar files in the {@code jvmciDir} directory as well as the entries + * specified by the {@code "jvmci.class.path.append"} system property. + */ + private static URL[] getJVMCIJarsUrls(Path jvmciDir) { + String[] dirEntries = jvmciDir.toFile().list(); + + String append = VM.getSavedProperty("jvmci.class.path.append"); + String[] appendEntries = append != null ? append.split(File.pathSeparator) : new String[0]; + List urls = new ArrayList<>(dirEntries.length + appendEntries.length); + + for (String fileName : dirEntries) { if (fileName.endsWith(".jar")) { - File file = new File(jvmci, fileName); - if (file.isDirectory()) { + Path path = jvmciDir.resolve(fileName); + if (Files.isDirectory(path)) { continue; } try { - urls.add(file.toURI().toURL()); + urls.add(path.toFile().toURI().toURL()); } catch (MalformedURLException e) { throw new InternalError(e); } } } - - String append = VM.getSavedProperty("jvmci.class.path.append"); - if (append != null) { - for (String entry : append.split(File.pathSeparator)) { - File file = new File(entry); - try { - urls.add(file.toURI().toURL()); - } catch (MalformedURLException e) { - throw new InternalError(e); - } + for (String path : appendEntries) { + try { + urls.add(new File(path).toURI().toURL()); + } catch (MalformedURLException e) { + throw new InternalError(e); } } diff -r 0c5304ad61bd -r d4858e92c9b1 src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Mon Jun 12 16:03:24 2017 +0200 +++ b/src/share/vm/classfile/classFileParser.cpp Tue Jun 13 14:22:54 2017 +0200 @@ -1809,7 +1809,7 @@ #if INCLUDE_JVMCI case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_vm_ci_hotspot_Stable_signature): if (_location != _in_field) break; // only allow for fields - if (!privileged && loader_data->class_loader() != SystemDictionary::jvmci_loader()) break; // only allow in privileged code + if (!privileged && !SystemDictionary::in_jvmci_loader_hierarchy(loader_data->class_loader())) break; // only allow in privileged code return _field_Stable; #endif case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_Stable_signature): diff -r 0c5304ad61bd -r d4858e92c9b1 src/share/vm/classfile/javaClasses.cpp --- a/src/share/vm/classfile/javaClasses.cpp Mon Jun 12 16:03:24 2017 +0200 +++ b/src/share/vm/classfile/javaClasses.cpp Tue Jun 13 14:22:54 2017 +0200 @@ -564,7 +564,7 @@ // Set protection domain also #if INCLUDE_JVMCI - if (k->class_loader() == SystemDictionary::jvmci_loader()) { + if (SystemDictionary::in_jvmci_loader_hierarchy(k->class_loader())) { // Same protection domain as for classes loaded by the boot loader protection_domain = Handle(); } diff -r 0c5304ad61bd -r d4858e92c9b1 src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Mon Jun 12 16:03:24 2017 +0200 +++ b/src/share/vm/classfile/systemDictionary.cpp Tue Jun 13 14:22:54 2017 +0200 @@ -98,6 +98,7 @@ #if INCLUDE_JVMCI oop SystemDictionary::_jvmci_loader = NULL; +oop SystemDictionary::_jvmci_loader_parent = NULL; #endif // lazily initialized klass variables @@ -131,6 +132,21 @@ return ClassLoaderDataGraph::find_or_create(class_loader, CHECK_NULL); } +#if INCLUDE_JVMCI +void SystemDictionary::init_jvmci_loader(oop loader) { + assert(UseJVMCIClassLoader == (loader != NULL), "must be"); + _jvmci_loader = loader; + if (loader != NULL) { + _jvmci_loader_parent = java_lang_ClassLoader::parent(loader); + assert(_jvmci_loader_parent == NULL || + java_lang_ClassLoader::parent(_jvmci_loader_parent) == NULL, + "at most one parent allowed between the JVMCI loader and the boot loader"); + } +} +#include "jvmci/jvmciRuntime.hpp" +#endif + + // ---------------------------------------------------------------------------- // debugging diff -r 0c5304ad61bd -r d4858e92c9b1 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Mon Jun 12 16:03:24 2017 +0200 +++ b/src/share/vm/classfile/systemDictionary.hpp Tue Jun 13 14:22:54 2017 +0200 @@ -500,11 +500,13 @@ // in which case it's equivalent to the boot loader static oop jvmci_loader() { return _jvmci_loader; } - // Sets the JVMCI loader. This is called at most once. - static void init_jvmci_loader(oop loader) { - assert(UseJVMCIClassLoader == (loader != NULL), "must be"); - _jvmci_loader = loader; + // Determines if loader is in the JVMCI class loader hierarchy + static bool in_jvmci_loader_hierarchy (oop loader) { + return loader == NULL || loader == _jvmci_loader || loader == _jvmci_loader_parent; } + + // Sets the JVMCI loader. This must be called at most once. + static void init_jvmci_loader(oop loader); #endif // Compute the default system loader @@ -739,6 +741,7 @@ static oop _java_system_loader; #if INCLUDE_JVMCI static oop _jvmci_loader; + static oop _jvmci_loader_parent; #endif static bool _has_loadClassInternal; diff -r 0c5304ad61bd -r d4858e92c9b1 src/share/vm/classfile/verifier.cpp --- a/src/share/vm/classfile/verifier.cpp Mon Jun 12 16:03:24 2017 +0200 +++ b/src/share/vm/classfile/verifier.cpp Tue Jun 13 14:22:54 2017 +0200 @@ -94,7 +94,7 @@ // Methods in Verifier bool Verifier::should_verify_for(oop class_loader, bool should_verify_class) { - return (class_loader == NULL JVMCI_ONLY(|| class_loader == SystemDictionary::jvmci_loader()) || !should_verify_class) ? + return (class_loader == NULL JVMCI_ONLY(|| SystemDictionary::in_jvmci_loader_hierarchy(class_loader)) || !should_verify_class) ? BytecodeVerificationLocal : BytecodeVerificationRemote; } diff -r 0c5304ad61bd -r d4858e92c9b1 src/share/vm/jvmci/jvmciRuntime.cpp --- a/src/share/vm/jvmci/jvmciRuntime.cpp Mon Jun 12 16:03:24 2017 +0200 +++ b/src/share/vm/jvmci/jvmciRuntime.cpp Tue Jun 13 14:22:54 2017 +0200 @@ -849,7 +849,7 @@ bool JVMCIRuntime::treat_as_trivial(Method* method) { if (_HotSpotJVMCIRuntime_initialized) { oop loader = method->method_holder()->class_loader(); - if (loader == NULL || loader == SystemDictionary::jvmci_loader()) { + if (SystemDictionary::in_jvmci_loader_hierarchy(loader)) { for (int i = 0; i < _trivial_prefixes_count; i++) { if (method->method_holder()->name()->starts_with(_trivial_prefixes[i])) { return true; diff -r 0c5304ad61bd -r d4858e92c9b1 src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Mon Jun 12 16:03:24 2017 +0200 +++ b/src/share/vm/prims/jvm.cpp Tue Jun 13 14:22:54 2017 +0200 @@ -2370,7 +2370,7 @@ ResourceMark rm(THREAD); const char* name = k->name()->as_C_string(); - bool system_class = k->class_loader() == NULL JVMCI_ONLY(|| SystemDictionary::jvmci_loader() == k->class_loader()); + bool system_class = k->class_loader() == NULL JVMCI_ONLY(|| SystemDictionary::in_jvmci_loader_hierarchy(k->class_loader())); return JavaAssertions::enabled(name, system_class); JVM_END diff -r 0c5304ad61bd -r d4858e92c9b1 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Mon Jun 12 16:03:24 2017 +0200 +++ b/src/share/vm/runtime/arguments.cpp Tue Jun 13 14:22:54 2017 +0200 @@ -371,10 +371,10 @@ // must free the string if/when no longer needed. char* combined_path(); -private: // Utility routines. static char* add_to_path(const char* path, const char* str, bool prepend); static char* add_jars_to_path(char* path, const char* directory); +private: inline void reset_item_at(int index); @@ -3574,27 +3574,25 @@ scp_p->expand_endorsed(); #if INCLUDE_JVMCI + // Append lib/boot/*.jar to boot class path + char bootDir[JVM_MAXPATHLEN]; + const char* fileSep = os::file_separator(); + jio_snprintf(bootDir, sizeof(bootDir), "%s%slib%sboot", Arguments::get_java_home(), fileSep, fileSep); + char* boot_suffix_path = SysClassPath::add_jars_to_path(NULL, bootDir); + if (boot_suffix_path != NULL) { + scp_p->add_suffix(boot_suffix_path); + scp_assembly_required = true; + } + if (!UseJVMCIClassLoader) { // Append lib/jvmci/*.jar to boot class path char jvmciDir[JVM_MAXPATHLEN]; const char* fileSep = os::file_separator(); jio_snprintf(jvmciDir, sizeof(jvmciDir), "%s%slib%sjvmci", Arguments::get_java_home(), fileSep, fileSep); - DIR* dir = os::opendir(jvmciDir); - if (dir != NULL) { - struct dirent *entry; - char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(jvmciDir), mtInternal); - while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL) { - const char* name = entry->d_name; - const char* ext = name + strlen(name) - 4; - if (ext > name && strcmp(ext, ".jar") == 0) { - char fileName[JVM_MAXPATHLEN]; - jio_snprintf(fileName, sizeof(fileName), "%s%s%s", jvmciDir, fileSep, name); - scp_p->add_suffix(fileName); - scp_assembly_required = true; - } - } - FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); - os::closedir(dir); + char* jvmci_path = SysClassPath::add_jars_to_path(NULL, jvmciDir); + if (jvmci_path != NULL) { + scp_p->add_suffix(jvmci_path); + scp_assembly_required = true; } const char* path = Arguments::get_property("jvmci.class.path.append"); if (path != NULL) {