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-53508] Refactor cross layer calls and link base layer .so. #8845

Merged
merged 11 commits into from
Apr 26, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ public ImageLayerLoader(ImageLayerSnapshotUtil imageLayerSnapshotUtil, List<Path
this.loadPaths = loadPaths;
}

public List<Path> getLoadPaths() {
return loadPaths;
}

public void setUniverse(AnalysisUniverse newUniverse) {
this.universe = newUniverse;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import java.util.EnumSet;
import java.util.function.BiConsumer;

import com.oracle.svm.core.graal.code.CGlobalDataInfo;
import org.graalvm.collections.EconomicMap;
import org.graalvm.nativeimage.ImageSingletons;

Expand All @@ -53,6 +54,7 @@
import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.amd64.AMD64CPUFeatureAccess;
import com.oracle.svm.core.code.BaseLayerMethodAccessor;
import com.oracle.svm.core.config.ConfigurationValues;
import com.oracle.svm.core.cpufeature.Stubs;
import com.oracle.svm.core.deopt.Deoptimizer;
Expand All @@ -79,7 +81,6 @@
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 @@ -200,7 +201,6 @@
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 @@ -669,16 +669,15 @@ 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);
/*
* Load the absolute address of the target method from the method entry stored in
* the data section.
*/
CGlobalDataInfo methodDataInfo = BaseLayerMethodAccessor.singleton().getMethodData(targetMethod);
AllocatableValue methodPointerAddress = newVariable(getLIRKindTool().getWordKind());
append(new AMD64CGlobalDataLoadAddressOp(methodDataInfo, methodPointerAddress));
AMD64AddressValue methodTableEntryAddress = new AMD64AddressValue(getLIRKindTool().getWordKind(), methodPointerAddress, Value.ILLEGAL, Stride.S1, 0);
return getArithmetic().emitLoad(getLIRKindTool().getWordKind(), methodTableEntryAddress, null, MemoryOrderMode.PLAIN, MemoryExtendKind.DEFAULT);
}
if (!shouldEmitOnlyIndirectCalls()) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import static com.oracle.svm.core.graal.llvm.LLVMToolchainUtils.llvmLink;
import static com.oracle.svm.core.graal.llvm.LLVMToolchainUtils.llvmOptimize;
import static com.oracle.svm.core.graal.llvm.LLVMToolchainUtils.nativeLink;
import static com.oracle.svm.core.util.VMError.intentionallyUnimplemented;
import static com.oracle.svm.core.util.VMError.shouldNotReachHereUnexpectedInput;
import static com.oracle.svm.hosted.image.NativeImage.RWDATA_CGLOBALS_PARTITION_OFFSET;

Expand All @@ -46,11 +47,6 @@
import java.util.stream.IntStream;

import org.graalvm.collections.Pair;
import jdk.graal.compiler.code.CompilationResult;
import jdk.graal.compiler.core.common.NumUtil;
import jdk.graal.compiler.debug.DebugContext;
import jdk.graal.compiler.debug.GraalError;
import jdk.graal.compiler.debug.Indent;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;

Expand Down Expand Up @@ -78,6 +74,11 @@
import com.oracle.svm.hosted.image.RelocatableBuffer;
import com.oracle.svm.hosted.meta.HostedMethod;

import jdk.graal.compiler.code.CompilationResult;
import jdk.graal.compiler.core.common.NumUtil;
import jdk.graal.compiler.debug.DebugContext;
import jdk.graal.compiler.debug.GraalError;
import jdk.graal.compiler.debug.Indent;
import jdk.vm.ci.code.site.Call;
import jdk.vm.ci.code.site.DataPatch;
import jdk.vm.ci.code.site.DataSectionReference;
Expand Down Expand Up @@ -317,6 +318,11 @@ public void patchMethods(DebugContext debug, RelocatableBuffer relocs, ObjectFil
@Override
public NativeTextSectionImpl getTextSectionImpl(RelocatableBuffer buffer, ObjectFile objectFile, NativeImageCodeCache codeCache) {
return new NativeTextSectionImpl(buffer, objectFile, codeCache) {
@Override
protected void defineBaseLayerMethodSymbol(String name, Element section, HostedMethod method) {
throw intentionallyUnimplemented(); // ExcludeFromJacocoGeneratedReport
}

@Override
protected void defineMethodSymbol(String name, boolean global, Element section, HostedMethod method, CompilationResult result) {
ObjectFile.Symbol symbol = objectFile.createUndefinedSymbol(name, 0, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/
package com.oracle.svm.core;

import static com.oracle.svm.core.Containers.Options.UseContainerSupport;
import static com.oracle.svm.core.option.RuntimeOptionKey.RuntimeOptionKeyFlag.Immutable;
import static com.oracle.svm.core.option.RuntimeOptionKey.RuntimeOptionKeyFlag.RelevantForCompilationIsolates;
import static jdk.graal.compiler.core.common.SpectrePHTMitigations.None;
Expand Down Expand Up @@ -113,6 +114,12 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Boolean o
PersistImageLayerSingletons.update(values, newValue);
DeleteLocalSymbols.update(values, !newValue);
StripDebugInfo.update(values, !newValue);
InternalSymbolsAreGlobal.update(values, newValue);
AOTTrivialInline.update(values, !newValue);
if (imageLayerEnabledHandler != null) {
imageLayerEnabledHandler.onOptionEnabled(values);
}
UseContainerSupport.update(values, !newValue);
}
};

Expand Down Expand Up @@ -707,6 +714,10 @@ public static boolean useLIRBackend() {
*/
@Option(help = "Use linker option to prevent unreferenced symbols in image.")//
public static final HostedOptionKey<Boolean> RemoveUnusedSymbols = new HostedOptionKey<>(OS.getCurrent() != OS.DARWIN);
@Option(help = "Keep all undefined symbols.")//
public static final HostedOptionKey<Boolean> PreserveUndefinedSymbols = new HostedOptionKey<>(false);
@Option(help = "Ignore undefined symbols referenced from the built image.")//
public static final HostedOptionKey<Boolean> IgnoreUndefinedReferences = new HostedOptionKey<>(false);
@Option(help = "Use linker option to remove all local symbols from image.")//
public static final HostedOptionKey<Boolean> DeleteLocalSymbols = new HostedOptionKey<>(true);
@Option(help = "Compatibility option to make symbols used for the image heap global. " +
Expand Down Expand Up @@ -1133,6 +1144,10 @@ public static boolean closedTypeWorld() {
public void update(EconomicMap<OptionKey<?>, Object> values, Object boxedValue) {
super.update(values, boxedValue);
ClosedTypeWorld.update(values, false);
PreserveUndefinedSymbols.update(values, true);
/* Ignore any potential undefined references caused by inlining in base layer. */
IgnoreUndefinedReferences.update(values, true);
AOTTrivialInline.update(values, false);
if (imageLayerEnabledHandler != null) {
imageLayerEnabledHandler.onOptionEnabled(values);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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.code;

import org.graalvm.nativeimage.ImageSingletons;

import com.oracle.svm.core.graal.code.CGlobalDataInfo;
import com.oracle.svm.core.meta.SharedMethod;

public interface BaseLayerMethodAccessor {
CGlobalDataInfo getMethodData(SharedMethod method);

static BaseLayerMethodAccessor singleton() {
return ImageSingletons.lookup(BaseLayerMethodAccessor.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,13 @@
import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.c.BoxedRelocatedPointer;
import com.oracle.svm.core.code.BaseLayerMethodAccessor;
import com.oracle.svm.core.config.ConfigurationValues;
import com.oracle.svm.core.graal.code.CGlobalDataInfo;
import com.oracle.svm.core.graal.code.SubstrateBackend;
import com.oracle.svm.core.graal.meta.KnownOffsets;
import com.oracle.svm.core.graal.meta.RuntimeConfiguration;
import com.oracle.svm.core.graal.nodes.CGlobalDataLoadAddressNode;
import com.oracle.svm.core.graal.nodes.LoadOpenTypeWorldDispatchTableStartingOffset;
import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode;
import com.oracle.svm.core.graal.nodes.ThrowBytecodeExceptionNode;
Expand Down Expand Up @@ -109,7 +112,6 @@
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 {
Expand Down Expand Up @@ -369,18 +371,15 @@ public void lower(FixedNode node, LoweringTool tool) {
targetMethod = implementations[0];
}

if (targetMethod.forceIndirectCall()) {
if (SubstrateUtil.HOSTED && 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.
* Lower cross layer boundary direct calls to indirect calls. First load the
* target method absolute address from the method entry stored in the data
* section. Then call that address indirectly.
*/
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);
CGlobalDataInfo methodDataInfo = BaseLayerMethodAccessor.singleton().getMethodData(targetMethod);
AddressNode methodPointerAddress = graph.addOrUniqueWithInputs(OffsetAddressNode.create(new CGlobalDataLoadAddressNode(methodDataInfo)));

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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
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 @@ -84,7 +83,4 @@ public interface SharedMethod extends ResolvedJavaMethod {

/** 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 @@ -60,7 +60,6 @@
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 @@ -230,11 +229,6 @@ public boolean forceIndirectCall() {
return false;
}

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

@Override
public int getEncodedGraphStartOffset() {
return encodedGraphStartOffset;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1299,7 +1299,25 @@ protected NativeLibraries setupNativeLibraries(HostedProviders providers, CEnumC
if (CAnnotationProcessorCache.Options.ExitAfterCAPCache.getValue()) {
throw new InterruptImageBuilding("Exiting image generation because of " + SubstrateOptionsParser.commandArgument(CAnnotationProcessorCache.Options.ExitAfterCAPCache, "+"));
}

if (SVMImageLayerSupport.singleton().hasLoader()) {
for (Path layerPath : SVMImageLayerSupport.singleton().getLoader().getLoadPaths()) {
Path snapshotFileName = layerPath.getFileName();
if (snapshotFileName != null) {
String layerName = snapshotFileName.toString().split(ImageLayerSnapshotUtil.FILE_NAME_PREFIX)[1].split(ImageLayerSnapshotUtil.FILE_EXTENSION)[0].trim();
/*
* This currently assumes lib{layer}.so is in the same dir as the layer
* snapshot. GR-53663 will create a proper bundle that contains both files.
*/
Path layerPathDir = layerPath.getParent();
if (layerPathDir != null && layerName.startsWith("lib") && Files.exists(layerPathDir.resolve(layerName + ".so"))) {
nativeLibs.getLibraryPaths().add(layerPathDir.toString());
nativeLibs.addDynamicNonJniLibrary(layerName.split("lib")[1]);
} else {
throw VMError.shouldNotReachHere("Missing " + layerName + ".so. It must be placed in the same dir as the layer snapshot.");
}
}
}
}
return nativeLibs;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ public static SVMImageLayerSupport singleton() {
return ImageSingletons.lookup(SVMImageLayerSupport.class);
}

public boolean hasLoader() {
return loader != null;
}

public SVMImageLayerLoader getLoader() {
return loader;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public enum NativeImageKind {
IMAGE_LAYER(false, true) {
@Override
public String getFilenameSuffix() {
return ".gso"; // Graal shared object
return ".so";
}
},
SHARED_LIBRARY(false) {
Expand Down