Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GR-52265] Extend layered images support. #8794

Merged
merged 16 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,22 @@ protected void apply(boolean forceReparse, Object reason) {
assert !processed : "can only call apply once per MethodTypeFlowBuilder";
processed = true;

if (bb.getHostVM().useBaseLayer() && method.isInBaseLayer()) {
/*
* We don't need to analyze this method. We already know its return type state from the
* open world analysis. We just install a return flow to link it with its uses.
*/
AnalysisType returnType = method.getSignature().getReturnType();
if (returnType.getJavaKind().isObject()) {
// GR-52421: the return type state should not be all-instantiated, it should be the
// persisted result of the open-world analysis
insertAllInstantiatedTypesReturn();
}
// GR-52421: verify that tracked parameter state is subset of persisted state
insertPlaceholderParamAndReturnFlows();
return;
}

// assert method.getAnnotation(Fold.class) == null : method;
if (handleNodeIntrinsic()) {
assert !method.getReturnsAllInstantiatedTypes() : method;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ private static JavaType getCatchType(AnalysisUniverse universe, ResolvedJavaMeth
}

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

protected Object getImplementationInvokedReason() {
public Object getImplementationInvokedReason() {
return isImplementationInvoked;
}

Expand Down Expand Up @@ -775,6 +775,9 @@ public Type[] getGenericParameterTypes() {

@Override
public boolean canBeInlined() {
if (isInBaseLayer) {
return false;
}
return !hasNeverInlineDirective();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import com.oracle.graal.pointsto.meta.AnalysisMethod;
import com.oracle.graal.pointsto.meta.AnalysisType;
import com.oracle.graal.pointsto.meta.InvokeInfo;
import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod;
import com.oracle.graal.pointsto.util.AnalysisError;

import jdk.graal.compiler.java.LambdaUtils;
Expand Down Expand Up @@ -275,7 +276,8 @@ private void printMethods(PrintWriter out) {
while (iterator.hasNext()) {
MethodNode node = iterator.next();
boolean lastEntryPoint = !iterator.hasNext();
out.format("%s%s %s %n", lastEntryPoint ? LAST_CHILD : CHILD, "entry", node.format());
out.format("%s%s %s, parsing reason: %s %n", lastEntryPoint ? LAST_CHILD : CHILD, "entry", node.format(),
PointsToAnalysisMethod.unwrapInvokeReason(node.method.getImplementationInvokedReason()));
printCallTreeNode(out, lastEntryPoint ? EMPTY_INDENT : CONNECTING_INDENT, node);
}
out.println();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode.Computation;
import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode.FieldLoad;
import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode.FieldLoadIfZero;
import com.oracle.svm.core.graal.snippets.NonSnippetLowerings;
import com.oracle.svm.core.heap.ReferenceAccess;
import com.oracle.svm.core.heap.SubstrateReferenceMapBuilder;
import com.oracle.svm.core.meta.CompressedNullConstant;
Expand Down Expand Up @@ -199,6 +200,7 @@
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.ResolvedJavaField;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.Value;

Expand Down Expand Up @@ -664,12 +666,23 @@ protected boolean getDestroysCallerSavedRegisters(ResolvedJavaMethod targetMetho

@Override
protected Value emitIndirectForeignCallAddress(ForeignCallLinkage linkage) {
SubstrateForeignCallLinkage callTarget = (SubstrateForeignCallLinkage) linkage;
SharedMethod targetMethod = (SharedMethod) callTarget.getMethod();
if (SubstrateUtil.HOSTED && targetMethod.forceIndirectCall()) {
// Emit a load for the BoxedRelocatedPointer.pointer field holding the
// MethodPointer to the target method
ResolvedJavaField boxedPointerField = getMetaAccess().lookupJavaField(NonSnippetLowerings.boxedRelocatedPointerField);
int displacement = boxedPointerField.getOffset();
JavaConstant boxedPointerBase = targetMethod.getMethodPointer();
RegisterValue heapBaseRegister = ReservedRegisters.singleton().getHeapBaseRegister().asValue();
AMD64AddressValue boxedRelocatedPointerBaseAddress = new AMD64AddressValue(getLIRKindTool().getWordKind(), heapBaseRegister, Value.ILLEGAL,
Stride.S1, displacement + SubstrateAMD64Backend.addressDisplacement(boxedPointerBase, getConstantReflection()),
SubstrateAMD64Backend.addressDisplacementAnnotation(boxedPointerBase));
return getArithmetic().emitLoad(getLIRKindTool().getWordKind(), boxedRelocatedPointerBaseAddress, null, MemoryOrderMode.PLAIN, MemoryExtendKind.DEFAULT);
}
if (!shouldEmitOnlyIndirectCalls()) {
return null;
}
SubstrateForeignCallLinkage callTarget = (SubstrateForeignCallLinkage) linkage;
SharedMethod targetMethod = (SharedMethod) callTarget.getMethod();

Value codeOffsetInImage = emitConstant(getLIRKindTool().getWordKind(), JavaConstant.forLong(targetMethod.getImageCodeOffset()));
Value codeInfo = emitJavaConstant(SubstrateObjectConstant.forObject(targetMethod.getImageCodeInfo()));
Value codeStartField = new AMD64AddressValue(getLIRKindTool().getWordKind(), asAllocatable(codeInfo), KnownOffsets.singleton().getImageCodeInfoCodeStartOffset());
Expand All @@ -684,9 +697,9 @@ protected void emitForeignCallOp(ForeignCallLinkage linkage, Value targetAddress
Value exceptionTemp = getExceptionTemp(info != null && info.exceptionEdge != null);

vzeroupperBeforeCall(this, arguments, info, targetMethod);
if (shouldEmitOnlyIndirectCalls()) {
if (shouldEmitOnlyIndirectCalls() || targetMethod.forceIndirectCall()) {
AllocatableValue targetRegister = AMD64.rax.asValue(FrameAccess.getWordStamp().getLIRKind(getLIRKindTool()));
emitMove(targetRegister, targetAddress);
emitMove(targetRegister, targetAddress); // targetAddress is a CFunctionPointer
append(new SubstrateAMD64IndirectCallOp(targetMethod, result, arguments, temps, targetRegister, info,
Value.ILLEGAL, Value.ILLEGAL, StatusSupport.STATUS_ILLEGAL, getDestroysCallerSavedRegisters(targetMethod), exceptionTemp, null));
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ enum ArtifactType {

/* For all executables needed at run-time. */
EXECUTABLE("executables"),
/* Native image layer. */
IMAGE_LAYER("image_layer"),
/* For all shared libraries that are not JDK-related and needed at run-time. */
SHARED_LIBRARY("shared_libraries"),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,18 @@ public class SubstrateOptions {
@Option(help = "Build shared library")//
public static final HostedOptionKey<Boolean> SharedLibrary = new HostedOptionKey<>(false);

@Option(help = "Build a Native Image layer.")//
public static final HostedOptionKey<Boolean> ImageLayer = new HostedOptionKey<>(false) {
@Override
protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Boolean oldValue, Boolean newValue) {
LayeredBaseImageAnalysis.update(values, newValue);
ClosedTypeWorld.update(values, !newValue);
PersistImageLayer.update(values, newValue);
DeleteLocalSymbols.update(values, !newValue);
StripDebugInfo.update(values, !newValue);
}
};

@APIOption(name = "static")//
@Option(help = "Build statically linked executable (requires static libc and zlib)")//
public static final HostedOptionKey<Boolean> StaticExecutable = new HostedOptionKey<>(false, key -> {
Expand Down Expand Up @@ -176,6 +188,7 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, String ol
public static final String IMAGE_MODULEPATH_PREFIX = "-imagemp";
public static final String KEEP_ALIVE_PREFIX = "-keepalive";
private static ValueUpdateHandler<OptimizationLevel> optimizeValueUpdateHandler;
private static OptionEnabledHandler<Boolean> imageLayerEnabledHandler;

@Fold
public static boolean getSourceLevelDebug() {
Expand Down Expand Up @@ -324,10 +337,18 @@ public interface ValueUpdateHandler<T> {
void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, T newValue);
}

public interface OptionEnabledHandler<T> {
void onOptionEnabled(EconomicMap<OptionKey<?>, Object> values);
}

public static void setOptimizeValueUpdateHandler(ValueUpdateHandler<OptimizationLevel> updateHandler) {
SubstrateOptions.optimizeValueUpdateHandler = updateHandler;
}

public static void setImageLayerEnabledHandler(OptionEnabledHandler<Boolean> updateHandler) {
SubstrateOptions.imageLayerEnabledHandler = updateHandler;
}

@Option(help = "Track NodeSourcePositions during runtime-compilation")//
public static final HostedOptionKey<Boolean> IncludeNodeSourcePositions = new HostedOptionKey<>(false);

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

@Option(help = "Names of layer snapshots produced by PersistImageLayer", type = OptionType.Debug) //
public static final HostedOptionKey<LocatableMultiOptionValue.Paths> LoadImageLayer = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.build());
@BundleMember(role = BundleMember.Role.Input)//
public static final HostedOptionKey<LocatableMultiOptionValue.Paths> LoadImageLayer = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.build()) {
@Override
public void update(EconomicMap<OptionKey<?>, Object> values, Object boxedValue) {
super.update(values, boxedValue);
ClosedTypeWorld.update(values, false);
if (imageLayerEnabledHandler != null) {
imageLayerEnabledHandler.onOptionEnabled(values);
}
}
};

public static class TruffleStableOptions {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,16 @@

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

import com.oracle.svm.core.BuildPhaseProvider.AfterCompilation;
import com.oracle.svm.core.heap.UnknownPrimitiveField;

/**
* A variant of {@link BoxedPointer} that is immutable, but has a non-final field, intended to work
* around limitations on folding {@link RelocatedPointer} into a constant in call stub code.
*/
public final class BoxedRelocatedPointer {

@UnknownPrimitiveField(availability = AfterCompilation.class)//
private RelocatedPointer pointer;

public BoxedRelocatedPointer(RelocatedPointer pointer) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

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

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
Expand All @@ -37,6 +38,7 @@
import com.oracle.svm.core.FrameAccess;
import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.c.BoxedRelocatedPointer;
import com.oracle.svm.core.config.ConfigurationValues;
import com.oracle.svm.core.graal.code.SubstrateBackend;
import com.oracle.svm.core.graal.meta.KnownOffsets;
Expand All @@ -50,6 +52,7 @@
import com.oracle.svm.core.snippets.SnippetRuntime;
import com.oracle.svm.core.snippets.SubstrateForeignCallTarget;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.ReflectionUtil;

import jdk.graal.compiler.core.common.memory.BarrierType;
import jdk.graal.compiler.core.common.memory.MemoryOrderMode;
Expand Down Expand Up @@ -106,12 +109,14 @@
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.ResolvedJavaField;
import jdk.vm.ci.meta.ResolvedJavaMethod;

public abstract class NonSnippetLowerings {

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

private final Predicate<ResolvedJavaMethod> mustNotAllocatePredicate;

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

if (!SubstrateBackend.shouldEmitOnlyIndirectCalls()) {
if (targetMethod.forceIndirectCall()) {
/*
* Lower cross layer boundary direct calls to indirect calls. First emit a
* load for the BoxedRelocatedPointer.pointer field holding the
* MethodPointer to the target method, then emit an indirect call to that
* pointer.
*/
ResolvedJavaField boxedPointerField = tool.getMetaAccess().lookupJavaField(NonSnippetLowerings.boxedRelocatedPointerField);
ConstantNode boxedPointerFieldOffset = ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), boxedPointerField.getOffset(), graph);
ConstantNode boxedPointerBase = ConstantNode.forConstant(targetMethod.getMethodPointer(), tool.getMetaAccess(), graph);

AddressNode methodPointerAddress = graph.unique(new OffsetAddressNode(boxedPointerBase, boxedPointerFieldOffset));
/*
* Use the ANY location identity to prevent ReadNode.canonicalizeRead() to
* try to constant fold the method address.
*/
ReadNode entry = graph.add(new ReadNode(methodPointerAddress, LocationIdentity.any(), FrameAccess.getWordStamp(), BarrierType.NONE, MemoryOrderMode.PLAIN));
loweredCallTarget = createIndirectCall(graph, callTarget, parameters, method, signature, callType, invokeKind, entry);
graph.addBeforeFixed(node, entry);
} else if (!SubstrateBackend.shouldEmitOnlyIndirectCalls()) {
loweredCallTarget = createDirectCall(graph, callTarget, parameters, signature, callType, invokeKind, targetMethod, node);
} else if (!targetMethod.hasImageCodeOffset()) {
/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind;
import com.oracle.svm.core.graal.code.SubstrateCallingConventionType;

import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.ResolvedJavaMethod;

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

/** Always call this method indirectly, even if it is normally called directly. */
boolean forceIndirectCall();

/** Return a boxed pointer to this method. */
JavaConstant getMethodPointer();
}
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ private static <T> String oR(OptionKey<T> option) {
final String oHUseLibC = oH(SubstrateOptions.UseLibC);
final String oHEnableStaticExecutable = oHEnabled(SubstrateOptions.StaticExecutable);
final String oHEnableSharedLibraryFlagPrefix = oHEnabled + SubstrateOptions.SharedLibrary.getName();
final String oHEnableImageLayerFlagPrefix = oHEnabled + SubstrateOptions.ImageLayer.getName();
final String oHColor = oH(SubstrateOptions.Color);
final String oHEnableBuildOutputProgress = oHEnabledByDriver(SubstrateOptions.BuildOutputProgress);
final String oHEnableBuildOutputLinks = oHEnabledByDriver(SubstrateOptions.BuildOutputLinks);
Expand Down Expand Up @@ -1168,7 +1169,7 @@ private int completeImageBuild() {
imageBuilderJavaArgs.addAll(getAgentArguments());

mainClass = getHostedOptionArgumentValue(imageBuilderArgs, oHClass);
buildExecutable = imageBuilderArgs.stream().noneMatch(arg -> arg.startsWith(oHEnableSharedLibraryFlagPrefix));
buildExecutable = imageBuilderArgs.stream().noneMatch(arg -> arg.startsWith(oHEnableSharedLibraryFlagPrefix) || arg.startsWith(oHEnableImageLayerFlagPrefix));
staticExecutable = imageBuilderArgs.stream().anyMatch(arg -> arg.contains(oHEnableStaticExecutable));
boolean listModules = imageBuilderArgs.stream().anyMatch(arg -> arg.contains(oH + "+" + "ListModules"));
printFlags |= imageBuilderArgs.stream().anyMatch(arg -> arg.matches("-H:MicroArchitecture(@[^=]*)?=list"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import jdk.vm.ci.meta.ConstantPool;
import jdk.vm.ci.meta.DefaultProfilingInfo;
import jdk.vm.ci.meta.ExceptionHandler;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.LineNumberTable;
import jdk.vm.ci.meta.LocalVariableTable;
import jdk.vm.ci.meta.ProfilingInfo;
Expand Down Expand Up @@ -224,6 +225,16 @@ public int getImageCodeDeoptOffset() {
return imageCodeDeoptOffset;
}

@Override
public boolean forceIndirectCall() {
return false;
}

@Override
public JavaConstant getMethodPointer() {
throw VMError.intentionallyUnimplemented(); // ExcludeFromJacocoGeneratedReport
}

@Override
public int getEncodedGraphStartOffset() {
return encodedGraphStartOffset;
Expand Down
Loading