Skip to content

Commit

Permalink
[GR-53669] Add layered stack walking support
Browse files Browse the repository at this point in the history
PullRequest: graal/18085
  • Loading branch information
teshull committed Jun 24, 2024
2 parents 0517eee + 0f58a18 commit ee0e5b6
Show file tree
Hide file tree
Showing 13 changed files with 365 additions and 64 deletions.
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

0 comments on commit ee0e5b6

Please sign in to comment.