Skip to content

Commit 4c1366a

Browse files
committed
[GR-69085] Make IsolateArgumentParser layer aware.
PullRequest: graal/22083
2 parents 7d72d58 + 2270dce commit 4c1366a

File tree

9 files changed

+168
-16
lines changed

9 files changed

+168
-16
lines changed

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,10 @@ public boolean isDelayed() {
353353
return compilationBehavior == CompilationBehavior.FULLY_DELAYED_TO_APPLICATION_LAYER && buildingSharedLayer;
354354
}
355355

356+
/**
357+
* Ensures this method is compiled in the initial layer. See
358+
* {@link CompilationBehavior#PINNED_TO_INITIAL_LAYER} for more details.
359+
*/
356360
public void setPinnedToInitialLayer(Object reason) {
357361
BigBang bigbang = getUniverse().getBigbang();
358362
AnalysisError.guarantee(bigbang.getHostVM().buildingInitialLayer(), "Methods can only be pinned to the initial layer: %s", this);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java

Lines changed: 111 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
import java.nio.ByteBuffer;
3535
import java.nio.ByteOrder;
3636
import java.nio.charset.StandardCharsets;
37+
import java.util.Collections;
3738
import java.util.List;
39+
import java.util.Objects;
3840

3941
import org.graalvm.nativeimage.ImageSingletons;
4042
import org.graalvm.nativeimage.Platform;
@@ -53,12 +55,28 @@
5355
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
5456
import com.oracle.svm.core.graal.RuntimeCompilation;
5557
import com.oracle.svm.core.headers.LibC;
58+
import com.oracle.svm.core.imagelayer.BuildingImageLayerPredicate;
59+
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
60+
import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader;
61+
import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter;
62+
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton;
5663
import com.oracle.svm.core.memory.UntrackedNullableNativeMemory;
5764
import com.oracle.svm.core.option.RuntimeOptionKey;
65+
import com.oracle.svm.core.traits.BuiltinTraits.AllAccess;
66+
import com.oracle.svm.core.traits.BuiltinTraits.BuildtimeAccessOnly;
67+
import com.oracle.svm.core.traits.BuiltinTraits.SingleLayer;
68+
import com.oracle.svm.core.traits.SingletonLayeredCallbacks;
69+
import com.oracle.svm.core.traits.SingletonLayeredCallbacksSupplier;
70+
import com.oracle.svm.core.traits.SingletonLayeredInstallationKind.Independent;
71+
import com.oracle.svm.core.traits.SingletonLayeredInstallationKind.InitialLayerOnly;
72+
import com.oracle.svm.core.traits.SingletonTrait;
73+
import com.oracle.svm.core.traits.SingletonTraitKind;
74+
import com.oracle.svm.core.traits.SingletonTraits;
5875
import com.oracle.svm.core.util.ImageHeapList;
5976
import com.oracle.svm.core.util.VMError;
6077

6178
import jdk.graal.compiler.api.replacements.Fold;
79+
import jdk.graal.compiler.options.OptionKey;
6280
import jdk.graal.compiler.word.Word;
6381

6482
/**
@@ -69,6 +87,7 @@
6987
* stored in {@code argv} is used.
7088
*/
7189
@AutomaticallyRegisteredImageSingleton
90+
@SingletonTraits(access = AllAccess.class, layeredCallbacks = SingleLayer.class, layeredInstallationKind = InitialLayerOnly.class)
7291
public class IsolateArgumentParser {
7392
@SuppressWarnings("unchecked")//
7493
private final List<RuntimeOptionKey<?>> options = (List<RuntimeOptionKey<?>>) ImageHeapList.createGeneric(RuntimeOptionKey.class);
@@ -183,7 +202,11 @@ protected static List<RuntimeOptionKey<?>> getOptions() {
183202

184203
@Fold
185204
protected static int getOptionCount() {
186-
return getOptions().size();
205+
if (ImageLayerBuildingSupport.firstImageBuild()) {
206+
return getOptions().size();
207+
} else {
208+
return LayeredOptionInfo.singleton().getNumOptions();
209+
}
187210
}
188211

189212
@Uninterruptible(reason = "Still being initialized.")
@@ -559,10 +582,20 @@ private static CCharPointer startsWith(CCharPointer input, CCharPointer prefix)
559582

560583
@Fold
561584
public static int getOptionIndex(RuntimeOptionKey<?> key) {
562-
List<RuntimeOptionKey<?>> options = getOptions();
563-
for (int i = 0; i < options.size(); i++) {
564-
if (options.get(i) == key) {
565-
return i;
585+
if (ImageLayerBuildingSupport.firstImageBuild()) {
586+
List<RuntimeOptionKey<?>> options = getOptions();
587+
for (int i = 0; i < options.size(); i++) {
588+
if (options.get(i) == key) {
589+
return i;
590+
}
591+
}
592+
} else {
593+
var keyName = key.getName();
594+
var optionNames = LayeredOptionInfo.singleton().getOptionNames();
595+
for (int i = 0; i < optionNames.size(); i++) {
596+
if (optionNames.get(i).equals(keyName)) {
597+
return i;
598+
}
566599
}
567600
}
568601

@@ -599,4 +632,77 @@ public static boolean isNumeric(byte optionValueType) {
599632
return optionValueType == INTEGER || optionValueType == LONG;
600633
}
601634
}
635+
636+
/**
637+
* Within {@link IsolateArgumentParser} many methods need to be {@link Fold}ed. This class adds
638+
* support so that we can handle these method folds within the application layer.
639+
*/
640+
@Platforms(Platform.HOSTED_ONLY.class)
641+
@AutomaticallyRegisteredImageSingleton(onlyWith = BuildingImageLayerPredicate.class)
642+
@SingletonTraits(access = BuildtimeAccessOnly.class, layeredCallbacks = LayeredCallbacks.class, layeredInstallationKind = Independent.class)
643+
static class LayeredOptionInfo {
644+
private static final int UNSET = -1;
645+
final int numOptions;
646+
final List<String> optionNames;
647+
648+
LayeredOptionInfo() {
649+
this(UNSET, null);
650+
}
651+
652+
LayeredOptionInfo(int numOptions, List<String> optionNames) {
653+
this.numOptions = numOptions;
654+
this.optionNames = optionNames;
655+
}
656+
657+
static LayeredOptionInfo singleton() {
658+
return ImageSingletons.lookup(LayeredOptionInfo.class);
659+
}
660+
661+
int getNumOptions() {
662+
if (numOptions == UNSET) {
663+
throw VMError.shouldNotReachHere("numOptions is unset");
664+
}
665+
return numOptions;
666+
}
667+
668+
List<String> getOptionNames() {
669+
Objects.requireNonNull(optionNames);
670+
return optionNames;
671+
}
672+
}
673+
674+
static class LayeredCallbacks extends SingletonLayeredCallbacksSupplier {
675+
676+
@Override
677+
public SingletonTrait getLayeredCallbacksTrait() {
678+
return new SingletonTrait(SingletonTraitKind.LAYERED_CALLBACKS, new SingletonLayeredCallbacks() {
679+
@Override
680+
public LayeredImageSingleton.PersistFlags doPersist(ImageSingletonWriter writer, Object singleton) {
681+
if (ImageLayerBuildingSupport.firstImageBuild()) {
682+
writer.writeInt("numOptions", IsolateArgumentParser.getOptionCount());
683+
writer.writeStringList("optionNames", IsolateArgumentParser.getOptions().stream().map(OptionKey::getName).toList());
684+
} else {
685+
var metadata = (LayeredOptionInfo) singleton;
686+
writer.writeInt("numOptions", metadata.getNumOptions());
687+
writer.writeStringList("optionNames", metadata.optionNames);
688+
}
689+
return LayeredImageSingleton.PersistFlags.CREATE;
690+
}
691+
692+
@Override
693+
public Class<? extends SingletonLayeredCallbacks.LayeredSingletonInstantiator> getSingletonInstantiator() {
694+
return SingletonInstantiator.class;
695+
}
696+
});
697+
}
698+
}
699+
700+
static class SingletonInstantiator implements SingletonLayeredCallbacks.LayeredSingletonInstantiator {
701+
@Override
702+
public Object createFromLoader(ImageSingletonLoader loader) {
703+
int numOptions = loader.readInt("numOptions");
704+
var optionNames = Collections.unmodifiableList(loader.readStringList("optionNames"));
705+
return new LayeredOptionInfo(numOptions, optionNames);
706+
}
707+
}
602708
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@ public List<String> getInputArguments() {
161161
}
162162
}
163163

164+
/**
165+
* For layered images this method is delayed until the application layer. This is necessary so
166+
* that the method handle can be inlined before analysis.
167+
*/
164168
public static void invokeMain(String[] args) throws Throwable {
165169
String[] mainArgs = args;
166170
if (ImageSingletons.contains(PreMainSupport.class)) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspectionOptions.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,18 @@ public static boolean hasHeapDumpSupport() {
168168
return hasAllOrKeywordMonitoringSupport(MONITORING_HEAPDUMP_NAME) && !Platform.includedIn(WINDOWS_BASE.class);
169169
}
170170

171+
/**
172+
* This needs to be an explicit method so that in layered builds compilation can be deferred to
173+
* the app layer. Otherwise {@link SubstrateOptions#Name} will refer to the initial layer's
174+
* name.
175+
*/
176+
static String determineHeapDumpPath() {
177+
return HeapDumping.getHeapDumpPath(SubstrateOptions.Name.getValue() + ".hprof");
178+
}
179+
171180
public static boolean dumpImageHeap() {
172181
if (hasHeapDumpSupport()) {
173-
String absoluteHeapDumpPath = HeapDumping.getHeapDumpPath(SubstrateOptions.Name.getValue() + ".hprof");
182+
String absoluteHeapDumpPath = determineHeapDumpPath();
174183
try {
175184
HeapDumping.singleton().dumpHeap(absoluteHeapDumpPath, true);
176185
} catch (IOException e) {

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageSingletonsSupportImpl.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,9 @@ <T> T doLookup(Class<T> key, boolean buildtimeAccess, boolean allowMultiLayered)
617617

618618
VMError.guarantee(info.singleton() != null);
619619
Object singleton = info.singleton();
620+
if (singleton == SINGLETON_INSTALLATION_FORBIDDEN) {
621+
throw UserError.abort("Singleton is forbidden in current layer. Key: %s", key.getTypeName());
622+
}
620623
if (!allowMultiLayered) {
621624
var trait = info.traitMap().getTrait(SingletonTraitKind.LAYERED_INSTALLATION_KIND);
622625
trait.ifPresent(t -> {

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/HeapDumpFeature.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import com.oracle.svm.core.meta.SharedType;
6464
import com.oracle.svm.core.util.ByteArrayReader;
6565
import com.oracle.svm.core.util.VMError;
66+
import com.oracle.svm.hosted.FeatureImpl;
6667
import com.oracle.svm.hosted.FeatureImpl.AfterCompilationAccessImpl;
6768
import com.oracle.svm.util.ReflectionUtil;
6869

@@ -110,6 +111,10 @@ public void beforeAnalysis(BeforeAnalysisAccess access) {
110111
if (VMInspectionOptions.hasHeapDumpSupport()) {
111112
RuntimeSupport.getRuntimeSupport().addStartupHook(new HeapDumpStartupHook());
112113
RuntimeSupport.getRuntimeSupport().addShutdownHook(new HeapDumpShutdownHook());
114+
if (ImageLayerBuildingSupport.buildingImageLayer()) {
115+
var method = ReflectionUtil.lookupMethod(VMInspectionOptions.class, "determineHeapDumpPath");
116+
((FeatureImpl.BeforeAnalysisAccessImpl) access).getMetaAccess().lookupJavaMethod(method).setFullyDelayedToApplicationLayer();
117+
}
113118
}
114119
}
115120

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,6 @@ public static void processLayerOptions(EconomicMap<OptionKey<?>, Object> values,
245245

246246
if (isLayerUseOptionEnabled(hostedOptions)) {
247247
SubstrateOptions.ClosedTypeWorldHubLayout.update(values, false);
248-
SubstrateOptions.ParseRuntimeOptions.update(values, false);
249248
if (SubstrateOptions.imageLayerEnabledHandler != null) {
250249
SubstrateOptions.imageLayerEnabledHandler.onOptionEnabled(values);
251250
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/InitialLayerFeature.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
*/
2525
package com.oracle.svm.hosted.imagelayer;
2626

27-
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
27+
import org.graalvm.nativeimage.c.type.CCharPointerPointer;
2828
import org.graalvm.nativeimage.hosted.Feature;
2929

30+
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
31+
import com.oracle.svm.core.JavaMainWrapper;
3032
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
3133
import com.oracle.svm.core.feature.InternalFeature;
3234
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
@@ -59,6 +61,14 @@ public void beforeAnalysis(BeforeAnalysisAccess a) {
5961
metaAccess.lookupJavaMethod(ReflectionUtil.lookupMethod(Runtime.class, "getRuntime")).setPinnedToInitialLayer(pinReason);
6062
metaAccess.lookupJavaMethod(ReflectionUtil.lookupMethod(Runtime.class, "gc")).setPinnedToInitialLayer(pinReason);
6163
metaAccess.lookupJavaMethod(ReflectionUtil.lookupMethod(Class.class, "getResource", String.class)).setPinnedToInitialLayer(pinReason);
64+
65+
/* SVM start-up logic should be pinned to the initial layer. */
66+
metaAccess.lookupJavaMethod(ReflectionUtil.lookupMethod(JavaMainWrapper.class, "doRun", int.class, CCharPointerPointer.class)).setPinnedToInitialLayer(pinReason);
67+
/*
68+
* We want the method handle invocation present in this method to be inlined, and that is
69+
* only possible within the application layer.
70+
*/
71+
metaAccess.lookupJavaMethod(ReflectionUtil.lookupMethod(JavaMainWrapper.class, "invokeMain", String[].class)).setFullyDelayedToApplicationLayer();
6272
}
6373

6474
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/option/RuntimeOptionFeature.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.oracle.svm.core.IsolateArgumentParser;
3535
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
3636
import com.oracle.svm.core.feature.InternalFeature;
37+
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
3738
import com.oracle.svm.core.option.HostedOptionKey;
3839
import com.oracle.svm.core.option.HostedOptionValues;
3940
import com.oracle.svm.core.option.RuntimeOptionKey;
@@ -65,20 +66,31 @@ public void duringSetup(DuringSetupAccess a) {
6566
public void beforeAnalysis(BeforeAnalysisAccess access) {
6667
FeatureImpl.BeforeAnalysisAccessImpl accessImpl = (FeatureImpl.BeforeAnalysisAccessImpl) access;
6768

69+
boolean extensionLayer = ImageLayerBuildingSupport.buildingExtensionLayer();
6870
UnmodifiableEconomicMap<OptionKey<?>, Object> map = HostedOptionValues.singleton().getMap();
6971
for (OptionKey<?> key : map.getKeys()) {
7072
if (key instanceof RuntimeOptionKey<?> runtimeOptionKey && runtimeOptionKey.shouldRegisterForIsolateArgumentParser()) {
71-
/*
72-
* The list of options IsolateArgumentParser has to parse, is built dynamically, to
73-
* include only options of the current configuration. Here, all options that should
74-
* get parsed by the IsolateArgumentParser are added to this list.
75-
*/
76-
IsolateArgumentParser.singleton().register(runtimeOptionKey);
77-
registerOptionAsRead(accessImpl, runtimeOptionKey.getDescriptor().getDeclaringClass(), runtimeOptionKey.getName());
73+
if (!extensionLayer) {
74+
/*
75+
* The list of options IsolateArgumentParser has to parse, is built dynamically,
76+
* to include only options of the current configuration. Here, all options that
77+
* should get parsed by the IsolateArgumentParser are added to this list.
78+
*/
79+
IsolateArgumentParser.singleton().register(runtimeOptionKey);
80+
registerOptionAsRead(accessImpl, runtimeOptionKey.getDescriptor().getDeclaringClass(), runtimeOptionKey.getName());
81+
} else {
82+
/*
83+
* All runtime options must have already been installed within the base layer.
84+
* Within the extension layer we only confirm they are present.
85+
*/
86+
assert IsolateArgumentParser.getOptionIndex(runtimeOptionKey) >= 0;
87+
}
7888
}
7989
}
8090

81-
IsolateArgumentParser.singleton().sealOptions();
91+
if (!extensionLayer) {
92+
IsolateArgumentParser.singleton().sealOptions();
93+
}
8294
}
8395

8496
@SuppressWarnings("unused")

0 commit comments

Comments
 (0)