Skip to content

Commit

Permalink
[GR-55552] Layered Micronaut Hello World
Browse files Browse the repository at this point in the history
PullRequest: graal/18329
  • Loading branch information
Zeavee committed Oct 29, 2024
2 parents 8a88c44 + ffa764a commit 4e691ab
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.ARGUMENT_IDS_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.ARRAY_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CAN_BE_STATICALLY_BOUND_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CLASS_INIT_NAME;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CLASS_JAVA_NAME_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CLASS_NAME_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CODE_SIZE_TAG;
Expand Down Expand Up @@ -700,6 +701,8 @@ private void loadMethod(EconomicMap<String, Object> methodData) {

if (name.equals(CONSTRUCTOR_NAME)) {
type.findConstructor(signature);
} else if (name.equals(CLASS_INIT_NAME)) {
type.getClassInitializer();
} else {
type.findMethod(name, signature);
}
Expand Down Expand Up @@ -905,7 +908,13 @@ private void loadField(FieldIdentifier fieldIdentifier, EconomicMap<String, Obje
clazz = declaringClass.getJavaClass();
}

Field field = ReflectionUtil.lookupField(true, clazz, fieldIdentifier.name);
Field field;
try {
field = ReflectionUtil.lookupField(true, clazz, fieldIdentifier.name);
} catch (Throwable e) {
field = null;
}

if (field == null) {
AnalysisType type = getAnalysisType(get(fieldData, FIELD_TYPE_TAG));
BaseLayerField baseLayerField = new BaseLayerField(get(fieldData, ID_TAG), fieldIdentifier.name, declaringClass, type, get(fieldData, IS_INTERNAL_TAG), get(fieldData, MODIFIERS_TAG),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public class ImageLayerSnapshotUtil {
public static final String FILE_EXTENSION = ".json";

public static final String CONSTRUCTOR_NAME = "<init>";
public static final String CLASS_INIT_NAME = "<clinit>";

public static final String PERSISTED = "persisted";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Boolean o
@BundleMember(role = Role.Input) //
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Paths> LayerUse = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Paths.build());

@Option(help = "Mark singleton as application layer only")//
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> ApplicationLayerOnlySingletons = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build());

@APIOption(name = "libc")//
@Option(help = "Selects the libc implementation to use. Available implementations: glibc, musl, bionic")//
public static final HostedOptionKey<String> UseLibC = new HostedOptionKey<>(null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,36 @@
*/
package com.oracle.svm.core.layeredimagesingleton;

import org.graalvm.nativeimage.ImageSingletons;

import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.option.HostedOptionValues;

/**
* Identifies a singleton for which all lookups refer to a single singleton which will be created in
* the application layer. See {@link LayeredImageSingleton} for full explanation.
*/
public interface ApplicationLayerOnlyImageSingleton extends LayeredImageSingleton {

static boolean isSingletonInstanceOf(Object singleton) {
if (singleton instanceof ApplicationLayerOnlyImageSingleton) {
return true;
}
if (ImageSingletons.contains(HostedOptionValues.class)) {
return SubstrateOptions.ApplicationLayerOnlySingletons.getValue().contains(singleton.getClass().getName());
}

return false;
}

static boolean isAssignableFrom(Class<?> klass) {
if (ApplicationLayerOnlyImageSingleton.class.isAssignableFrom(klass)) {
return true;
}
if (ImageSingletons.contains(HostedOptionValues.class)) {
return SubstrateOptions.ApplicationLayerOnlySingletons.getValue().contains(klass.getName());
}

return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,13 @@ public static boolean verifyImageBuilderFlags(LayeredImageSingleton singleton) {
assert flags.equals(EnumSet.of(UNSUPPORTED)) : "Unsupported should be the only flag set " + flags;
}

if (singleton instanceof MultiLayeredImageSingleton || singleton instanceof ApplicationLayerOnlyImageSingleton) {
if (singleton instanceof MultiLayeredImageSingleton || ApplicationLayerOnlyImageSingleton.isSingletonInstanceOf(singleton)) {
assert flags.contains(RUNTIME_ACCESS) : String.format("%s must be set when implementing either %s or %s: %s", RUNTIME_ACCESS, MultiLayeredImageSingleton.class,
ApplicationLayerOnlyImageSingleton.class, singleton);
}

assert !(singleton instanceof MultiLayeredImageSingleton && singleton instanceof ApplicationLayerOnlyImageSingleton) : String.format("%s can only implement one of %s or %s", singleton,
assert !(singleton instanceof MultiLayeredImageSingleton && ApplicationLayerOnlyImageSingleton.isSingletonInstanceOf(singleton)) : String.format("%s can only implement one of %s or %s",
singleton,
MultiLayeredImageSingleton.class, ApplicationLayerOnlyImageSingleton.class);

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,17 +210,17 @@ private void doAddInternal(Class<?> key, Object value) {
throw UserError.abort("Unsupported image singleton is being installed %s %s", key.getTypeName(), singleton);
}

if (singleton instanceof MultiLayeredImageSingleton || singleton instanceof ApplicationLayerOnlyImageSingleton) {
if (singleton instanceof MultiLayeredImageSingleton || ApplicationLayerOnlyImageSingleton.isSingletonInstanceOf(singleton)) {

if (!key.equals(singleton.getClass())) {
throw UserError.abort("The implementation class must be the same as the key class. key: %s, singleton: %s", key, singleton);
}

if (singleton instanceof MultiLayeredImageSingleton && singleton instanceof ApplicationLayerOnlyImageSingleton) {
if (singleton instanceof MultiLayeredImageSingleton && ApplicationLayerOnlyImageSingleton.isSingletonInstanceOf(singleton)) {
throw UserError.abort("Singleton cannot implement both %s and %s. singleton: %s", MultiLayeredImageSingleton.class, ApplicationLayerOnlyImageSingleton.class, singleton);
}

if (singleton instanceof ApplicationLayerOnlyImageSingleton && !ImageLayerBuildingSupport.lastImageBuild()) {
if (ApplicationLayerOnlyImageSingleton.isSingletonInstanceOf(singleton) && !ImageLayerBuildingSupport.lastImageBuild()) {
throw UserError.abort("Application layer only image singleton can only be installed in the final layer: %s", singleton);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@
import com.oracle.svm.hosted.image.NativeImageCodeCacheFactory;
import com.oracle.svm.hosted.image.NativeImageHeap;
import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport;
import com.oracle.svm.hosted.imagelayer.LoadImageSingletonFeature;
import com.oracle.svm.hosted.jdk.localization.LocalizationFeature;
import com.oracle.svm.hosted.meta.HostedConstantReflectionProvider;
import com.oracle.svm.hosted.meta.HostedField;
Expand Down Expand Up @@ -826,6 +827,9 @@ protected boolean runPointsToAnalysis(String imageName, OptionValues options, De
featureHandler.forEachFeature(feature -> feature.beforeAnalysis(config));
ServiceCatalogSupport.singleton().seal();
bb.getHostVM().getClassInitializationSupport().setConfigurationSealed(true);
if (ImageLayerBuildingSupport.buildingImageLayer()) {
ImageSingletons.lookup(LoadImageSingletonFeature.class).processRegisteredSingletons(aUniverse);
}
}

try (ReporterClosable c = ProgressReporter.singleton().printAnalysis(bb.getUniverse(), nativeLibraries.getLibraries())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
import com.oracle.svm.hosted.config.ConfigurationParserUtils;
import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport;
import com.oracle.svm.hosted.jdk.localization.LocalizationFeature;
import com.oracle.svm.hosted.reflect.NativeImageConditionResolver;
import com.oracle.svm.hosted.snippets.SubstrateGraphBuilderPlugins;
Expand Down Expand Up @@ -393,9 +394,10 @@ protected boolean collectEmbeddedResourcesInfo() {
}

@Override
public void beforeAnalysis(BeforeAnalysisAccess access) {
public void beforeAnalysis(BeforeAnalysisAccess a) {
FeatureImpl.BeforeAnalysisAccessImpl access = (FeatureImpl.BeforeAnalysisAccessImpl) a;
/* load and parse resource configuration files */
ConfigurationConditionResolver<ConfigurationCondition> conditionResolver = new NativeImageConditionResolver(((FeatureImpl.BeforeAnalysisAccessImpl) access).getImageClassLoader(),
ConfigurationConditionResolver<ConfigurationCondition> conditionResolver = new NativeImageConditionResolver(access.getImageClassLoader(),
ClassInitializationSupport.singleton());

ResourceConfigurationParser<ConfigurationCondition> parser = ResourceConfigurationParser.create(true, conditionResolver, ResourcesRegistry.singleton(),
Expand All @@ -415,6 +417,21 @@ public void beforeAnalysis(BeforeAnalysisAccess access) {
GlobTrieNode<ConditionWithOrigin> trie = CompressedGlobTrie.CompressedGlobTrieBuilder.build(patternsWithInfo);
Resources.singleton().setResourcesTrieRoot(trie);

/*
* GR-58701: The SVM core is currently not included in the base layer of a Layered Image.
* Those specific types can be reachable from Resources#resourcesTrieRoot, but they can be
* missed by the analysis because the GlobTrieNode#children field is only available after
* analysis and the only reference to those types is with ThrowMissingRegistrationErrors
* enabled. Until a clear SVM core separation is created and included in the base layer,
* those types should be manually registered as instantiated before the analysis.
*/
if (HostedImageLayerBuildingSupport.buildingSharedLayer()) {
String reason = "Included in the base image";
access.getMetaAccess().lookupJavaType(ReflectionUtil.lookupClass(false, "com.oracle.svm.core.jdk.resources.CompressedGlobTrie.LiteralNode")).registerAsInstantiated(reason);
access.getMetaAccess().lookupJavaType(ReflectionUtil.lookupClass(false, "com.oracle.svm.core.jdk.resources.CompressedGlobTrie.DoubleStarNode")).registerAsInstantiated(reason);
access.getMetaAccess().lookupJavaType(ReflectionUtil.lookupClass(false, "com.oracle.svm.core.jdk.resources.CompressedGlobTrie.StarTrieNode")).registerAsInstantiated(reason);
}

/* prepare regex patterns for resource registration */
resourcePatternWorkSet.addAll(Options.IncludeResources.getValue()
.getValuesWithOrigins()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@

import com.oracle.graal.pointsto.heap.ImageHeapConstant;
import com.oracle.graal.pointsto.heap.ImageHeapObjectArray;
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
import com.oracle.graal.pointsto.meta.AnalysisType;
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
import com.oracle.svm.core.ParsingReason;
import com.oracle.svm.core.c.CGlobalData;
import com.oracle.svm.core.c.CGlobalDataFactory;
Expand Down Expand Up @@ -148,18 +150,26 @@ public void duringSetup(DuringSetupAccess access) {
LayeredImageHeapObjectAdder.singleton().registerObjectAdder(this::addInitialObjects);
}

@Override
public void beforeAnalysis(BeforeAnalysisAccess access) {
var config = (FeatureImpl.BeforeAnalysisAccessImpl) access;
loader = (SVMImageLayerLoader) config.getUniverse().getImageLayerLoader();
/**
* This method needs to be called after all image singletons are registered. Currently, some
* singletons are registered in
* {@link org.graalvm.nativeimage.hosted.Feature#beforeAnalysis(BeforeAnalysisAccess)}, but the
* singleton registration might get restricted to only
* {@link org.graalvm.nativeimage.hosted.Feature#duringSetup(DuringSetupAccess)} or before. In
* this case, this method should override
* {@link org.graalvm.nativeimage.hosted.Feature#beforeAnalysis(BeforeAnalysisAccess)}.
*/
public void processRegisteredSingletons(AnalysisUniverse universe) {
AnalysisMetaAccess metaAccess = universe.getBigbang().getMetaAccess();
loader = (SVMImageLayerLoader) universe.getImageLayerLoader();

LayeredImageSingletonSupport layeredImageSingletonSupport = LayeredImageSingletonSupport.singleton();
layeredImageSingletonSupport.freezeMultiLayeredImageSingletons();

Consumer<Object[]> multiLayerEmbeddedRootsRegistration = (objArray) -> {
var method = config.getMetaAccess().lookupJavaMethod(ReflectionUtil.lookupMethod(MultiLayeredImageSingleton.class, "getAllLayers", Class.class));
var javaConstant = config.getUniverse().getSnippetReflection().forObject(objArray);
config.getUniverse().registerEmbeddedRoot(javaConstant, new BytecodePosition(null, method, BytecodeFrame.UNKNOWN_BCI));
var method = metaAccess.lookupJavaMethod(ReflectionUtil.lookupMethod(MultiLayeredImageSingleton.class, "getAllLayers", Class.class));
var javaConstant = universe.getSnippetReflection().forObject(objArray);
universe.registerEmbeddedRoot(javaConstant, new BytecodePosition(null, method, BytecodeFrame.UNKNOWN_BCI));
};

if (ImageLayerBuildingSupport.buildingSharedLayer()) {
Expand Down Expand Up @@ -208,13 +218,13 @@ public void beforeAnalysis(BeforeAnalysisAccess access) {
* Within the application layer there will be an array created to hold all
* multi-layered image singletons. We must record this type is in the heap.
*/
config.registerAsInHeap(slotInfo.keyClass().arrayType());
metaAccess.lookupJavaType(slotInfo.keyClass().arrayType()).registerAsInstantiated("Array holding multi-layered image singletons");
if (!getCrossLayerSingletonMappingInfo().getPriorLayerObjectIDs(slotInfo.keyClass()).isEmpty()) {
/*
* We also must ensure the type is registered as instantiated in this
* heap if we know the array will refer to a prior object.
*/
config.registerAsInHeap(slotInfo.keyClass());
metaAccess.lookupJavaType(slotInfo.keyClass()).registerAsInstantiated("Refers to a prior singleton");
}
/*
* GR-55294: The constants have to be created before the end of the analysis
Expand All @@ -228,9 +238,9 @@ public void beforeAnalysis(BeforeAnalysisAccess access) {
}

if (!applicationLayerEmbeddedRoots.isEmpty()) {
var method = config.getMetaAccess().lookupJavaMethod(ReflectionUtil.lookupMethod(ImageSingletons.class, "lookup", Class.class));
var javaConstant = config.getUniverse().getSnippetReflection().forObject(applicationLayerEmbeddedRoots.toArray());
config.getUniverse().registerEmbeddedRoot(javaConstant, new BytecodePosition(null, method, BytecodeFrame.UNKNOWN_BCI));
var method = metaAccess.lookupJavaMethod(ReflectionUtil.lookupMethod(ImageSingletons.class, "lookup", Class.class));
var javaConstant = universe.getSnippetReflection().forObject(applicationLayerEmbeddedRoots.toArray());
universe.registerEmbeddedRoot(javaConstant, new BytecodePosition(null, method, BytecodeFrame.UNKNOWN_BCI));
}

if (!multiLayerEmbeddedRoots.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1131,7 +1131,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
Class<?> key = constantObjectParameter(b, targetMethod, 0, Class.class, classNode);
boolean result = ImageSingletons.contains(key);
if (!result && ImageLayerBuildingSupport.buildingImageLayer()) {
if (ApplicationLayerOnlyImageSingleton.class.isAssignableFrom(key) || MultiLayeredImageSingleton.class.isAssignableFrom(key)) {
if (ApplicationLayerOnlyImageSingleton.isAssignableFrom(key) || MultiLayeredImageSingleton.class.isAssignableFrom(key)) {
/*
* ApplicationLayerOnlyImageSingletons and the array representation of a
* MultiLayeredImageSingleton will only be created in the final layer.
Expand All @@ -1151,7 +1151,8 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode classNode) {
Class<?> key = constantObjectParameter(b, targetMethod, 0, Class.class, classNode);

if (ApplicationLayerOnlyImageSingleton.class.isAssignableFrom(key) && ImageLayerBuildingSupport.buildingSharedLayer()) {
if (ApplicationLayerOnlyImageSingleton.isAssignableFrom(key) &&
ImageLayerBuildingSupport.buildingSharedLayer()) {
/*
* This singleton is only installed in the application layer heap. All other
* layers looks refer to this singleton.
Expand Down

0 comments on commit 4e691ab

Please sign in to comment.