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-53669] Add layered stack walking support #9168

Merged
merged 1 commit into from
Jun 24, 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 @@ -29,7 +29,6 @@
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 Down Expand Up @@ -318,11 +317,6 @@ 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 @@ -27,6 +27,7 @@
import static com.oracle.svm.core.util.VMError.shouldNotReachHereUnexpectedInput;

import java.util.BitSet;
import java.util.EnumSet;
import java.util.Objects;
import java.util.TreeMap;
import java.util.function.Consumer;
Expand All @@ -53,6 +54,7 @@
import com.oracle.svm.core.config.ConfigurationValues;
import com.oracle.svm.core.config.ObjectLayout;
import com.oracle.svm.core.deopt.DeoptEntryInfopoint;
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
import com.oracle.svm.core.graal.RuntimeCompilation;
import com.oracle.svm.core.heap.CodeReferenceMapDecoder;
import com.oracle.svm.core.heap.CodeReferenceMapEncoder;
Expand All @@ -61,7 +63,13 @@
import com.oracle.svm.core.heap.SubstrateReferenceMap;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.hub.LayoutEncoding;
import com.oracle.svm.core.imagelayer.BuildingImageLayerPredicate;
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
import com.oracle.svm.core.jfr.HasJfrSupport;
import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader;
import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter;
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton;
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
import com.oracle.svm.core.meta.SharedField;
import com.oracle.svm.core.meta.SharedMethod;
import com.oracle.svm.core.meta.SharedType;
Expand Down Expand Up @@ -201,12 +209,14 @@ private void encodeAllAndInstall(CodeInfo target, ReferenceAdjuster adjuster) {
String[] memberNamesArray = encodeArray(memberNames, String[]::new);
String[] otherStringsArray = encodeArray(otherStrings, String[]::new);

/*
* For image code, we currently have a single code info for which method ids start at 0
* (with 0 meaning invalid). Runtime code info can only reference image methods via
* these same ids and doesn't have its own method table.
*/
int methodTableFirstId = 0;
int methodTableFirstId;
if (ImageLayerBuildingSupport.buildingImageLayer()) {
var idTracker = MethodTableFirstIDTracker.singleton();
methodTableFirstId = idTracker.startingID;
idTracker.nextStartingId = methodTableFirstId + methods.getLength();
} else {
methodTableFirstId = 0;
}
NonmovableArray<Byte> methodTable = encodeMethodTable();

install(target, objectConstantsArray, classesArray, memberNamesArray, otherStringsArray, methodTable, methodTableFirstId, adjuster);
Expand Down Expand Up @@ -863,6 +873,41 @@ private static ValueInfo findActualValue(ValueInfo[] actualObject, UnsignedWord
}
}

@AutomaticallyRegisteredImageSingleton(onlyWith = BuildingImageLayerPredicate.class)
class MethodTableFirstIDTracker implements LayeredImageSingleton {
public final int startingID;
public int nextStartingId = -1;

MethodTableFirstIDTracker() {
this(0);
}

static MethodTableFirstIDTracker singleton() {
return ImageSingletons.lookup(MethodTableFirstIDTracker.class);
}

private MethodTableFirstIDTracker(int id) {
startingID = id;
}

@Override
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
return LayeredImageSingletonBuilderFlags.BUILDTIME_ACCESS_ONLY;
}

@Override
public PersistFlags preparePersist(ImageSingletonWriter writer) {
assert nextStartingId > 0 : nextStartingId;
writer.writeInt("startingID", nextStartingId);
return PersistFlags.CREATE;
}

@SuppressWarnings("unused")
public static Object createFromLoader(ImageSingletonLoader loader) {
return new MethodTableFirstIDTracker(loader.readInt("startingID"));
}
}

class CollectingObjectReferenceVisitor implements ObjectReferenceVisitor {
protected final SubstrateReferenceMap result = new SubstrateReferenceMap();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ protected static FrameInfoQueryResult decodeFrameInfo(boolean isDeoptEntry, Reus

FrameInfoQueryResult result;
if (CompressedFrameDecoderHelper.isCompressedFrameSlice(state.firstValue)) {
result = decodeCompressedFrameInfo(isDeoptEntry, readBuffer, resultAllocator, state);
result = decodeCompressedFrameInfo(isDeoptEntry, readBuffer, resultAllocator, state, CodeInfoAccess.getMethodTableFirstId(info));
} else {
result = decodeUncompressedFrameInfo(isDeoptEntry, readBuffer, info, resultAllocator, valueInfoAllocator, constantAccess, state);
}
Expand All @@ -302,7 +302,8 @@ protected static FrameInfoQueryResult decodeFrameInfo(boolean isDeoptEntry, Reus
* compressed encoding format.
*/
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
private static FrameInfoQueryResult decodeCompressedFrameInfo(boolean isDeoptEntry, ReusableTypeReader readBuffer, FrameInfoQueryResultAllocator resultAllocator, FrameInfoState state) {
private static FrameInfoQueryResult decodeCompressedFrameInfo(boolean isDeoptEntry, ReusableTypeReader readBuffer, FrameInfoQueryResultAllocator resultAllocator, FrameInfoState state,
int methodIdAddend) {
FrameInfoQueryResult result = null;
FrameInfoQueryResult prev = null;

Expand Down Expand Up @@ -340,13 +341,13 @@ private static FrameInfoQueryResult decodeCompressedFrameInfo(boolean isDeoptEnt

int methodId = readBuffer.getSVInt();
VMError.guarantee(!CompressedFrameDecoderHelper.isSharedFramePointer(methodId));
decodeCompressedFrameData(readBuffer, state, methodId, cur);
decodeCompressedFrameData(readBuffer, state, methodId, cur, methodIdAddend);

// jump back to frame slice information
readBuffer.setByteIndex(bufferIndexToRestore);
bufferIndexToRestore = -1;
} else {
decodeCompressedFrameData(readBuffer, state, firstEntry, cur);
decodeCompressedFrameData(readBuffer, state, firstEntry, cur, methodIdAddend);
}

if (bufferIndexToRestore != -1) {
Expand All @@ -373,8 +374,8 @@ private static FrameInfoQueryResult newFrameInfoQueryResult(FrameInfoQueryResult
}

@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
private static void decodeCompressedFrameData(ReusableTypeReader readBuffer, FrameInfoState state, int methodId, FrameInfoQueryResult queryResult) {
queryResult.sourceMethodId = methodId;
private static void decodeCompressedFrameData(ReusableTypeReader readBuffer, FrameInfoState state, int methodId, FrameInfoQueryResult queryResult, int methodIdAddend) {
queryResult.sourceMethodId = methodId + methodIdAddend;

int encodedSourceLineNumber = readBuffer.getSVInt();
long compressedBci = readBuffer.getSV();
Expand All @@ -400,6 +401,7 @@ private static FrameInfoQueryResult decodeUncompressedFrameInfo(boolean isDeoptE
FrameInfoQueryResult prev = null;
ValueInfo[][] virtualObjects = null;

int methodIdAddend = CodeInfoAccess.getMethodTableFirstId(info);
while (!state.isDone) {
long start = readBuffer.getByteIndex();
long encodedBci = readBuffer.getUV();
Expand Down Expand Up @@ -460,7 +462,7 @@ private static FrameInfoQueryResult decodeUncompressedFrameInfo(boolean isDeoptE
}
cur.virtualObjects = virtualObjects;

cur.sourceMethodId = readBuffer.getSVInt();
cur.sourceMethodId = readBuffer.getSVInt() + methodIdAddend;
cur.sourceLineNumber = readBuffer.getSVInt();

if (prev == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1052,15 +1052,16 @@ void verifyEncoding(CodeInfo info) {
for (FrameData expectedData : allDebugInfos) {
ReusableTypeReader reader = new ReusableTypeReader(CodeInfoAccess.getFrameInfoEncodings(info), expectedData.encodedFrameInfoIndex);
FrameInfoQueryResult actualFrame = FrameInfoDecoder.decodeFrameInfo(expectedData.frame.isDeoptEntry, reader, info, constantAccess);
FrameInfoVerifier.verifyFrames(expectedData, expectedData.frame, actualFrame);
FrameInfoVerifier.verifyFrames(expectedData, expectedData.frame, actualFrame, info);
}
}
}

class FrameInfoVerifier {
protected static void verifyFrames(FrameInfoEncoder.FrameData expectedData, FrameInfoQueryResult expectedTopFrame, FrameInfoQueryResult actualTopFrame) {
protected static void verifyFrames(FrameInfoEncoder.FrameData expectedData, FrameInfoQueryResult expectedTopFrame, FrameInfoQueryResult actualTopFrame, CodeInfo info) {
FrameInfoQueryResult expectedFrame = expectedTopFrame;
FrameInfoQueryResult actualFrame = actualTopFrame;
int methodIdAddend = CodeInfoAccess.getMethodTableFirstId(info);
while (expectedFrame != null) {
assert actualFrame != null;
assert expectedFrame.isDeoptEntry() == actualFrame.isDeoptEntry() : actualFrame;
Expand All @@ -1079,7 +1080,7 @@ protected static void verifyFrames(FrameInfoEncoder.FrameData expectedData, Fram
assert actualFrame.getVirtualObjects() == actualTopFrame.getVirtualObjects() : actualFrame;
}

assert expectedFrame.getSourceMethodId() == actualFrame.getSourceMethodId() : actualFrame;
assert expectedFrame.getSourceMethodId() == (actualFrame.getSourceMethodId() - methodIdAddend) : actualFrame;
assert expectedFrame.getSourceLineNumber() == actualFrame.getSourceLineNumber() : actualFrame;

expectedFrame = expectedFrame.caller;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,33 +24,35 @@
*/
package com.oracle.svm.core.code;

import java.util.EnumSet;
import java.util.List;

import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.c.function.CodePointer;
import org.graalvm.word.ComparableWord;
import org.graalvm.word.UnsignedWord;
import org.graalvm.word.WordFactory;

import com.oracle.svm.core.BuildPhaseProvider.AfterCompilation;
import com.oracle.svm.core.Uninterruptible;
import com.oracle.svm.core.c.CIsolateData;
import com.oracle.svm.core.c.CIsolateDataFactory;
import com.oracle.svm.core.c.NonmovableArray;
import com.oracle.svm.core.c.NonmovableArrays;
import com.oracle.svm.core.c.NonmovableObjectArray;
import com.oracle.svm.core.heap.UnknownObjectField;
import com.oracle.svm.core.heap.UnknownPrimitiveField;
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton;
import com.oracle.svm.core.nmt.NmtCategory;
import com.oracle.svm.core.util.VMError;

import jdk.graal.compiler.word.Word;

public class ImageCodeInfo {
public class ImageCodeInfo implements MultiLayeredImageSingleton, UnsavedSingleton {
public static final String CODE_INFO_NAME = "image code";

private final CIsolateData<CodeInfoImpl> runtimeCodeInfo = CIsolateDataFactory.createStruct("runtimeCodeInfo", CodeInfoImpl.class);

@Platforms(Platform.HOSTED_ONLY.class) //
private final HostedImageCodeInfo hostedImageCodeInfo = new HostedImageCodeInfo();

Expand Down Expand Up @@ -85,28 +87,49 @@ public class ImageCodeInfo {

@Uninterruptible(reason = "Executes during isolate creation.")
CodeInfo prepareCodeInfo() {
CodeInfoImpl info = runtimeCodeInfo.get();
assert info.getCodeStart().isNull() : "already initialized";

info.setObjectFields(NonmovableArrays.fromImageHeap(objectFields));
info.setCodeStart(codeStart);
info.setCodeSize(codeSize);
info.setDataOffset(dataOffset);
info.setDataSize(dataSize);
info.setCodeAndDataMemorySize(codeAndDataMemorySize);
info.setCodeInfoIndex(NonmovableArrays.fromImageHeap(codeInfoIndex));
info.setCodeInfoEncodings(NonmovableArrays.fromImageHeap(codeInfoEncodings));
info.setStackReferenceMapEncoding(NonmovableArrays.fromImageHeap(referenceMapEncoding));
info.setFrameInfoEncodings(NonmovableArrays.fromImageHeap(frameInfoEncodings));
info.setObjectConstants(NonmovableArrays.fromImageHeap(objectConstants));
info.setClasses(NonmovableArrays.fromImageHeap(classes));
info.setMemberNames(NonmovableArrays.fromImageHeap(memberNames));
info.setOtherStrings(NonmovableArrays.fromImageHeap(otherStrings));
info.setMethodTable(NonmovableArrays.fromImageHeap(methodTable));
info.setMethodTableFirstId(methodTableFirstId);
info.setIsAOTImageCode(true);

return info;
if (!ImageLayerBuildingSupport.buildingImageLayer()) {
ImageCodeInfo imageCodeInfo = CodeInfoTable.getImageCodeCache();
CodeInfoImpl codeInfo = ImageCodeInfoStorage.get();
return ImageCodeInfo.prepareCodeInfo0(imageCodeInfo, codeInfo, WordFactory.nullPointer());
} else {
ImageCodeInfo[] imageCodeInfos = MultiLayeredImageSingleton.getAllLayers(ImageCodeInfo.class);
ImageCodeInfoStorage[] runtimeCodeInfos = MultiLayeredImageSingleton.getAllLayers(ImageCodeInfoStorage.class);
int size = imageCodeInfos.length;
for (int i = 0; i < size; i++) {
ImageCodeInfo imageCodeInfo = imageCodeInfos[i];
CodeInfoImpl codeInfoImpl = runtimeCodeInfos[i].getData();
CodeInfoImpl nextCodeInfoImpl = i + 1 < size ? runtimeCodeInfos[i + 1].getData() : WordFactory.nullPointer();

ImageCodeInfo.prepareCodeInfo0(imageCodeInfo, codeInfoImpl, nextCodeInfoImpl);
}
return runtimeCodeInfos[0].getData();
}
}

@Uninterruptible(reason = "Executes during isolate creation.")
private static CodeInfo prepareCodeInfo0(ImageCodeInfo imageCodeInfo, CodeInfoImpl infoImpl, CodeInfo next) {
assert infoImpl.getCodeStart().isNull() : "already initialized";

infoImpl.setObjectFields(NonmovableArrays.fromImageHeap(imageCodeInfo.objectFields));
infoImpl.setCodeStart(imageCodeInfo.codeStart);
infoImpl.setCodeSize(imageCodeInfo.codeSize);
infoImpl.setDataOffset(imageCodeInfo.dataOffset);
infoImpl.setDataSize(imageCodeInfo.dataSize);
infoImpl.setCodeAndDataMemorySize(imageCodeInfo.codeAndDataMemorySize);
infoImpl.setCodeInfoIndex(NonmovableArrays.fromImageHeap(imageCodeInfo.codeInfoIndex));
infoImpl.setCodeInfoEncodings(NonmovableArrays.fromImageHeap(imageCodeInfo.codeInfoEncodings));
infoImpl.setStackReferenceMapEncoding(NonmovableArrays.fromImageHeap(imageCodeInfo.referenceMapEncoding));
infoImpl.setFrameInfoEncodings(NonmovableArrays.fromImageHeap(imageCodeInfo.frameInfoEncodings));
infoImpl.setObjectConstants(NonmovableArrays.fromImageHeap(imageCodeInfo.objectConstants));
infoImpl.setClasses(NonmovableArrays.fromImageHeap(imageCodeInfo.classes));
infoImpl.setMemberNames(NonmovableArrays.fromImageHeap(imageCodeInfo.memberNames));
infoImpl.setOtherStrings(NonmovableArrays.fromImageHeap(imageCodeInfo.otherStrings));
infoImpl.setMethodTable(NonmovableArrays.fromImageHeap(imageCodeInfo.methodTable));
infoImpl.setMethodTableFirstId(imageCodeInfo.methodTableFirstId);
infoImpl.setIsAOTImageCode(true);
infoImpl.setNextImageCodeInfo(next);

return infoImpl;
}

/**
Expand All @@ -126,6 +149,11 @@ public List<Integer> getTotalByteArrayLengths() {
return List.of(codeInfoIndex.length, codeInfoEncodings.length, referenceMapEncoding.length, frameInfoEncodings.length, methodTable.length);
}

@Override
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
return LayeredImageSingletonBuilderFlags.ALL_ACCESS;
}

/**
* Pure-hosted {@link CodeInfo} to collect and persist image code metadata in
* {@link ImageCodeInfo} and provide accesses during image generation.
Expand Down
Loading