diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/BuildingInitialLayerPredicate.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/BuildingInitialLayerPredicate.java new file mode 100644 index 000000000000..93e08ac1f764 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/BuildingInitialLayerPredicate.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024, 2024, 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.imagelayer; + +import java.util.function.BooleanSupplier; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +@Platforms(Platform.HOSTED_ONLY.class) +public class BuildingInitialLayerPredicate implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return ImageLayerBuildingSupport.buildingInitialLayer(); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/LayeredModuleSingleton.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/LayeredModuleSingleton.java new file mode 100644 index 000000000000..0711dc4afc8b --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/LayeredModuleSingleton.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2025, 2025, 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.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; +import com.oracle.svm.core.util.UserError; + +/** + * This singleton keeps track of the {@code Module#openPackages} and {@code Module#exportedPackages} + * from all image layers. + */ +@Platforms(Platform.HOSTED_ONLY.class) +public abstract class LayeredModuleSingleton implements LayeredImageSingleton { + public static final String ALL_UNNAMED_MODULE_NAME = "native-image-all-unnamed"; + public static final String EVERYONE_MODULE_NAME = "native-image-everyone"; + + protected final Map>> moduleOpenPackages; + protected final Map>> moduleExportedPackages; + + private final Map moduleNames = new HashMap<>(); + + private Module everyoneModule; + private Module allUnnamedModule; + + public LayeredModuleSingleton() { + this(new HashMap<>(), new HashMap<>()); + } + + public LayeredModuleSingleton(Map>> moduleOpenPackages, Map>> moduleExportedPackages) { + this.moduleOpenPackages = moduleOpenPackages; + this.moduleExportedPackages = moduleExportedPackages; + } + + public static LayeredModuleSingleton singleton() { + return ImageSingletons.lookup(LayeredModuleSingleton.class); + } + + public void setUnnamedModules(Module everyoneModule, Module allUnnamedModule) { + this.everyoneModule = everyoneModule; + this.allUnnamedModule = allUnnamedModule; + } + + public Map> getOpenPackages(Module module) { + return moduleOpenPackages.get(module.getName()); + } + + public Map> getExportedPackages(Module module) { + return moduleExportedPackages.get(module.getName()); + } + + public Collection getModules() { + return moduleNames.values(); + } + + public void setOpenPackages(Module module, Map> openPackages) { + setPackages(module, moduleOpenPackages, openPackages, "opened"); + } + + public void setExportedPackages(Module module, Map> exportedPackages) { + setPackages(module, moduleExportedPackages, exportedPackages, "exported"); + } + + private void setPackages(Module module, Map>> modulePackages, Map> packages, String mode) { + Module oldValue = moduleNames.put(module.toString(), module); + if (oldValue != null && oldValue != module) { + throw UserError.abort("Layered images require all modules to have a different name because their identity hash code is not consistent across layers. " + + "The modules %s and %s have the same name and were added to the %s packages", module, oldValue, mode); + } + Map> namesMap = modulePackages.computeIfAbsent(module.getName(), k -> new HashMap<>()); + for (var entry : packages.entrySet()) { + Set modules = namesMap.computeIfAbsent(entry.getKey(), k -> new HashSet<>()); + modules.addAll(entry.getValue().stream().map(Module::getName).toList()); + modules.remove(null); + if (entry.getValue().contains(allUnnamedModule)) { + modules.add(ALL_UNNAMED_MODULE_NAME); + } + if (entry.getValue().contains(everyoneModule)) { + modules.add(EVERYONE_MODULE_NAME); + } + } + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java index 3c1c5e164616..b911fcfa2ac0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java @@ -39,6 +39,7 @@ import java.util.Objects; import java.util.Set; import java.util.function.BiConsumer; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -147,6 +148,9 @@ public record ModuleResourceKey(Module module, String resource) { private GlobTrieNode resourcesTrieRoot; + @Platforms(Platform.HOSTED_ONLY.class) // + private Function hostedToRuntimeModuleMapper; + Resources() { } @@ -194,12 +198,17 @@ public static ModuleResourceKey createStorageKey(Module module, String resourceN Module m = module != null && module.isNamed() ? module : null; if (ImageInfo.inImageBuildtimeCode()) { if (m != null) { - m = RuntimeModuleSupport.instance().getRuntimeModuleForHostedModule(m); + m = currentLayer().hostedToRuntimeModuleMapper.apply(m); } } return new ModuleResourceKey(m, resourceName); } + @Platforms(Platform.HOSTED_ONLY.class) // + public void setHostedToRuntimeModuleMapper(Function hostedToRuntimeModuleMapper) { + this.hostedToRuntimeModuleMapper = hostedToRuntimeModuleMapper; + } + @Platforms(Platform.HOSTED_ONLY.class) public static Set getIncludedResourcesModules() { return StreamSupport.stream(currentLayer().resources.getKeys().spliterator(), false) @@ -472,7 +481,7 @@ public static InputStream createInputStream(Module module, String resourceName) * If module is not specified or is an unnamed module and entry was not found as * classpath-resource we have to search for the resource in all modules in the image. */ - for (Module m : RuntimeModuleSupport.instance().getBootLayer().modules()) { + for (Module m : RuntimeModuleSupport.singleton().getBootLayer().modules()) { entry = getAtRuntime(m, resourceName, false); if (entry != MISSING_METADATA_MARKER) { isInMetadata = true; @@ -510,7 +519,7 @@ public static Enumeration createURLs(Module module, String resourceName) { /* If moduleName was unspecified we have to consider all modules in the image */ if (moduleName(module) == null) { - for (Module m : RuntimeModuleSupport.instance().getBootLayer().modules()) { + for (Module m : RuntimeModuleSupport.singleton().getBootLayer().modules()) { ResourceStorageEntryBase entry = getAtRuntime(m, resourceName, false); if (entry == MISSING_METADATA_MARKER) { continue; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RuntimeModuleSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RuntimeModuleSupport.java index ee6d23ffd5c8..43e00a3866ed 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RuntimeModuleSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RuntimeModuleSupport.java @@ -24,14 +24,19 @@ */ package com.oracle.svm.core.jdk; -import java.util.function.Function; +import java.util.EnumSet; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import com.oracle.svm.core.BuildPhaseProvider.AfterHostedUniverse; +import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.heap.UnknownObjectField; +import com.oracle.svm.core.imagelayer.LastImageBuildPredicate; +import com.oracle.svm.core.layeredimagesingleton.ApplicationLayerOnlyImageSingleton; +import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; +import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton; /** * Runtime module support singleton, containing the runtime boot module layer. The boot module layer @@ -42,18 +47,15 @@ * counterpart. The lookup function is implemented inside the module layer synthesis feature. See * {@code ModuleLayerFeature} for more information. */ -public final class RuntimeModuleSupport { - - public static RuntimeModuleSupport instance() { +@AutomaticallyRegisteredImageSingleton(onlyWith = LastImageBuildPredicate.class) +public final class RuntimeModuleSupport implements ApplicationLayerOnlyImageSingleton, UnsavedSingleton { + public static RuntimeModuleSupport singleton() { return ImageSingletons.lookup(RuntimeModuleSupport.class); } @UnknownObjectField(availability = AfterHostedUniverse.class) // private ModuleLayer bootLayer; - @Platforms(Platform.HOSTED_ONLY.class) // - private Function hostedToRuntimeModuleMapper; - @Platforms(Platform.HOSTED_ONLY.class) // public void setBootLayer(ModuleLayer bootLayer) { this.bootLayer = bootLayer; @@ -63,13 +65,8 @@ public ModuleLayer getBootLayer() { return bootLayer; } - @Platforms(Platform.HOSTED_ONLY.class) // - public void setHostedToRuntimeModuleMapper(Function hostedToRuntimeModuleMapper) { - this.hostedToRuntimeModuleMapper = hostedToRuntimeModuleMapper; + @Override + public EnumSet getImageBuilderFlags() { + return LayeredImageSingletonBuilderFlags.ALL_ACCESS; } - - public Module getRuntimeModuleForHostedModule(Module hostedModule) { - return hostedToRuntimeModuleMapper.apply(hostedModule); - } - } 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 93b6e5588409..5de001a218db 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 @@ -24,11 +24,15 @@ */ package com.oracle.svm.core.jdk; +import java.util.Objects; +import java.util.Set; + 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.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.util.BasedOnJDKFile; /** @@ -54,6 +58,17 @@ public final class Target_java_lang_Module { // @Stable (no effect currently GR-60154) private ModuleLayer layer; + /** + * Creating an {@link Alias} directly for {@code ALL_UNNAMED_MODULE} and {@code EVERYONE_MODULE} + * makes {@code java.util.regex.Pattern} reachable, which increases the size of the binary. + */ + // Checkstyle: stop + @Alias // + private static Set ALL_UNNAMED_MODULE_SET; + @Alias // + private static Set EVERYONE_SET; + // Checkstyle: resume + @Substitute @TargetElement(onlyWith = ForeignDisabled.class) @SuppressWarnings("static-method") @@ -93,4 +108,35 @@ private static void addExportsToAll0(Module from, String pn) { private static void addExportsToAllUnnamed0(Module from, String pn) { ModuleNative.addExportsToAllUnnamed(from, pn); } + + @Substitute + @SuppressWarnings("static-method") + private boolean allows(Set targets, Module module) { + if (targets != null) { + Module everyoneModule = EVERYONE_SET.stream().findFirst().get(); + if (targets.contains(everyoneModule)) { + return true; + } + if (module != everyoneModule) { + if (targets.contains(module)) { + return true; + } + if (!module.isNamed() && targets.contains(ALL_UNNAMED_MODULE_SET.stream().findFirst().get())) { + return true; + } + if (ImageLayerBuildingSupport.buildingImageLayer()) { + for (var m : targets) { + /* + * This is based on the assumption that in Layered Image, all modules have + * different names. This is ensured in LayeredModuleSingleton.setPackages. + */ + if (Objects.equals(m.getName(), module.getName())) { + return true; + } + } + } + } + } + return false; + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ModuleLayer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ModuleLayer.java index b1144eaef57b..f2ffe2438d03 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ModuleLayer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ModuleLayer.java @@ -24,14 +24,16 @@ */ package com.oracle.svm.core.jdk; +import java.util.List; + +import org.graalvm.nativeimage.hosted.FieldValueTransformer; + 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 jdk.internal.loader.ClassLoaderValue; -import org.graalvm.nativeimage.hosted.FieldValueTransformer; -import java.util.List; +import jdk.internal.loader.ClassLoaderValue; @SuppressWarnings("unused") @TargetClass(value = java.lang.ModuleLayer.class) @@ -39,7 +41,7 @@ final class Target_java_lang_ModuleLayer { @Substitute public static ModuleLayer boot() { - return RuntimeModuleSupport.instance().getBootLayer(); + return RuntimeModuleSupport.singleton().getBootLayer(); } @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = ModuleLayerCLVTransformer.class, isFinal = true) // diff --git a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp index b224e0851024..721a95cb1ef4 100644 --- a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp +++ b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp @@ -278,6 +278,8 @@ struct SharedLayerSnapshot { dynamicHubInfos @18 :List(DynamicHubInfo); hostedMethods @19 :List(PersistedHostedMethod); nodeClassMapLocation @20 :Text; + sharedLayerBootLayerModules @21 :List(Text); + layeredModule @22 :LayeredModule; } struct StaticFinalFieldFoldingSingleton { @@ -293,6 +295,21 @@ struct LayeredRuntimeMetadataSingleton { fields @1 :List(FieldId); } +struct LayeredModule { + openModulePackages @0 :List(ModulePackages); + exportedModulePackages @1 :List(ModulePackages); +} + +struct ModulePackages { + moduleKey @0 :Text; + packages @1 :List(Packages); +} + +struct Packages { + packageKey @0 :Text; + modules @1 :List(Text); +} + struct PrimitiveValue { typeChar @0 :Int8; rawValue @1 :Int64; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderFeature.java index e4a787f005b4..84f6ffaa7078 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderFeature.java @@ -27,21 +27,22 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; +import org.graalvm.nativeimage.libgraal.hosted.LibGraalLoader; + import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.svm.core.BuildPhaseProvider; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability; +import com.oracle.svm.core.fieldvaluetransformer.ObjectToConstantFieldValueTransformer; import com.oracle.svm.core.hub.ClassForNameSupport; import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; import com.oracle.svm.hosted.imagelayer.CrossLayerConstantRegistry; -import com.oracle.svm.core.fieldvaluetransformer.ObjectToConstantFieldValueTransformer; import com.oracle.svm.hosted.jdk.HostedClassLoaderPackageManagement; import com.oracle.svm.util.ReflectionUtil; -import org.graalvm.nativeimage.libgraal.hosted.LibGraalLoader; import jdk.internal.loader.ClassLoaders; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaField; @@ -94,7 +95,7 @@ private Object runtimeClassLoaderObjectReplacer(Object replaceCandidate) { return replaceCandidate; } - ImageHeapConstant replaceClassLoadersWithLayerConstant(CrossLayerConstantRegistry registry, Object object) { + JavaConstant replaceClassLoadersWithLayerConstant(CrossLayerConstantRegistry registry, Object object) { if (object instanceof ClassLoader loader) { if (replaceWithAppClassLoader(loader) || loader == nativeImageSystemClassLoader.defaultSystemClassLoader) { return registry.getConstant(APP_KEY_NAME); @@ -136,7 +137,7 @@ public void duringSetup(DuringSetupAccess access) { }); } } else { - config.registerObjectToConstantReplacer(obj -> replaceClassLoadersWithLayerConstant(registry, obj)); + config.registerObjectToConstantReplacer(obj -> (ImageHeapConstant) replaceClassLoadersWithLayerConstant(registry, obj)); // relink packages defined in the prior layers config.registerObjectToConstantReplacer(packageManager::replaceWithPriorLayerPackage); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedLayeredModuleSingleton.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedLayeredModuleSingleton.java new file mode 100644 index 000000000000..77369412becc --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedLayeredModuleSingleton.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted; + +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; +import com.oracle.svm.core.imagelayer.BuildingInitialLayerPredicate; +import com.oracle.svm.core.jdk.LayeredModuleSingleton; +import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader; +import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter; +import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerLoader; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerSingletonLoader; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerWriter; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ModulePackages; +import com.oracle.svm.shaded.org.capnproto.StructList; + +@AutomaticallyRegisteredImageSingleton(value = LayeredModuleSingleton.class, onlyWith = BuildingInitialLayerPredicate.class) +public class HostedLayeredModuleSingleton extends LayeredModuleSingleton { + public HostedLayeredModuleSingleton() { + super(); + } + + public HostedLayeredModuleSingleton(Map>> moduleOpenPackages, Map>> moduleExportedPackages) { + super(moduleOpenPackages, moduleExportedPackages); + } + + @Override + public EnumSet getImageBuilderFlags() { + return LayeredImageSingletonBuilderFlags.BUILDTIME_ACCESS_ONLY; + } + + @Override + public PersistFlags preparePersist(ImageSingletonWriter writer) { + SVMImageLayerWriter.ImageSingletonWriterImpl writerImpl = (SVMImageLayerWriter.ImageSingletonWriterImpl) writer; + var builder = writerImpl.getSnapshotBuilder().initLayeredModule(); + persistModulePackages(builder.initOpenModulePackages(moduleOpenPackages.size()), moduleOpenPackages); + persistModulePackages(builder.initExportedModulePackages(moduleExportedPackages.size()), moduleExportedPackages); + return PersistFlags.CREATE; + } + + private static void persistModulePackages(StructList.Builder modulePackagesBuilder, Map>> modulePackages) { + int i = 0; + for (var entry : modulePackages.entrySet()) { + var entryBuilder = modulePackagesBuilder.get(i); + entryBuilder.setModuleKey(entry.getKey()); + Map> value = entry.getValue(); + var packagesBuilder = entryBuilder.initPackages(value.size()); + int j = 0; + for (var packageEntry : value.entrySet()) { + var packageEntryBuilder = packagesBuilder.get(j); + packageEntryBuilder.setPackageKey(packageEntry.getKey()); + SVMImageLayerWriter.initStringList(packageEntryBuilder::initModules, packageEntry.getValue().stream()); + j++; + } + i++; + } + } + + public static Object createFromLoader(ImageSingletonLoader loader) { + SVMImageLayerSingletonLoader.ImageSingletonLoaderImpl loaderImpl = (SVMImageLayerSingletonLoader.ImageSingletonLoaderImpl) loader; + var reader = loaderImpl.getSnapshotReader().getLayeredModule(); + + Map>> moduleOpenPackages = getModulePackages(reader.getOpenModulePackages()); + Map>> moduleExportedPackages = getModulePackages(reader.getExportedModulePackages()); + + return new HostedLayeredModuleSingleton(moduleOpenPackages, moduleExportedPackages); + } + + private static Map>> getModulePackages(StructList.Reader modulePackagesReader) { + Map>> modulePackages = new HashMap<>(); + for (int i = 0; i < modulePackagesReader.size(); ++i) { + var entryReader = modulePackagesReader.get(i); + var packagesReader = entryReader.getPackages(); + Map> packages = new HashMap<>(); + for (int j = 0; j < packagesReader.size(); ++j) { + var packageEntryReader = packagesReader.get(j); + HashSet modules = SVMImageLayerLoader.streamStrings(packageEntryReader.getModules()).collect(Collectors.toCollection(HashSet::new)); + packages.put(packageEntryReader.getPackageKey().toString(), modules); + } + modulePackages.put(entryReader.getModuleKey().toString(), packages); + } + return modulePackages; + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ModuleLayerFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ModuleLayerFeature.java index 2d15c78de15e..2a20da378a03 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ModuleLayerFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ModuleLayerFeature.java @@ -56,19 +56,22 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.hosted.FieldValueTransformer; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.svm.core.BuildPhaseProvider; import com.oracle.svm.core.NativeImageClassLoaderOptions; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.fieldvaluetransformer.ObjectToConstantFieldValueTransformer; import com.oracle.svm.core.heap.UnknownObjectField; import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; +import com.oracle.svm.core.jdk.LayeredModuleSingleton; import com.oracle.svm.core.jdk.Resources; import com.oracle.svm.core.jdk.RuntimeClassLoaderValueSupport; import com.oracle.svm.core.jdk.RuntimeModuleSupport; @@ -77,6 +80,8 @@ import com.oracle.svm.hosted.FeatureImpl.AfterAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.AnalysisAccessBase; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; +import com.oracle.svm.hosted.imagelayer.CrossLayerConstantRegistryFeature; +import com.oracle.svm.hosted.reflect.proxy.ProxyRenamingSubstitutionProcessor; import com.oracle.svm.util.LogUtils; import com.oracle.svm.util.ModuleSupport; import com.oracle.svm.util.ReflectionUtil; @@ -86,6 +91,8 @@ import jdk.internal.module.ModuleReferenceImpl; import jdk.internal.module.ServicesCatalog; import jdk.internal.module.SystemModuleFinders; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaField; /** * This feature: @@ -129,12 +136,13 @@ @SuppressWarnings("unused") public final class ModuleLayerFeature implements InternalFeature { private ModuleLayerFeatureUtils moduleLayerFeatureUtils; + private ModuleLayer bootLayer; @Override public void duringSetup(DuringSetupAccess access) { FeatureImpl.DuringSetupAccessImpl accessImpl = (FeatureImpl.DuringSetupAccessImpl) access; moduleLayerFeatureUtils = new ModuleLayerFeatureUtils(accessImpl.imageClassLoader); - RuntimeModuleSupport.instance().setHostedToRuntimeModuleMapper(m -> moduleLayerFeatureUtils.getOrCreateRuntimeModuleForHostedModule(m, accessImpl)); + Resources.currentLayer().setHostedToRuntimeModuleMapper(m -> moduleLayerFeatureUtils.getOrCreateRuntimeModuleForHostedModule(m, accessImpl)); /* * Register an object replacer that will ensure all references to hosted module instances @@ -160,8 +168,6 @@ private Object replaceHostedModules(Object source, AnalysisAccessBase access) { @Override public void afterRegistration(AfterRegistrationAccess access) { - ImageSingletons.add(RuntimeModuleSupport.class, new RuntimeModuleSupport()); - List bootLayerAutomaticModules = ModuleLayer.boot().modules() .stream() .filter(m -> m.isNamed() && m.getDescriptor().isAutomatic()) @@ -176,13 +182,95 @@ public void afterRegistration(AfterRegistrationAccess access) { } @Override - public void beforeAnalysis(BeforeAnalysisAccess access) { - scanRuntimeBootLayerPrototype((BeforeAnalysisAccessImpl) access); + public void beforeAnalysis(BeforeAnalysisAccess a) { + BeforeAnalysisAccessImpl access = (BeforeAnalysisAccessImpl) a; + if (ImageLayerBuildingSupport.buildingImageLayer()) { + AnalysisType futureType = access.getMetaAccess().lookupJavaType(HashMap.class); + access.registerFieldValueTransformer(moduleLayerFeatureUtils.moduleOpenPackagesField, new LayerPackagesTransformer(PackageType.OPENED, futureType)); + access.registerFieldValueTransformer(moduleLayerFeatureUtils.moduleExportedPackagesField, new LayerPackagesTransformer(PackageType.EXPORTED, futureType)); + } + + scanRuntimeBootLayerPrototype(access); access.registerFieldValueTransformer(moduleLayerFeatureUtils.moduleReferenceLocationField, ModuleLayerFeatureUtils.ResetModuleReferenceLocation.INSTANCE); access.registerFieldValueTransformer(moduleLayerFeatureUtils.moduleReferenceImplLocationField, ModuleLayerFeatureUtils.ResetModuleReferenceLocation.INSTANCE); } + /** + * This transformer delays the Module#open/exportedPackages fields computation until the + * application layer. + */ + static class LayerPackagesTransformer implements ObjectToConstantFieldValueTransformer { + final CrossLayerConstantRegistryFeature registry = CrossLayerConstantRegistryFeature.singleton(); + private final PackageType type; + private final AnalysisType futureType; + + LayerPackagesTransformer(PackageType packageType, AnalysisType futureType) { + this.type = packageType; + this.futureType = futureType; + } + + @Override + public JavaConstant transformToConstant(ResolvedJavaField field, Object receiver, Object originalValue, Function toConstant) { + Module module = (Module) receiver; + if (!LayeredModuleSingleton.singleton().getModules().contains(module)) { + /* + * Modules that are not processed by the LayeredModuleSingleton don't need to be + * delayed until the application layer. + */ + return toConstant.apply(originalValue); + } + /* + * This key is unique because layered images require all modules to have a different + * name. This is ensured in LayeredModuleSingleton.setPackages. + */ + String keyName = type.getModuleKeyName(module); + if (ImageLayerBuildingSupport.buildingApplicationLayer()) { + /* + * Once the constant is finalized, or if the field was not reachable in any previous + * layer, the final constant can be computed and returned. + */ + return toConstant.apply(originalValue); + } else { + if (registry.constantExists(keyName)) { + return registry.getConstant(keyName); + } else { + if (ProxyRenamingSubstitutionProcessor.isModuleDynamic(module)) { + LogUtils.warning("Dynamic module %s was found in runtime module opens/exports, which might lead to missing relations from the shared layers at runtime", module); + } + return registry.registerFutureHeapConstant(keyName, futureType); + } + } + } + + @Override + public boolean isAvailable() { + /* + * This transformer needs to be computed after all module relations are finalized in the + * application layer as transformer are computed only once and the value is then cached. + */ + return ImageLayerBuildingSupport.buildingSharedLayer() || BuildPhaseProvider.isHostedUniverseBuilt(); + } + } + + private enum PackageType { + + OPENED("opened"), + EXPORTED("exported"); + + private static final String PACKAGE_TYPE_SEPARATOR = "."; + + private final String packageType; + + PackageType(String packageType) { + this.packageType = packageType; + } + + public String getModuleKeyName(Module module) { + return module.getName() + PACKAGE_TYPE_SEPARATOR + packageType; + } + } + /** * Generate a temporary module layer to serve as a prototype object for * {@link RuntimeModuleSupport}.bootLayer. The value doesn't need to actually be set in the @@ -262,7 +350,13 @@ public void afterAnalysis(AfterAnalysisAccess access) { Set rootModules = calculateRootModules(extraModules); List runtimeModuleLayers = synthesizeRuntimeModuleLayers(accessImpl, reachableModuleLayers, runtimeImageNamedModules, analysisReachableSyntheticModules, rootModules); ModuleLayer runtimeBootLayer = runtimeModuleLayers.getFirst(); - RuntimeModuleSupport.instance().setBootLayer(runtimeBootLayer); + if (ImageLayerBuildingSupport.buildingImageLayer()) { + SharedLayerBootLayerModulesSingleton.singleton().setBootLayer(runtimeBootLayer); + } + if (ImageLayerBuildingSupport.lastImageBuild()) { + RuntimeModuleSupport.singleton().setBootLayer(runtimeBootLayer); + } + bootLayer = runtimeBootLayer; RuntimeClassLoaderValueSupport.instance().update(runtimeModuleLayers); /* @@ -273,6 +367,29 @@ public void afterAnalysis(AfterAnalysisAccess access) { replicateNativeAccess(accessImpl, runtimeImageNamedModules); } + @Override + public void beforeCompilation(BeforeCompilationAccess a) { + if (ImageLayerBuildingSupport.buildingApplicationLayer()) { + /* + * The packages fields need to be rescanned to ensure that all the future constants are + * finalized, even if they were not modified in the application layer. + */ + FeatureImpl.BeforeCompilationAccessImpl access = (FeatureImpl.BeforeCompilationAccessImpl) a; + CrossLayerConstantRegistryFeature singleton = CrossLayerConstantRegistryFeature.singleton(); + for (var module : LayeredModuleSingleton.singleton().getModules()) { + finalizeFutureHeapConstant(singleton, module, PackageType.OPENED, moduleLayerFeatureUtils.moduleOpenPackagesField); + finalizeFutureHeapConstant(singleton, module, PackageType.EXPORTED, moduleLayerFeatureUtils.moduleExportedPackagesField); + } + } + } + + private static void finalizeFutureHeapConstant(CrossLayerConstantRegistryFeature singleton, Module module, PackageType packageType, Field field) { + String moduleKeyName = packageType.getModuleKeyName(module); + if (singleton.constantExists(moduleKeyName)) { + singleton.finalizeFutureHeapConstant(moduleKeyName, ReflectionUtil.readField(Module.class, field.getName(), module)); + } + } + /** * This method is a custom version of jdk.internal.module.ModuleBootstrap#boot2() used to * compute the root module set that should be seen at image runtime. It reuses the same methods @@ -420,6 +537,9 @@ private List synthesizeRuntimeModuleLayers(AfterAnalysisAccessImpl moduleNames.retainAll(allReachableAndRequiredModuleNames); if (isBootModuleLayer) { moduleNames.addAll(rootModuleNames); + if (ImageLayerBuildingSupport.buildingApplicationLayer()) { + moduleNames.addAll(SharedLayerBootLayerModulesSingleton.singleton().getSharedBootLayerModules()); + } } Set syntheticModules = new HashSet<>(); @@ -623,7 +743,7 @@ private void patchRuntimeModuleLayer(AnalysisAccessBase accessImpl, ModuleLayer } @Platforms(Platform.HOSTED_ONLY.class) - private static final class ModuleLayerFeatureUtils { + private final class ModuleLayerFeatureUtils { private final Map> runtimeModules; private final ImageClassLoader imageClassLoader; @@ -675,6 +795,11 @@ private static final class ModuleLayerFeatureUtils { allUnnamedModuleField.setAccessible(true); allUnnamedModule = (Module) allUnnamedModuleField.get(null); + if (ImageLayerBuildingSupport.buildingImageLayer()) { + LayeredModuleSingleton singleton = LayeredModuleSingleton.singleton(); + singleton.setUnnamedModules(everyoneModule, allUnnamedModule); + } + moduleDescriptorField = findFieldByName(moduleClassFields, "descriptor"); moduleLayerField = findFieldByName(moduleClassFields, "layer"); moduleLoaderField = findFieldByName(moduleClassFields, "loader"); @@ -729,7 +854,7 @@ private boolean isNativeAccessEnabledForRuntimeBootLayerModule(String runtimeMod private boolean isNativeAccessEnabledForRuntimeModule(Module runtimeModule) { String runtimeModuleName = runtimeModule.getName(); - return RuntimeModuleSupport.instance().getBootLayer() == runtimeModule.getLayer() && isNativeAccessEnabledForRuntimeBootLayerModule(runtimeModuleName); + return bootLayer == runtimeModule.getLayer() && isNativeAccessEnabledForRuntimeBootLayerModule(runtimeModuleName); } /** @@ -929,10 +1054,11 @@ Map synthesizeNameToModule(AnalysisAccessBase access, ModuleLaye if (!descriptor.isOpen() && !descriptor.isAutomatic()) { if (descriptor.opens().isEmpty()) { Map> exportedPackages = new HashMap<>(m.getDescriptor().exports().size()); + addPreviousLayerExportedPackages(m, exportedPackages, moduleName -> getModule(moduleName, nameToModule)); for (ModuleDescriptor.Exports exports : m.getDescriptor().exports()) { String source = exports.source(); if (exports.isQualified()) { - Set targets = new HashSet<>(exports.targets().size()); + Set targets = exportedPackages.getOrDefault(source, new HashSet<>(exports.targets().size())); for (String target : exports.targets()) { Module m2 = nameToModule.get(target); if (m2 != null) { @@ -947,13 +1073,17 @@ Map synthesizeNameToModule(AnalysisAccessBase access, ModuleLaye } } moduleExportedPackagesField.set(m, exportedPackages); - access.rescanField(m, moduleExportedPackagesField); + if (ImageLayerBuildingSupport.buildingImageLayer()) { + LayeredModuleSingleton.singleton().setExportedPackages(m, exportedPackages); + } + rescan(access, exportedPackages, m, moduleExportedPackagesField); } else { Map> openPackages = new HashMap<>(descriptor.opens().size()); + addPreviousLayerOpenPackages(m, openPackages, moduleName -> getModule(moduleName, nameToModule)); for (ModuleDescriptor.Opens opens : descriptor.opens()) { String source = opens.source(); if (opens.isQualified()) { - Set targets = new HashSet<>(opens.targets().size()); + Set targets = openPackages.getOrDefault(source, new HashSet<>(opens.targets().size())); for (String target : opens.targets()) { Module m2 = (Module) moduleFindModuleMethod.invoke(null, target, Map.of(), nameToModule, runtimeModuleLayer.parents()); if (m2 != null) { @@ -969,6 +1099,7 @@ Map synthesizeNameToModule(AnalysisAccessBase access, ModuleLaye } Map> exportedPackages = new HashMap<>(descriptor.exports().size()); + addPreviousLayerExportedPackages(m, exportedPackages, moduleName -> getModule(moduleName, nameToModule)); for (ModuleDescriptor.Exports exports : descriptor.exports()) { String source = exports.source(); Set openToTargets = openPackages.get(source); @@ -977,7 +1108,7 @@ Map synthesizeNameToModule(AnalysisAccessBase access, ModuleLaye } if (exports.isQualified()) { - Set targets = new HashSet<>(exports.targets().size()); + Set targets = exportedPackages.getOrDefault(source, new HashSet<>(exports.targets().size())); for (String target : exports.targets()) { Module m2 = (Module) moduleFindModuleMethod.invoke(null, target, Map.of(), nameToModule, runtimeModuleLayer.parents()); if (m2 != null) { @@ -995,9 +1126,14 @@ Map synthesizeNameToModule(AnalysisAccessBase access, ModuleLaye } moduleOpenPackagesField.set(m, openPackages); - access.rescanField(m, moduleOpenPackagesField); moduleExportedPackagesField.set(m, exportedPackages); - access.rescanField(m, moduleExportedPackagesField); + if (ImageLayerBuildingSupport.buildingImageLayer()) { + LayeredModuleSingleton singleton = LayeredModuleSingleton.singleton(); + singleton.setOpenPackages(m, openPackages); + singleton.setExportedPackages(m, exportedPackages); + } + rescan(access, openPackages, m, moduleOpenPackagesField); + rescan(access, exportedPackages, m, moduleExportedPackagesField); } } access.rescanObject(m); @@ -1006,6 +1142,34 @@ Map synthesizeNameToModule(AnalysisAccessBase access, ModuleLaye return nameToModule; } + private void rescan(AnalysisAccessBase access, Map> packages, Module m, Field modulePackagesField) { + if (ImageLayerBuildingSupport.buildingImageLayer()) { + access.rescanObject(packages); + } else { + access.rescanField(m, modulePackagesField); + } + } + + private Module getModule(String moduleName, Map nameToModule) { + if (moduleName.equals(LayeredModuleSingleton.ALL_UNNAMED_MODULE_NAME)) { + return allUnnamedModule; + } else if (moduleName.equals(LayeredModuleSingleton.EVERYONE_MODULE_NAME)) { + return everyoneModule; + } else { + return nameToModule.get(moduleName); + } + } + + private Module getModule(String moduleName, AnalysisAccessBase access) { + if (moduleName.equals(LayeredModuleSingleton.ALL_UNNAMED_MODULE_NAME)) { + return allUnnamedModule; + } else if (moduleName.equals(LayeredModuleSingleton.EVERYONE_MODULE_NAME)) { + return everyoneModule; + } else { + return imageClassLoader.findModule(moduleName).map(value -> getOrCreateRuntimeModuleForHostedModule(value, access)).orElse(null); + } + } + @SuppressWarnings("unchecked") void addReads(AfterAnalysisAccessImpl accessImpl, Module module, Module other) throws IllegalAccessException { Set reads = (Set) moduleReadsField.get(module); @@ -1026,6 +1190,7 @@ void addExports(AfterAnalysisAccessImpl accessImpl, Module module, String pn, Mo Map> exports = (Map>) moduleExportedPackagesField.get(module); if (exports == null) { exports = new HashMap<>(1); + addPreviousLayerExportedPackages(module, exports, moduleName -> getModule(moduleName, accessImpl)); moduleExportedPackagesField.set(module, exports); } @@ -1041,7 +1206,10 @@ void addExports(AfterAnalysisAccessImpl accessImpl, Module module, String pn, Mo if (prev != null) { prev.add(other == null ? allUnnamedModule : other); } - accessImpl.rescanField(module, moduleExportedPackagesField); + if (ImageLayerBuildingSupport.buildingImageLayer()) { + LayeredModuleSingleton.singleton().setExportedPackages(module, exports); + } + rescan(accessImpl, exports, module, moduleExportedPackagesField); } @SuppressWarnings("unchecked") @@ -1053,6 +1221,7 @@ void addOpens(AfterAnalysisAccessImpl accessImpl, Module module, String pn, Modu Map> opens = (Map>) moduleOpenPackagesField.get(module); if (opens == null) { opens = new HashMap<>(1); + addPreviousLayerOpenPackages(module, opens, moduleName -> getModule(moduleName, accessImpl)); moduleOpenPackagesField.set(module, opens); } @@ -1068,7 +1237,30 @@ void addOpens(AfterAnalysisAccessImpl accessImpl, Module module, String pn, Modu if (prev != null) { prev.add(other == null ? allUnnamedModule : other); } - accessImpl.rescanField(module, moduleOpenPackagesField); + if (ImageLayerBuildingSupport.buildingImageLayer()) { + LayeredModuleSingleton.singleton().setOpenPackages(module, opens); + } + rescan(accessImpl, opens, module, moduleOpenPackagesField); + } + + private void addPreviousLayerOpenPackages(Module module, Map> packages, Function nameToModule) { + if (ImageLayerBuildingSupport.buildingApplicationLayer()) { + addPreviousLayerPackages(packages, nameToModule, LayeredModuleSingleton.singleton().getOpenPackages(module)); + } + } + + private void addPreviousLayerExportedPackages(Module module, Map> packages, Function nameToModule) { + if (ImageLayerBuildingSupport.buildingApplicationLayer()) { + addPreviousLayerPackages(packages, nameToModule, LayeredModuleSingleton.singleton().getExportedPackages(module)); + } + } + + private static void addPreviousLayerPackages(Map> packages, Function nameToModule, Map> previousOpens) { + if (previousOpens != null) { + for (var entry : previousOpens.entrySet()) { + packages.put(entry.getKey(), entry.getValue().stream().map(nameToModule).filter(Objects::nonNull).collect(Collectors.toCollection(HashSet::new))); + } + } } void patchModuleLayerField(AnalysisAccessBase accessImpl, Module module, ModuleLayer runtimeBootLayer) throws IllegalAccessException { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SharedLayerBootLayerModulesSingleton.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SharedLayerBootLayerModulesSingleton.java new file mode 100644 index 000000000000..3694da7beb61 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SharedLayerBootLayerModulesSingleton.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted; + +import java.util.Collection; +import java.util.EnumSet; +import java.util.List; +import java.util.stream.Stream; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; +import com.oracle.svm.core.imagelayer.BuildingInitialLayerPredicate; +import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader; +import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter; +import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; +import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerLoader; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerSingletonLoader; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerWriter; + +@Platforms(Platform.HOSTED_ONLY.class) +@AutomaticallyRegisteredImageSingleton(onlyWith = BuildingInitialLayerPredicate.class) +public class SharedLayerBootLayerModulesSingleton implements LayeredImageSingleton { + private final Collection sharedBootLayerModules; + private ModuleLayer bootLayer; + + public SharedLayerBootLayerModulesSingleton() { + this.sharedBootLayerModules = null; + } + + private SharedLayerBootLayerModulesSingleton(Collection baseBootLayerModules) { + this.sharedBootLayerModules = baseBootLayerModules; + } + + public static SharedLayerBootLayerModulesSingleton singleton() { + return ImageSingletons.lookup(SharedLayerBootLayerModulesSingleton.class); + } + + public void setBootLayer(ModuleLayer bootLayer) { + this.bootLayer = bootLayer; + } + + public Collection getSharedBootLayerModules() { + return sharedBootLayerModules; + } + + @Override + public EnumSet getImageBuilderFlags() { + return LayeredImageSingletonBuilderFlags.BUILDTIME_ACCESS_ONLY; + } + + @Override + public PersistFlags preparePersist(ImageSingletonWriter writer) { + SVMImageLayerWriter.ImageSingletonWriterImpl writerImpl = (SVMImageLayerWriter.ImageSingletonWriterImpl) writer; + Stream moduleNames = bootLayer.modules().stream().map(Module::getName); + + if (sharedBootLayerModules != null) { + moduleNames = Stream.concat(moduleNames, sharedBootLayerModules.stream()); + } + + SVMImageLayerWriter.initStringList(writerImpl.getSnapshotBuilder()::initSharedLayerBootLayerModules, moduleNames); + + return PersistFlags.CREATE; + } + + @SuppressWarnings("unused") + public static Object createFromLoader(ImageSingletonLoader loader) { + SVMImageLayerSingletonLoader.ImageSingletonLoaderImpl loaderImpl = (SVMImageLayerSingletonLoader.ImageSingletonLoaderImpl) loader; + List moduleNames = SVMImageLayerLoader.streamStrings(loaderImpl.getSnapshotReader().getSharedLayerBootLayerModules()).toList(); + return new SharedLayerBootLayerModulesSingleton(moduleNames); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SystemInOutErrFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SystemInOutErrFeature.java index 57b5510bf316..151c7d00f79d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SystemInOutErrFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SystemInOutErrFeature.java @@ -41,6 +41,7 @@ import com.oracle.svm.hosted.imagelayer.CrossLayerConstantRegistry; import jdk.internal.access.SharedSecrets; +import jdk.vm.ci.meta.JavaConstant; /** * We use an {@link Feature.DuringSetupAccess#registerObjectReplacer object replacer} because the @@ -96,7 +97,7 @@ public void duringSetup(DuringSetupAccess access) { access.registerObjectReplacer(this::replaceStreamsWithRuntimeObject); } else { var registry = CrossLayerConstantRegistry.singletonOrNull(); - ((FeatureImpl.DuringSetupAccessImpl) access).registerObjectToConstantReplacer(obj -> replaceStreamsWithLayerConstant(registry, obj)); + ((FeatureImpl.DuringSetupAccessImpl) access).registerObjectToConstantReplacer(obj -> (ImageHeapConstant) replaceStreamsWithLayerConstant(registry, obj)); } } @@ -121,7 +122,7 @@ Object replaceStreamsWithRuntimeObject(Object object) { } } - ImageHeapConstant replaceStreamsWithLayerConstant(CrossLayerConstantRegistry registry, Object object) { + JavaConstant replaceStreamsWithLayerConstant(CrossLayerConstantRegistry registry, Object object) { if (object == hostedIn) { return registry.getConstant(SYSTEM_IN_KEY_NAME); } else if (object == hostedOut) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/CrossLayerConstantRegistry.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/CrossLayerConstantRegistry.java index 856d14da9520..c4bbf08d8bb0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/CrossLayerConstantRegistry.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/CrossLayerConstantRegistry.java @@ -29,6 +29,8 @@ import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.meta.AnalysisType; +import jdk.vm.ci.meta.JavaConstant; + /** * Registry to manage cross-layer constant references. */ @@ -46,7 +48,7 @@ static CrossLayerConstantRegistry singletonOrNull() { * Retrieves the constant associated with {@code keyName}. If a constant does not exist then an * error is thrown. */ - ImageHeapConstant getConstant(String keyName); + JavaConstant getConstant(String keyName); /** * Checks whether a constant for {@code keyName} was registered in a prior layer. diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/CrossLayerConstantRegistryFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/CrossLayerConstantRegistryFeature.java index 8f08ab148761..8bd1441c6a32 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/CrossLayerConstantRegistryFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/CrossLayerConstantRegistryFeature.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.hosted.imagelayer; +import static com.oracle.svm.hosted.imagelayer.CrossLayerConstantRegistryFeature.INVALID; + import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; @@ -56,9 +58,12 @@ import jdk.graal.compiler.core.common.CompressEncoding; import jdk.graal.compiler.core.common.NumUtil; import jdk.graal.compiler.debug.Assertions; +import jdk.vm.ci.meta.JavaConstant; @AutomaticallyRegisteredFeature public class CrossLayerConstantRegistryFeature implements InternalFeature, FeatureSingleton, CrossLayerConstantRegistry { + static final int INVALID = -1; + private static final Object NULL_CONSTANT_MARKER = new Object(); private record FutureConstantCandidateInfo(ImageHeapRelocatableConstant constant) { } @@ -122,7 +127,7 @@ public void duringSetup(DuringSetupAccess access) { */ ImageHeapConstant replacePriorMarkersWithConstant(CrossLayerConstantRegistry registry, Object object) { if (object instanceof PriorLayerMarker priorLayerMarker) { - return registry.getConstant(priorLayerMarker.getKey()); + return (ImageHeapConstant) registry.getConstant(priorLayerMarker.getKey()); } return null; @@ -142,7 +147,7 @@ private void addInitialObjects(NativeImageHeap heap, HostedUniverse hUniverse) { * used by a prior layer. However, currently it is not worth introducing this * complication to the code. */ - ImageHeapConstant singletonConstant = (ImageHeapConstant) hUniverse.getSnippetReflection().forObject(futureConstant); + JavaConstant singletonConstant = futureConstant == NULL_CONSTANT_MARKER ? JavaConstant.NULL_POINTER : (ImageHeapConstant) hUniverse.getSnippetReflection().forObject(futureConstant); heap.addConstant(singletonConstant, false, addReason); } } @@ -159,7 +164,7 @@ public void afterCompilation(AfterCompilationAccess access) { FutureConstantCandidateInfo futureConstant = (FutureConstantCandidateInfo) entry.getValue(); var constant = futureConstant.constant(); AnalysisType type = constant.getType(); - tracker.registerFutureTrackingInfo(new FutureTrackingInfo(key, FutureTrackingInfo.State.Type, type.getId(), -1)); + tracker.registerFutureTrackingInfo(new FutureTrackingInfo(key, FutureTrackingInfo.State.Type, type.getId(), INVALID)); }); } @@ -194,11 +199,17 @@ public void beforeImageWrite(BeforeImageWriteAccess access) { */ for (var entry : finalizedFutureConstants.entrySet()) { // We know these constants have been installed via addInitialObjects - var futureConstant = (ImageHeapConstant) snippetReflection.forObject(entry.getValue()); - var objectInfo = heap.getConstantInfo(futureConstant); - int id = ImageHeapConstant.getConstantID(futureConstant); - FutureTrackingInfo info = (FutureTrackingInfo) tracker.getTrackingInfo(entry.getKey()); - tracker.updateFutureTrackingInfo(new FutureTrackingInfo(info.key(), FutureTrackingInfo.State.Final, id, NumUtil.safeToInt(objectInfo.getOffset()))); + Object value = entry.getValue(); + if (value == NULL_CONSTANT_MARKER) { + FutureTrackingInfo info = (FutureTrackingInfo) tracker.getTrackingInfo(entry.getKey()); + tracker.updateFutureTrackingInfo(new FutureTrackingInfo(info.key(), FutureTrackingInfo.State.Final, INVALID, INVALID)); + } else { + var futureConstant = (ImageHeapConstant) snippetReflection.forObject(value); + var objectInfo = heap.getConstantInfo(futureConstant); + int id = ImageHeapConstant.getConstantID(futureConstant); + FutureTrackingInfo info = (FutureTrackingInfo) tracker.getTrackingInfo(entry.getKey()); + tracker.updateFutureTrackingInfo(new FutureTrackingInfo(info.key(), FutureTrackingInfo.State.Final, id, NumUtil.safeToInt(objectInfo.getOffset()))); + } } if (ImageLayerBuildingSupport.buildingApplicationLayer()) { @@ -241,7 +252,8 @@ private void generateRelocationPatchArray() { FutureTrackingInfo info = (FutureTrackingInfo) tracker.getTrackingInfo(entry.getKey()); VMError.guarantee(info.state() == FutureTrackingInfo.State.Final, "Invalid future %s", info); - int referenceEncoding = info.offset() >>> shift; + int offset = info.offset(); + int referenceEncoding = offset == INVALID ? 0 : offset >>> shift; for (int heapOffset : offsetsToPatch) { patchArray.add(heapOffset - heapBeginOffset); patchArray.add(referenceEncoding); @@ -271,7 +283,7 @@ public boolean constantExists(String keyName) { } @Override - public ImageHeapConstant getConstant(String keyName) { + public JavaConstant getConstant(String keyName) { TrackingInfo idInfo = tracker.getTrackingInfo(keyName); if (idInfo instanceof PriorTrackingInfo prior) { return loader.getOrCreateConstant(prior.constantId()); @@ -287,6 +299,10 @@ public ImageHeapConstant getConstant(String keyName) { if (idInfo instanceof FutureTrackingInfo future) { VMError.guarantee(!finalizedFutureConstants.containsKey(keyName), "Future was finalized in this layer: %s", future); + if (future.loaderId() == INVALID) { + return JavaConstant.NULL_POINTER; + } + if (future.state() != FutureTrackingInfo.State.Type) { return loader.getOrCreateConstant(future.loaderId()); } @@ -339,7 +355,8 @@ public void finalizeFutureHeapConstant(String keyName, Object obj) { checkCandidateRegistry(); VMError.guarantee(tracker.getTrackingInfo(keyName) instanceof FutureTrackingInfo, "This key was not registered as a future constant %s", keyName); - var previous = finalizedFutureConstants.putIfAbsent(keyName, obj); + Object object = obj == null ? NULL_CONSTANT_MARKER : obj; + var previous = finalizedFutureConstants.putIfAbsent(keyName, object); VMError.guarantee(previous == null, "This key has been registered before: %s", keyName); } @@ -351,7 +368,7 @@ public void markFutureHeapConstantPatchSite(ImageHeapRelocatableConstant constan VMError.guarantee(!patchingSealed, "Cross layer patching is sealed"); var data = constant.getConstantData(); tracker.registerPatchSite(data.key, heapOffset); - tracker.updateFutureTrackingInfo(new FutureTrackingInfo(data.key, FutureTrackingInfo.State.Relocatable, ImageHeapConstant.getConstantID(constant), -1)); + tracker.updateFutureTrackingInfo(new FutureTrackingInfo(data.key, FutureTrackingInfo.State.Relocatable, ImageHeapConstant.getConstantID(constant), INVALID)); } /** @@ -506,7 +523,7 @@ public static Object createFromLoader(ImageSingletonLoader loader) { String key = futureKeys.next(); FutureTrackingInfo.State state = FutureTrackingInfo.State.values()[futureStates.next()]; int loaderId = futureLoaderIds.next(); - int offset = state == FutureTrackingInfo.State.Final ? futureOffsets.next() : -1; + int offset = state == FutureTrackingInfo.State.Final ? futureOffsets.next() : INVALID; tracker.registerFutureTrackingInfo(new FutureTrackingInfo(key, state, loaderId, offset)); List offsetsToPatch = loader.readIntList(futureKeyPatchKey(key)); @@ -531,14 +548,14 @@ enum State { } public FutureTrackingInfo { - assert key != null && loaderId >= 0 : Assertions.errorMessage(key, loaderId); + assert key != null && loaderId >= INVALID : Assertions.errorMessage(key, loaderId); switch (state) { case Type: case Relocatable: - assert offset == -1 : Assertions.errorMessage(state, offset); + assert offset == INVALID : Assertions.errorMessage(state, offset); break; case Final: - assert offset > 0 : Assertions.errorMessage(state, offset); + assert offset > 0 || (offset == INVALID && loaderId == INVALID) : Assertions.errorMessage(state, offset); } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java index 176f8b4bcbf7..951cd06b53b2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java @@ -32,8 +32,6 @@ import java.util.ArrayList; import java.util.List; -import com.oracle.svm.shaded.org.capnproto.ReaderOptions; -import com.oracle.svm.shaded.org.capnproto.Serialize; import org.graalvm.collections.EconomicMap; import org.graalvm.nativeimage.ImageSingletons; @@ -55,6 +53,8 @@ import com.oracle.svm.hosted.c.NativeLibraries; import com.oracle.svm.hosted.driver.IncludeOptionsSupport; import com.oracle.svm.hosted.driver.LayerOptionsSupport.LayerOption; +import com.oracle.svm.shaded.org.capnproto.ReaderOptions; +import com.oracle.svm.shaded.org.capnproto.Serialize; import com.oracle.svm.util.TypeResult; import jdk.graal.compiler.core.common.SuppressFBWarnings; @@ -189,6 +189,12 @@ public static void processLayerOptions(EconomicMap, Object> values, } SubstrateOptions.UseContainerSupport.update(values, false); enableConservativeUnsafeAccess(values); + /* + * Module needs to be initialized in the application layer because of ALL_UNNAMED_MODULE + * and EVERYONE_MODULE. This allows to have a consistent hash code for those modules at + * run time and build time. + */ + SubstrateOptions.ApplicationLayerInitializedClasses.update(values, Module.class.getName()); } if (isLayerUseOptionEnabled(hostedOptions)) { @@ -198,6 +204,7 @@ public static void processLayerOptions(EconomicMap, Object> values, SubstrateOptions.imageLayerEnabledHandler.onOptionEnabled(values); } enableConservativeUnsafeAccess(values); + SubstrateOptions.ApplicationLayerInitializedClasses.update(values, Module.class.getName()); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java index d2891970b944..dc725088d0cc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java @@ -4604,7 +4604,7 @@ public final com.oracle.svm.shaded.org.capnproto.StructList.Reader { public Factory() { } @@ -4840,6 +4840,27 @@ public final void setNodeClassMapLocation(String value) { public final com.oracle.svm.shaded.org.capnproto.Text.Builder initNodeClassMapLocation(int size) { return _initPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 12, size); } + public final boolean hasSharedLayerBootLayerModules() { + return !_pointerFieldIsNull(13); + } + public final com.oracle.svm.shaded.org.capnproto.TextList.Builder getSharedLayerBootLayerModules() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.TextList.factory, 13, null, 0); + } + public final void setSharedLayerBootLayerModules(com.oracle.svm.shaded.org.capnproto.TextList.Reader value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.TextList.factory, 13, value); + } + public final com.oracle.svm.shaded.org.capnproto.TextList.Builder initSharedLayerBootLayerModules(int size) { + return _initPointerField(com.oracle.svm.shaded.org.capnproto.TextList.factory, 13, size); + } + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.LayeredModule.Builder getLayeredModule() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.LayeredModule.factory, 14, null, 0); + } + public final void setLayeredModule(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.LayeredModule.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.LayeredModule.factory,14, value); + } + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.LayeredModule.Builder initLayeredModule() { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.LayeredModule.factory,14, 0); + } } public static final class Reader extends com.oracle.svm.shaded.org.capnproto.StructReader { @@ -4970,6 +4991,20 @@ public com.oracle.svm.shaded.org.capnproto.Text.Reader getNodeClassMapLocation() return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 12, null, 0, 0); } + public final boolean hasSharedLayerBootLayerModules() { + return !_pointerFieldIsNull(13); + } + public final com.oracle.svm.shaded.org.capnproto.TextList.Reader getSharedLayerBootLayerModules() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.TextList.factory, 13, null, 0); + } + + public boolean hasLayeredModule() { + return !_pointerFieldIsNull(14); + } + public com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.LayeredModule.Reader getLayeredModule() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.LayeredModule.factory,14,null, 0); + } + } } @@ -5188,6 +5223,246 @@ public final com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.Reader getFie } + public static class LayeredModule { + public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)0,(short)2); + public static final class Factory extends com.oracle.svm.shaded.org.capnproto.StructFactory { + public Factory() { + } + public final Reader constructReader(com.oracle.svm.shaded.org.capnproto.SegmentReader segment, int data,int pointers, int dataSize, short pointerCount, int nestingLimit) { + return new Reader(segment,data,pointers,dataSize,pointerCount,nestingLimit); + } + public final Builder constructBuilder(com.oracle.svm.shaded.org.capnproto.SegmentBuilder segment, int data,int pointers, int dataSize, short pointerCount) { + return new Builder(segment, data, pointers, dataSize, pointerCount); + } + public final com.oracle.svm.shaded.org.capnproto.StructSize structSize() { + return LayeredModule.STRUCT_SIZE; + } + public final Reader asReader(Builder builder) { + return builder.asReader(); + } + } + public static final Factory factory = new Factory(); + public static final com.oracle.svm.shaded.org.capnproto.StructList.Factory listFactory = + new com.oracle.svm.shaded.org.capnproto.StructList.Factory(factory); + public static final class Builder extends com.oracle.svm.shaded.org.capnproto.StructBuilder { + Builder(com.oracle.svm.shaded.org.capnproto.SegmentBuilder segment, int data, int pointers,int dataSize, short pointerCount){ + super(segment, data, pointers, dataSize, pointerCount); + } + public final Reader asReader() { + return new Reader(segment, data, pointers, dataSize, pointerCount, 0x7fffffff); + } + public final boolean hasOpenModulePackages() { + return !_pointerFieldIsNull(0); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Builder getOpenModulePackages() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ModulePackages.listFactory, 0, null, 0); + } + public final void setOpenModulePackages(com.oracle.svm.shaded.org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ModulePackages.listFactory, 0, value); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Builder initOpenModulePackages(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ModulePackages.listFactory, 0, size); + } + public final boolean hasExportedModulePackages() { + return !_pointerFieldIsNull(1); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Builder getExportedModulePackages() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ModulePackages.listFactory, 1, null, 0); + } + public final void setExportedModulePackages(com.oracle.svm.shaded.org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ModulePackages.listFactory, 1, value); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Builder initExportedModulePackages(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ModulePackages.listFactory, 1, size); + } + } + + public static final class Reader extends com.oracle.svm.shaded.org.capnproto.StructReader { + Reader(com.oracle.svm.shaded.org.capnproto.SegmentReader segment, int data, int pointers,int dataSize, short pointerCount, int nestingLimit){ + super(segment, data, pointers, dataSize, pointerCount, nestingLimit); + } + + public final boolean hasOpenModulePackages() { + return !_pointerFieldIsNull(0); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Reader getOpenModulePackages() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ModulePackages.listFactory, 0, null, 0); + } + + public final boolean hasExportedModulePackages() { + return !_pointerFieldIsNull(1); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Reader getExportedModulePackages() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ModulePackages.listFactory, 1, null, 0); + } + + } + + } + + + public static class ModulePackages { + public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)0,(short)2); + public static final class Factory extends com.oracle.svm.shaded.org.capnproto.StructFactory { + public Factory() { + } + public final Reader constructReader(com.oracle.svm.shaded.org.capnproto.SegmentReader segment, int data,int pointers, int dataSize, short pointerCount, int nestingLimit) { + return new Reader(segment,data,pointers,dataSize,pointerCount,nestingLimit); + } + public final Builder constructBuilder(com.oracle.svm.shaded.org.capnproto.SegmentBuilder segment, int data,int pointers, int dataSize, short pointerCount) { + return new Builder(segment, data, pointers, dataSize, pointerCount); + } + public final com.oracle.svm.shaded.org.capnproto.StructSize structSize() { + return ModulePackages.STRUCT_SIZE; + } + public final Reader asReader(Builder builder) { + return builder.asReader(); + } + } + public static final Factory factory = new Factory(); + public static final com.oracle.svm.shaded.org.capnproto.StructList.Factory listFactory = + new com.oracle.svm.shaded.org.capnproto.StructList.Factory(factory); + public static final class Builder extends com.oracle.svm.shaded.org.capnproto.StructBuilder { + Builder(com.oracle.svm.shaded.org.capnproto.SegmentBuilder segment, int data, int pointers,int dataSize, short pointerCount){ + super(segment, data, pointers, dataSize, pointerCount); + } + public final Reader asReader() { + return new Reader(segment, data, pointers, dataSize, pointerCount, 0x7fffffff); + } + public final boolean hasModuleKey() { + return !_pointerFieldIsNull(0); + } + public final com.oracle.svm.shaded.org.capnproto.Text.Builder getModuleKey() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, null, 0, 0); + } + public final void setModuleKey(com.oracle.svm.shaded.org.capnproto.Text.Reader value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, value); + } + public final void setModuleKey(String value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, new com.oracle.svm.shaded.org.capnproto.Text.Reader(value)); + } + public final com.oracle.svm.shaded.org.capnproto.Text.Builder initModuleKey(int size) { + return _initPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, size); + } + public final boolean hasPackages() { + return !_pointerFieldIsNull(1); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Builder getPackages() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Packages.listFactory, 1, null, 0); + } + public final void setPackages(com.oracle.svm.shaded.org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Packages.listFactory, 1, value); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Builder initPackages(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Packages.listFactory, 1, size); + } + } + + public static final class Reader extends com.oracle.svm.shaded.org.capnproto.StructReader { + Reader(com.oracle.svm.shaded.org.capnproto.SegmentReader segment, int data, int pointers,int dataSize, short pointerCount, int nestingLimit){ + super(segment, data, pointers, dataSize, pointerCount, nestingLimit); + } + + public boolean hasModuleKey() { + return !_pointerFieldIsNull(0); + } + public com.oracle.svm.shaded.org.capnproto.Text.Reader getModuleKey() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, null, 0, 0); + } + + public final boolean hasPackages() { + return !_pointerFieldIsNull(1); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Reader getPackages() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Packages.listFactory, 1, null, 0); + } + + } + + } + + + public static class Packages { + public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)0,(short)2); + public static final class Factory extends com.oracle.svm.shaded.org.capnproto.StructFactory { + public Factory() { + } + public final Reader constructReader(com.oracle.svm.shaded.org.capnproto.SegmentReader segment, int data,int pointers, int dataSize, short pointerCount, int nestingLimit) { + return new Reader(segment,data,pointers,dataSize,pointerCount,nestingLimit); + } + public final Builder constructBuilder(com.oracle.svm.shaded.org.capnproto.SegmentBuilder segment, int data,int pointers, int dataSize, short pointerCount) { + return new Builder(segment, data, pointers, dataSize, pointerCount); + } + public final com.oracle.svm.shaded.org.capnproto.StructSize structSize() { + return Packages.STRUCT_SIZE; + } + public final Reader asReader(Builder builder) { + return builder.asReader(); + } + } + public static final Factory factory = new Factory(); + public static final com.oracle.svm.shaded.org.capnproto.StructList.Factory listFactory = + new com.oracle.svm.shaded.org.capnproto.StructList.Factory(factory); + public static final class Builder extends com.oracle.svm.shaded.org.capnproto.StructBuilder { + Builder(com.oracle.svm.shaded.org.capnproto.SegmentBuilder segment, int data, int pointers,int dataSize, short pointerCount){ + super(segment, data, pointers, dataSize, pointerCount); + } + public final Reader asReader() { + return new Reader(segment, data, pointers, dataSize, pointerCount, 0x7fffffff); + } + public final boolean hasPackageKey() { + return !_pointerFieldIsNull(0); + } + public final com.oracle.svm.shaded.org.capnproto.Text.Builder getPackageKey() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, null, 0, 0); + } + public final void setPackageKey(com.oracle.svm.shaded.org.capnproto.Text.Reader value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, value); + } + public final void setPackageKey(String value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, new com.oracle.svm.shaded.org.capnproto.Text.Reader(value)); + } + public final com.oracle.svm.shaded.org.capnproto.Text.Builder initPackageKey(int size) { + return _initPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, size); + } + public final boolean hasModules() { + return !_pointerFieldIsNull(1); + } + public final com.oracle.svm.shaded.org.capnproto.TextList.Builder getModules() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.TextList.factory, 1, null, 0); + } + public final void setModules(com.oracle.svm.shaded.org.capnproto.TextList.Reader value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.TextList.factory, 1, value); + } + public final com.oracle.svm.shaded.org.capnproto.TextList.Builder initModules(int size) { + return _initPointerField(com.oracle.svm.shaded.org.capnproto.TextList.factory, 1, size); + } + } + + public static final class Reader extends com.oracle.svm.shaded.org.capnproto.StructReader { + Reader(com.oracle.svm.shaded.org.capnproto.SegmentReader segment, int data, int pointers,int dataSize, short pointerCount, int nestingLimit){ + super(segment, data, pointers, dataSize, pointerCount, nestingLimit); + } + + public boolean hasPackageKey() { + return !_pointerFieldIsNull(0); + } + public com.oracle.svm.shaded.org.capnproto.Text.Reader getPackageKey() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, null, 0, 0); + } + + public final boolean hasModules() { + return !_pointerFieldIsNull(1); + } + public final com.oracle.svm.shaded.org.capnproto.TextList.Reader getModules() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.TextList.factory, 1, null, 0); + } + + } + + } + + public static class PrimitiveValue { public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)2,(short)0); public static final class Factory extends com.oracle.svm.shaded.org.capnproto.StructFactory { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/ForkJoinPoolFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/ForkJoinPoolFeature.java index dc30c7344f99..70cf837c6afd 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/ForkJoinPoolFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/ForkJoinPoolFeature.java @@ -35,6 +35,8 @@ import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.imagelayer.CrossLayerConstantRegistry; +import jdk.vm.ci.meta.JavaConstant; + @AutomaticallyRegisteredFeature class ForkJoinPoolFeature implements InternalFeature, FeatureSingleton { @@ -44,7 +46,7 @@ class ForkJoinPoolFeature implements InternalFeature, FeatureSingleton { public void duringSetup(DuringSetupAccess access) { CrossLayerConstantRegistry registry = CrossLayerConstantRegistry.singletonOrNull(); if (ImageLayerBuildingSupport.buildingExtensionLayer() && registry.constantExists(KEY_NAME)) { - ((FeatureImpl.DuringSetupAccessImpl) access).registerObjectToConstantReplacer(obj -> replaceCommonPoolWithLayerConstant(registry, obj)); + ((FeatureImpl.DuringSetupAccessImpl) access).registerObjectToConstantReplacer(obj -> (ImageHeapConstant) replaceCommonPoolWithLayerConstant(registry, obj)); } else { var commonPool = new DeferredCommonPool(); access.registerObjectReplacer(obj -> replaceCommonPoolWithRuntimeObject(obj, commonPool)); @@ -62,7 +64,7 @@ private static Object replaceCommonPoolWithRuntimeObject(Object original, Deferr return original; } - private static ImageHeapConstant replaceCommonPoolWithLayerConstant(CrossLayerConstantRegistry registry, Object original) { + private static JavaConstant replaceCommonPoolWithLayerConstant(CrossLayerConstantRegistry registry, Object original) { if (original == ForkJoinPool.commonPool()) { return registry.getConstant(KEY_NAME); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/HostedClassLoaderPackageManagement.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/HostedClassLoaderPackageManagement.java index a378f2efd97e..d99914c34d1a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/HostedClassLoaderPackageManagement.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/HostedClassLoaderPackageManagement.java @@ -236,7 +236,7 @@ public ImageHeapConstant replaceWithPriorLayerPackage(Object obj) { var keyName = generateKeyName(hostedPackage.getName()); if (registry.constantExists(keyName)) { - return registry.getConstant(keyName); + return (ImageHeapConstant) registry.getConstant(keyName); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/proxy/ProxyRenamingSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/proxy/ProxyRenamingSubstitutionProcessor.java index 91726a101414..d2662a1ad0c5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/proxy/ProxyRenamingSubstitutionProcessor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/proxy/ProxyRenamingSubstitutionProcessor.java @@ -67,7 +67,7 @@ public static boolean isProxyType(ResolvedJavaType type) { * The code creating the name of dynamic modules can be found in * Proxy$ProxyBuilder.getDynamicModule. */ - private static boolean isModuleDynamic(Module module) { + public static boolean isModuleDynamic(Module module) { return module != null && module.getName() != null && module.getName().matches(DYNAMIC_MODULE_REGEX); }