diff --git a/compiler/mx.compiler/suite.py b/compiler/mx.compiler/suite.py index eddfce50712d..f57d2784e224 100644 --- a/compiler/mx.compiler/suite.py +++ b/compiler/mx.compiler/suite.py @@ -2169,13 +2169,14 @@ ], "exports" : [ "* to com.oracle.graal.graal_enterprise,org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.llvm,com.oracle.svm.svm_enterprise", - "org.graalvm.compiler.core.common to jdk.internal.vm.compiler.management", + "org.graalvm.compiler.core.common to jdk.internal.vm.compiler.management,org.graalvm.nativeimage.agent.tracing", "org.graalvm.compiler.debug to jdk.internal.vm.compiler.management,org.graalvm.nativeimage.objectfile", "org.graalvm.compiler.hotspot to jdk.internal.vm.compiler.management", "org.graalvm.compiler.nodes.graphbuilderconf to org.graalvm.nativeimage.driver", "org.graalvm.compiler.options to jdk.internal.vm.compiler.management,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.librarysupport", + "org.graalvm.compiler.phases.common to org.graalvm.nativeimage.agent.tracing,org.graalvm.nativeimage.configure", "org.graalvm.compiler.phases.common.jmx to jdk.internal.vm.compiler.management", - "org.graalvm.compiler.serviceprovider to jdk.internal.vm.compiler.management,org.graalvm.nativeimage.driver", + "org.graalvm.compiler.serviceprovider to jdk.internal.vm.compiler.management,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.agent.jvmtibase,org.graalvm.nativeimage.agent.diagnostics", "org.graalvm.compiler.truffle.jfr to jdk.internal.vm.compiler.truffle.jfr", "org.graalvm.libgraal to jdk.internal.vm.compiler.management", "org.graalvm.util to jdk.internal.vm.compiler.management", diff --git a/sdk/mx.sdk/mx_sdk_vm.py b/sdk/mx.sdk/mx_sdk_vm.py index 3d08066449aa..efbf5fa15f22 100644 --- a/sdk/mx.sdk/mx_sdk_vm.py +++ b/sdk/mx.sdk/mx_sdk_vm.py @@ -133,6 +133,15 @@ def get_add_exports_list(required_exports, custom_target_module_str=None): add_exports.append('--add-exports=' + required_module_name + '/' + required_package_name + "=" + target_modules_str) return sorted(add_exports) + def get_add_exports(self, missing_jars): + if self.use_modules is None: + return '' + distributions = self.jar_distributions + distributions_transitive = mx.classpath_entries(distributions) + distributions_transitive_clean = [entry for entry in distributions_transitive if str(entry) not in missing_jars] + required_exports = mx_javamodules.requiredExports(distributions_transitive_clean, base_jdk()) + return AbstractNativeImageConfig.get_add_exports_list(required_exports) + class LauncherConfig(AbstractNativeImageConfig): def __init__(self, destination, jar_distributions, main_class, build_args, is_main_launcher=True, @@ -148,10 +157,10 @@ def __init__(self, destination, jar_distributions, main_class, build_args, is_ma :param str custom_launcher_script: Custom launcher script, to be used when not compiled as a native image """ super(LauncherConfig, self).__init__(destination, jar_distributions, build_args, use_modules, home_finder=home_finder, **kwargs) + self.main_module = main_module + assert self.use_modules is None or self.main_module self.main_class = main_class self.is_main_launcher = is_main_launcher - assert use_modules is None or main_module - self.main_module = main_module self.default_symlinks = default_symlinks self.is_sdk_launcher = is_sdk_launcher self.custom_launcher_script = custom_launcher_script @@ -166,15 +175,6 @@ def add_relative_home_path(self, language, path): language, self.relative_home_paths[language], path, self.destination)) self.relative_home_paths[language] = path - def get_add_exports(self, missing_jars): - if self.use_modules is None: - return '' - distributions = self.jar_distributions - distributions_transitive = mx.classpath_entries(distributions) - distributions_transitive_clean = [entry for entry in distributions_transitive if str(entry) not in missing_jars] - required_exports = mx_javamodules.requiredExports(distributions_transitive_clean, base_jdk()) - return ' '.join(AbstractNativeImageConfig.get_add_exports_list(required_exports)) - class LanguageLauncherConfig(LauncherConfig): def __init__(self, destination, jar_distributions, main_class, build_args, language, @@ -191,11 +191,11 @@ def __init__(self, destination, jar_distributions, main_class, build_args, langu class LibraryConfig(AbstractNativeImageConfig): - def __init__(self, destination, jar_distributions, build_args, jvm_library=False, **kwargs): + def __init__(self, destination, jar_distributions, build_args, jvm_library=False, use_modules=None, **kwargs): """ :param bool jvm_library """ - super(LibraryConfig, self).__init__(destination, jar_distributions, build_args, **kwargs) + super(LibraryConfig, self).__init__(destination, jar_distributions, build_args, use_modules, **kwargs) self.jvm_library = jvm_library diff --git a/sdk/mx.sdk/mx_sdk_vm_impl.py b/sdk/mx.sdk/mx_sdk_vm_impl.py index 0d5f34e3216c..d4c091e761a6 100644 --- a/sdk/mx.sdk/mx_sdk_vm_impl.py +++ b/sdk/mx.sdk/mx_sdk_vm_impl.py @@ -704,6 +704,7 @@ def _find_escaping_links(root_dir): _add(layout, _component_base, 'dependency:{}/polyglot.config'.format(launcher_project), _component) for _library_config in sorted(_get_library_configs(_component), key=lambda c: c.destination): graalvm_dists.update(_library_config.jar_distributions) + self.jimage_ignore_jars.update(_library_config.jar_distributions) if _library_config.jvm_library: assert isinstance(_component, (mx_sdk.GraalVmJdkComponent, mx_sdk.GraalVmJreComponent)) _svm_library_home = _jvm_library_dest @@ -1113,8 +1114,11 @@ def __init__(self, component, image_config, **kw_args): :type component: mx_sdk.GraalVmComponent | None :type image_config: mx_sdk.AbstractNativeImageConfig """ - deps = [] self.image_config = image_config + # With Java > 8 there are cases where image_config.get_add_exports is getting called in + # mx_sdk_vm_impl.NativePropertiesBuildTask.contents. This only works after the jar_distributions + # are made into proper modules. Therefore they have to be specified as dependencies here. + deps = [] if _src_jdk_version == 8 else list(image_config.jar_distributions) super(GraalVmNativeProperties, self).__init__(component, GraalVmNativeProperties.project_name(image_config), deps=deps, **kw_args) @staticmethod @@ -1272,6 +1276,11 @@ def contents(self): raise mx.abort("Profiles for an image must have unique filenames.\nThis is not the case for {}: {}.".format(canonical_name, profiles)) build_args += ['--pgo=' + ','.join(('${.}/' + n for n in basenames))] + build_with_module_path = image_config.use_modules == 'image' + if build_with_module_path: + export_deps_to_exclude = [str(dep) for dep in mx.classpath_entries(['substratevm:LIBRARY_SUPPORT'])] + list(_known_missing_jars) + build_args += image_config.get_add_exports(set(export_deps_to_exclude)) + requires = [arg[2:] for arg in build_args if arg.startswith('--language:') or arg.startswith('--tool:') or arg.startswith('--macro:')] build_args = [arg for arg in build_args if not (arg.startswith('--language:') or arg.startswith('--tool:') or arg.startswith('--macro:'))] @@ -1291,7 +1300,6 @@ def _write_ln(s): _write_ln(u'ImagePath=' + java_properties_escape("${.}/" + relpath(dirname(graalvm_image_destination), graalvm_location).replace(os.sep, '/'))) if requires: _write_ln(u'Requires=' + java_properties_escape(' '.join(requires), ' ', len('Requires'))) - build_with_module_path = image_config.use_modules == 'image' if isinstance(image_config, mx_sdk.LauncherConfig): _write_ln(u'ImageClass=' + java_properties_escape(image_config.main_class)) if build_with_module_path: @@ -1898,7 +1906,7 @@ def _get_launcher_args(): return '' def _get_add_exports(): - res = self.subject.native_image_config.get_add_exports(_known_missing_jars) + res = ' '.join(self.subject.native_image_config.get_add_exports(_known_missing_jars)) if mx.is_windows(): res = ' '.join(('"{}"'.format(a) for a in res.split())) return res diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index ab1b963b3f34..95bfaa117bf4 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -831,9 +831,9 @@ def _native_image_launcher_extra_jvm_args(): launcher_configs=[ mx_sdk_vm.LauncherConfig( use_modules='image' if USE_NI_JPMS else 'launcher' if not svm_java8() else None, + main_module="org.graalvm.nativeimage.driver", destination="bin/", jar_distributions=["substratevm:SVM_DRIVER"], - main_module="org.graalvm.nativeimage.driver", main_class=_native_image_launcher_main_class(), build_args=[], extra_jvm_args=_native_image_launcher_extra_jvm_args(), @@ -841,9 +841,11 @@ def _native_image_launcher_extra_jvm_args(): ], library_configs=[ mx_sdk_vm.LibraryConfig( + use_modules='image' if USE_NI_JPMS else 'launcher' if not svm_java8() else None, destination="", jvm_library=True, jar_distributions=[ + 'substratevm:SVM_CONFIGURE', 'substratevm:JVMTI_AGENT_BASE', 'substratevm:SVM_AGENT', ], @@ -853,6 +855,7 @@ def _native_image_launcher_extra_jvm_args(): ], ), mx_sdk_vm.LibraryConfig( + use_modules='image' if USE_NI_JPMS else 'launcher' if not svm_java8() else None, destination="", jvm_library=True, jar_distributions=[ @@ -1006,6 +1009,8 @@ def _native_image_configure_extra_jvm_args(): support_distributions=[], launcher_configs=[ mx_sdk_vm.LauncherConfig( + use_modules='image' if USE_NI_JPMS else 'launcher' if not svm_java8() else None, + main_module="org.graalvm.nativeimage.configure", destination="bin/", jar_distributions=["substratevm:SVM_CONFIGURE"], main_class="com.oracle.svm.configure.ConfigurationTool", @@ -1086,17 +1091,28 @@ def hellomodule(args): proj_dir = join(suite.dir, 'src', 'native-image-module-tests', 'hello.app') mx.run_maven(['-e', 'install'], cwd=proj_dir) module_path.append(join(proj_dir, 'target', 'hello-app-1.0-SNAPSHOT.jar')) - config = GraalVMConfig.build(native_images=['native-image']) + config = GraalVMConfig.build(native_images=['native-image', 'lib:native-image-agent', 'lib:native-image-diagnostics-agent']) with native_image_context(hosted_assertions=False, config=config) as native_image: + module_path_sep = ';' if mx.is_windows() else ':' + moduletest_run_args = [ + '--add-exports=moduletests.hello.lib/hello.privateLib=moduletests.hello.app', + '--add-opens=moduletests.hello.lib/hello.privateLib2=moduletests.hello.app', + '-p', module_path_sep.join(module_path), '-m', 'moduletests.hello.app' + ] + mx.log('Running module-tests on JVM:') build_dir = join(svmbuild_dir(), 'hellomodule') + mx.run([ + vm_executable_path('java', config), + # also test if native-image-agent works + '-agentlib:native-image-agent=config-output-dir=' + join(build_dir, 'config-output-dir-{pid}-{datetime}/'), + ] + moduletest_run_args) + # Build module into native image mx.log('Building image from java modules: ' + str(module_path)) - module_path_sep = ';' if mx.is_windows() else ':' built_image = native_image([ - '--verbose', '-ea', '-H:Path=' + build_dir, - '--add-exports=moduletests.hello.lib/hello.privateLib=moduletests.hello.app', - '--add-exports=moduletests.hello.lib/hello.privateLib2=moduletests.hello.app', - '-p', module_path_sep.join(module_path), '-m', 'moduletests.hello.app']) + '--verbose', '-H:Path=' + build_dir, + '--trace-class-initialization=hello.lib.Greeter', # also test native-image-diagnostics-agent + ] + moduletest_run_args) mx.log('Running image ' + built_image + ' built from module:') mx.run([built_image]) diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 170e63c07c35..cbde02f45837 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -1,3 +1,4 @@ +# pylint: disable=line-too-long suite = { "mxversion": "5.301.0", "name": "substratevm", @@ -1090,7 +1091,8 @@ "com.oracle.svm.hosted.agent to java.instrument", "com.oracle.svm.core.graal.thread to jdk.internal.vm.compiler", "com.oracle.svm.core.classinitialization to jdk.internal.vm.compiler", - "* to org.graalvm.nativeimage.driver,org.graalvm.nativeimage.librarysupport,org.graalvm.nativeimage.llvm,com.oracle.svm.svm_enterprise", + "com.oracle.svm.truffle.api to org.graalvm.truffle", + "* to org.graalvm.nativeimage.driver,org.graalvm.nativeimage.configure,org.graalvm.nativeimage.librarysupport,org.graalvm.nativeimage.llvm,org.graalvm.nativeimage.agent.jvmtibase,org.graalvm.nativeimage.agent.tracing,org.graalvm.nativeimage.agent.diagnostics,com.oracle.svm.svm_enterprise", ], "opens" : [ "com.oracle.svm.core.nodes to jdk.internal.vm.compiler", @@ -1109,6 +1111,8 @@ ], "uses" : [ "org.graalvm.nativeimage.Platform", + "com.oracle.truffle.api.TruffleLanguage.Provider", + "com.oracle.truffle.api.instrumentation.TruffleInstrument.Provider", ], "requiresConcealed": { "jdk.internal.vm.ci": [ @@ -1167,6 +1171,13 @@ "LIBRARY_SUPPORT", "SVM_DRIVER", ], + "moduleInfo" : { + "name" : "org.graalvm.nativeimage.agent.jvmtibase", + "exports" : [ + "com.oracle.svm.jvmtiagentbase", + "com.oracle.svm.jvmtiagentbase.jvmti", + ], + }, }, "LIBRARY_SUPPORT": { @@ -1278,6 +1289,7 @@ "name" : "org.graalvm.nativeimage.driver", "exports" : [ "com.oracle.svm.driver", + "com.oracle.svm.driver.metainf", ], "uses" : [ "org.graalvm.compiler.options.OptionDescriptors", @@ -1304,10 +1316,19 @@ "JVMTI_AGENT_BASE", "LIBRARY_SUPPORT", "SVM_DRIVER", + "SVM_CONFIGURE" ], - "overlaps" : [ - "SVM_CONFIGURE", - ], + "moduleInfo" : { + "name" : "org.graalvm.nativeimage.agent.tracing", + "exports" : [ + "com.oracle.svm.agent", + ], + "requiresConcealed" : { + "jdk.internal.vm.ci" : [ + "jdk.vm.ci.meta", + ], + } + }, # vm: included as binary, tool descriptor intentionally not copied }, @@ -1321,6 +1342,12 @@ "JVMTI_AGENT_BASE", "LIBRARY_SUPPORT", ], + "moduleInfo" : { + "name" : "org.graalvm.nativeimage.agent.diagnostics", + "exports" : [ + "com.oracle.svm.diagnosticsagent", + ], + }, }, "SVM_CONFIGURE": { @@ -1333,6 +1360,13 @@ "distDependencies": [ "LIBRARY_SUPPORT", ], + "moduleInfo" : { + "name" : "org.graalvm.nativeimage.configure", + "exports" : [ + "* to org.graalvm.nativeimage.agent.tracing", + "com.oracle.svm.configure", + ], + }, }, diff --git a/substratevm/src/com.oracle.objectfile.jdk11/src/com/oracle/objectfile/ModuleAccess.java b/substratevm/src/com.oracle.objectfile.jdk11/src/com/oracle/objectfile/ModuleAccess.java index aae274611d97..46b82f2f54bb 100644 --- a/substratevm/src/com.oracle.objectfile.jdk11/src/com/oracle/objectfile/ModuleAccess.java +++ b/substratevm/src/com.oracle.objectfile.jdk11/src/com/oracle/objectfile/ModuleAccess.java @@ -31,11 +31,18 @@ public class ModuleAccess { public static void openModuleByClass(Class declaringClass, Class accessingClass) { Module declaringModule = declaringClass.getModule(); String packageName = declaringClass.getPackageName(); - Module accessingModule = accessingClass == null ? null : accessingClass.getModule(); - if (accessingModule != null && accessingModule.isNamed()) { - if (!declaringModule.isOpen(packageName, accessingModule)) { - Modules.addOpens(declaringModule, packageName, accessingModule); + Module namedAccessingModule = null; + if (accessingClass != null) { + Module accessingModule = accessingClass.getModule(); + if (accessingModule.isNamed()) { + namedAccessingModule = accessingModule; } + } + if (namedAccessingModule != null ? declaringModule.isOpen(packageName, namedAccessingModule) : declaringModule.isOpen(packageName)) { + return; + } + if (namedAccessingModule != null) { + Modules.addOpens(declaringModule, packageName, namedAccessingModule); } else { Modules.addOpensToAllUnnamed(declaringModule, packageName); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ClassLoaderQuery.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ClassLoaderSupport.java similarity index 65% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ClassLoaderQuery.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ClassLoaderSupport.java index 4b82bad60297..9bc4850a6e9c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ClassLoaderQuery.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ClassLoaderSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, 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 @@ -24,11 +24,28 @@ */ package com.oracle.svm.core; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; + import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @Platforms(Platform.HOSTED_ONLY.class) -public interface ClassLoaderQuery { +public abstract class ClassLoaderSupport { + + public boolean isNativeImageClassLoader(ClassLoader classLoader) { + ClassLoader loader = classLoader; + while (loader != null) { + if (isNativeImageClassLoaderImpl(loader)) { + return true; + } + loader = loader.getParent(); + } + return false; + } + + protected abstract boolean isNativeImageClassLoaderImpl(ClassLoader classLoader); - boolean isNativeImageClassLoader(ClassLoader c); + public abstract List getResourceBundle(String bundleName, Locale locale); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/RuntimeAssertionsSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/RuntimeAssertionsSupport.java index b7c1d486fbc7..e8c2848527dc 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/RuntimeAssertionsSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/RuntimeAssertionsSupport.java @@ -184,7 +184,7 @@ private boolean desiredAssertionStatusImpl(String name, boolean fallback) { } private boolean desiredAssertionStatusImpl(String name, ClassLoader classLoader) { - boolean isNativeImageClassLoader = ImageSingletons.lookup(ClassLoaderQuery.class).isNativeImageClassLoader(classLoader); + boolean isNativeImageClassLoader = ImageSingletons.lookup(ClassLoaderSupport.class).isNativeImageClassLoader(classLoader); return desiredAssertionStatusImpl(name, isNativeImageClassLoader ? defaultAssertionStatus : systemAssertionStatus); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationFeature.java index 9668e71e5093..a25c81e6f1f7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationFeature.java @@ -69,6 +69,7 @@ import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.hosted.Feature; +import com.oracle.svm.core.ClassLoaderSupport; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.jdk.localization.compression.GzipBundleCompression; import com.oracle.svm.core.jdk.localization.substitutions.Target_sun_util_locale_provider_LocaleServiceProviderPool_OptimizedLocaleMode; @@ -77,7 +78,6 @@ import com.oracle.svm.core.option.OptionUtils; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.util.ModuleSupport; import com.oracle.svm.util.ReflectionUtil; import jdk.vm.ci.meta.ResolvedJavaField; @@ -456,29 +456,16 @@ public void prepareBundle(String baseName, Collection wantedLocales) { boolean somethingFound = false; for (Locale locale : wantedLocales) { - ResourceBundle resourceBundle; + List resourceBundle; try { - resourceBundle = ModuleSupport.getResourceBundle(baseName, locale, Thread.currentThread().getContextClassLoader()); + resourceBundle = ImageSingletons.lookup(ClassLoaderSupport.class).getResourceBundle(baseName, locale); } catch (MissingResourceException mre) { - if (!baseName.contains("/")) { - // fallthrough - continue; - } - // Due to a possible bug in the JDK, bundle names not following proper naming - // convention - // need to be - // converted to fully qualified class names before loading can succeed. - // see GR-24211 - String dotBundleName = baseName.replace("/", "."); - try { - resourceBundle = ModuleSupport.getResourceBundle(dotBundleName, locale, Thread.currentThread().getContextClassLoader()); - } catch (MissingResourceException ex) { - // fallthrough - continue; - } + continue; + } + somethingFound = !resourceBundle.isEmpty(); + for (ResourceBundle bundle : resourceBundle) { + prepareBundle(baseName, bundle, locale); } - somethingFound = true; - prepareBundle(baseName, resourceBundle, locale); } if (!somethingFound) { diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/MacroOptionHandler.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/MacroOptionHandler.java index 7c7d5dff0085..1588f6256326 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/MacroOptionHandler.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/MacroOptionHandler.java @@ -83,8 +83,6 @@ private void applyEnabled(MacroOption.EnabledOption enabledOption, String argume BuildConfiguration config = nativeImage.config; if (!config.useJavaModules()) { enabledOption.forEachPropertyValue(config, "ImageBuilderBootClasspath8", entry -> nativeImage.addImageBuilderBootClasspath(ClasspathUtils.stringToClasspath(entry)), PATH_SEPARATOR_REGEX); - } else { - enabledOption.forEachPropertyValue(config, "ImageIncludeBuiltinModules", entry -> nativeImage.addImageIncludeBuiltinModules(entry), ","); } if (!enabledOption.forEachPropertyValue(config, "ImageBuilderClasspath", entry -> nativeImage.addImageBuilderClasspath(ClasspathUtils.stringToClasspath(entry)), PATH_SEPARATOR_REGEX)) { diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index 686af3012d67..5842e2ca2c0f 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -88,7 +88,6 @@ import com.oracle.svm.driver.MacroOption.EnabledOption; import com.oracle.svm.driver.MacroOption.MacroOptionKind; import com.oracle.svm.driver.MacroOption.Registry; -import com.oracle.svm.hosted.AbstractNativeImageClassLoaderSupport; import com.oracle.svm.hosted.NativeImageGeneratorRunner; import com.oracle.svm.hosted.NativeImageSystemClassLoader; import com.oracle.svm.util.ModuleSupport; @@ -236,7 +235,6 @@ private static String oR(OptionKey option) { private final ArrayList imageBuilderArgs = new ArrayList<>(); private final LinkedHashSet imageBuilderClasspath = new LinkedHashSet<>(); private final LinkedHashSet imageBuilderBootClasspath = new LinkedHashSet<>(); - private final LinkedHashSet imageIncludeBuiltinModules = new LinkedHashSet<>(); private final ArrayList imageBuilderJavaArgs = new ArrayList<>(); private final LinkedHashSet imageClasspath = new LinkedHashSet<>(); private final LinkedHashSet imageProvidedClasspath = new LinkedHashSet<>(); @@ -1120,9 +1118,6 @@ private int completeImageBuild() { // The following two are for backwards compatibility reasons. They should be removed. imageBuilderJavaArgs.add("-Djdk.internal.lambda.eagerlyInitialize=false"); imageBuilderJavaArgs.add("-Djava.lang.invoke.InnerClassLambdaMetafactory.initializeLambdas=false"); - if (!imageIncludeBuiltinModules.isEmpty()) { - imageBuilderJavaArgs.add("-D" + AbstractNativeImageClassLoaderSupport.PROPERTY_IMAGEINCLUDEBUILTINMODULES + "=" + String.join(",", imageIncludeBuiltinModules)); - } /* After JavaArgs consolidation add the user provided JavaArgs */ boolean afterOption = false; @@ -1549,10 +1544,6 @@ void addImageBuilderBootClasspath(Path classpath) { imageBuilderBootClasspath.add(canonicalize(classpath)); } - public void addImageIncludeBuiltinModules(String moduleName) { - imageIncludeBuiltinModules.add(moduleName); - } - void addImageBuilderJavaArgs(String... javaArgs) { addImageBuilderJavaArgs(Arrays.asList(javaArgs)); } diff --git a/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java index bed2e489d569..218f14afd9be 100644 --- a/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java +++ b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java @@ -25,14 +25,16 @@ package com.oracle.svm.hosted; import java.io.File; +import java.io.IOException; import java.lang.module.Configuration; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -48,7 +50,6 @@ import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.util.ModuleSupport; import jdk.internal.module.Modules; @@ -58,7 +59,7 @@ public class NativeImageClassLoaderSupport extends AbstractNativeImageClassLoade private final List buildmp; private final ClassLoader classLoader; - private final ModuleLayer moduleLayerForImageBuild; + public final ModuleLayer moduleLayerForImageBuild; NativeImageClassLoaderSupport(ClassLoader defaultSystemClassLoader, String[] classpath, String[] modulePath) { super(defaultSystemClassLoader, classpath); @@ -67,14 +68,9 @@ public class NativeImageClassLoaderSupport extends AbstractNativeImageClassLoade buildmp = Arrays.stream(System.getProperty("jdk.module.path", "").split(File.pathSeparator)).map(Paths::get).collect(Collectors.toUnmodifiableList()); ModuleLayer moduleLayer = createModuleLayer(imagemp.toArray(Path[]::new), classPathClassLoader); - if (moduleLayer.modules().isEmpty()) { - this.moduleLayerForImageBuild = null; - classLoader = classPathClassLoader; - } else { - adjustBootLayerQualifiedExports(moduleLayer); - this.moduleLayerForImageBuild = moduleLayer; - classLoader = getSingleClassloader(moduleLayer); - } + adjustBootLayerQualifiedExports(moduleLayer); + moduleLayerForImageBuild = moduleLayer; + classLoader = getSingleClassloader(moduleLayer); } private static ModuleLayer createModuleLayer(Path[] modulePaths, ClassLoader parent) { @@ -112,11 +108,11 @@ private void adjustBootLayerQualifiedExports(ModuleLayer layer) { } } - private static ClassLoader getSingleClassloader(ModuleLayer moduleLayer) { - ClassLoader singleClassloader = null; + private ClassLoader getSingleClassloader(ModuleLayer moduleLayer) { + ClassLoader singleClassloader = classPathClassLoader; for (Module module : moduleLayer.modules()) { ClassLoader moduleClassLoader = module.getClassLoader(); - if (singleClassloader == null) { + if (singleClassloader == classPathClassLoader) { singleClassloader = moduleClassLoader; } else { VMError.guarantee(singleClassloader == moduleClassLoader); @@ -137,9 +133,6 @@ List applicationModulePath() { @Override public Optional findModule(String moduleName) { - if (moduleLayerForImageBuild == null) { - return Optional.empty(); - } return moduleLayerForImageBuild.findModule(moduleName); } @@ -227,79 +220,78 @@ private static UserError.UserException userErrorAddExportsAndOpens(String origin @Override Class loadClassFromModule(Object module, String className) throws ClassNotFoundException { - if (module == null) { - return Class.forName(className, false, classPathClassLoader); - } - if (!(module instanceof Module)) { - throw new IllegalArgumentException("Argument `module` is not an instance of java.lang.Module"); - } + assert module instanceof Module : "Argument `module` is not an instance of java.lang.Module"; Module m = (Module) module; - if (m.getClassLoader() != classLoader) { - throw new IllegalArgumentException("Argument `module` is java.lang.Module from different ClassLoader"); - } - String moduleClassName = className; - if (moduleClassName.isEmpty()) { - moduleClassName = m.getDescriptor().mainClass().orElseThrow( - () -> UserError.abort("module %s does not have a ModuleMainClass attribute, use -m /", m.getName())); - } - Class clazz = Class.forName(m, moduleClassName); - if (clazz == null) { - throw new ClassNotFoundException(moduleClassName); + assert isModuleClassLoader(classLoader, m.getClassLoader()) : "Argument `module` is java.lang.Module from unknown ClassLoader"; + return Class.forName(m, className); + } + + private static boolean isModuleClassLoader(ClassLoader loader, ClassLoader moduleClassLoader) { + if (moduleClassLoader == loader) { + return true; + } else { + if (loader == null) { + return false; + } + return isModuleClassLoader(loader.getParent(), moduleClassLoader); } - return clazz; } @Override - ClassLoader getClassLoader() { + Optional getMainClassFromModule(Object module) { + assert module instanceof Module : "Argument `module` is not an instance of java.lang.Module"; + return ((Module) module).getDescriptor().mainClass(); + } + + @Override + public ClassLoader getClassLoader() { return classLoader; } - private static class ClassInitWithModules extends ClassInit { + private class ClassInitWithModules extends ClassInit { - ClassInitWithModules(ForkJoinPool executor, ImageClassLoader imageClassLoader, AbstractNativeImageClassLoaderSupport nativeImageClassLoader) { - super(executor, imageClassLoader, nativeImageClassLoader); + ClassInitWithModules(ForkJoinPool executor, ImageClassLoader imageClassLoader) { + super(executor, imageClassLoader); } @Override protected void init() { - Set modules = new HashSet<>(); - modules.add("jdk.internal.vm.ci"); - - addOptionalModule(modules, "org.graalvm.sdk"); - addOptionalModule(modules, "jdk.internal.vm.compiler"); - addOptionalModule(modules, "com.oracle.graal.graal_enterprise"); + List requiresInit = Arrays.asList( + "jdk.internal.vm.ci", "jdk.internal.vm.compiler", "com.oracle.graal.graal_enterprise", + "org.graalvm.sdk", "org.graalvm.truffle"); - String includeModulesStr = System.getProperty(PROPERTY_IMAGEINCLUDEBUILTINMODULES); - if (includeModulesStr != null) { - modules.addAll(Arrays.asList(includeModulesStr.split(","))); + for (ModuleReference moduleReference : ModuleFinder.ofSystem().findAll()) { + if (requiresInit.contains(moduleReference.descriptor().name())) { + initModule(moduleReference); + } } - - for (String moduleResource : ModuleSupport.getSystemModuleResources(modules)) { - handleClassInModuleResource(moduleResource); - } - - for (String moduleResource : ModuleSupport.getModuleResources(nativeImageClassLoader.modulepath())) { - handleClassInModuleResource(moduleResource); + for (ModuleReference moduleReference : ModuleFinder.of(modulepath().toArray(Path[]::new)).findAll()) { + initModule(moduleReference); } super.init(); } - private void handleClassInModuleResource(String moduleResource) { - if (moduleResource.endsWith(CLASS_EXTENSION)) { - executor.execute(() -> handleClassFileName(classFileWithoutSuffix(moduleResource), '/')); + private void initModule(ModuleReference moduleReference) { + Optional optionalModule = findModule(moduleReference.descriptor().name()); + if (optionalModule.isEmpty()) { + return; } - } - - private static void addOptionalModule(Set modules, String name) { - if (ModuleSupport.hasSystemModule(name)) { - modules.add(name); + try (ModuleReader moduleReader = moduleReference.open()) { + Module module = optionalModule.get(); + moduleReader.list().forEach(moduleResource -> { + if (moduleResource.endsWith(CLASS_EXTENSION)) { + executor.execute(() -> handleClassFileName(module, moduleResource, '/')); + } + }); + } catch (IOException e) { + throw new RuntimeException("Unable get list of resources in module" + moduleReference.descriptor().name(), e); } } } @Override public void initAllClasses(ForkJoinPool executor, ImageClassLoader imageClassLoader) { - new ClassInitWithModules(executor, imageClassLoader, this).init(); + new ClassInitWithModules(executor, imageClassLoader).init(); } } diff --git a/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/ClassLoaderSupportImplJDK11OrLater.java b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/ClassLoaderSupportImplJDK11OrLater.java new file mode 100644 index 000000000000..df9556d65046 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/jdk11/ClassLoaderSupportImplJDK11OrLater.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2021, 2021, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.svm.hosted.jdk11; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.stream.Collectors; + +import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.hosted.Feature; + +import com.oracle.svm.core.ClassLoaderSupport; +import com.oracle.svm.core.annotate.AutomaticFeature; +import com.oracle.svm.hosted.FeatureImpl; +import com.oracle.svm.hosted.NativeImageClassLoaderSupport; +import com.oracle.svm.hosted.NativeImageSystemClassLoader; + +import jdk.internal.module.Modules; + +public final class ClassLoaderSupportImplJDK11OrLater extends ClassLoaderSupport { + + private final NativeImageClassLoaderSupport classLoaderSupport; + private final Map> packageToModules; + + ClassLoaderSupportImplJDK11OrLater(NativeImageClassLoaderSupport classLoaderSupport) { + this.classLoaderSupport = classLoaderSupport; + packageToModules = new HashMap<>(); + buildPackageToModulesMap(classLoaderSupport); + } + + @Override + protected boolean isNativeImageClassLoaderImpl(ClassLoader loader) { + return loader == classLoaderSupport.getClassLoader() || loader instanceof NativeImageSystemClassLoader; + } + + @Override + public List getResourceBundle(String bundleSpec, Locale locale) { + String[] specParts = bundleSpec.split(":", 2); + String moduleName; + String bundleName; + if (specParts.length > 1) { + moduleName = specParts[0]; + bundleName = specParts[1]; + } else { + moduleName = null; + bundleName = specParts[0]; + } + String packageName = packageName(bundleName); + if (packageName == null) { + throw new MissingResourceException("ResourceBundle does not seem to be a fully qualified class name.", bundleName, locale.toLanguageTag()); + } + Set modules; + if (moduleName != null) { + modules = classLoaderSupport.findModule(moduleName).stream().collect(Collectors.toSet()); + } else { + modules = packageToModules.getOrDefault(packageName, Collections.emptySet()); + } + if (modules.isEmpty()) { + /* If bundle is not located in any module get it via classloader (from ALL_UNNAMED) */ + return Collections.singletonList(ResourceBundle.getBundle(bundleName, locale, classLoaderSupport.getClassLoader())); + } + ArrayList resourceBundles = new ArrayList<>(); + for (Module module : modules) { + Module exportTargetModule = ClassLoaderSupportImplJDK11OrLater.class.getModule(); + if (!module.isOpen(packageName, exportTargetModule)) { + Modules.addOpens(module, packageName, exportTargetModule); + } + resourceBundles.add(ResourceBundle.getBundle(bundleName, locale, module)); + } + return resourceBundles; + } + + private static String packageName(String bundleName) { + int classSep = bundleName.replace('/', '.').lastIndexOf('.'); + if (classSep == -1) { + /* The bundle is not specified via a java.class or java.properties format. */ + return null; + } + return bundleName.substring(0, classSep); + } + + private void buildPackageToModulesMap(NativeImageClassLoaderSupport classLoaderSupport) { + for (ModuleLayer layer : allLayers(classLoaderSupport.moduleLayerForImageBuild)) { + for (Module module : layer.modules()) { + for (String packageName : module.getDescriptor().packages()) { + addToPackageNameModules(module, packageName); + } + } + } + } + + private static List allLayers(ModuleLayer moduleLayer) { + /** Implementation taken from {@link ModuleLayer#layers()} */ + List allLayers = new ArrayList<>(); + Set visited = new HashSet<>(); + Deque stack = new ArrayDeque<>(); + visited.add(moduleLayer); + stack.push(moduleLayer); + + while (!stack.isEmpty()) { + ModuleLayer layer = stack.pop(); + allLayers.add(layer); + + // push in reverse order + for (int i = layer.parents().size() - 1; i >= 0; i--) { + ModuleLayer parent = layer.parents().get(i); + if (!visited.contains(parent)) { + visited.add(parent); + stack.push(parent); + } + } + } + return allLayers; + } + + private void addToPackageNameModules(Module moduleName, String packageName) { + Set prevValue = packageToModules.get(packageName); + if (prevValue == null) { + /* Mostly packageName is only used in a single module */ + packageToModules.put(packageName, Collections.singleton(moduleName)); + } else if (prevValue.size() == 1) { + /* Transition to HashSet - happens rarely */ + HashSet newValue = new HashSet<>(); + newValue.add(prevValue.iterator().next()); + newValue.add(moduleName); + packageToModules.put(packageName, newValue); + } else if (prevValue.size() > 1) { + /* Add to exiting HashSet - happens rarely */ + prevValue.add(moduleName); + } + } + +} + +@AutomaticFeature +class ClassLoaderSupportFeatureJDK11OrLater implements Feature { + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return JavaVersionUtil.JAVA_SPEC >= 11; + } + + @Override + public void afterRegistration(AfterRegistrationAccess a) { + FeatureImpl.AfterRegistrationAccessImpl access = (FeatureImpl.AfterRegistrationAccessImpl) a; + ImageSingletons.add(ClassLoaderSupport.class, new ClassLoaderSupportImplJDK11OrLater(access.getImageClassLoader().classLoaderSupport)); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/AbstractNativeImageClassLoaderSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/AbstractNativeImageClassLoaderSupport.java index a891896cbb9d..ccd17efde865 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/AbstractNativeImageClassLoaderSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/AbstractNativeImageClassLoaderSupport.java @@ -65,12 +65,6 @@ public abstract class AbstractNativeImageClassLoaderSupport { - /* - * This cannot be a HostedOption because all Subclasses of OptionDescriptors from inside builtin - * modules need to be initialized prior to option parsing so that they can be found. - */ - public static final String PROPERTY_IMAGEINCLUDEBUILTINMODULES = "substratevm.ImageIncludeBuiltinModules"; - final List imagecp; private final List buildcp; @@ -107,6 +101,8 @@ ClassLoader getClassLoader() { abstract Class loadClassFromModule(Object module, String className) throws ClassNotFoundException; + abstract Optional getMainClassFromModule(Object module); + abstract List modulepath(); abstract List applicationModulePath(); @@ -154,25 +150,23 @@ static Path urlToPath(URL url) { } } - protected static class ClassInit { + protected class ClassInit { protected final ForkJoinPool executor; protected final ImageClassLoader imageClassLoader; - protected final AbstractNativeImageClassLoaderSupport nativeImageClassLoader; - ClassInit(ForkJoinPool executor, ImageClassLoader imageClassLoader, AbstractNativeImageClassLoaderSupport nativeImageClassLoader) { + ClassInit(ForkJoinPool executor, ImageClassLoader imageClassLoader) { this.executor = executor; this.imageClassLoader = imageClassLoader; - this.nativeImageClassLoader = nativeImageClassLoader; } protected void init() { - Set uniquePaths = new TreeSet<>(Comparator.comparing(ClassInit::toRealPath)); - uniquePaths.addAll(nativeImageClassLoader.classpath()); + Set uniquePaths = new TreeSet<>(Comparator.comparing(this::toRealPath)); + uniquePaths.addAll(classpath()); uniquePaths.parallelStream().forEach(path -> loadClassesFromPath(path)); } - private static Path toRealPath(Path p) { + private Path toRealPath(Path p) { try { return p.toRealPath(); } catch (IOException e) { @@ -180,9 +174,9 @@ private static Path toRealPath(Path p) { } } - private static final Set excludeDirectories = getExcludeDirectories(); + private final Set excludeDirectories = getExcludeDirectories(); - private static Set getExcludeDirectories() { + private Set getExcludeDirectories() { Path root = Paths.get("/"); return Stream.of("dev", "sys", "proc", "etc", "var", "tmp", "boot", "lost+found") .map(root::resolve).collect(Collectors.toSet()); @@ -233,7 +227,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { assert !excludes.contains(file.getParent()) : "Visiting file '" + file + "' with excluded parent directory"; String fileName = root.relativize(file).toString(); if (fileName.endsWith(CLASS_EXTENSION)) { - executor.execute(() -> handleClassFileName(unversionedFileName(fileName), fileSystemSeparatorChar)); + executor.execute(() -> handleClassFileName(null, fileName, fileSystemSeparatorChar)); } return FileVisitResult.CONTINUE; } @@ -243,32 +237,6 @@ public FileVisitResult visitFileFailed(Path file, IOException exc) { /* Silently ignore inaccessible files or directories. */ return FileVisitResult.CONTINUE; } - - /** - * Take a file name from a possibly-multi-versioned jar file and remove the - * versioning information. See - * https://docs.oracle.com/javase/9/docs/api/java/util/jar/JarFile.html for the - * specification of the versioning strings. - * - * Then, depend on the JDK class loading mechanism to prefer the - * appropriately-versioned class when the class is loaded. The same class name be - * loaded multiple times, but each request will return the same - * appropriately-versioned class. If a higher-versioned class is not available in a - * lower-versioned JDK, a ClassNotFoundException will be thrown, which will be - * handled appropriately. - */ - private String unversionedFileName(String fileName) { - final String versionedPrefix = "META-INF/versions/"; - final String versionedSuffix = "/"; - String result = fileName; - if (fileName.startsWith(versionedPrefix)) { - final int versionedSuffixIndex = fileName.indexOf(versionedSuffix, versionedPrefix.length()); - if (versionedSuffixIndex >= 0) { - result = fileName.substring(versionedSuffixIndex + versionedSuffix.length()); - } - } - return classFileWithoutSuffix(result); - } }; try { @@ -278,20 +246,41 @@ private String unversionedFileName(String fileName) { } } - static String classFileWithoutSuffix(String result) { + /** + * Take a file name from a possibly-multi-versioned jar file and remove the versioning + * information. See https://docs.oracle.com/javase/9/docs/api/java/util/jar/JarFile.html for + * the specification of the versioning strings. + * + * Then, depend on the JDK class loading mechanism to prefer the appropriately-versioned + * class when the class is loaded. The same class name be loaded multiple times, but each + * request will return the same appropriately-versioned class. If a higher-versioned class + * is not available in a lower-versioned JDK, a ClassNotFoundException will be thrown, which + * will be handled appropriately. + */ + private String strippedClassFileName(String fileName) { + final String versionedPrefix = "META-INF/versions/"; + final String versionedSuffix = "/"; + String result = fileName; + if (fileName.startsWith(versionedPrefix)) { + final int versionedSuffixIndex = fileName.indexOf(versionedSuffix, versionedPrefix.length()); + if (versionedSuffixIndex >= 0) { + result = fileName.substring(versionedSuffixIndex + versionedSuffix.length()); + } + } return result.substring(0, result.length() - CLASS_EXTENSION.length()); } - protected void handleClassFileName(String strippedClassFileName, char fileSystemSeparatorChar) { + protected void handleClassFileName(Object module, String fileName, char fileSystemSeparatorChar) { + String strippedClassFileName = strippedClassFileName(fileName); if (strippedClassFileName.equals("module-info")) { return; } - String className = strippedClassFileName.replace(fileSystemSeparatorChar, '.'); - Class clazz = null; try { - clazz = imageClassLoader.forName(className); + clazz = imageClassLoader.forName(className, module); + } catch (AssertionError error) { + VMError.shouldNotReachHere(error); } catch (Throwable t) { ImageClassLoader.handleClassLoadingError(t); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderSupportImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderSupportImpl.java new file mode 100644 index 000000000000..e7cae08861d7 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderSupportImpl.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021, 2021, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.svm.hosted; + +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; + +import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.hosted.Feature; + +import com.oracle.svm.core.ClassLoaderSupport; +import com.oracle.svm.core.annotate.AutomaticFeature; + +public final class ClassLoaderSupportImpl extends ClassLoaderSupport { + + private final ClassLoader imageClassLoader; + + ClassLoaderSupportImpl(NativeImageClassLoaderSupport classLoaderSupport) { + this.imageClassLoader = classLoaderSupport.getClassLoader(); + } + + @Override + protected boolean isNativeImageClassLoaderImpl(ClassLoader loader) { + return loader == imageClassLoader || loader instanceof NativeImageSystemClassLoader; + } + + @Override + public List getResourceBundle(String bundleName, Locale locale) { + return Collections.singletonList(ResourceBundle.getBundle(bundleName, locale, imageClassLoader)); + } +} + +@AutomaticFeature +class ClassLoaderSupportFeature implements Feature { + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return JavaVersionUtil.JAVA_SPEC == 8; + } + + @Override + public void afterRegistration(AfterRegistrationAccess a) { + FeatureImpl.AfterRegistrationAccessImpl access = (FeatureImpl.AfterRegistrationAccessImpl) a; + ImageSingletons.add(ClassLoaderSupport.class, new ClassLoaderSupportImpl(access.getImageClassLoader().classLoaderSupport)); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java index 322eea7660a9..40f71626f596 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageClassLoader.java @@ -49,7 +49,6 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import com.oracle.svm.core.ClassLoaderQuery; import com.oracle.svm.core.TypeResult; public final class ImageClassLoader { @@ -70,7 +69,7 @@ public final class ImageClassLoader { } public final Platform platform; - final NativeImageClassLoaderSupport classLoaderSupport; + public final NativeImageClassLoaderSupport classLoaderSupport; private final EconomicSet> applicationClasses = EconomicSet.create(); private final EconomicSet> hostedOnlyClasses = EconomicSet.create(); @@ -287,6 +286,13 @@ Class forName(String name) throws ClassNotFoundException { return Class.forName(name, false, classLoaderSupport.getClassLoader()); } + public Class forName(String className, Object module) throws ClassNotFoundException { + if (module == null) { + return forName(className); + } + return classLoaderSupport.loadClassFromModule(module, className); + } + /** * Deprecated. Use {@link ImageClassLoader#classpath()} instead. * @@ -414,11 +420,11 @@ public ClassLoader getClassLoader() { return classLoaderSupport.getClassLoader(); } - public Class loadClassFromModule(Object module, String className) throws ClassNotFoundException { - return classLoaderSupport.loadClassFromModule(module, className); + public Optional getMainClassFromModule(Object module) { + return classLoaderSupport.getMainClassFromModule(module); } - public Optional findModule(String moduleName) { + public Optional findModule(String moduleName) { return classLoaderSupport.findModule(moduleName); } @@ -426,24 +432,3 @@ public void processAddExportsAndAddOpens(OptionValues parsedHostedOptions) { classLoaderSupport.processAddExportsAndAddOpens(parsedHostedOptions); } } - -class ClassLoaderQueryImpl implements ClassLoaderQuery { - - private final ClassLoader imageClassLoader; - - ClassLoaderQueryImpl(ClassLoader imageClassLoader) { - this.imageClassLoader = imageClassLoader; - } - - @Override - public boolean isNativeImageClassLoader(ClassLoader classLoader) { - ClassLoader loader = classLoader; - while (loader != null) { - if (loader == imageClassLoader || loader instanceof NativeImageSystemClassLoader) { - return true; - } - loader = loader.getParent(); - } - return false; - } -} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java index a9f209bcbb76..f63ad8d6ccf5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java @@ -60,15 +60,16 @@ void processAddExportsAndAddOpens(OptionValues parsedHostedOptions) { @Override Class loadClassFromModule(Object module, String className) throws ClassNotFoundException { - if (module != null) { - throw new ClassNotFoundException(className, - new UnsupportedOperationException("NativeImageClassLoader for Java 8 does not support modules")); - } - return Class.forName(className, false, classPathClassLoader); + throw new UnsupportedOperationException("NativeImageClassLoader for Java 8 does not support modules"); + } + + @Override + Optional getMainClassFromModule(Object module) { + return Optional.empty(); } @Override public void initAllClasses(ForkJoinPool executor, ImageClassLoader imageClassLoader) { - new ClassInit(executor, imageClassLoader, this).init(); + new ClassInit(executor, imageClassLoader).init(); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index edb16b5b2275..046496e9bc78 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -155,7 +155,6 @@ import com.oracle.graal.pointsto.util.Timer.StopTimer; import com.oracle.svm.core.BuildArtifacts; import com.oracle.svm.core.BuildArtifacts.ArtifactType; -import com.oracle.svm.core.ClassLoaderQuery; import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.JavaMainWrapper.JavaMainSupport; import com.oracle.svm.core.LinkerInvocation; @@ -482,7 +481,6 @@ public void run(Map entryPoints, ImageSingletonsSupportImpl.HostedManagement.install(new ImageSingletonsSupportImpl.HostedManagement()); ImageSingletons.add(BuildArtifacts.class, (type, artifact) -> buildArtifacts.computeIfAbsent(type, t -> new ArrayList<>()).add(artifact)); - ImageSingletons.add(ClassLoaderQuery.class, new ClassLoaderQueryImpl(loader.getClassLoader())); ImageSingletons.add(HostedOptionValues.class, new HostedOptionValues(optionProvider.getHostedValues())); ImageSingletons.add(RuntimeOptionValues.class, new RuntimeOptionValues(optionProvider.getRuntimeValues(), allOptionNames)); watchdog = new DeadlockWatchdog(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java index ebf47a5dd526..5673e9e427ed 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java @@ -305,20 +305,22 @@ private int buildImage(String[] arguments, ImageClassLoader classLoader) { SubstrateOptionsParser.commandArgument(SubstrateOptions.Class, "")); } + classLoader.processAddExportsAndAddOpens(parsedHostedOptions); + if (!className.isEmpty() || !moduleName.isEmpty()) { - classLoader.processAddExportsAndAddOpens(parsedHostedOptions); Method mainEntryPoint; Class mainClass; try { - Object jpmsModule = null; + Object mainModule = null; if (!moduleName.isEmpty()) { - jpmsModule = classLoader.findModule(moduleName) - .orElseThrow(() -> { - String errorMsg = "Module " + moduleName + " for mainclass not found."; - return UserError.abort(errorMsg); - }); + mainModule = classLoader.findModule(moduleName) + .orElseThrow(() -> UserError.abort("Module " + moduleName + " for mainclass not found.")); + } + if (className.isEmpty()) { + className = classLoader.getMainClassFromModule(mainModule) + .orElseThrow(() -> UserError.abort("module %s does not have a ModuleMainClass attribute, use -m /", moduleName)); } - mainClass = classLoader.loadClassFromModule(jpmsModule, className); + mainClass = classLoader.forName(className, mainModule); } catch (ClassNotFoundException ex) { throw UserError.abort("Main entry point class '%s' not found.", className); } diff --git a/substratevm/src/com.oracle.svm.util.jdk11/src/com/oracle/svm/util/ModuleSupport.java b/substratevm/src/com.oracle.svm.util.jdk11/src/com/oracle/svm/util/ModuleSupport.java index 989393fe1891..d33b3e208d21 100644 --- a/substratevm/src/com.oracle.svm.util.jdk11/src/com/oracle/svm/util/ModuleSupport.java +++ b/substratevm/src/com.oracle.svm.util.jdk11/src/com/oracle/svm/util/ModuleSupport.java @@ -24,160 +24,44 @@ */ package com.oracle.svm.util; -import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.lang.module.ModuleFinder; import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; import java.lang.module.ResolvedModule; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; -import java.util.Locale; -import java.util.MissingResourceException; import java.util.NoSuchElementException; import java.util.Optional; -import java.util.ResourceBundle; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Predicate; import java.util.stream.Collectors; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + import jdk.internal.module.Modules; +@Platforms(Platform.HOSTED_ONLY.class) public final class ModuleSupport { private ModuleSupport() { } - public static ResourceBundle getResourceBundle(String bundleName, Locale locale, ClassLoader loader) { - Class bundleClass; - try { - bundleClass = loader.loadClass(bundleName); - } catch (ClassNotFoundException ex) { - return getResourceBundleFallback(bundleName, locale, loader); - } - /* - * Open up module that contains the bundleClass so that ResourceBundle.getBundle can - * succeed. - */ - ModuleSupport.openModuleByClass(bundleClass, ModuleSupport.class); - return ResourceBundle.getBundle(bundleName, locale, bundleClass.getModule()); - } - - private static ResourceBundle getResourceBundleFallback(String bundleName, Locale locale, ClassLoader loader) { - /* Try looking through all modules to find a match. */ - Optional packageName = packageName(bundleName); - for (Module module : ModuleLayer.boot().modules()) { - try { - packageName.ifPresent(p -> { - if (module.getPackages().contains(p)) { - Modules.addExportsToAllUnnamed(module, p); - Modules.addOpensToAllUnnamed(module, p); - } - }); - return ResourceBundle.getBundle(bundleName, locale, module); - } catch (MissingResourceException e2) { - /* Continue the loop. */ - } - } - - /* - * This call will most likely throw an exception because it will also not find the bundle - * class. But it avoids special and JDK-specific handling here. - */ - return ResourceBundle.getBundle(bundleName, locale, loader); - } - - /** - * If the bundle is specified via java.class or java.properties format extract the package from - * the name. - */ - private static Optional packageName(String bundleName) { - int classSep = bundleName.replace('/', '.').lastIndexOf('.'); - if (classSep == -1) { - /* The bundle is not specified via a java.class or java.properties format. */ - return Optional.empty(); - } - return Optional.of(bundleName.substring(0, classSep)); - } - - private static ModuleFinder upgradeAndSystemModuleFinder; - - /** - * Creates a finder from a module path specified by the {@code prop} system property. - */ - private static ModuleFinder finderFor(String prop) { - String s = System.getProperty(prop); - if (s == null || s.isEmpty()) { - return null; - } else { - String[] dirs = s.split(File.pathSeparator); - Path[] paths = new Path[dirs.length]; - int i = 0; - for (String dir : dirs) { - paths[i++] = Path.of(dir); - } - return ModuleFinder.of(paths); - } - } - - /** - * Gets a finder that locates the upgrade modules and the system modules, in that order. - */ - private static ModuleFinder getUpgradeAndSystemModuleFinder() { - if (upgradeAndSystemModuleFinder == null) { - ModuleFinder finder = ModuleFinder.ofSystem(); - ModuleFinder upgradeModulePath = finderFor("jdk.module.upgrade.path"); - if (upgradeModulePath != null) { - finder = ModuleFinder.compose(upgradeModulePath, finder); - } - upgradeAndSystemModuleFinder = finder; - } - return upgradeAndSystemModuleFinder; - } - - public static boolean hasSystemModule(String moduleName) { - return getUpgradeAndSystemModuleFinder().find(moduleName).isPresent(); - } - - public static List getModuleResources(Collection modulePath) { - ArrayList result = new ArrayList<>(); - for (ModuleReference moduleReference : ModuleFinder.of(modulePath.toArray(Path[]::new)).findAll()) { - try (ModuleReader moduleReader = moduleReference.open()) { - result.addAll(moduleReader.list().collect(Collectors.toList())); - } catch (IOException e) { - throw new RuntimeException("Unable get list of resources in module" + moduleReference.descriptor().name(), e); - } - } - return result; - } - - public static List getSystemModuleResources(Collection names) { - List result = new ArrayList<>(); - for (String name : names) { - Optional moduleReference = getUpgradeAndSystemModuleFinder().find(name); - if (moduleReference.isEmpty()) { - throw new RuntimeException("Unable find ModuleReference for module " + name); - } - try (ModuleReader moduleReader = moduleReference.get().open()) { - result.addAll(moduleReader.list().collect(Collectors.toList())); - } catch (IOException e) { - throw new RuntimeException("Unable get list of resources in module" + name, e); - } - } - return result; - } - public static void openModuleByClass(Class declaringClass, Class accessingClass) { Module declaringModule = declaringClass.getModule(); String packageName = declaringClass.getPackageName(); - Module accessingModule = accessingClass == null ? null : accessingClass.getModule(); - if (accessingModule != null && accessingModule.isNamed()) { - if (!declaringModule.isOpen(packageName, accessingModule)) { - Modules.addOpens(declaringModule, packageName, accessingModule); + Module namedAccessingModule = null; + if (accessingClass != null) { + Module accessingModule = accessingClass.getModule(); + if (accessingModule.isNamed()) { + namedAccessingModule = accessingModule; } + } + if (namedAccessingModule != null ? declaringModule.isOpen(packageName, namedAccessingModule) : declaringModule.isOpen(packageName)) { + return; + } + if (namedAccessingModule != null) { + Modules.addOpens(declaringModule, packageName, namedAccessingModule); } else { Modules.addOpensToAllUnnamed(declaringModule, packageName); } diff --git a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ModuleSupport.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ModuleSupport.java index d8b957358cfc..2f451deab2d2 100644 --- a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ModuleSupport.java +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ModuleSupport.java @@ -26,53 +26,19 @@ import java.io.IOException; import java.io.InputStream; -import java.nio.file.Path; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Locale; import java.util.NoSuchElementException; -import java.util.ResourceBundle; import java.util.function.BiConsumer; import java.util.function.Predicate; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +@Platforms(Platform.HOSTED_ONLY.class) public final class ModuleSupport { private ModuleSupport() { } - public static ResourceBundle getResourceBundle(String bundleName, Locale locale, ClassLoader loader) { - return ResourceBundle.getBundle(bundleName, locale, loader); - } - - /** - * Checks if the Java run-time image contains a module with the given name. - */ - @SuppressWarnings("unused") - public static boolean hasSystemModule(String moduleName) { - /* Nothing to do in JDK 8 version. JDK 11 version provides a proper implementation. */ - assert JavaVersionUtil.JAVA_SPEC <= 8; - return false; - } - - /** - * Gets all resources in the modules named by {@code modules} from the Java runtime image. - */ - @SuppressWarnings("unused") - public static List getModuleResources(Collection modulePath) { - /* Nothing to do in JDK 8 version. JDK 11 version provides a proper implementation. */ - assert JavaVersionUtil.JAVA_SPEC <= 8; - return Collections.emptyList(); - } - - @SuppressWarnings("unused") - public static List getSystemModuleResources(Collection names) { - /* Nothing to do in JDK 8 version. JDK 11 version provides a proper implementation. */ - assert JavaVersionUtil.JAVA_SPEC <= 8; - return Collections.emptyList(); - } - /** * Add the proper module opening to allow accesses from accessingClass to declaringClass. */ diff --git a/truffle/mx.truffle/macro-truffle.properties b/truffle/mx.truffle/macro-truffle.properties index 0c4eae8e808d..8ecf9e01d8d4 100644 --- a/truffle/mx.truffle/macro-truffle.properties +++ b/truffle/mx.truffle/macro-truffle.properties @@ -1,6 +1,5 @@ # This file contains support for building truffle images ImageBuilderBootClasspath8 = ${.}/../../../truffle/truffle-api.jar -ImageIncludeBuiltinModules = org.graalvm.truffle Args = -H:Features=com.oracle.svm.truffle.TruffleFeature,org.graalvm.home.HomeFinderFeature \ -H:MaxRuntimeCompileMethods=2000 \ diff --git a/truffle/mx.truffle/suite.py b/truffle/mx.truffle/suite.py index 36ae41e89c6d..37ce8551ccd8 100644 --- a/truffle/mx.truffle/suite.py +++ b/truffle/mx.truffle/suite.py @@ -860,7 +860,7 @@ ], "exports" : [ # Qualified exports - "com.oracle.truffle.api* to com.oracle.truffle.regex, jdk.internal.vm.compiler, com.oracle.graal.graal_enterprise", + "com.oracle.truffle.api* to com.oracle.truffle.regex, jdk.internal.vm.compiler, com.oracle.graal.graal_enterprise, org.graalvm.nativeimage.builder", "com.oracle.truffle.api.impl to org.graalvm.locator", "com.oracle.truffle.api to org.graalvm.locator, com.oracle.truffle.truffle_nfi, org.graalvm.nativeimage.builder", "com.oracle.truffle.object to jdk.internal.vm.compiler, com.oracle.graal.graal_enterprise",