Skip to content

Commit 4e002c8

Browse files
committed
[GR-52265] Extend layered images support.
PullRequest: graal/17266
2 parents 8ac24ac + 59ab0fd commit 4e002c8

File tree

29 files changed

+538
-70
lines changed

29 files changed

+538
-70
lines changed

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,22 @@ protected void apply(boolean forceReparse, Object reason) {
620620
assert !processed : "can only call apply once per MethodTypeFlowBuilder";
621621
processed = true;
622622

623+
if (bb.getHostVM().useBaseLayer() && method.isInBaseLayer()) {
624+
/*
625+
* We don't need to analyze this method. We already know its return type state from the
626+
* open world analysis. We just install a return flow to link it with its uses.
627+
*/
628+
AnalysisType returnType = method.getSignature().getReturnType();
629+
if (returnType.getJavaKind().isObject()) {
630+
// GR-52421: the return type state should not be all-instantiated, it should be the
631+
// persisted result of the open-world analysis
632+
insertAllInstantiatedTypesReturn();
633+
}
634+
// GR-52421: verify that tracked parameter state is subset of persisted state
635+
insertPlaceholderParamAndReturnFlows();
636+
return;
637+
}
638+
623639
// assert method.getAnnotation(Fold.class) == null : method;
624640
if (handleNodeIntrinsic()) {
625641
assert !method.getReturnsAllInstantiatedTypes() : method;

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ private static JavaType getCatchType(AnalysisUniverse universe, ResolvedJavaMeth
301301
}
302302

303303
@Override
304-
protected AnalysisUniverse getUniverse() {
304+
public AnalysisUniverse getUniverse() {
305305
/* Access the universe via the declaring class to avoid storing it here. */
306306
return declaringClass.getUniverse();
307307
}
@@ -517,7 +517,7 @@ public boolean isImplementationInvoked() {
517517
return !Modifier.isAbstract(getModifiers()) && (isIntrinsicMethod() || AtomicUtils.isSet(this, isImplementationInvokedUpdater));
518518
}
519519

520-
protected Object getImplementationInvokedReason() {
520+
public Object getImplementationInvokedReason() {
521521
return isImplementationInvoked;
522522
}
523523

@@ -775,6 +775,9 @@ public Type[] getGenericParameterTypes() {
775775

776776
@Override
777777
public boolean canBeInlined() {
778+
if (isInBaseLayer) {
779+
return false;
780+
}
778781
return !hasNeverInlineDirective();
779782
}
780783

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/CallTreePrinter.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import com.oracle.graal.pointsto.meta.AnalysisMethod;
6262
import com.oracle.graal.pointsto.meta.AnalysisType;
6363
import com.oracle.graal.pointsto.meta.InvokeInfo;
64+
import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod;
6465
import com.oracle.graal.pointsto.util.AnalysisError;
6566

6667
import jdk.graal.compiler.java.LambdaUtils;
@@ -275,7 +276,8 @@ private void printMethods(PrintWriter out) {
275276
while (iterator.hasNext()) {
276277
MethodNode node = iterator.next();
277278
boolean lastEntryPoint = !iterator.hasNext();
278-
out.format("%s%s %s %n", lastEntryPoint ? LAST_CHILD : CHILD, "entry", node.format());
279+
out.format("%s%s %s, parsing reason: %s %n", lastEntryPoint ? LAST_CHILD : CHILD, "entry", node.format(),
280+
PointsToAnalysisMethod.unwrapInvokeReason(node.method.getImplementationInvokedReason()));
279281
printCallTreeNode(out, lastEntryPoint ? EMPTY_INDENT : CONNECTING_INDENT, node);
280282
}
281283
out.println();

substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode.Computation;
8080
import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode.FieldLoad;
8181
import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode.FieldLoadIfZero;
82+
import com.oracle.svm.core.graal.snippets.NonSnippetLowerings;
8283
import com.oracle.svm.core.heap.ReferenceAccess;
8384
import com.oracle.svm.core.heap.SubstrateReferenceMapBuilder;
8485
import com.oracle.svm.core.meta.CompressedNullConstant;
@@ -199,6 +200,7 @@
199200
import jdk.vm.ci.meta.JavaConstant;
200201
import jdk.vm.ci.meta.JavaKind;
201202
import jdk.vm.ci.meta.JavaType;
203+
import jdk.vm.ci.meta.ResolvedJavaField;
202204
import jdk.vm.ci.meta.ResolvedJavaMethod;
203205
import jdk.vm.ci.meta.Value;
204206

@@ -664,12 +666,23 @@ protected boolean getDestroysCallerSavedRegisters(ResolvedJavaMethod targetMetho
664666

665667
@Override
666668
protected Value emitIndirectForeignCallAddress(ForeignCallLinkage linkage) {
669+
SubstrateForeignCallLinkage callTarget = (SubstrateForeignCallLinkage) linkage;
670+
SharedMethod targetMethod = (SharedMethod) callTarget.getMethod();
671+
if (SubstrateUtil.HOSTED && targetMethod.forceIndirectCall()) {
672+
// Emit a load for the BoxedRelocatedPointer.pointer field holding the
673+
// MethodPointer to the target method
674+
ResolvedJavaField boxedPointerField = getMetaAccess().lookupJavaField(NonSnippetLowerings.boxedRelocatedPointerField);
675+
int displacement = boxedPointerField.getOffset();
676+
JavaConstant boxedPointerBase = targetMethod.getMethodPointer();
677+
RegisterValue heapBaseRegister = ReservedRegisters.singleton().getHeapBaseRegister().asValue();
678+
AMD64AddressValue boxedRelocatedPointerBaseAddress = new AMD64AddressValue(getLIRKindTool().getWordKind(), heapBaseRegister, Value.ILLEGAL,
679+
Stride.S1, displacement + SubstrateAMD64Backend.addressDisplacement(boxedPointerBase, getConstantReflection()),
680+
SubstrateAMD64Backend.addressDisplacementAnnotation(boxedPointerBase));
681+
return getArithmetic().emitLoad(getLIRKindTool().getWordKind(), boxedRelocatedPointerBaseAddress, null, MemoryOrderMode.PLAIN, MemoryExtendKind.DEFAULT);
682+
}
667683
if (!shouldEmitOnlyIndirectCalls()) {
668684
return null;
669685
}
670-
SubstrateForeignCallLinkage callTarget = (SubstrateForeignCallLinkage) linkage;
671-
SharedMethod targetMethod = (SharedMethod) callTarget.getMethod();
672-
673686
Value codeOffsetInImage = emitConstant(getLIRKindTool().getWordKind(), JavaConstant.forLong(targetMethod.getImageCodeOffset()));
674687
Value codeInfo = emitJavaConstant(SubstrateObjectConstant.forObject(targetMethod.getImageCodeInfo()));
675688
Value codeStartField = new AMD64AddressValue(getLIRKindTool().getWordKind(), asAllocatable(codeInfo), KnownOffsets.singleton().getImageCodeInfoCodeStartOffset());
@@ -684,9 +697,9 @@ protected void emitForeignCallOp(ForeignCallLinkage linkage, Value targetAddress
684697
Value exceptionTemp = getExceptionTemp(info != null && info.exceptionEdge != null);
685698

686699
vzeroupperBeforeCall(this, arguments, info, targetMethod);
687-
if (shouldEmitOnlyIndirectCalls()) {
700+
if (shouldEmitOnlyIndirectCalls() || targetMethod.forceIndirectCall()) {
688701
AllocatableValue targetRegister = AMD64.rax.asValue(FrameAccess.getWordStamp().getLIRKind(getLIRKindTool()));
689-
emitMove(targetRegister, targetAddress);
702+
emitMove(targetRegister, targetAddress); // targetAddress is a CFunctionPointer
690703
append(new SubstrateAMD64IndirectCallOp(targetMethod, result, arguments, temps, targetRegister, info,
691704
Value.ILLEGAL, Value.ILLEGAL, StatusSupport.STATUS_ILLEGAL, getDestroysCallerSavedRegisters(targetMethod), exceptionTemp, null));
692705
} else {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ enum ArtifactType {
4040

4141
/* For all executables needed at run-time. */
4242
EXECUTABLE("executables"),
43+
/* Native image layer. */
44+
IMAGE_LAYER("image_layer"),
4345
/* For all shared libraries that are not JDK-related and needed at run-time. */
4446
SHARED_LIBRARY("shared_libraries"),
4547

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,18 @@ public class SubstrateOptions {
103103
@Option(help = "Build shared library")//
104104
public static final HostedOptionKey<Boolean> SharedLibrary = new HostedOptionKey<>(false);
105105

106+
@Option(help = "Build a Native Image layer.")//
107+
public static final HostedOptionKey<Boolean> ImageLayer = new HostedOptionKey<>(false) {
108+
@Override
109+
protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Boolean oldValue, Boolean newValue) {
110+
LayeredBaseImageAnalysis.update(values, newValue);
111+
ClosedTypeWorld.update(values, !newValue);
112+
PersistImageLayer.update(values, newValue);
113+
DeleteLocalSymbols.update(values, !newValue);
114+
StripDebugInfo.update(values, !newValue);
115+
}
116+
};
117+
106118
@APIOption(name = "static")//
107119
@Option(help = "Build statically linked executable (requires static libc and zlib)")//
108120
public static final HostedOptionKey<Boolean> StaticExecutable = new HostedOptionKey<>(false, key -> {
@@ -176,6 +188,7 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, String ol
176188
public static final String IMAGE_MODULEPATH_PREFIX = "-imagemp";
177189
public static final String KEEP_ALIVE_PREFIX = "-keepalive";
178190
private static ValueUpdateHandler<OptimizationLevel> optimizeValueUpdateHandler;
191+
private static OptionEnabledHandler<Boolean> imageLayerEnabledHandler;
179192

180193
@Fold
181194
public static boolean getSourceLevelDebug() {
@@ -324,10 +337,18 @@ public interface ValueUpdateHandler<T> {
324337
void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, T newValue);
325338
}
326339

340+
public interface OptionEnabledHandler<T> {
341+
void onOptionEnabled(EconomicMap<OptionKey<?>, Object> values);
342+
}
343+
327344
public static void setOptimizeValueUpdateHandler(ValueUpdateHandler<OptimizationLevel> updateHandler) {
328345
SubstrateOptions.optimizeValueUpdateHandler = updateHandler;
329346
}
330347

348+
public static void setImageLayerEnabledHandler(OptionEnabledHandler<Boolean> updateHandler) {
349+
SubstrateOptions.imageLayerEnabledHandler = updateHandler;
350+
}
351+
331352
@Option(help = "Track NodeSourcePositions during runtime-compilation")//
332353
public static final HostedOptionKey<Boolean> IncludeNodeSourcePositions = new HostedOptionKey<>(false);
333354

@@ -1102,7 +1123,17 @@ public static boolean closedTypeWorld() {
11021123
public static final HostedOptionKey<Boolean> AbortOnNameConflict = new HostedOptionKey<>(false);
11031124

11041125
@Option(help = "Names of layer snapshots produced by PersistImageLayer", type = OptionType.Debug) //
1105-
public static final HostedOptionKey<LocatableMultiOptionValue.Paths> LoadImageLayer = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.build());
1126+
@BundleMember(role = BundleMember.Role.Input)//
1127+
public static final HostedOptionKey<LocatableMultiOptionValue.Paths> LoadImageLayer = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.build()) {
1128+
@Override
1129+
public void update(EconomicMap<OptionKey<?>, Object> values, Object boxedValue) {
1130+
super.update(values, boxedValue);
1131+
ClosedTypeWorld.update(values, false);
1132+
if (imageLayerEnabledHandler != null) {
1133+
imageLayerEnabledHandler.onOptionEnabled(values);
1134+
}
1135+
}
1136+
};
11061137

11071138
public static class TruffleStableOptions {
11081139

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/BoxedRelocatedPointer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,16 @@
2626

2727
import org.graalvm.nativeimage.c.function.RelocatedPointer;
2828

29+
import com.oracle.svm.core.BuildPhaseProvider.AfterCompilation;
30+
import com.oracle.svm.core.heap.UnknownPrimitiveField;
31+
2932
/**
3033
* A variant of {@link BoxedPointer} that is immutable, but has a non-final field, intended to work
3134
* around limitations on folding {@link RelocatedPointer} into a constant in call stub code.
3235
*/
3336
public final class BoxedRelocatedPointer {
3437

38+
@UnknownPrimitiveField(availability = AfterCompilation.class)//
3539
private RelocatedPointer pointer;
3640

3741
public BoxedRelocatedPointer(RelocatedPointer pointer) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import static jdk.graal.compiler.core.common.spi.ForeignCallDescriptor.CallSideEffect.HAS_SIDE_EFFECT;
2828

29+
import java.lang.reflect.Field;
2930
import java.util.ArrayList;
3031
import java.util.EnumMap;
3132
import java.util.List;
@@ -37,6 +38,7 @@
3738
import com.oracle.svm.core.FrameAccess;
3839
import com.oracle.svm.core.SubstrateOptions;
3940
import com.oracle.svm.core.SubstrateUtil;
41+
import com.oracle.svm.core.c.BoxedRelocatedPointer;
4042
import com.oracle.svm.core.config.ConfigurationValues;
4143
import com.oracle.svm.core.graal.code.SubstrateBackend;
4244
import com.oracle.svm.core.graal.meta.KnownOffsets;
@@ -50,6 +52,7 @@
5052
import com.oracle.svm.core.snippets.SnippetRuntime;
5153
import com.oracle.svm.core.snippets.SubstrateForeignCallTarget;
5254
import com.oracle.svm.core.util.VMError;
55+
import com.oracle.svm.util.ReflectionUtil;
5356

5457
import jdk.graal.compiler.core.common.memory.BarrierType;
5558
import jdk.graal.compiler.core.common.memory.MemoryOrderMode;
@@ -106,12 +109,14 @@
106109
import jdk.vm.ci.meta.JavaConstant;
107110
import jdk.vm.ci.meta.JavaKind;
108111
import jdk.vm.ci.meta.JavaType;
112+
import jdk.vm.ci.meta.ResolvedJavaField;
109113
import jdk.vm.ci.meta.ResolvedJavaMethod;
110114

111115
public abstract class NonSnippetLowerings {
112116

113117
public static final SnippetRuntime.SubstrateForeignCallDescriptor REPORT_VERIFY_TYPES_ERROR = SnippetRuntime.findForeignCall(NonSnippetLowerings.class, "reportVerifyTypesError", HAS_SIDE_EFFECT,
114118
LocationIdentity.any());
119+
public static final Field boxedRelocatedPointerField = ReflectionUtil.lookupField(BoxedRelocatedPointer.class, "pointer");
115120

116121
private final Predicate<ResolvedJavaMethod> mustNotAllocatePredicate;
117122

@@ -364,7 +369,26 @@ public void lower(FixedNode node, LoweringTool tool) {
364369
targetMethod = implementations[0];
365370
}
366371

367-
if (!SubstrateBackend.shouldEmitOnlyIndirectCalls()) {
372+
if (targetMethod.forceIndirectCall()) {
373+
/*
374+
* Lower cross layer boundary direct calls to indirect calls. First emit a
375+
* load for the BoxedRelocatedPointer.pointer field holding the
376+
* MethodPointer to the target method, then emit an indirect call to that
377+
* pointer.
378+
*/
379+
ResolvedJavaField boxedPointerField = tool.getMetaAccess().lookupJavaField(NonSnippetLowerings.boxedRelocatedPointerField);
380+
ConstantNode boxedPointerFieldOffset = ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), boxedPointerField.getOffset(), graph);
381+
ConstantNode boxedPointerBase = ConstantNode.forConstant(targetMethod.getMethodPointer(), tool.getMetaAccess(), graph);
382+
383+
AddressNode methodPointerAddress = graph.unique(new OffsetAddressNode(boxedPointerBase, boxedPointerFieldOffset));
384+
/*
385+
* Use the ANY location identity to prevent ReadNode.canonicalizeRead() to
386+
* try to constant fold the method address.
387+
*/
388+
ReadNode entry = graph.add(new ReadNode(methodPointerAddress, LocationIdentity.any(), FrameAccess.getWordStamp(), BarrierType.NONE, MemoryOrderMode.PLAIN));
389+
loweredCallTarget = createIndirectCall(graph, callTarget, parameters, method, signature, callType, invokeKind, entry);
390+
graph.addBeforeFixed(node, entry);
391+
} else if (!SubstrateBackend.shouldEmitOnlyIndirectCalls()) {
368392
loweredCallTarget = createDirectCall(graph, callTarget, parameters, signature, callType, invokeKind, targetMethod, node);
369393
} else if (!targetMethod.hasImageCodeOffset()) {
370394
/*

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SharedMethod.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind;
3131
import com.oracle.svm.core.graal.code.SubstrateCallingConventionType;
3232

33+
import jdk.vm.ci.meta.JavaConstant;
3334
import jdk.vm.ci.meta.ResolvedJavaMethod;
3435

3536
/**
@@ -81,4 +82,9 @@ public interface SharedMethod extends ResolvedJavaMethod {
8182
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
8283
int getImageCodeDeoptOffset();
8384

85+
/** Always call this method indirectly, even if it is normally called directly. */
86+
boolean forceIndirectCall();
87+
88+
/** Return a boxed pointer to this method. */
89+
JavaConstant getMethodPointer();
8490
}

substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ private static <T> String oR(OptionKey<T> option) {
257257
final String oHUseLibC = oH(SubstrateOptions.UseLibC);
258258
final String oHEnableStaticExecutable = oHEnabled(SubstrateOptions.StaticExecutable);
259259
final String oHEnableSharedLibraryFlagPrefix = oHEnabled + SubstrateOptions.SharedLibrary.getName();
260+
final String oHEnableImageLayerFlagPrefix = oHEnabled + SubstrateOptions.ImageLayer.getName();
260261
final String oHColor = oH(SubstrateOptions.Color);
261262
final String oHEnableBuildOutputProgress = oHEnabledByDriver(SubstrateOptions.BuildOutputProgress);
262263
final String oHEnableBuildOutputLinks = oHEnabledByDriver(SubstrateOptions.BuildOutputLinks);
@@ -1168,7 +1169,7 @@ private int completeImageBuild() {
11681169
imageBuilderJavaArgs.addAll(getAgentArguments());
11691170

11701171
mainClass = getHostedOptionArgumentValue(imageBuilderArgs, oHClass);
1171-
buildExecutable = imageBuilderArgs.stream().noneMatch(arg -> arg.startsWith(oHEnableSharedLibraryFlagPrefix));
1172+
buildExecutable = imageBuilderArgs.stream().noneMatch(arg -> arg.startsWith(oHEnableSharedLibraryFlagPrefix) || arg.startsWith(oHEnableImageLayerFlagPrefix));
11721173
staticExecutable = imageBuilderArgs.stream().anyMatch(arg -> arg.contains(oHEnableStaticExecutable));
11731174
boolean listModules = imageBuilderArgs.stream().anyMatch(arg -> arg.contains(oH + "+" + "ListModules"));
11741175
printFlags |= imageBuilderArgs.stream().anyMatch(arg -> arg.matches("-H:MicroArchitecture(@[^=]*)?=list"));

substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateMethod.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import jdk.vm.ci.meta.ConstantPool;
6161
import jdk.vm.ci.meta.DefaultProfilingInfo;
6262
import jdk.vm.ci.meta.ExceptionHandler;
63+
import jdk.vm.ci.meta.JavaConstant;
6364
import jdk.vm.ci.meta.LineNumberTable;
6465
import jdk.vm.ci.meta.LocalVariableTable;
6566
import jdk.vm.ci.meta.ProfilingInfo;
@@ -224,6 +225,16 @@ public int getImageCodeDeoptOffset() {
224225
return imageCodeDeoptOffset;
225226
}
226227

228+
@Override
229+
public boolean forceIndirectCall() {
230+
return false;
231+
}
232+
233+
@Override
234+
public JavaConstant getMethodPointer() {
235+
throw VMError.intentionallyUnimplemented(); // ExcludeFromJacocoGeneratedReport
236+
}
237+
227238
@Override
228239
public int getEncodedGraphStartOffset() {
229240
return encodedGraphStartOffset;

0 commit comments

Comments
 (0)