diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 598b9f33f67c..fd6ceead2c57 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -80,6 +80,11 @@ jobs: JDK: "labsjdk-ce-11" GATE: "build,debuginfotest" PRIMARY: "substratevm" + - env: + JDK: "labsjdk-ce-11" + GATE: "hellomodule" + PRIMARY: "substratevm" + USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM: true - env: JDK: "labsjdk-ce-11" GATE: "style,fullbuild" diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 02ba9bd36b95..1cd197fb9920 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -198,7 +198,8 @@ "dependencies": ["com.oracle.svm.core"], "requires" : [ "java.logging", - "jdk.unsupported" + "jdk.unsupported", + "java.compiler", ], "requiresConcealed" : { "java.base" : [ @@ -235,7 +236,10 @@ "com.oracle.svm.core.jdk15": { "subDir": "src", "sourceDirs": ["src"], - "dependencies": ["com.oracle.svm.core"], + "dependencies": [ + "com.oracle.svm.core", + "com.oracle.svm.core.jdk11" + ], "requiresConcealed" : { "java.base" : [ "jdk.internal.loader", @@ -403,6 +407,7 @@ "sourceDirs": ["src"], "dependencies": [ "com.oracle.svm.hosted", + "com.oracle.svm.core.jdk11" ], "requires" : ["java.instrument"], "requiresConcealed" : { diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/BootModuleLayerSupport.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/BootModuleLayerSupport.java new file mode 100644 index 000000000000..502265882b6e --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/BootModuleLayerSupport.java @@ -0,0 +1,47 @@ +/* + * 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.core.jdk11; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +public final class BootModuleLayerSupport { + + public static BootModuleLayerSupport instance() { + return ImageSingletons.lookup(BootModuleLayerSupport.class); + } + + private ModuleLayer bootLayer; + + @Platforms(Platform.HOSTED_ONLY.class) + public void setBootLayer(ModuleLayer bootLayer) { + this.bootLayer = bootLayer; + } + + public ModuleLayer getBootLayer() { + return bootLayer; + } +} diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/JavaLangSubstitutions_JDK11OrLater.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/JavaLangSubstitutions_JDK11OrLater.java new file mode 100644 index 000000000000..c9fd579dcd7d --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/JavaLangSubstitutions_JDK11OrLater.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, Red Hat Inc. 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.core.jdk11; + +import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.Delete; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.hub.ClassForNameSupport; +import com.oracle.svm.core.jdk.JDK11OrLater; +import com.oracle.svm.core.jdk.Target_java_lang_Package; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; + +@TargetClass(value = jdk.internal.loader.ClassLoaders.class, onlyWith = JDK11OrLater.class) +final class Target_jdk_internal_loader_ClassLoaders_JDK11OrLater { + @Alias + static native Target_jdk_internal_loader_BuiltinClassLoader bootLoader(); + + @Alias + public static native ClassLoader platformClassLoader(); +} + +@TargetClass(value = jdk.internal.loader.BootLoader.class, onlyWith = JDK11OrLater.class) +final class Target_jdk_internal_loader_BootLoader_JDK11OrLater { + + @Substitute + static Package getDefinedPackage(String name) { + if (name != null) { + Target_java_lang_Package pkg = new Target_java_lang_Package(name, null, null, null, + null, null, null, null, null); + return SubstrateUtil.cast(pkg, Package.class); + } else { + return null; + } + } + + @Substitute + public static Stream packages() { + Target_jdk_internal_loader_BuiltinClassLoader bootClassLoader = Target_jdk_internal_loader_ClassLoaders_JDK11OrLater.bootLoader(); + Target_java_lang_ClassLoader_JDK11OrLater systemClassLoader = SubstrateUtil.cast(bootClassLoader, Target_java_lang_ClassLoader_JDK11OrLater.class); + return systemClassLoader.packages(); + } + + @Delete("only used by #packages()") + private static native String[] getSystemPackageNames(); + + @Substitute + private static Class loadClassOrNull(String name) { + return ClassForNameSupport.forNameOrNull(name, null); + } + + @SuppressWarnings("unused") + @Substitute + private static Class loadClass(Target_java_lang_Module_JDK11OrLater module, String name) { + /* The module system is not supported for now, therefore the module parameter is ignored. */ + return ClassForNameSupport.forNameOrNull(name, null); + } + + @Substitute + private static boolean hasClassPath() { + return true; + } + + /** + * All ClassLoaderValue are reset at run time for now. See also + * {@link Target_java_lang_ClassLoader_JDK11OrLater#classLoaderValueMap} for resetting of individual class + * loaders. + */ + // Checkstyle: stop + @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClass = ConcurrentHashMap.class)// + static ConcurrentHashMap CLASS_LOADER_VALUE_MAP; + // Checkstyle: resume +} + +/** Dummy class to have a class with the file's name. */ +public final class JavaLangSubstitutions_JDK11OrLater { + +} diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/ModuleUtil.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/ModuleUtil.java new file mode 100644 index 000000000000..fc8cb07c709a --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/ModuleUtil.java @@ -0,0 +1,217 @@ +/* + * 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.core.jdk11; + +import com.oracle.svm.core.SubstrateUtil; + +import javax.lang.model.SourceVersion; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +public final class ModuleUtil { + private ModuleUtil() { + } + + private static final Object moduleLock = new Object(); + private static final Map> definedModules = new HashMap<>(); + + public static Map> getDefinedModules() { + if (definedModules.size() == 0) { + for (Module module : ModuleLayer.boot().modules()) { + Set modules = definedModules.get(module.getClassLoader()); + if (Objects.isNull(modules)) { + modules = new HashSet<>(); + modules.add(module); + definedModules.put(module.getClassLoader(), modules); + } else { + modules.add(module); + } + } + } + return definedModules; + } + + public static void checkFromModuleAndPackageNullability(Module from, String pn) { + if (Objects.isNull(from)) { + throw new NullPointerException("from_module is null"); + } + + if (Objects.isNull(pn)) { + throw new NullPointerException("package is null"); + } + } + + public static boolean isPackageNameForbidden(String pn) { + if (!pn.startsWith("java")) { + return false; + } + char trailingChar = pn.length() < 5 ? '.' : pn.charAt("java".length()); + return trailingChar == '.'; + } + + public static boolean isValidPackageName(String pn) { + // It is OK to use SourceVersion.isName here even though it calls String.split() + // because pattern "\\." will take the fast path in the String.split() method + return Objects.nonNull(pn) && SourceVersion.isName(pn); + } + + public static boolean isModuleDefinedToLoader(ClassLoader loader, String moduleName) { + return getDefinedModules().getOrDefault(loader, Set.of()).stream().anyMatch(m -> m.getName().equals(moduleName)); + } + + public static void addDefinedModule(ClassLoader loader, Module module) { + Set modules = getDefinedModules().get(loader); + if (Objects.isNull(modules)) { + modules = new HashSet<>(); + modules.add(module); + getDefinedModules().put(loader, modules); + } else { + modules.add(module); + } + } + + public static void checkIsPackageContainedInModule(String pn, Module module) { + ClassLoader loader = module.getClassLoader() == null ? ClassLoader.getPlatformClassLoader() : module.getClassLoader(); + Package definedPackage = loader.getDefinedPackage(pn); + if (definedPackage != null) { + Target_java_lang_NamedPackage namedPackage = SubstrateUtil.cast(definedPackage, Target_java_lang_NamedPackage.class); + Module actualModule = namedPackage.module; + if (!actualModule.equals(module)) { + throw new IllegalArgumentException("Package " + pn + " found in module " + actualModule.getName() + + ", not in module: " + module.getName()); + } + } + if (!module.getPackages().contains(pn)) { + throw new IllegalArgumentException("Package " + pn + " not found in from_module " + module.getName()); + } + } + + public static List getPackagesDefinedToLoader(ClassLoader loader) { + return getDefinedModules().getOrDefault(loader, Set.of()) + .stream() + .flatMap(m -> m.getPackages().stream()) + .collect(Collectors.toUnmodifiableList()); + } + + public static Object getModuleContainingPackage(ClassLoader loader, String pn) { + return getDefinedModules().getOrDefault(loader, Set.of()) + .stream() + .filter(m -> m.getPackages().contains(pn)) + .findFirst().orElse(null); + } + + public static boolean bootLayerContainsModule(String name) { + return ModuleLayer.boot().modules().stream().anyMatch(m -> m.getName().equals(name)); + } + + //Checkstyle: allow synchronization + public static void defineModule(Module module, boolean isOpen, List pns) { + if (Objects.isNull(module)) { + throw new NullPointerException("Null module object"); + } + + if (Objects.isNull(module.getName())) { + throw new IllegalArgumentException("Module name cannot be null"); + } + + if (module.getName().equals("java.base")) { + if (isOpen) { + throw new AssertionError("java.base module cannot be open"); + } + + for (String pn : pns) { + if (!ModuleUtil.isValidPackageName(pn)) { + throw new IllegalArgumentException("Invalid package name: " + pn + " for module: java.base"); + } + } + + if (module.getClassLoader() != null) { + throw new IllegalArgumentException("Class loader must be the boot class loader"); + } + + synchronized (moduleLock) { + boolean duplicateJavaBase = ModuleUtil.bootLayerContainsModule("java.base"); + if (duplicateJavaBase) { + throw new InternalError("Module java.base is already defined"); + } + } + + return; + } + + ClassLoader loader = module.getClassLoader(); + if (Objects.isNull(loader) || loader.getClass().getName().equals("jdk.internal.reflect.DelegatingClassLoader")) { + throw new IllegalArgumentException("Class loader is an invalid delegating class loader"); + } + + for (String pn : pns) { + if (!ModuleUtil.isValidPackageName(pn)) { + throw new IllegalArgumentException("Invalid package name: " + pn + " for module: " + module.getName()); + } + + if (loader != ClassLoader.getPlatformClassLoader() && ModuleUtil.isPackageNameForbidden(pn)) { + throw new IllegalArgumentException("Class loader (instance of): " + loader.getClass().getName() + + " tried to define prohibited package name: " + pn); + } + } + + String definedPackage = null; + boolean moduleAlreadyDefined; + synchronized (moduleLock) { + moduleAlreadyDefined = ModuleUtil.isModuleDefinedToLoader(loader, module.getName()); + if (!moduleAlreadyDefined) { + List definedPackages = ModuleUtil.getPackagesDefinedToLoader(loader); + for (String pn : pns) { + if (definedPackages.contains(pn)) { + definedPackage = pn; + break; + } + } + } + } + + if (moduleAlreadyDefined) { + throw new IllegalStateException("Module " + module.getName() + " is already defined"); + } else if (Objects.nonNull(definedPackage)) { + Module moduleContainingDefinedPackage = SubstrateUtil.cast(ModuleUtil.getModuleContainingPackage(loader, definedPackage), Module.class); + if (moduleContainingDefinedPackage.isNamed()) { + throw new IllegalStateException("Package " + definedPackage + " is already in another module, " + + moduleContainingDefinedPackage.getName() + ", defined to the class loader"); + } else { + throw new IllegalStateException("Package " + definedPackage + + " is already in the unnamed module defined to the class loader"); + } + } + + synchronized (moduleLock) { + ModuleUtil.addDefinedModule(loader, module); + } + } +} diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_ClassLoader_JDK11OrLater.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_ClassLoader_JDK11OrLater.java new file mode 100644 index 000000000000..335d7feedad6 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_ClassLoader_JDK11OrLater.java @@ -0,0 +1,69 @@ +/* + * 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.core.jdk11; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; +import com.oracle.svm.core.jdk.JDK11OrLater; +import com.oracle.svm.core.util.LazyFinalReference; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; + +@SuppressWarnings({"unused"}) +@TargetClass(value = ClassLoader.class, onlyWith = JDK11OrLater.class) +public final class Target_java_lang_ClassLoader_JDK11OrLater { + + /** + * All ClassLoaderValue are reset at run time for now. See also + * {@link Target_jdk_internal_loader_BootLoader_JDK11OrLater#CLASS_LOADER_VALUE_MAP} for resetting of the + * boot class loader. + */ + @Alias + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClass = ConcurrentHashMap.class)// + @TargetElement(onlyWith = JDK11OrLater.class)// + ConcurrentHashMap classLoaderValueMap; + + @Alias + @TargetElement(onlyWith = JDK11OrLater.class) + native Stream packages(); + + @Substitute + public Target_java_lang_Module_JDK11OrLater getUnnamedModule() { + return ClassLoaderUtil.unnamedModuleReference.get(); + } + + @Alias + protected native Class findLoadedClass(String name); + +} + +final class ClassLoaderUtil { + + public static final LazyFinalReference unnamedModuleReference = new LazyFinalReference<>(Target_java_lang_Module_JDK11OrLater::new); +} diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_ModuleLayer.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_ModuleLayer.java new file mode 100644 index 000000000000..0822f32dfec8 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_ModuleLayer.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018, 2019, 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.core.jdk11; + +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.jdk.JDK11OrLater; + +@SuppressWarnings("unused") +@TargetClass(value = java.lang.ModuleLayer.class, onlyWith = JDK11OrLater.class) +final class Target_java_lang_ModuleLayer { + + @SuppressWarnings("unused") + @Substitute + public static ModuleLayer boot() { + return BootModuleLayerSupport.instance().getBootLayer(); + } +} diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_Module_JDK11OrLater.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_Module_JDK11OrLater.java new file mode 100644 index 000000000000..ede6765b07e7 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_Module_JDK11OrLater.java @@ -0,0 +1,95 @@ +/* + * 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.core.jdk11; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; +import com.oracle.svm.core.jdk.JDK11OrLater; +import com.oracle.svm.core.jdk.JDK11To14; +import com.oracle.svm.core.jdk.Resources; +import com.oracle.svm.core.jdk.resources.ResourceStorageEntry; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Objects; + +@SuppressWarnings("unused") +@TargetClass(value = java.lang.Module.class, onlyWith = JDK11OrLater.class) +public final class Target_java_lang_Module_JDK11OrLater { + + @SuppressWarnings("static-method") + @Substitute + public InputStream getResourceAsStream(String name) { + ResourceStorageEntry res = Resources.get(name); + return res == null ? null : new ByteArrayInputStream(res.getData().get(0)); + } + + @Substitute // + @TargetElement(onlyWith = JDK11To14.class) + private static void defineModule0(Module module, boolean isOpen, String version, String location, String[] pns) { + ModuleUtil.defineModule(module, isOpen, Arrays.asList(pns)); + } + + @Substitute + private static void addReads0(Module from, Module to) { + if (Objects.isNull(from)) { + throw new NullPointerException("from_module is null"); + } + } + + @Substitute + private static void addExports0(Module from, String pn, Module to) { + if (Objects.isNull(to)) { + throw new NullPointerException("to_module is null"); + } + + ModuleUtil.checkFromModuleAndPackageNullability(from, pn); + ModuleUtil.checkIsPackageContainedInModule(pn, from); + } + + @Substitute + private static void addExportsToAll0(Module from, String pn) { + ModuleUtil.checkFromModuleAndPackageNullability(from, pn); + ModuleUtil.checkIsPackageContainedInModule(pn, from); + } + + @Substitute + private static void addExportsToAllUnnamed0(Module from, String pn) { + ModuleUtil.checkFromModuleAndPackageNullability(from, pn); + if (from.isNamed()) { + ModuleUtil.checkIsPackageContainedInModule(pn, from); + } + } + + @TargetClass(className = "java.lang.Module", innerClass = "ReflectionData", onlyWith = JDK11OrLater.class) // + private static final class Target_java_lang_Module_ReflectionData { + @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClassName = "java.lang.WeakPairMap") // + static Target_java_lang_WeakPairMap, Boolean> uses; + } +} diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_NamedPackage.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_NamedPackage.java new file mode 100644 index 000000000000..eb42f7f59c2e --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_NamedPackage.java @@ -0,0 +1,34 @@ +/* + * 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.core.jdk11; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.jdk.JDK11OrLater; + +@TargetClass(className = "java.lang.NamedPackage", onlyWith = JDK11OrLater.class) // +final class Target_java_lang_NamedPackage { + @Alias Module module; +} diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_WeakPairMap.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_WeakPairMap.java new file mode 100644 index 000000000000..c028ce9f6b47 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_WeakPairMap.java @@ -0,0 +1,32 @@ +/* + * 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 + * 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.core.jdk11; + +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.jdk.JDK11OrLater; + +@TargetClass(className = "java.lang.WeakPairMap", onlyWith = JDK11OrLater.class) +final class Target_java_lang_WeakPairMap { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_module_ModuleReference.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_module_ModuleReference.java similarity index 90% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_module_ModuleReference.java rename to substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_module_ModuleReference.java index fe7bb7485eeb..fa6d8ce4a1c0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_module_ModuleReference.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_module_ModuleReference.java @@ -22,12 +22,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - -package com.oracle.svm.core.jdk; +package com.oracle.svm.core.jdk11; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.jdk.JDK11OrLater; -@TargetClass(className = "java.lang.module.ModuleReference", onlyWith = JDK11OrLater.class) +@TargetClass(value = java.lang.module.ModuleReference.class, onlyWith = JDK11OrLater.class) @SuppressWarnings("unused") public final class Target_java_lang_module_ModuleReference { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_loader_BuiltinClassLoader.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_jdk_internal_loader_BuiltinClassLoader.java similarity index 89% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_loader_BuiltinClassLoader.java rename to substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_jdk_internal_loader_BuiltinClassLoader.java index f7a0d13a53cd..3807a6d73568 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_loader_BuiltinClassLoader.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_jdk_internal_loader_BuiltinClassLoader.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk; +package com.oracle.svm.core.jdk11; import java.io.IOException; import java.io.InputStream; @@ -33,8 +33,10 @@ import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.jdk.JDK11OrLater; +import com.oracle.svm.core.jdk.ResourcesHelper; -@TargetClass(className = "jdk.internal.loader.BuiltinClassLoader", onlyWith = JDK11OrLater.class) +@TargetClass(value = jdk.internal.loader.BuiltinClassLoader.class, onlyWith = JDK11OrLater.class) @SuppressWarnings({"unused", "static-method"}) final class Target_jdk_internal_loader_BuiltinClassLoader { @@ -45,7 +47,7 @@ protected Class findClass(String name) throws ClassNotFoundException { @Substitute protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - Target_java_lang_ClassLoader self = SubstrateUtil.cast(this, Target_java_lang_ClassLoader.class); + Target_java_lang_ClassLoader_JDK11OrLater self = SubstrateUtil.cast(this, Target_java_lang_ClassLoader_JDK11OrLater.class); Class clazz = self.findLoadedClass(name); if (clazz == null) { throw new ClassNotFoundException(name); diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/substitutions/Target_java_util_ResourceBundle.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/substitutions/Target_java_util_ResourceBundle.java new file mode 100644 index 000000000000..7c5f36d0acd3 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/substitutions/Target_java_util_ResourceBundle.java @@ -0,0 +1,55 @@ +/* + * 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.core.jdk11.substitutions; + +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.jdk.JDK11OrLater; +import com.oracle.svm.core.jdk11.Target_java_lang_Module_JDK11OrLater; +import com.oracle.svm.core.jdk.localization.LocalizationSupport; +import com.oracle.svm.core.jdk.localization.substitutions.modes.OptimizedLocaleMode; +import org.graalvm.nativeimage.ImageSingletons; + +import java.util.Locale; +import java.util.ResourceBundle; + +@TargetClass(value = java.util.ResourceBundle.class, onlyWith = {JDK11OrLater.class, OptimizedLocaleMode.class}) +public final class Target_java_util_ResourceBundle { + + /** + * Currently there is no support for the module system at run time. Module arguments are + * therefore ignored. + */ + + @Substitute + private static ResourceBundle getBundle(String baseName, Target_java_lang_Module_JDK11OrLater module) { + return ImageSingletons.lookup(LocalizationSupport.class).asOptimizedSupport().getCached(baseName, Locale.getDefault()); + } + + @Substitute + private static ResourceBundle getBundle(String baseName, Locale targetLocale, Target_java_lang_Module_JDK11OrLater module) { + return ImageSingletons.lookup(LocalizationSupport.class).asOptimizedSupport().getCached(baseName, targetLocale); + } +} diff --git a/substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/Target_java_lang_Module_JDK15OrLater.java b/substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/Target_java_lang_Module_JDK15OrLater.java new file mode 100644 index 000000000000..94a0719002f1 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/Target_java_lang_Module_JDK15OrLater.java @@ -0,0 +1,50 @@ +/* + * 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.core.jdk15; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.jdk.JDK15OrLater; +import com.oracle.svm.core.jdk11.ModuleUtil; + +@SuppressWarnings("unused") +@TargetClass(value = Module.class, onlyWith = JDK15OrLater.class) +public final class Target_java_lang_Module_JDK15OrLater { + + //Checkstyle: allow synchronization + @Substitute + private static void defineModule0(Module module, boolean isOpen, String version, String location, Object[] pns) { + if (Arrays.stream(pns).anyMatch(Objects::isNull)) { + throw new IllegalArgumentException("Bad package name"); + } + List packages = Arrays.stream(pns).map(Object::toString).collect(Collectors.toUnmodifiableList()); + ModuleUtil.defineModule(module, isOpen, packages); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index bc25ccd5acce..4c38624e886c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -53,6 +53,7 @@ import java.util.Set; import java.util.StringJoiner; +import com.oracle.svm.core.jdk.Target_java_lang_Module; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; @@ -81,7 +82,6 @@ import com.oracle.svm.core.jdk.JDK8OrEarlier; import com.oracle.svm.core.jdk.Package_jdk_internal_reflect; import com.oracle.svm.core.jdk.Resources; -import com.oracle.svm.core.jdk.Target_java_lang_Module; import com.oracle.svm.core.jdk.Target_jdk_internal_reflect_Reflection; import com.oracle.svm.core.meta.SharedType; import com.oracle.svm.core.util.LazyFinalReference; @@ -345,8 +345,6 @@ public void setModule(Object module) { return new java.security.ProtectionDomain(cs, perms); }); - public static final LazyFinalReference singleModuleReference = new LazyFinalReference<>(Target_java_lang_Module::new); - private final LazyFinalReference companion = new LazyFinalReference<>(() -> new DynamicHubCompanion(this)); @Platforms(Platform.HOSTED_ONLY.class) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java index d78a3361bf5e..cc63053484bf 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java @@ -31,13 +31,11 @@ import java.io.File; import java.io.InputStream; import java.io.PrintStream; -import java.net.URL; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.BooleanSupplier; -import java.util.stream.Stream; import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode; import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation; @@ -65,7 +63,6 @@ import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.TargetElement; import com.oracle.svm.core.annotate.Uninterruptible; -import com.oracle.svm.core.hub.ClassForNameSupport; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.jdk.JavaLangSubstitutions.ClassValueSupport; import com.oracle.svm.core.monitor.MonitorSupport; @@ -646,26 +643,6 @@ static void disable() { } } -@TargetClass(java.lang.Package.class) -final class Target_java_lang_Package { - - @Alias - @SuppressWarnings({"unused"}) - Target_java_lang_Package(String name, - String spectitle, String specversion, String specvendor, - String impltitle, String implversion, String implvendor, - URL sealbase, ClassLoader loader) { - } - - @Substitute - @TargetElement(onlyWith = JDK8OrEarlier.class) - private static Package getSystemPackage(String name) { - Target_java_lang_Package pkg = new Target_java_lang_Package(name, null, null, null, - null, null, null, null, null); - return SubstrateUtil.cast(pkg, Package.class); - } -} - @TargetClass(java.lang.NullPointerException.class) final class Target_java_lang_NullPointerException { @@ -679,65 +656,10 @@ private String getExtendedNPEMessage() { @TargetClass(className = "jdk.internal.loader.ClassLoaders", onlyWith = JDK11OrLater.class) final class Target_jdk_internal_loader_ClassLoaders { - @Alias - static native Target_jdk_internal_loader_BuiltinClassLoader bootLoader(); - @Alias public static native ClassLoader platformClassLoader(); } -@TargetClass(className = "jdk.internal.loader.BootLoader", onlyWith = JDK11OrLater.class) -final class Target_jdk_internal_loader_BootLoader { - - @Substitute - static Package getDefinedPackage(String name) { - if (name != null) { - Target_java_lang_Package pkg = new Target_java_lang_Package(name, null, null, null, - null, null, null, null, null); - return SubstrateUtil.cast(pkg, Package.class); - } else { - return null; - } - } - - @Substitute - public static Stream packages() { - Target_jdk_internal_loader_BuiltinClassLoader bootClassLoader = Target_jdk_internal_loader_ClassLoaders.bootLoader(); - Target_java_lang_ClassLoader systemClassLoader = SubstrateUtil.cast(bootClassLoader, Target_java_lang_ClassLoader.class); - return systemClassLoader.packages(); - } - - @Delete("only used by #packages()") - private static native String[] getSystemPackageNames(); - - @Substitute - private static Class loadClassOrNull(String name) { - return ClassForNameSupport.forNameOrNull(name, null); - } - - @SuppressWarnings("unused") - @Substitute - private static Class loadClass(Target_java_lang_Module module, String name) { - /* The module system is not supported for now, therefore the module parameter is ignored. */ - return ClassForNameSupport.forNameOrNull(name, null); - } - - @Substitute - private static boolean hasClassPath() { - return true; - } - - /** - * All ClassLoaderValue are reset at run time for now. See also - * {@link Target_java_lang_ClassLoader#classLoaderValueMap} for resetting of individual class - * loaders. - */ - // Checkstyle: stop - @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClass = ConcurrentHashMap.class)// - static ConcurrentHashMap CLASS_LOADER_VALUE_MAP; - // Checkstyle: resume -} - /** Dummy class to have a class with the file's name. */ public final class JavaLangSubstitutions { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/ResourcesHelper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/ResourcesHelper.java new file mode 100644 index 000000000000..6df5c428a893 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/ResourcesHelper.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2018, 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.core.jdk; + +import com.oracle.svm.core.util.VMError; +import org.graalvm.nativeimage.ImageSingletons; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; + +@SuppressWarnings("unchecked") +public class ResourcesHelper { + + private static T urlToResource(String resourceName, URL url) { + try { + if (url == null) { + return null; + } + URLConnection urlConnection = url.openConnection(); + Object resource = ImageSingletons.lookup(JDKVersionSpecificResourceBuilder.class).buildResource(resourceName, url, urlConnection); + VMError.guarantee(resource != null); + return (T) resource; + } catch (IOException e) { + return null; + } catch (ClassCastException classCastException) { + throw VMError.shouldNotReachHere(classCastException); + } + } + + public static T nameToResource(String resourceName) { + return urlToResource(resourceName, nameToResourceURL(resourceName)); + } + + public static Enumeration nameToResources(String resourceName) { + Enumeration urls = Resources.createURLs(resourceName); + List resourceURLs = new ArrayList<>(); + while (urls.hasMoreElements()) { + resourceURLs.add(urlToResource(resourceName, urls.nextElement())); + } + return Collections.enumeration(resourceURLs); + } + + public static URL nameToResourceURL(String resourceName) { + return Resources.createURL(resourceName); + } + + public static InputStream nameToResourceInputStream(String resourceName) throws IOException { + URL url = nameToResourceURL(resourceName); + return url != null ? url.openStream() : null; + } + + public static List nameToResourceListURLs(String resourcesName) { + Enumeration urls = Resources.createURLs(resourcesName); + List resourceURLs = new ArrayList<>(); + while (urls.hasMoreElements()) { + resourceURLs.add(urls.nextElement()); + } + return resourceURLs; + } + + public static Enumeration nameToResourceEnumerationURLs(String resourcesName) { + return Collections.enumeration(nameToResourceListURLs(resourcesName)); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java index f5d00930d759..94fbd081ab6a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java @@ -25,21 +25,13 @@ package com.oracle.svm.core.jdk; import java.io.File; -import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.net.URLConnection; import java.security.ProtectionDomain; -import java.util.ArrayList; -import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; -import java.util.List; import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Stream; - -import org.graalvm.nativeimage.ImageSingletons; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Alias; @@ -50,7 +42,6 @@ import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.TargetElement; import com.oracle.svm.core.hub.ClassForNameSupport; -import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.PredefinedClassesSupport; import com.oracle.svm.core.util.VMError; @@ -69,61 +60,6 @@ final class Target_sun_misc_Resource_JDK8OrEarlier { } -@SuppressWarnings("unchecked") -class ResourcesHelper { - - private static T urlToResource(String resourceName, URL url) { - try { - if (url == null) { - return null; - } - URLConnection urlConnection = url.openConnection(); - Object resource = ImageSingletons.lookup(JDKVersionSpecificResourceBuilder.class).buildResource(resourceName, url, urlConnection); - VMError.guarantee(resource != null); - return (T) resource; - } catch (IOException e) { - return null; - } catch (ClassCastException classCastException) { - throw VMError.shouldNotReachHere(classCastException); - } - } - - static T nameToResource(String resourceName) { - return urlToResource(resourceName, nameToResourceURL(resourceName)); - } - - static Enumeration nameToResources(String resourceName) { - Enumeration urls = Resources.createURLs(resourceName); - List resourceURLs = new ArrayList<>(); - while (urls.hasMoreElements()) { - resourceURLs.add(urlToResource(resourceName, urls.nextElement())); - } - return Collections.enumeration(resourceURLs); - } - - static URL nameToResourceURL(String resourceName) { - return Resources.createURL(resourceName); - } - - static InputStream nameToResourceInputStream(String resourceName) throws IOException { - URL url = nameToResourceURL(resourceName); - return url != null ? url.openStream() : null; - } - - static List nameToResourceListURLs(String resourcesName) { - Enumeration urls = Resources.createURLs(resourcesName); - List resourceURLs = new ArrayList<>(); - while (urls.hasMoreElements()) { - resourceURLs.add(urls.nextElement()); - } - return resourceURLs; - } - - static Enumeration nameToResourceEnumerationURLs(String resourcesName) { - return Collections.enumeration(nameToResourceListURLs(resourcesName)); - } -} - @TargetClass(ClassLoader.class) @SuppressWarnings("static-method") public final class Target_java_lang_ClassLoader { @@ -163,10 +99,6 @@ public static ClassLoader getSystemClassLoader() { return scl; } - @Alias - @TargetElement(onlyWith = JDK11OrLater.class) - native Stream packages(); - @Delete private static native void initSystemClassLoader(); @@ -252,7 +184,7 @@ static void checkClassLoaderPermission(ClassLoader cl, Class caller) { @Substitute // @TargetElement(onlyWith = JDK11OrLater.class) // - @SuppressWarnings({"unused"}) + @SuppressWarnings("unused") Class loadClass(Target_java_lang_Module module, String name) { /* The module system is not supported for now, therefore the module parameter is ignored. */ try { @@ -262,22 +194,6 @@ Class loadClass(Target_java_lang_Module module, String name) { } } - /** - * All ClassLoaderValue are reset at run time for now. See also - * {@link Target_jdk_internal_loader_BootLoader#CLASS_LOADER_VALUE_MAP} for resetting of the - * boot class loader. - */ - @Alias @RecomputeFieldValue(kind = Kind.NewInstance, declClass = ConcurrentHashMap.class)// - @TargetElement(onlyWith = JDK11OrLater.class)// - ConcurrentHashMap classLoaderValueMap; - - @Substitute // - @TargetElement(onlyWith = JDK11OrLater.class) // - @SuppressWarnings({"unused"}) - private boolean trySetObjectField(String name, Object obj) { - throw VMError.unsupportedFeature("JDK11OrLater: Target_java_lang_ClassLoader.trySetObjectField(String name, Object obj)"); - } - @Substitute // @SuppressWarnings({"unused"}) Object getClassLoadingLock(String className) { @@ -293,13 +209,6 @@ private Class findLoadedClass0(String name) { return ClassForNameSupport.forNameOrNull(name, SubstrateUtil.cast(this, ClassLoader.class)); } - @Substitute - @TargetElement(onlyWith = JDK11OrLater.class) - @SuppressWarnings({"unused"}) - public Target_java_lang_Module getUnnamedModule() { - return DynamicHub.singleModuleReference.get(); - } - /* * The assertion status of classes is fixed at image build time because it is baked into the AOT * compiled code. All methods that modify the assertion status are substituted to throw an diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java index 4e1b03662c8c..d8fac0b61361 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,73 +24,9 @@ */ package com.oracle.svm.core.jdk; -import java.io.ByteArrayInputStream; -import java.io.InputStream; - -import com.oracle.svm.core.annotate.Delete; -import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.jdk.resources.ResourceStorageEntry; +@SuppressWarnings("unused") @TargetClass(className = "java.lang.Module", onlyWith = JDK11OrLater.class) public final class Target_java_lang_Module { - - @SuppressWarnings("static-method") - @Substitute - public InputStream getResourceAsStream(String name) { - ResourceStorageEntry entry = Resources.get(name); - if (entry == null) { - return null; - } else { - return new ByteArrayInputStream(entry.getData().get(0)); - } - } - - /* - * All implementations of these stubs are completely empty no-op. This seems appropriate as - * DynamicHub only references a singleton Module implementation anyhow, effectively neutering - * the module system within JDK11. - */ - - @SuppressWarnings({"unused", "static-method"}) - @Substitute - public boolean isReflectivelyExportedOrOpen(String pn, Target_java_lang_Module other, boolean open) { - return true; - } - - @SuppressWarnings({"unused", "static-method"}) - @Substitute - private void implAddReads(Target_java_lang_Module other, boolean syncVM) { - } - - @SuppressWarnings({"unused", "static-method"}) - @Substitute - private void implAddExportsOrOpens(String pn, - Target_java_lang_Module other, - boolean open, - boolean syncVM) { - } - - @SuppressWarnings({"unused", "static-method"}) - @Substitute - void implAddUses(Class service) { - } - - @SuppressWarnings({"unused", "static-method"}) - @Substitute - public boolean canUse(Class service) { - return true; - } - - @SuppressWarnings({"unused", "static-method"}) - @Substitute - public boolean canRead(Target_java_lang_Module other) { - return true; - } - - @Delete - @TargetClass(className = "java.lang.Module", innerClass = "ReflectionData", onlyWith = JDK11OrLater.class) - public static final class ReflectionData { - } - } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Package.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Package.java new file mode 100644 index 000000000000..2035ecbbca27 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Package.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018, 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.core.jdk; + +import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; + +import java.net.URL; + +@SuppressWarnings({"unused"}) +@TargetClass(Package.class) +public final class Target_java_lang_Package { + + @Alias + public Target_java_lang_Package(String name, + String spectitle, String specversion, String specvendor, + String impltitle, String implversion, String implvendor, + URL sealbase, ClassLoader loader) { + } + + @Substitute + @TargetElement(onlyWith = JDK8OrEarlier.class) + private static Package getSystemPackage(String name) { + Target_java_lang_Package pkg = new Target_java_lang_Package(name, null, null, null, + null, null, null, null, null); + return SubstrateUtil.cast(pkg, Package.class); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/Target_java_util_ResourceBundle.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/Target_java_util_ResourceBundle.java index e1119e6e7f90..4cf500543839 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/Target_java_util_ResourceBundle.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/Target_java_util_ResourceBundle.java @@ -29,8 +29,6 @@ import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.TargetElement; -import com.oracle.svm.core.jdk.JDK11OrLater; -import com.oracle.svm.core.jdk.Target_java_lang_Module; import com.oracle.svm.core.jdk.localization.LocalizationSupport; import com.oracle.svm.core.jdk.localization.substitutions.modes.OptimizedLocaleMode; import org.graalvm.nativeimage.ImageSingletons; @@ -82,21 +80,4 @@ private static ResourceBundle getBundle(String baseName, Locale locale, ClassLoa private static ResourceBundle getBundle(String baseName, Locale targetLocale, ClassLoader loader, ResourceBundle.Control control) { return ImageSingletons.lookup(LocalizationSupport.class).asOptimizedSupport().getCached(baseName, targetLocale); } - - /* - * Currently there is no support for the module system at run time. Module arguments are - * therefore ignored. - */ - - @TargetElement(onlyWith = {JDK11OrLater.class, OptimizedLocaleMode.class}) - @Substitute - private static ResourceBundle getBundle(String baseName, Target_java_lang_Module module) { - return ImageSingletons.lookup(LocalizationSupport.class).asOptimizedSupport().getCached(baseName, Locale.getDefault()); - } - - @TargetElement(onlyWith = {JDK11OrLater.class, OptimizedLocaleMode.class}) - @Substitute - private static ResourceBundle getBundle(String baseName, Locale targetLocale, Target_java_lang_Module module) { - return ImageSingletons.lookup(LocalizationSupport.class).asOptimizedSupport().getCached(baseName, targetLocale); - } } diff --git a/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/ModuleLayerFeature.java b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/ModuleLayerFeature.java new file mode 100644 index 000000000000..187c7037b11c --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/ModuleLayerFeature.java @@ -0,0 +1,188 @@ +/* + * 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 com.oracle.graal.pointsto.meta.AnalysisUniverse; +import com.oracle.svm.core.annotate.AutomaticFeature; +import com.oracle.svm.core.jdk11.BootModuleLayerSupport; +import com.oracle.svm.core.jdk.JDK11OrLater; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.util.ReflectionUtil; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.hosted.Feature; + +import java.lang.module.Configuration; +import java.lang.module.FindException; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.lang.module.ResolutionException; +import java.lang.module.ResolvedModule; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * This feature: + *
    + *
  • synthesizes the runtime boot module layer
  • + *
  • ensures that fields/methods from the {@link ClassLoader} class are reachable in order to + * make native methods of the {@link Module} class work
  • + *
+ *

+ * This feature synthesizes the runtime boot module layer by using type reachability information. + * If a type is reachable, its module is also reachable and therefore should be included in the + * runtime boot module layer. + *

+ *

+ * The configuration for the runtime boot module layer is resolved using the module reachability + * data provided to us by the analysis as resolve roots. + *

+ *

+ * We are purposefully avoiding public API for module layer creation, such as + * {@link ModuleLayer#defineModulesWithOneLoader(Configuration, ClassLoader)}, because as a side + * effect this will create a new class loader. Instead, we use a private constructor to construct + * the {@link ModuleLayer} instance, which we then patch using the module reachability data + * provided to us by the analysis. + *

+ *

+ * Because the result of this feature is dependant on the analysis results, and because this feature + * will add reachable object(s) as it's result, it is necessary to perform the logic during the + * analysis, for lack of a better option (even though only the last analysis cycle is sufficient, + * but that cannot be known in advance). + *

+ */ +@AutomaticFeature +@Platforms(Platform.HOSTED_ONLY.class) +public final class ModuleLayerFeature implements Feature { + + private Field moduleNameToModuleField; + private Field moduleParentsField; + private Constructor moduleLayerConstructor; + + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return new JDK11OrLater().getAsBoolean(); + } + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + ImageSingletons.add(BootModuleLayerSupport.class, new BootModuleLayerSupport()); + moduleNameToModuleField = ReflectionUtil.lookupField(ModuleLayer.class, "nameToModule"); + moduleParentsField = ReflectionUtil.lookupField(ModuleLayer.class, "parents"); + moduleLayerConstructor = ReflectionUtil.lookupConstructor(ModuleLayer.class, Configuration.class, List.class, Function.class); + } + + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + FeatureImpl.BeforeAnalysisAccessImpl accessImpl = (FeatureImpl.BeforeAnalysisAccessImpl) access; + Map baseModules = ModuleLayer.boot().modules() + .stream() + .collect(Collectors.toMap(Module::getName, m -> m)); + ModuleLayer runtimeBootLayer = synthesizeRuntimeBootLayer(accessImpl.imageClassLoader, baseModules); + BootModuleLayerSupport.instance().setBootLayer(runtimeBootLayer); + } + + @Override + public void afterAnalysis(AfterAnalysisAccess access) { + FeatureImpl.AfterAnalysisAccessImpl accessImpl = (FeatureImpl.AfterAnalysisAccessImpl) access; + AnalysisUniverse universe = accessImpl.getUniverse(); + + Map reachableModules = universe.getTypes() + .stream() + .filter(t -> t.isReachable() && !t.isArray()) + .map(t -> t.getJavaClass().getModule()) + .distinct() + .filter(m -> m.isNamed() && !m.getDescriptor().modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC)) + .collect(Collectors.toMap(Module::getName, m -> m)); + + ModuleLayer runtimeBootLayer = synthesizeRuntimeBootLayer(accessImpl.imageClassLoader, reachableModules); + BootModuleLayerSupport.instance().setBootLayer(runtimeBootLayer); + } + + private ModuleLayer synthesizeRuntimeBootLayer(ImageClassLoader cl, Map reachableModules) { + Configuration cf = synthesizeRuntimeBootLayerConfiguration(cl.modulepath(), reachableModules); + try { + ModuleLayer runtimeBootLayer = moduleLayerConstructor.newInstance(cf, List.of(), null); + patchRuntimeBootLayer(runtimeBootLayer, reachableModules); + // Ensure that the lazy field ModuleLayer.modules gets set + runtimeBootLayer.modules(); + return runtimeBootLayer; + } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) { + throw VMError.shouldNotReachHere("Failed to synthesize the runtime boot module layer.", ex); + } + } + + private Configuration synthesizeRuntimeBootLayerConfiguration(List mp, Map reachableModules) { + ModuleFinder beforeFinder = new BootModuleLayerModuleFinder(); + ModuleFinder afterFinder = ModuleFinder.of(mp.toArray(Path[]::new)); + Set roots = reachableModules.keySet(); + try { + return Configuration.empty().resolve(beforeFinder, afterFinder, roots); + } catch (FindException | ResolutionException | SecurityException ex) { + throw VMError.shouldNotReachHere("Failed to synthesize the runtime boot module layer configuration.", ex); + } + } + + private void patchRuntimeBootLayer(ModuleLayer runtimeBootLayer, Map reachableModules) { + try { + moduleNameToModuleField.set(runtimeBootLayer, reachableModules); + moduleParentsField.set(runtimeBootLayer, List.of(ModuleLayer.empty())); + } catch (IllegalAccessException ex) { + throw VMError.shouldNotReachHere("Failed to patch the runtime boot module layer.", ex); + } + } + + + static class BootModuleLayerModuleFinder implements ModuleFinder { + + @Override + public Optional find(String name) { + return ModuleLayer.boot() + .configuration() + .findModule(name) + .map(ResolvedModule::reference); + } + + @Override + public Set findAll() { + return ModuleLayer.boot() + .configuration() + .modules() + .stream() + .map(ResolvedModule::reference) + .collect(Collectors.toSet()); + } + } +} diff --git a/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java b/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java index 1148c75705c7..2e5f4b55e697 100644 --- a/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java +++ b/substratevm/src/com.oracle.svm.methodhandles/src/com/oracle/svm/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java @@ -40,7 +40,6 @@ import com.oracle.svm.core.jdk.JDK11_0_10OrEarlier; import com.oracle.svm.core.jdk.JDK11_0_11OrLater; import com.oracle.svm.core.jdk.JDK15OrLater; -import com.oracle.svm.core.jdk.Target_java_lang_Module; @TargetClass(value = MethodHandles.class, innerClass = "Lookup", onlyWith = MethodHandlesSupported.class) final class Target_java_lang_invoke_MethodHandles_Lookup { @@ -89,7 +88,7 @@ private IllegalAccessException makeAccessException(Class targetClass) { if (this == SubstrateUtil.cast(MethodHandles.publicLookup(), Target_java_lang_invoke_MethodHandles_Lookup.class)) { message += ", from public Lookup"; } else { - Target_java_lang_Module m = SubstrateUtil.cast(lookupClass, DynamicHub.class).getModule(); + Object m = SubstrateUtil.cast(lookupClass, DynamicHub.class).getModule(); message += ", from " + lookupClass + " (" + m + ")"; if (prevLookupClass != null) { message += ", previous lookup " + diff --git a/substratevm/src/native-image-module-tests/hello.app/src/main/java/hello/Main.java b/substratevm/src/native-image-module-tests/hello.app/src/main/java/hello/Main.java index be8b80253545..a642af8e8291 100644 --- a/substratevm/src/native-image-module-tests/hello.app/src/main/java/hello/Main.java +++ b/substratevm/src/native-image-module-tests/hello.app/src/main/java/hello/Main.java @@ -26,21 +26,17 @@ import hello.lib.Greeter; +import java.lang.module.Configuration; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Set; +import java.util.stream.Collectors; public class Main { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Module helloAppModule = Main.class.getModule(); - assert helloAppModule.getName().equals("moduletests.hello.app"); - assert helloAppModule.isExported("hello"); - Module helloLibModule = Greeter.class.getModule(); - assert helloLibModule.getName().equals("moduletests.hello.lib"); - assert helloLibModule.isExported("hello.lib"); - - assert helloAppModule.canRead(helloLibModule); - // assert !helloLibModule.canRead(helloAppModule); GR-30957 + testModuleObjects(helloAppModule, helloLibModule); System.out.println("Basic Module test involving " + helloAppModule + " and " + helloLibModule); Greeter.greet(); @@ -52,5 +48,61 @@ public static void main(String[] args) throws NoSuchMethodException, InvocationT Method greetMethod = hello.privateLib2.PrivateGreeter.class.getDeclaredMethod("greet"); greetMethod.setAccessible(true); greetMethod.invoke(null); + + System.out.println("Now testing boot module layer"); + testBootLayer(helloAppModule, helloLibModule); + } + + private static void testModuleObjects(Module helloAppModule, Module helloLibModule) { + assert helloAppModule.getName().equals("moduletests.hello.app"); + assert helloAppModule.isExported(Main.class.getPackageName()); + assert helloAppModule.isNamed(); + assert helloAppModule.getPackages().contains(Main.class.getPackageName()); + + assert helloLibModule.getName().equals("moduletests.hello.lib"); + assert helloLibModule.isExported(Greeter.class.getPackageName()); + assert helloLibModule.isNamed(); + assert helloLibModule.getPackages().contains(Greeter.class.getPackageName()); + + assert !helloAppModule.isOpen(Main.class.getPackageName(), helloLibModule); + assert helloLibModule.isOpen(hello.privateLib2.PrivateGreeter.class.getPackageName(), helloAppModule); + + assert helloAppModule.canRead(helloLibModule); + assert !helloLibModule.canRead(helloAppModule); + } + + @SuppressWarnings("OptionalGetWithoutIsPresent") + private static void testBootLayer(Module helloAppModule, Module helloLibModule) { + ModuleLayer bootLayer = ModuleLayer.boot(); + + System.out.println("Now testing boot module layer configuration"); + Configuration cf = bootLayer.configuration(); + assert cf.findModule("java.base").get() + .reference() + .descriptor() + .exports() + .stream().anyMatch(e -> (e.source().equals("java.lang") && !e.isQualified())); + + System.out.println("Now testing boot module layer module set"); + Set modules = bootLayer.modules(); + assert modules.contains(Object.class.getModule()); + int uniqueModuleNameCount = modules.stream().map(Module::getName).collect(Collectors.toSet()).size(); + assert modules.size() == uniqueModuleNameCount; + + System.out.println("Now testing if boot module layer contains java.base"); + Module base = Object.class.getModule(); + assert bootLayer.findModule("java.base").get() == base; + assert base.getLayer() == bootLayer; + + System.out.println("Now testing boot module layer java.base loader"); + assert bootLayer.findLoader("java.base") == null; + + System.out.println("Now testing boot module layer parent"); + assert bootLayer.parents().size() == 1; + assert bootLayer.parents().get(0) == ModuleLayer.empty(); + + System.out.println("Now testing if user modules are part of the boot layer"); + assert ModuleLayer.boot().modules().contains(helloAppModule); + assert ModuleLayer.boot().modules().contains(helloLibModule); } }