From 3cd01a2201012f5d6c5a226783c323637d67c29f Mon Sep 17 00:00:00 2001 From: ivan-ristovic Date: Wed, 2 Jun 2021 13:12:08 +0200 Subject: [PATCH 1/8] Boot module layer synthesizing --- .../svm/core/jdk/BootModuleLayerSupport.java | 74 +++++++++++++++++++ .../svm/core/jdk/Target_java_lang_Module.java | 53 +++++++++++++ .../jdk/Target_java_lang_ModuleLayer.java | 38 ++++++++++ .../svm/core/jdk/Target_java_lang_System.java | 47 ++++++++++++ .../jdk/Target_java_lang_WeakPairMap.java | 31 ++++++++ .../svm/core/jdk/BootModuleLayerSupport.java | 52 +++++++++++++ .../svm/core/jdk/Target_java_lang_Module.java | 45 ----------- .../oracle/svm/hosted/ModuleLayerFeature.java | 67 +++++++++++++++++ 8 files changed, 362 insertions(+), 45 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java create mode 100644 substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java create mode 100644 substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_ModuleLayer.java create mode 100644 substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_System.java create mode 100644 substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_WeakPairMap.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java create mode 100644 substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/ModuleLayerFeature.java diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java new file mode 100644 index 000000000000..dd31a9d5f1e3 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java @@ -0,0 +1,74 @@ +/* + * 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.jdk; + +import com.oracle.svm.core.SubstrateUtil; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public final class BootModuleLayerSupport { + + public static BootModuleLayerSupport instance() { + return ImageSingletons.lookup(BootModuleLayerSupport.class); + } + + private final ModuleLayer bootLayer; + private final Set reachableModules; + private final Map nameToModule; + private boolean isAnalysisComplete; + + @Platforms(Platform.HOSTED_ONLY.class) + public BootModuleLayerSupport() { + bootLayer = ModuleLayer.boot(); + reachableModules = new HashSet<>(); + nameToModule = new HashMap<>(); + } + + @Platforms(Platform.HOSTED_ONLY.class) + public void setReachableModules(Set modules) { + isAnalysisComplete = true; + reachableModules.addAll(modules + .stream() + .map(o -> (Module) o) + .collect(Collectors.toSet())); + nameToModule.putAll(reachableModules.stream().collect(Collectors.toMap(Module::getName, m -> m))); + } + + public Object getBootLayer() { + Target_java_lang_ModuleLayer originalLayer = SubstrateUtil.cast(bootLayer, Target_java_lang_ModuleLayer.class); + if (isAnalysisComplete) { + originalLayer.nameToModule = nameToModule; + originalLayer.modules = reachableModules; + } + return originalLayer; + } +} diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java new file mode 100644 index 000000000000..293e58a09157 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java @@ -0,0 +1,53 @@ +/* + * 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.jdk; + +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 java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.List; + +@TargetClass(className = "java.lang.Module", onlyWith = JDK11OrLater.class) +public final class Target_java_lang_Module { + + @SuppressWarnings("static-method") + @Substitute + public InputStream getResourceAsStream(String name) { + List arr = Resources.get(name); + return arr == null ? null : new ByteArrayInputStream(arr.get(0)); + } + + + @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/jdk/Target_java_lang_ModuleLayer.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_ModuleLayer.java new file mode 100644 index 000000000000..f599957793bd --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_ModuleLayer.java @@ -0,0 +1,38 @@ +/* + * 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.jdk; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.TargetClass; +import java.util.Map; +import java.util.Set; + +@TargetClass(className = "java.lang.ModuleLayer", onlyWith = JDK11OrLater.class) +final class Target_java_lang_ModuleLayer { + + @Alias Map nameToModule; + @Alias volatile Set modules; + +} diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_System.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_System.java new file mode 100644 index 000000000000..9c57c13c6777 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_System.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.jdk; + +import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.InjectAccessors; +import com.oracle.svm.core.annotate.TargetClass; + +@TargetClass(value = System.class, onlyWith = JDK11OrLater.class) +@SuppressWarnings("unused") +final class Target_java_lang_System_JDK11OrLater { + + @Alias @InjectAccessors(BootModuleLayerAccessor.class) // + static ModuleLayer bootLayer; + +} + +final class BootModuleLayerAccessor { + @SuppressWarnings("unused") + static ModuleLayer get() { + Object bootLayer = BootModuleLayerSupport.instance().getBootLayer(); + return SubstrateUtil.cast(bootLayer, ModuleLayer.class); + } +} diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_WeakPairMap.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_WeakPairMap.java new file mode 100644 index 000000000000..77e1031efa26 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_WeakPairMap.java @@ -0,0 +1,31 @@ +/* + * 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.jdk; + +import com.oracle.svm.core.annotate.TargetClass; + +@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/BootModuleLayerSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java new file mode 100644 index 000000000000..1143041570cb --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java @@ -0,0 +1,52 @@ +/* + * 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.jdk; + +import java.util.Set; + +public final class BootModuleLayerSupport { + + public static BootModuleLayerSupport instance() { + return null; + } + + public BootModuleLayerSupport() { + } + + @SuppressWarnings({"unused", "static-method"}) + public void setReachableModules(Set modules) { + } + + @SuppressWarnings("static-method") + public boolean isAnalysisComplete() { + return false; + } + + @SuppressWarnings("static-method") + public Object getBootLayer() { + return null; + } + +} 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..44110b82f7ed 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 @@ -27,7 +27,6 @@ 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; @@ -46,51 +45,7 @@ public InputStream getResourceAsStream(String name) { } } - /* - * 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.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..332b5fb5b14a --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/ModuleLayerFeature.java @@ -0,0 +1,67 @@ +/* + * 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.jdk.BootModuleLayerSupport; +import com.oracle.svm.core.jdk.JDK11OrLater; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.hosted.Feature; + +import java.util.Set; +import java.util.stream.Collectors; + +@AutomaticFeature +@Platforms(Platform.HOSTED_ONLY.class) +public final class ModuleLayerFeature implements Feature { + + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return new JDK11OrLater().getAsBoolean(); + } + + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + ImageSingletons.add(BootModuleLayerSupport.class, new BootModuleLayerSupport()); + } + + @Override + public void afterAnalysis(AfterAnalysisAccess access) { + FeatureImpl.AfterAnalysisAccessImpl accessImpl = (FeatureImpl.AfterAnalysisAccessImpl) access; + AnalysisUniverse universe = accessImpl.getUniverse(); + + Set moduleSet = universe.getTypes() + .stream() + .filter(t -> t.isReachable() && !t.isArray()) + .map(t -> t.getJavaClass().getModule()) + .filter(Module::isNamed) + .collect(Collectors.toSet()); + + BootModuleLayerSupport.instance().setReachableModules(moduleSet); + } +} From 1ef1491fd5da09d5fee542c64f5cc3fdd1525526 Mon Sep 17 00:00:00 2001 From: ivan-ristovic Date: Thu, 17 Jun 2021 20:04:14 +0200 Subject: [PATCH 2/8] Extend mx hellomodule with more tests --- .../hello.app/src/main/java/hello/Main.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) 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..62ddb5a8b1b3 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 @@ -33,14 +33,25 @@ 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"); + assert helloAppModule.isExported(Main.class.getPackageName()); + assert helloAppModule.isNamed(); + assert helloAppModule.getPackages().contains(Main.class.getPackageName()); Module helloLibModule = Greeter.class.getModule(); assert helloLibModule.getName().equals("moduletests.hello.lib"); - assert helloLibModule.isExported("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); GR-30957 + assert !helloLibModule.canRead(helloAppModule); + + 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); System.out.println("Basic Module test involving " + helloAppModule + " and " + helloLibModule); Greeter.greet(); From 10f5812d2a34dfe548464ed5e5130cef81424bde Mon Sep 17 00:00:00 2001 From: ivan-ristovic Date: Thu, 17 Jun 2021 21:04:18 +0200 Subject: [PATCH 3/8] Add hellomodule GitHub gate Add hellomodule gate Restrict access to Module$ReflectionData Remove unnececary overlay for BootModuleLayerSupport Synthesize boot layer in a safer way --- .github/workflows/main.yml | 5 ++ substratevm/mx.substratevm/suite.py | 1 + .../svm/core/jdk/BootModuleLayerSupport.java | 37 ++---------- .../svm/core/jdk/Target_java_lang_Module.java | 8 +-- .../jdk/Target_java_lang_ModuleLayer.java | 13 +++-- .../svm/core/jdk/Target_java_lang_System.java | 47 ---------------- .../svm/core/jdk/BootModuleLayerSupport.java | 52 ----------------- .../svm/core/jdk/Target_java_lang_Module.java | 8 +-- .../oracle/svm/hosted/ModuleLayerFeature.java | 56 ++++++++++++++++++- 9 files changed, 76 insertions(+), 151 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_System.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java 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..2a9f982a2911 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -403,6 +403,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/jdk/BootModuleLayerSupport.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java index dd31a9d5f1e3..08776be5d837 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java @@ -24,51 +24,24 @@ */ package com.oracle.svm.core.jdk; -import com.oracle.svm.core.SubstrateUtil; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - public final class BootModuleLayerSupport { public static BootModuleLayerSupport instance() { return ImageSingletons.lookup(BootModuleLayerSupport.class); } - private final ModuleLayer bootLayer; - private final Set reachableModules; - private final Map nameToModule; - private boolean isAnalysisComplete; - - @Platforms(Platform.HOSTED_ONLY.class) - public BootModuleLayerSupport() { - bootLayer = ModuleLayer.boot(); - reachableModules = new HashSet<>(); - nameToModule = new HashMap<>(); - } + private ModuleLayer bootLayer; @Platforms(Platform.HOSTED_ONLY.class) - public void setReachableModules(Set modules) { - isAnalysisComplete = true; - reachableModules.addAll(modules - .stream() - .map(o -> (Module) o) - .collect(Collectors.toSet())); - nameToModule.putAll(reachableModules.stream().collect(Collectors.toMap(Module::getName, m -> m))); + public void setBootLayer(ModuleLayer bootLayer) { + this.bootLayer = bootLayer; } - public Object getBootLayer() { - Target_java_lang_ModuleLayer originalLayer = SubstrateUtil.cast(bootLayer, Target_java_lang_ModuleLayer.class); - if (isAnalysisComplete) { - originalLayer.nameToModule = nameToModule; - originalLayer.modules = reachableModules; - } - return originalLayer; + public ModuleLayer getBootLayer() { + return bootLayer; } } diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java index 293e58a09157..d1d6d59c6366 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java @@ -28,10 +28,10 @@ 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.jdk.resources.ResourceStorageEntry; import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.util.List; @TargetClass(className = "java.lang.Module", onlyWith = JDK11OrLater.class) public final class Target_java_lang_Module { @@ -39,15 +39,13 @@ public final class Target_java_lang_Module { @SuppressWarnings("static-method") @Substitute public InputStream getResourceAsStream(String name) { - List arr = Resources.get(name); - return arr == null ? null : new ByteArrayInputStream(arr.get(0)); + ResourceStorageEntry res = Resources.get(name); + return res == null ? null : new ByteArrayInputStream(res.getData().get(0)); } - @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/jdk/Target_java_lang_ModuleLayer.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_ModuleLayer.java index f599957793bd..8e1b07f7decb 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_ModuleLayer.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_ModuleLayer.java @@ -24,15 +24,16 @@ */ package com.oracle.svm.core.jdk; -import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; -import java.util.Map; -import java.util.Set; +@SuppressWarnings("unused") @TargetClass(className = "java.lang.ModuleLayer", onlyWith = JDK11OrLater.class) final class Target_java_lang_ModuleLayer { - @Alias Map nameToModule; - @Alias volatile Set modules; - + @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/jdk/Target_java_lang_System.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_System.java deleted file mode 100644 index 9c57c13c6777..000000000000 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_System.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.jdk; - -import com.oracle.svm.core.SubstrateUtil; -import com.oracle.svm.core.annotate.Alias; -import com.oracle.svm.core.annotate.InjectAccessors; -import com.oracle.svm.core.annotate.TargetClass; - -@TargetClass(value = System.class, onlyWith = JDK11OrLater.class) -@SuppressWarnings("unused") -final class Target_java_lang_System_JDK11OrLater { - - @Alias @InjectAccessors(BootModuleLayerAccessor.class) // - static ModuleLayer bootLayer; - -} - -final class BootModuleLayerAccessor { - @SuppressWarnings("unused") - static ModuleLayer get() { - Object bootLayer = BootModuleLayerSupport.instance().getBootLayer(); - return SubstrateUtil.cast(bootLayer, ModuleLayer.class); - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java deleted file mode 100644 index 1143041570cb..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.jdk; - -import java.util.Set; - -public final class BootModuleLayerSupport { - - public static BootModuleLayerSupport instance() { - return null; - } - - public BootModuleLayerSupport() { - } - - @SuppressWarnings({"unused", "static-method"}) - public void setReachableModules(Set modules) { - } - - @SuppressWarnings("static-method") - public boolean isAnalysisComplete() { - return false; - } - - @SuppressWarnings("static-method") - public Object getBootLayer() { - return null; - } - -} 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 44110b82f7ed..6d2b3ae8b033 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 @@ -38,14 +38,10 @@ public final class Target_java_lang_Module { @Substitute public InputStream getResourceAsStream(String name) { ResourceStorageEntry entry = Resources.get(name); - if (entry == null) { - return null; - } else { - return new ByteArrayInputStream(entry.getData().get(0)); - } + return entry == null ? null : new ByteArrayInputStream(entry.getData().get(0)); } @TargetClass(className = "java.lang.Module", innerClass = "ReflectionData", onlyWith = JDK11OrLater.class) - public static final class ReflectionData { + private static final class Target_java_lang_Module_ReflectionData { } } 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 index 332b5fb5b14a..294d294a86c7 100644 --- 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 @@ -28,12 +28,23 @@ import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.jdk.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.ModuleFinder; +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.Set; +import java.util.function.Function; import java.util.stream.Collectors; @AutomaticFeature @@ -46,7 +57,7 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { } @Override - public void beforeAnalysis(BeforeAnalysisAccess access) { + public void afterRegistration(AfterRegistrationAccess access) { ImageSingletons.add(BootModuleLayerSupport.class, new BootModuleLayerSupport()); } @@ -55,13 +66,52 @@ public void afterAnalysis(AfterAnalysisAccess access) { FeatureImpl.AfterAnalysisAccessImpl accessImpl = (FeatureImpl.AfterAnalysisAccessImpl) access; AnalysisUniverse universe = accessImpl.getUniverse(); - Set moduleSet = universe.getTypes() + Set reachableModules = universe.getTypes() .stream() .filter(t -> t.isReachable() && !t.isArray()) .map(t -> t.getJavaClass().getModule()) .filter(Module::isNamed) + .filter(m -> !m.getName().startsWith("jdk.proxy")) .collect(Collectors.toSet()); - BootModuleLayerSupport.instance().setReachableModules(moduleSet); + ModuleLayer runtimeBootLayer = synthesizeRuntimeBootLayer(accessImpl.imageClassLoader.modulepath(), reachableModules); + BootModuleLayerSupport.instance().setBootLayer(runtimeBootLayer); + } + + private ModuleLayer synthesizeRuntimeBootLayer(List mp, Set reachableModules) { + Configuration cf = synthesizeRuntimeBootLayerConfiguration(mp, reachableModules); + try { + Constructor ctor = ReflectionUtil.lookupConstructor(ModuleLayer.class, Configuration.class, List.class, Function.class); + ctor.setAccessible(true); + ModuleLayer runtimeBootLayer = ctor.newInstance(cf, List.of(), null); + patchRuntimeBootLayer(runtimeBootLayer, reachableModules); + return runtimeBootLayer; + } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) { + throw VMError.shouldNotReachHere("Failed to instantiate the runtime boot module layer.", ex); + } + } + + private Configuration synthesizeRuntimeBootLayerConfiguration(List mp, Set reachableModules) { + ModuleFinder finder = ModuleFinder.of(mp.toArray(Path[]::new)); + Set roots = reachableModules.stream().map(Module::getName).collect(Collectors.toSet()); + List parents = List.of(ModuleLayer.boot().configuration()); + return Configuration.resolve(finder, parents, finder, roots); + } + + private void patchRuntimeBootLayer(ModuleLayer runtimeBootLayer, Set reachableModules) { + Map nameToModule = reachableModules + .stream() + .collect(Collectors.toMap(Module::getName, m -> m)); + + Field nameToModuleField = ReflectionUtil.lookupField(ModuleLayer.class, "nameToModule"); + Field modulesField = ReflectionUtil.lookupField(ModuleLayer.class, "modules"); + try { + nameToModuleField.setAccessible(true); + modulesField.setAccessible(true); + nameToModuleField.set(runtimeBootLayer, nameToModule); + modulesField.set(runtimeBootLayer, reachableModules); + } catch (IllegalAccessException ex) { + throw VMError.shouldNotReachHere("Failed to patch the runtime boot module layer.", ex); + } } } From 6c2bf0b506bcba61ec710f08cbcef1458cff0ab5 Mon Sep 17 00:00:00 2001 From: ivan-ristovic Date: Tue, 13 Jul 2021 12:20:40 +0200 Subject: [PATCH 4/8] Replace runtime boot layer correctly --- .../svm/core/jdk/BootModuleLayerSupport.java | 2 + .../oracle/svm/hosted/ModuleLayerFeature.java | 102 +++++++++++++----- 2 files changed, 76 insertions(+), 28 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java index 08776be5d837..d29758386c17 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.jdk; +import com.oracle.svm.core.annotate.UnknownObjectField; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -34,6 +35,7 @@ public static BootModuleLayerSupport instance() { return ImageSingletons.lookup(BootModuleLayerSupport.class); } + @UnknownObjectField private ModuleLayer bootLayer; @Platforms(Platform.HOSTED_ONLY.class) 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 index 294d294a86c7..e013aa4918ab 100644 --- 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 @@ -34,9 +34,13 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.hosted.RuntimeReflection; import java.lang.module.Configuration; +import java.lang.module.FindException; +import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleFinder; +import java.lang.module.ResolutionException; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -47,10 +51,45 @@ 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 Field configurationParentsField; + private Constructor moduleLayerConstructor; + @Override public boolean isInConfiguration(IsInConfigurationAccess access) { return new JDK11OrLater().getAsBoolean(); @@ -59,57 +98,64 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { @Override public void afterRegistration(AfterRegistrationAccess access) { ImageSingletons.add(BootModuleLayerSupport.class, new BootModuleLayerSupport()); + moduleNameToModuleField = ReflectionUtil.lookupField(ModuleLayer.class, "nameToModule"); + moduleParentsField = ReflectionUtil.lookupField(ModuleLayer.class, "parents"); + configurationParentsField = ReflectionUtil.lookupField(Configuration.class, "parents"); + moduleLayerConstructor = ReflectionUtil.lookupConstructor(ModuleLayer.class, Configuration.class, List.class, Function.class); + } + + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + access.registerReachabilityHandler( + a -> a.registerAsUnsafeAccessed(ReflectionUtil.lookupField(ClassLoader.class, "classLoaderValueMap")), + ReflectionUtil.lookupMethod(ClassLoader.class, "trySetObjectField", String.class, Object.class) + ); + RuntimeReflection.register(ReflectionUtil.lookupField(ClassLoader.class, "classLoaderValueMap")); } @Override - public void afterAnalysis(AfterAnalysisAccess access) { - FeatureImpl.AfterAnalysisAccessImpl accessImpl = (FeatureImpl.AfterAnalysisAccessImpl) access; + public void duringAnalysis(DuringAnalysisAccess access) { + FeatureImpl.DuringAnalysisAccessImpl accessImpl = (FeatureImpl.DuringAnalysisAccessImpl) access; AnalysisUniverse universe = accessImpl.getUniverse(); - Set reachableModules = universe.getTypes() + Map reachableModules = universe.getTypes() .stream() .filter(t -> t.isReachable() && !t.isArray()) .map(t -> t.getJavaClass().getModule()) - .filter(Module::isNamed) - .filter(m -> !m.getName().startsWith("jdk.proxy")) - .collect(Collectors.toSet()); + .filter(m -> m.isNamed() && !m.getDescriptor().modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC)) + .collect(Collectors.toMap(Module::getName, m -> m, (m1, m2) -> m1)); - ModuleLayer runtimeBootLayer = synthesizeRuntimeBootLayer(accessImpl.imageClassLoader.modulepath(), reachableModules); + ModuleLayer runtimeBootLayer = synthesizeRuntimeBootLayer(accessImpl.imageClassLoader, reachableModules); BootModuleLayerSupport.instance().setBootLayer(runtimeBootLayer); } - private ModuleLayer synthesizeRuntimeBootLayer(List mp, Set reachableModules) { - Configuration cf = synthesizeRuntimeBootLayerConfiguration(mp, reachableModules); + private ModuleLayer synthesizeRuntimeBootLayer(ImageClassLoader cl, Map reachableModules) { + Configuration cf = synthesizeRuntimeBootLayerConfiguration(cl.modulepath(), reachableModules); try { - Constructor ctor = ReflectionUtil.lookupConstructor(ModuleLayer.class, Configuration.class, List.class, Function.class); - ctor.setAccessible(true); - ModuleLayer runtimeBootLayer = ctor.newInstance(cf, List.of(), null); + ModuleLayer runtimeBootLayer = moduleLayerConstructor.newInstance(cf, List.of(), null); patchRuntimeBootLayer(runtimeBootLayer, reachableModules); return runtimeBootLayer; } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) { - throw VMError.shouldNotReachHere("Failed to instantiate the runtime boot module layer.", ex); + throw VMError.shouldNotReachHere("Failed to synthesize the runtime boot module layer.", ex); } } - private Configuration synthesizeRuntimeBootLayerConfiguration(List mp, Set reachableModules) { + private Configuration synthesizeRuntimeBootLayerConfiguration(List mp, Map reachableModules) { ModuleFinder finder = ModuleFinder.of(mp.toArray(Path[]::new)); - Set roots = reachableModules.stream().map(Module::getName).collect(Collectors.toSet()); - List parents = List.of(ModuleLayer.boot().configuration()); - return Configuration.resolve(finder, parents, finder, roots); + Set roots = reachableModules.keySet(); + try { + Configuration cf = ModuleLayer.boot().configuration().resolve(finder, finder, roots); + configurationParentsField.set(cf, List.of(Configuration.empty())); + return cf; + } catch (IllegalAccessException | FindException | ResolutionException | SecurityException ex) { + throw VMError.shouldNotReachHere("Failed to synthesize the runtime boot module layer configuration.", ex); + } } - private void patchRuntimeBootLayer(ModuleLayer runtimeBootLayer, Set reachableModules) { - Map nameToModule = reachableModules - .stream() - .collect(Collectors.toMap(Module::getName, m -> m)); - - Field nameToModuleField = ReflectionUtil.lookupField(ModuleLayer.class, "nameToModule"); - Field modulesField = ReflectionUtil.lookupField(ModuleLayer.class, "modules"); + private void patchRuntimeBootLayer(ModuleLayer runtimeBootLayer, Map reachableModules) { try { - nameToModuleField.setAccessible(true); - modulesField.setAccessible(true); - nameToModuleField.set(runtimeBootLayer, nameToModule); - modulesField.set(runtimeBootLayer, reachableModules); + 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); } From 87c1fb663c42c7262c452e2e9f57449728c330f7 Mon Sep 17 00:00:00 2001 From: ivan-ristovic Date: Tue, 13 Jul 2021 13:22:07 +0200 Subject: [PATCH 5/8] Substitute native methods of the Module class Substitute native methods of the Module class Fix boot layer configuration resolving Expand `mx hellomodule` with more boot layer tests --- .../svm/core/jdk/Target_java_lang_Module.java | 21 ++++++ .../jdk/Target_java_lang_ClassLoader.java | 7 -- .../oracle/svm/hosted/ModuleLayerFeature.java | 36 ++++++++-- .../hello.app/src/main/java/hello/Main.java | 65 +++++++++++++++---- 4 files changed, 103 insertions(+), 26 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java index d1d6d59c6366..0e403445d254 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java @@ -33,6 +33,7 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; +@SuppressWarnings("unused") @TargetClass(className = "java.lang.Module", onlyWith = JDK11OrLater.class) public final class Target_java_lang_Module { @@ -43,6 +44,26 @@ public InputStream getResourceAsStream(String name) { return res == null ? null : new ByteArrayInputStream(res.getData().get(0)); } + @Substitute + private static void defineModule0(Module module, boolean isOpen, String version, String location, String[] pns) { + } + + @Substitute + private static void addReads0(Module from, Module to) { + } + + @Substitute + private static void addExports0(Module from, String pn, Module to) { + } + + @Substitute + private static void addExportsToAll0(Module from, String pn) { + } + + @Substitute + private static void addExportsToAllUnnamed0(Module from, String pn) { + } + @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") // 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..8f8378f58e5a 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 @@ -271,13 +271,6 @@ Class loadClass(Target_java_lang_Module module, String name) { @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) { 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 index e013aa4918ab..b88431a2ed6c 100644 --- 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 @@ -40,13 +40,16 @@ 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; @@ -87,7 +90,6 @@ public final class ModuleLayerFeature implements Feature { private Field moduleNameToModuleField; private Field moduleParentsField; - private Field configurationParentsField; private Constructor moduleLayerConstructor; @Override @@ -100,7 +102,6 @@ public void afterRegistration(AfterRegistrationAccess access) { ImageSingletons.add(BootModuleLayerSupport.class, new BootModuleLayerSupport()); moduleNameToModuleField = ReflectionUtil.lookupField(ModuleLayer.class, "nameToModule"); moduleParentsField = ReflectionUtil.lookupField(ModuleLayer.class, "parents"); - configurationParentsField = ReflectionUtil.lookupField(Configuration.class, "parents"); moduleLayerConstructor = ReflectionUtil.lookupConstructor(ModuleLayer.class, Configuration.class, List.class, Function.class); } @@ -141,13 +142,12 @@ private ModuleLayer synthesizeRuntimeBootLayer(ImageClassLoader cl, Map mp, Map reachableModules) { - ModuleFinder finder = ModuleFinder.of(mp.toArray(Path[]::new)); + ModuleFinder beforeFinder = new BootModuleLayerModuleFinder(); + ModuleFinder afterFinder = ModuleFinder.of(mp.toArray(Path[]::new)); Set roots = reachableModules.keySet(); try { - Configuration cf = ModuleLayer.boot().configuration().resolve(finder, finder, roots); - configurationParentsField.set(cf, List.of(Configuration.empty())); - return cf; - } catch (IllegalAccessException | FindException | ResolutionException | SecurityException ex) { + 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); } } @@ -160,4 +160,26 @@ private void patchRuntimeBootLayer(ModuleLayer runtimeBootLayer, Map 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/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 62ddb5a8b1b3..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,18 +26,39 @@ 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(); + Module helloLibModule = Greeter.class.getModule(); + testModuleObjects(helloAppModule, helloLibModule); + + System.out.println("Basic Module test involving " + helloAppModule + " and " + helloLibModule); + Greeter.greet(); + + System.out.println("Now accessing package that is not exported in " + helloLibModule); + hello.privateLib.Greeter.greet(); + + System.out.println("Now accessing private method from not exported package in " + helloLibModule); + 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()); - Module helloLibModule = Greeter.class.getModule(); assert helloLibModule.getName().equals("moduletests.hello.lib"); assert helloLibModule.isExported(Greeter.class.getPackageName()); assert helloLibModule.isNamed(); @@ -48,20 +69,40 @@ public static void main(String[] args) throws NoSuchMethodException, InvocationT assert helloAppModule.canRead(helloLibModule); assert !helloLibModule.canRead(helloAppModule); + } - 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); + @SuppressWarnings("OptionalGetWithoutIsPresent") + private static void testBootLayer(Module helloAppModule, Module helloLibModule) { + ModuleLayer bootLayer = ModuleLayer.boot(); - System.out.println("Basic Module test involving " + helloAppModule + " and " + helloLibModule); - Greeter.greet(); + 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 accessing package that is not exported in " + helloLibModule); - hello.privateLib.Greeter.greet(); + 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 accessing private method from not exported package in " + helloLibModule); - Method greetMethod = hello.privateLib2.PrivateGreeter.class.getDeclaredMethod("greet"); - greetMethod.setAccessible(true); - greetMethod.invoke(null); + 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); } } From e204f9bae527cb624d9b51ced92f63c52e707839 Mon Sep 17 00:00:00 2001 From: ivan-ristovic Date: Sun, 18 Jul 2021 23:16:47 +0200 Subject: [PATCH 6/8] Implement module/package checks in runtime for `defineModules0` Implement checks inside Module native methods Calculate boot layer once after analysis Implement module/package checks in runtime for `defineModule0` --- substratevm/mx.substratevm/suite.py | 3 +- .../svm/core/jdk/BootModuleLayerSupport.java | 2 +- .../svm/core/jdk/Target_java_lang_Module.java | 191 ++++++++++++++++++ .../jdk/Target_java_lang_NamedPackage.java | 33 +++ .../oracle/svm/hosted/ModuleLayerFeature.java | 17 +- 5 files changed, 241 insertions(+), 5 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_NamedPackage.java diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 2a9f982a2911..8324d5c3d5dc 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" : [ diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java index d29758386c17..ef3f29a000da 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java @@ -35,7 +35,7 @@ public static BootModuleLayerSupport instance() { return ImageSingletons.lookup(BootModuleLayerSupport.class); } - @UnknownObjectField + @UnknownObjectField(types = ModuleLayer.class) private ModuleLayer bootLayer; @Platforms(Platform.HOSTED_ONLY.class) diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java index 0e403445d254..125efb472f55 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java @@ -24,14 +24,23 @@ */ 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.RecomputeFieldValue; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.jdk.resources.ResourceStorageEntry; +import javax.lang.model.SourceVersion; import java.io.ByteArrayInputStream; import java.io.InputStream; +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; @SuppressWarnings("unused") @TargetClass(className = "java.lang.Module", onlyWith = JDK11OrLater.class) @@ -44,24 +53,120 @@ public InputStream getResourceAsStream(String name) { return res == null ? null : new ByteArrayInputStream(res.getData().get(0)); } + //Checkstyle: allow synchronization @Substitute private static void defineModule0(Module module, boolean isOpen, String version, String location, String[] 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 (ModuleUtil.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 (ModuleUtil.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 = ModuleUtil.getModuleContainingPackage(loader, definedPackage); + 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 (ModuleUtil.moduleLock) { + ModuleUtil.addDefinedModule(loader, module); + } } @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) // @@ -70,3 +175,89 @@ private static final class Target_java_lang_Module_ReflectionData { static Target_java_lang_WeakPairMap, Boolean> uses; } } + +class ModuleUtil { + + static final Object moduleLock = new Object(); + static final Map> definedModules = new HashMap<>(); + + static { + for (Module module : ModuleLayer.boot().modules()) { + addDefinedModule(module.getClassLoader(), module); + } + } + + 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"); + } + } + + 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()); + } + } + + static boolean isPackageNameForbidden(String pn) { + if (!pn.startsWith("java")) { + return false; + } + char trailingChar = pn.length() < 5 ? '.' : pn.charAt("java".length()); + return trailingChar == '.'; + } + + 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); + } + + static boolean isModuleDefinedToLoader(ClassLoader loader, String moduleName) { + return definedModules.getOrDefault(loader, Set.of()).stream().anyMatch(m -> m.getName().equals(moduleName)); + } + + static void addDefinedModule(ClassLoader loader, Module module) { + Set modules = definedModules.get(loader); + if (Objects.isNull(modules)) { + modules = new HashSet<>(); + modules.add(module); + definedModules.put(loader, modules); + } else { + modules.add(module); + } + } + + static List getPackagesDefinedToLoader(ClassLoader loader) { + return definedModules.getOrDefault(loader, Set.of()) + .stream() + .flatMap(m -> m.getPackages().stream()) + .collect(Collectors.toUnmodifiableList()); + } + + static Module getModuleContainingPackage(ClassLoader loader, String pn) { + return definedModules.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)); + } +} diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_NamedPackage.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_NamedPackage.java new file mode 100644 index 000000000000..eb21a2c09e95 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_NamedPackage.java @@ -0,0 +1,33 @@ +/* + * 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.jdk; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.TargetClass; + +@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.hosted.jdk11/src/com/oracle/svm/hosted/ModuleLayerFeature.java b/substratevm/src/com.oracle.svm.hosted.jdk11/src/com/oracle/svm/hosted/ModuleLayerFeature.java index b88431a2ed6c..e66db60cdc5f 100644 --- 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 @@ -30,6 +30,7 @@ import com.oracle.svm.core.jdk.JDK11OrLater; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; +import jdk.internal.module.ModuleReferenceImpl; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -107,6 +108,13 @@ public void afterRegistration(AfterRegistrationAccess access) { @Override public void beforeAnalysis(BeforeAnalysisAccess access) { + // Because we synthesize the boot layer after analysis, we need to + // register every type in ModuleLayer's object graph as in heap + access.registerAsInHeap(ModuleLayer.class); + access.registerAsInHeap(Configuration.class); + access.registerAsInHeap(ResolvedModule.class); + access.registerAsInHeap(ModuleReferenceImpl.class); + access.registerReachabilityHandler( a -> a.registerAsUnsafeAccessed(ReflectionUtil.lookupField(ClassLoader.class, "classLoaderValueMap")), ReflectionUtil.lookupMethod(ClassLoader.class, "trySetObjectField", String.class, Object.class) @@ -115,16 +123,17 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { } @Override - public void duringAnalysis(DuringAnalysisAccess access) { - FeatureImpl.DuringAnalysisAccessImpl accessImpl = (FeatureImpl.DuringAnalysisAccessImpl) access; + 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, (m1, m2) -> m1)); + .collect(Collectors.toMap(Module::getName, m -> m)); ModuleLayer runtimeBootLayer = synthesizeRuntimeBootLayer(accessImpl.imageClassLoader, reachableModules); BootModuleLayerSupport.instance().setBootLayer(runtimeBootLayer); @@ -135,6 +144,8 @@ private ModuleLayer synthesizeRuntimeBootLayer(ImageClassLoader cl, Map Date: Fri, 13 Aug 2021 16:51:28 +0200 Subject: [PATCH 7/8] Add specific JDK16 `defineModuele0` substitution Update overlays related to module system Specific `defineModule0` implementation for JDK16 Add dependency to `com.oracle.svm.core.jdk11` from `com.oracle.svm.core.jdk15` --- substratevm/mx.substratevm/suite.py | 5 +- .../BootModuleLayerSupport.java | 2 +- .../JavaLangSubstitutions_JDK11OrLater.java | 105 ++++++++ .../ModuleUtil.java} | 244 +++++++----------- ...et_java_lang_ClassLoader_JDK11OrLater.java | 69 +++++ .../Target_java_lang_ModuleLayer.java | 5 +- .../Target_java_lang_Module_JDK11OrLater.java | 95 +++++++ .../Target_java_lang_NamedPackage.java | 3 +- .../Target_java_lang_WeakPairMap.java | 3 +- ...rget_java_lang_module_ModuleReference.java | 6 +- ...dk_internal_loader_BuiltinClassLoader.java | 8 +- .../Target_java_util_ResourceBundle.java | 55 ++++ .../Target_java_lang_Module_JDK15OrLater.java | 50 ++++ .../com/oracle/svm/core/hub/DynamicHub.java | 4 +- .../svm/core/jdk/JavaLangSubstitutions.java | 78 ------ .../oracle/svm/core/jdk/ResourcesHelper.java | 92 +++++++ .../jdk/Target_java_lang_ClassLoader.java | 86 +----- .../svm/core/jdk/Target_java_lang_Module.java | 19 +- .../core/jdk/Target_java_lang_Package.java | 53 ++++ .../Target_java_util_ResourceBundle.java | 19 -- .../oracle/svm/hosted/ModuleLayerFeature.java | 9 +- ...java_lang_invoke_MethodHandles_Lookup.java | 3 +- 22 files changed, 644 insertions(+), 369 deletions(-) rename substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/{jdk => jdk11}/BootModuleLayerSupport.java (98%) create mode 100644 substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/JavaLangSubstitutions_JDK11OrLater.java rename substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/{jdk/Target_java_lang_Module.java => jdk11/ModuleUtil.java} (64%) create mode 100644 substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_ClassLoader_JDK11OrLater.java rename substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/{jdk => jdk11}/Target_java_lang_ModuleLayer.java (91%) create mode 100644 substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_Module_JDK11OrLater.java rename substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/{jdk => jdk11}/Target_java_lang_NamedPackage.java (94%) rename substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/{jdk => jdk11}/Target_java_lang_WeakPairMap.java (94%) rename substratevm/src/{com.oracle.svm.core/src/com/oracle/svm/core/jdk => com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11}/Target_java_lang_module_ModuleReference.java (90%) rename substratevm/src/{com.oracle.svm.core/src/com/oracle/svm/core/jdk => com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11}/Target_jdk_internal_loader_BuiltinClassLoader.java (89%) create mode 100644 substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/substitutions/Target_java_util_ResourceBundle.java create mode 100644 substratevm/src/com.oracle.svm.core.jdk15/src/com/oracle/svm/core/jdk15/Target_java_lang_Module_JDK15OrLater.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/ResourcesHelper.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Package.java diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 8324d5c3d5dc..1cd197fb9920 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -236,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", diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/BootModuleLayerSupport.java similarity index 98% rename from substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java rename to substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/BootModuleLayerSupport.java index ef3f29a000da..8964825475f2 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/BootModuleLayerSupport.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 com.oracle.svm.core.annotate.UnknownObjectField; import org.graalvm.nativeimage.ImageSingletons; 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/jdk/Target_java_lang_Module.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/ModuleUtil.java similarity index 64% rename from substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java rename to substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/ModuleUtil.java index 125efb472f55..fc8cb07c709a 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/ModuleUtil.java @@ -22,18 +22,11 @@ * 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.SubstrateUtil; -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.jdk.resources.ResourceStorageEntry; import javax.lang.model.SourceVersion; -import java.io.ByteArrayInputStream; -import java.io.InputStream; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -42,20 +35,104 @@ import java.util.Set; import java.util.stream.Collectors; -@SuppressWarnings("unused") -@TargetClass(className = "java.lang.Module", onlyWith = JDK11OrLater.class) -public final class Target_java_lang_Module { +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); + } + } - @SuppressWarnings("static-method") - @Substitute - public InputStream getResourceAsStream(String name) { - ResourceStorageEntry res = Resources.get(name); - return res == null ? null : new ByteArrayInputStream(res.getData().get(0)); + 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 - @Substitute - private static void defineModule0(Module module, boolean isOpen, String version, String location, String[] pns) { + public static void defineModule(Module module, boolean isOpen, List pns) { if (Objects.isNull(module)) { throw new NullPointerException("Null module object"); } @@ -79,7 +156,7 @@ private static void defineModule0(Module module, boolean isOpen, String version, throw new IllegalArgumentException("Class loader must be the boot class loader"); } - synchronized (ModuleUtil.moduleLock) { + synchronized (moduleLock) { boolean duplicateJavaBase = ModuleUtil.bootLayerContainsModule("java.base"); if (duplicateJavaBase) { throw new InternalError("Module java.base is already defined"); @@ -107,7 +184,7 @@ private static void defineModule0(Module module, boolean isOpen, String version, String definedPackage = null; boolean moduleAlreadyDefined; - synchronized (ModuleUtil.moduleLock) { + synchronized (moduleLock) { moduleAlreadyDefined = ModuleUtil.isModuleDefinedToLoader(loader, module.getName()); if (!moduleAlreadyDefined) { List definedPackages = ModuleUtil.getPackagesDefinedToLoader(loader); @@ -123,7 +200,7 @@ private static void defineModule0(Module module, boolean isOpen, String version, if (moduleAlreadyDefined) { throw new IllegalStateException("Module " + module.getName() + " is already defined"); } else if (Objects.nonNull(definedPackage)) { - Module moduleContainingDefinedPackage = ModuleUtil.getModuleContainingPackage(loader, 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"); @@ -133,131 +210,8 @@ private static void defineModule0(Module module, boolean isOpen, String version, } } - synchronized (ModuleUtil.moduleLock) { + synchronized (moduleLock) { ModuleUtil.addDefinedModule(loader, module); } } - - @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; - } -} - -class ModuleUtil { - - static final Object moduleLock = new Object(); - static final Map> definedModules = new HashMap<>(); - - static { - for (Module module : ModuleLayer.boot().modules()) { - addDefinedModule(module.getClassLoader(), module); - } - } - - 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"); - } - } - - 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()); - } - } - - static boolean isPackageNameForbidden(String pn) { - if (!pn.startsWith("java")) { - return false; - } - char trailingChar = pn.length() < 5 ? '.' : pn.charAt("java".length()); - return trailingChar == '.'; - } - - 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); - } - - static boolean isModuleDefinedToLoader(ClassLoader loader, String moduleName) { - return definedModules.getOrDefault(loader, Set.of()).stream().anyMatch(m -> m.getName().equals(moduleName)); - } - - static void addDefinedModule(ClassLoader loader, Module module) { - Set modules = definedModules.get(loader); - if (Objects.isNull(modules)) { - modules = new HashSet<>(); - modules.add(module); - definedModules.put(loader, modules); - } else { - modules.add(module); - } - } - - static List getPackagesDefinedToLoader(ClassLoader loader) { - return definedModules.getOrDefault(loader, Set.of()) - .stream() - .flatMap(m -> m.getPackages().stream()) - .collect(Collectors.toUnmodifiableList()); - } - - static Module getModuleContainingPackage(ClassLoader loader, String pn) { - return definedModules.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)); - } } 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/jdk/Target_java_lang_ModuleLayer.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_ModuleLayer.java similarity index 91% rename from substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_ModuleLayer.java rename to substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_ModuleLayer.java index 8e1b07f7decb..0822f32dfec8 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_ModuleLayer.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_ModuleLayer.java @@ -22,13 +22,14 @@ * 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.Substitute; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.jdk.JDK11OrLater; @SuppressWarnings("unused") -@TargetClass(className = "java.lang.ModuleLayer", onlyWith = JDK11OrLater.class) +@TargetClass(value = java.lang.ModuleLayer.class, onlyWith = JDK11OrLater.class) final class Target_java_lang_ModuleLayer { @SuppressWarnings("unused") 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/jdk/Target_java_lang_NamedPackage.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_NamedPackage.java similarity index 94% rename from substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_NamedPackage.java rename to substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_NamedPackage.java index eb21a2c09e95..eb42f7f59c2e 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_NamedPackage.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_NamedPackage.java @@ -22,10 +22,11 @@ * 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.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 { diff --git a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_WeakPairMap.java b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_WeakPairMap.java similarity index 94% rename from substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_WeakPairMap.java rename to substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_WeakPairMap.java index 77e1031efa26..c028ce9f6b47 100644 --- a/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk/Target_java_lang_WeakPairMap.java +++ b/substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/Target_java_lang_WeakPairMap.java @@ -22,9 +22,10 @@ * 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.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 8f8378f58e5a..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,15 +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 // @SuppressWarnings({"unused"}) Object getClassLoadingLock(String className) { @@ -286,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 6d2b3ae8b033..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,24 +24,9 @@ */ package com.oracle.svm.core.jdk; -import java.io.ByteArrayInputStream; -import java.io.InputStream; - -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); - return entry == null ? null : new ByteArrayInputStream(entry.getData().get(0)); - } - - @TargetClass(className = "java.lang.Module", innerClass = "ReflectionData", onlyWith = JDK11OrLater.class) - private static final class Target_java_lang_Module_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 index e66db60cdc5f..50faef5056cc 100644 --- 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 @@ -26,7 +26,7 @@ import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.svm.core.annotate.AutomaticFeature; -import com.oracle.svm.core.jdk.BootModuleLayerSupport; +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; @@ -35,7 +35,6 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.hosted.Feature; -import org.graalvm.nativeimage.hosted.RuntimeReflection; import java.lang.module.Configuration; import java.lang.module.FindException; @@ -114,12 +113,6 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { access.registerAsInHeap(Configuration.class); access.registerAsInHeap(ResolvedModule.class); access.registerAsInHeap(ModuleReferenceImpl.class); - - access.registerReachabilityHandler( - a -> a.registerAsUnsafeAccessed(ReflectionUtil.lookupField(ClassLoader.class, "classLoaderValueMap")), - ReflectionUtil.lookupMethod(ClassLoader.class, "trySetObjectField", String.class, Object.class) - ); - RuntimeReflection.register(ReflectionUtil.lookupField(ClassLoader.class, "classLoaderValueMap")); } @Override 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 " + From d811e482ab961a2a5654e1bc14f99b8eac0ffc14 Mon Sep 17 00:00:00 2001 From: ivan-ristovic Date: Wed, 25 Aug 2021 10:07:53 +0200 Subject: [PATCH 8/8] Synthesize boot layer once before analysis --- .../svm/core/jdk11/BootModuleLayerSupport.java | 2 -- .../com/oracle/svm/hosted/ModuleLayerFeature.java | 13 ++++++------- 2 files changed, 6 insertions(+), 9 deletions(-) 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 index 8964825475f2..502265882b6e 100644 --- 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 @@ -24,7 +24,6 @@ */ package com.oracle.svm.core.jdk11; -import com.oracle.svm.core.annotate.UnknownObjectField; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -35,7 +34,6 @@ public static BootModuleLayerSupport instance() { return ImageSingletons.lookup(BootModuleLayerSupport.class); } - @UnknownObjectField(types = ModuleLayer.class) private ModuleLayer bootLayer; @Platforms(Platform.HOSTED_ONLY.class) 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 index 50faef5056cc..187c7037b11c 100644 --- 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 @@ -30,7 +30,6 @@ import com.oracle.svm.core.jdk.JDK11OrLater; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; -import jdk.internal.module.ModuleReferenceImpl; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -107,12 +106,12 @@ public void afterRegistration(AfterRegistrationAccess access) { @Override public void beforeAnalysis(BeforeAnalysisAccess access) { - // Because we synthesize the boot layer after analysis, we need to - // register every type in ModuleLayer's object graph as in heap - access.registerAsInHeap(ModuleLayer.class); - access.registerAsInHeap(Configuration.class); - access.registerAsInHeap(ResolvedModule.class); - access.registerAsInHeap(ModuleReferenceImpl.class); + 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