diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoDecoder.java index f0019b45b7ab..7ca918d5f46b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoDecoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoDecoder.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.code; +import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE; import static com.oracle.svm.core.util.VMError.shouldNotReachHereUnexpectedInput; import org.graalvm.nativeimage.ImageSingletons; @@ -423,7 +424,7 @@ private static FrameInfoQueryResult loadFrameInfo(CodeInfo info, long entryOffse * @see CodeInfoEncoder.Encoders#encodeMethodTable */ @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - static void fillInSourceClassAndMethodName(FrameInfoQueryResult result) { + static void fillSourceFields(FrameInfoQueryResult result) { int methodId = result.sourceMethodId; CodeInfo info; CodeInfo next = CodeInfoTable.getFirstImageCodeInfo(); @@ -436,19 +437,46 @@ static void fillInSourceClassAndMethodName(FrameInfoQueryResult result) { boolean shortClass = NonmovableArrays.lengthOf(CodeInfoAccess.getClasses(info)) <= 0xffff; boolean shortName = NonmovableArrays.lengthOf(CodeInfoAccess.getMemberNames(info)) <= 0xffff; + boolean shortSignature = NonmovableArrays.lengthOf(CodeInfoAccess.getOtherStrings(info)) <= 0xffff; int classBytes = shortClass ? Short.BYTES : Integer.BYTES; - int entryBytes = classBytes + (shortName ? Short.BYTES : Integer.BYTES); + int nameBytes = shortName ? Short.BYTES : Integer.BYTES; + int signatureBytes = shortSignature ? Short.BYTES : Integer.BYTES; + int modifierBytes = Short.BYTES; + + int classOffset = 0; + int nameOffset = classOffset + classBytes; + int signatureOffset = nameOffset + nameBytes; + int modifierOffset = signatureOffset + signatureBytes; + + int entryBytes = classBytes + nameBytes; + if (CodeInfoEncoder.shouldEncodeAllMethodMetadata()) { + entryBytes += signatureBytes + modifierBytes; + } int methodIndex = methodId - CodeInfoAccess.getMethodTableFirstId(info); NonmovableArray methodEncodings = CodeInfoAccess.getMethodTable(info); VMError.guarantee(methodIndex >= 0 && methodIndex < NonmovableArrays.lengthOf(methodEncodings) / entryBytes); Pointer p = NonmovableArrays.addressOf(methodEncodings, methodIndex * entryBytes); - int classIndex = shortClass ? (p.readShort(0) & 0xffff) : p.readInt(0); + int classIndex = readIndex(p, shortClass, classOffset); Class sourceClass = NonmovableArrays.getObject(CodeInfoAccess.getClasses(info), classIndex); - int methodNameIndex = shortName ? (p.readShort(classBytes) & 0xffff) : p.readInt(classBytes); + int methodNameIndex = readIndex(p, shortName, nameOffset); String sourceMethodName = NonmovableArrays.getObject(CodeInfoAccess.getMemberNames(info), methodNameIndex); - result.setSourceClassAndMethodName(sourceClass, sourceMethodName); + + String sourceMethodSignature = CodeInfoEncoder.Encoders.INVALID_METHOD_SIGNATURE; + int sourceSignatureModifiers = CodeInfoEncoder.Encoders.INVALID_METHOD_MODIFIERS; + if (CodeInfoEncoder.shouldEncodeAllMethodMetadata()) { + int sourceSignatureIndex = readIndex(p, shortSignature, signatureOffset); + sourceMethodSignature = NonmovableArrays.getObject(CodeInfoAccess.getOtherStrings(info), sourceSignatureIndex); + + sourceSignatureModifiers = readIndex(p, true, modifierOffset); + } + result.setSourceFields(sourceClass, sourceMethodName, sourceMethodSignature, sourceSignatureModifiers); + } + + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) + private static int readIndex(Pointer p, boolean isShort, int offset) { + return isShort ? (p.readShort(offset) & 0xffff) : p.readInt(offset); } @AlwaysInline("Make IP-lookup loop call free") diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoEncoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoEncoder.java index a04e2d5ebd5d..5e24d6f9a13d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoEncoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoEncoder.java @@ -59,6 +59,7 @@ 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.jfr.HasJfrSupport; import com.oracle.svm.core.meta.SharedField; import com.oracle.svm.core.meta.SharedMethod; import com.oracle.svm.core.meta.SharedType; @@ -68,6 +69,7 @@ import com.oracle.svm.core.util.Counter; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.api.replacements.Fold; import jdk.graal.compiler.code.CompilationResult; import jdk.graal.compiler.core.common.NumUtil; import jdk.graal.compiler.core.common.util.FrequencyEncoder; @@ -118,8 +120,10 @@ public void addToReferenceMapSize(long size) { public static final class Encoders { static final Class INVALID_CLASS = null; static final String INVALID_METHOD_NAME = ""; + static final int INVALID_METHOD_MODIFIERS = -1; + static final String INVALID_METHOD_SIGNATURE = null; - public record Member(ResolvedJavaMethod method, Class clazz, String name) { + public record Member(ResolvedJavaMethod method, Class clazz, String name, String signature, int modifiers) { } public final FrequencyEncoder objectConstants; @@ -158,23 +162,29 @@ public Encoders(boolean imageCode) { this.methods.addObject(null); this.classes.addObject(INVALID_CLASS); this.memberNames.addObject(INVALID_METHOD_NAME); + if (shouldEncodeAllMethodMetadata()) { + this.otherStrings.addObject(INVALID_METHOD_SIGNATURE); + } } } - public void addMethod(ResolvedJavaMethod method, Class clazz, String name) { + public void addMethod(ResolvedJavaMethod method, Class clazz, String name, String signature, int modifiers) { VMError.guarantee(SubstrateUtil.HOSTED, "Runtime code info must reference image methods by id"); - Member member = new Member(Objects.requireNonNull(method), clazz, name); + Member member = new Member(Objects.requireNonNull(method), clazz, name, signature, modifiers); if (methods.addObject(member)) { classes.addObject(clazz); memberNames.addObject(name); + if (shouldEncodeAllMethodMetadata()) { + otherStrings.addObject(signature); + } } } - public int findMethodIndex(ResolvedJavaMethod method, Class clazz, String name, boolean optional) { + public int findMethodIndex(ResolvedJavaMethod method, Class clazz, String name, String signature, int modifiers, boolean optional) { VMError.guarantee(SubstrateUtil.HOSTED, "Runtime code info must obtain method ids from image code info"); - Member member = new Member(Objects.requireNonNull(method), clazz, name); + Member member = new Member(Objects.requireNonNull(method), clazz, name, signature, modifiers); return optional ? methods.findIndex(member) : methods.getIndex(member); } @@ -214,7 +224,7 @@ private static T[] encodeArray(FrequencyEncoder encoder, IntFunction * fewer bytes}. Still, the fields of the entries are dimensioned to not be larger than * necessary to index into another array such as {@link #classes}. * - * @see CodeInfoDecoder#fillInSourceClassAndMethodName + * @see CodeInfoDecoder#fillSourceFields */ private NonmovableArray encodeMethodTable() { if (methods == null) { @@ -225,18 +235,21 @@ private NonmovableArray encodeMethodTable() { final boolean shortClassIndexes = (classes.getLength() <= 0xffff); final boolean shortNameIndexes = (memberNames.getLength() <= 0xffff); + final boolean shortSignatureIndexes = (otherStrings.getLength() <= 0xffff); UnsafeArrayTypeWriter writer = UnsafeArrayTypeWriter.create(ByteArrayReader.supportsUnalignedMemoryAccess()); assert encodedMethods[0] == null : "id 0 must mean invalid"; - encodeMethod(writer, INVALID_CLASS, INVALID_METHOD_NAME, shortClassIndexes, shortNameIndexes); + encodeMethod(writer, INVALID_CLASS, INVALID_METHOD_NAME, INVALID_METHOD_SIGNATURE, INVALID_METHOD_MODIFIERS, shortClassIndexes, shortNameIndexes, shortSignatureIndexes); for (int id = 1; id < encodedMethods.length; id++) { - encodeMethod(writer, encodedMethods[id].clazz, encodedMethods[id].name, shortClassIndexes, shortNameIndexes); + encodeMethod(writer, encodedMethods[id].clazz, encodedMethods[id].name, encodedMethods[id].signature, encodedMethods[id].modifiers, shortClassIndexes, shortNameIndexes, + shortSignatureIndexes); } NonmovableArray bytes = NonmovableArrays.createByteArray(NumUtil.safeToInt(writer.getBytesWritten()), NmtCategory.Code); writer.toByteBuffer(NonmovableArrays.asByteBuffer(bytes)); return bytes; } - private void encodeMethod(UnsafeArrayTypeWriter writer, Class clazz, String name, boolean shortClassIndexes, boolean shortNameIndexes) { + private void encodeMethod(UnsafeArrayTypeWriter writer, Class clazz, String name, String signature, int modifiers, boolean shortClassIndexes, boolean shortNameIndexes, + boolean shortSignatureIndexes) { int classIndex = classes.getIndex(clazz); if (shortClassIndexes) { writer.putU2(classIndex); @@ -249,6 +262,15 @@ private void encodeMethod(UnsafeArrayTypeWriter writer, Class clazz, String n } else { writer.putU4(memberNamesIndex); } + if (shouldEncodeAllMethodMetadata()) { + int signatureNamesIndex = otherStrings.getIndex(signature); + if (shortSignatureIndexes) { + writer.putU2(signatureNamesIndex); + } else { + writer.putU4(signatureNamesIndex); + } + writer.putS2(modifiers); + } } @Uninterruptible(reason = "Nonmovable object arrays are not visible to GC until installed in target.") @@ -300,6 +322,11 @@ public Encoders getEncoders() { return encoders; } + @Fold + public static boolean shouldEncodeAllMethodMetadata() { + return HasJfrSupport.get(); + } + public static int getEntryOffset(Infopoint infopoint) { if (infopoint instanceof Call || infopoint instanceof DeoptEntryInfopoint) { int offset = infopoint.pcOffset; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoEncoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoEncoder.java index 1c6e65410c55..41a1dd5488dc 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoEncoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoEncoder.java @@ -143,8 +143,11 @@ protected void fillSourceFields(ResolvedJavaMethod method, FrameInfoQueryResult * StackTraceElement contains interned strings, so we un-intern these strings and * perform our own de-duplication. */ + int sourceMethodModifiers = method.getModifiers(); + String methodSignature = method.getSignature().toMethodDescriptor(); String sourceMethodName = stringTable.deduplicate(source.getMethodName(), true); - resultFrameInfo.setSourceClassAndMethodName(sourceClass, sourceMethodName); + String sourceMethodSignature = CodeInfoEncoder.shouldEncodeAllMethodMetadata() ? stringTable.deduplicate(methodSignature, true) : methodSignature; + resultFrameInfo.setSourceFields(sourceClass, sourceMethodName, sourceMethodSignature, sourceMethodModifiers); } protected abstract Class getDeclaringJavaClass(ResolvedJavaMethod method); @@ -197,6 +200,8 @@ record CompressedFrameData( ResolvedJavaMethod sourceMethod, // for when methodId is not yet known (== 0) Class sourceClass, String sourceMethodName, + String sourceMethodSignature, + int sourceMethodModifier, int sourceLineNumber, long encodedBci, boolean isSliceEnd) { @@ -400,7 +405,7 @@ private static void encodeCompressedFrame(UnsafeArrayTypeWriter encodingBuffer, int methodId = frame.methodId; if (frame.sourceMethod != null) { assert methodId == 0; - methodId = encoders.findMethodIndex(frame.sourceMethod, frame.sourceClass, frame.sourceMethodName, false); + methodId = encoders.findMethodIndex(frame.sourceMethod, frame.sourceClass, frame.sourceMethodName, frame.sourceMethodSignature, frame.sourceMethodModifier, false); } encodingBuffer.putSV(encodeCompressedFirstEntry(methodId, true)); @@ -428,13 +433,14 @@ boolean writeFrameVerificationInfo(FrameData data, Encoders encoders) { int previousMethodId = cur.sourceMethodId; if (cur.getSourceMethod() != null) { - cur.sourceMethodId = encoders.findMethodIndex(cur.getSourceMethod(), cur.getSourceClass(), cur.getSourceMethodName(), false); + cur.sourceMethodId = encoders.findMethodIndex(cur.getSourceMethod(), cur.getSourceClass(), cur.getSourceMethodName(), cur.getSourceMethodSignature(), + cur.getSourceMethodModifiers(), false); assert previousMethodId == 0 || previousMethodId == cur.sourceMethodId; } boolean isSliceEnd = (cur.caller == null); - CompressedFrameData expected = new CompressedFrameData(previousMethodId, cur.getSourceMethod(), cur.getSourceClass(), - cur.getSourceMethodName(), cur.sourceLineNumber, cur.encodedBci, isSliceEnd); + CompressedFrameData expected = new CompressedFrameData(previousMethodId, cur.getSourceMethod(), cur.getSourceClass(), cur.getSourceMethodName(), + cur.getSourceMethodSignature(), cur.getSourceMethodModifiers(), cur.sourceLineNumber, cur.encodedBci, isSliceEnd); assert expected.equals(slice.get(curIdx)) : expected; curIdx++; } @@ -487,14 +493,15 @@ protected FrameData addDebugInfo(ResolvedJavaMethod method, CompilationResult co if (resultFrame.getSourceMethod() != null) { assert resultFrame.sourceMethodId == 0; - encoders.addMethod(resultFrame.getSourceMethod(), resultFrame.getSourceClass(), resultFrame.getSourceMethodName()); + encoders.addMethod(resultFrame.getSourceMethod(), resultFrame.getSourceClass(), resultFrame.getSourceMethodName(), resultFrame.getSourceMethodSignature(), + resultFrame.getSourceMethodModifiers()); } // save encoding metadata assert resultFrame.hasLocalValueInfo() == includeLocalValues : resultFrame; if (!includeLocalValues) { - CompressedFrameData frame = new CompressedFrameData(resultFrame.sourceMethodId, resultFrame.getSourceMethod(), resultFrame.getSourceClass(), - resultFrame.getSourceMethodName(), resultFrame.sourceLineNumber, resultFrame.encodedBci, (resultFrame.caller == null)); + CompressedFrameData frame = new CompressedFrameData(resultFrame.sourceMethodId, resultFrame.getSourceMethod(), resultFrame.getSourceClass(), resultFrame.getSourceMethodName(), + resultFrame.getSourceMethodSignature(), resultFrame.getSourceMethodModifiers(), resultFrame.sourceLineNumber, resultFrame.encodedBci, (resultFrame.caller == null)); frameSlice.add(frame); } @@ -517,12 +524,13 @@ protected FrameData addDefaultDebugInfo(ResolvedJavaMethod method, int totalFram if (data.frame.getSourceMethod() != null) { assert data.frame.sourceMethodId == 0; - encoders.addMethod(data.frame.getSourceMethod(), data.frame.getSourceClass(), data.frame.getSourceMethodName()); + encoders.addMethod(data.frame.getSourceMethod(), data.frame.getSourceClass(), data.frame.getSourceMethodName(), data.frame.getSourceMethodSignature(), + data.frame.getSourceMethodModifiers()); } // save encoding metadata - CompressedFrameData frame = new CompressedFrameData(data.frame.sourceMethodId, data.frame.getSourceMethod(), data.frame.getSourceClass(), - data.frame.getSourceMethodName(), data.frame.sourceLineNumber, data.frame.encodedBci, true); + CompressedFrameData frame = new CompressedFrameData(data.frame.sourceMethodId, data.frame.getSourceMethod(), data.frame.getSourceClass(), data.frame.getSourceMethodName(), + data.frame.getSourceMethodSignature(), data.frame.getSourceMethodModifiers(), data.frame.sourceLineNumber, data.frame.encodedBci, true); frameMetadata.addFrameSlice(data, List.of(frame)); allDebugInfos.add(data); @@ -951,7 +959,8 @@ private void encodeUncompressedFrameData(FrameData data, UnsafeArrayTypeWriter e if (cur.getSourceMethod() != null) { assert cur.sourceMethodId == 0; - cur.sourceMethodId = encoders.findMethodIndex(cur.getSourceMethod(), cur.getSourceClass(), cur.getSourceMethodName(), false); + cur.sourceMethodId = encoders.findMethodIndex(cur.getSourceMethod(), cur.getSourceClass(), cur.getSourceMethodName(), cur.getSourceMethodSignature(), cur.getSourceMethodModifiers(), + false); } encodingBuffer.putSV(cur.sourceMethodId); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java index e772958431d2..a377061d9831 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.core.code; +import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE; + import java.lang.module.ModuleDescriptor; import java.util.Optional; @@ -177,6 +179,8 @@ public JavaConstant getValue() { private ResolvedJavaMethod sourceMethod; private Class sourceClass; private String sourceMethodName; + private int sourceMethodModifiers; + private String sourceMethodSignature; @SuppressWarnings("this-escape") public FrameInfoQueryResult() { @@ -202,6 +206,8 @@ public void init() { sourceMethod = null; sourceClass = Encoders.INVALID_CLASS; sourceMethodName = Encoders.INVALID_METHOD_NAME; + sourceMethodSignature = Encoders.INVALID_METHOD_SIGNATURE; + sourceMethodModifiers = Encoders.INVALID_METHOD_MODIFIERS; } /** @@ -336,7 +342,7 @@ public ValueInfo[][] getVirtualObjects() { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public Class getSourceClass() { - fillInSourceClassAndMethodNameIfMissing(); + fillSourceFieldsIfMissing(); return sourceClass; } @@ -347,29 +353,26 @@ public String getSourceClassName() { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public String getSourceMethodName() { - fillInSourceClassAndMethodNameIfMissing(); + fillSourceFieldsIfMissing(); return sourceMethodName; } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - private void fillInSourceClassAndMethodNameIfMissing() { - assert (sourceClass == Encoders.INVALID_CLASS) == isSourceMethodNameMissing(); + private void fillSourceFieldsIfMissing() { if (sourceMethodId != 0 && sourceClass == Encoders.INVALID_CLASS) { - CodeInfoDecoder.fillInSourceClassAndMethodName(this); + CodeInfoDecoder.fillSourceFields(this); } } - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "Identity comparison against sentinel string value") - private boolean isSourceMethodNameMissing() { - return sourceMethodName == Encoders.INVALID_METHOD_NAME; - } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - void setSourceClassAndMethodName(Class clazz, String methodName) { - assert sourceClass == Encoders.INVALID_CLASS && isSourceMethodNameMissing(); + void setSourceFields(Class clazz, String methodName, String signature, int modifiers) { + assert sourceClass == Encoders.INVALID_CLASS && sourceMethodName == Encoders.INVALID_METHOD_NAME && sourceMethodSignature == Encoders.INVALID_METHOD_SIGNATURE && + sourceMethodModifiers == Encoders.INVALID_METHOD_MODIFIERS; this.sourceClass = clazz; this.sourceMethodName = methodName; + this.sourceMethodSignature = signature; + this.sourceMethodModifiers = modifiers; } ResolvedJavaMethod getSourceMethod() { @@ -393,6 +396,18 @@ public int getSourceMethodId() { return sourceMethodId; } + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) + public int getSourceMethodModifiers() { + fillSourceFieldsIfMissing(); + return sourceMethodModifiers; + } + + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) + public String getSourceMethodSignature() { + fillSourceFieldsIfMissing(); + return sourceMethodSignature; + } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public String getSourceFileName() { Class clazz = getSourceClass(); @@ -406,7 +421,7 @@ public int getSourceLineNumber() { /** Returns the name and source code location of the method. */ public StackTraceElement getSourceReference() { - fillInSourceClassAndMethodNameIfMissing(); + fillSourceFieldsIfMissing(); return getSourceReference(sourceClass, sourceMethodName, sourceLineNumber); } @@ -436,7 +451,7 @@ public boolean isNativeMethod() { } public Log log(Log log) { - fillInSourceClassAndMethodNameIfMissing(); + fillSourceFieldsIfMissing(); String className = (sourceClass != null) ? sourceClass.getName() : ""; String methodName = (sourceMethodName != null) ? sourceMethodName : ""; log.string(className); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrMethodRepository.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrMethodRepository.java index 0547052b268d..abde3709d4c7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrMethodRepository.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrMethodRepository.java @@ -58,7 +58,7 @@ public void teardown() { } @Uninterruptible(reason = "Locking without transition and result is only valid until epoch changes.", callerMustBe = true) - public long getMethodId(Class clazz, String methodName, int methodId) { + public long getMethodId(Class clazz, String methodName, String methodSignature, int methodId, int methodModifier) { assert clazz != null; assert methodName != null; assert methodId > 0; @@ -87,10 +87,8 @@ public long getMethodId(Class clazz, String methodName, int methodId) { JfrNativeEventWriter.putLong(data, methodId); JfrNativeEventWriter.putLong(data, typeRepo.getClassId(clazz)); JfrNativeEventWriter.putLong(data, symbolRepo.getSymbolId(methodName, false)); - /* Dummy value for signature. */ - JfrNativeEventWriter.putLong(data, symbolRepo.getSymbolId("()V", false)); - /* Dummy value for modifiers. */ - JfrNativeEventWriter.putShort(data, (short) 0); + JfrNativeEventWriter.putLong(data, symbolRepo.getSymbolId(methodSignature, false)); + JfrNativeEventWriter.putInt(data, methodModifier); JfrNativeEventWriter.putBoolean(data, !StackTraceUtils.shouldShowFrame(clazz, methodName)); if (!JfrNativeEventWriter.commit(data)) { return methodId; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/SamplerJfrStackTraceSerializer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/SamplerJfrStackTraceSerializer.java index 0a7ce71a6190..7f1cc49c86d7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/SamplerJfrStackTraceSerializer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/SamplerJfrStackTraceSerializer.java @@ -178,7 +178,8 @@ private static int visitFrame(JfrNativeEventWriterData data, CodeInfo codeInfo, @Uninterruptible(reason = "Prevent JFR recording and epoch change.") private static void serializeStackTraceElement(JfrNativeEventWriterData data, FrameInfoQueryResult stackTraceElement) { - long methodId = SubstrateJVM.getMethodRepo().getMethodId(stackTraceElement.getSourceClass(), stackTraceElement.getSourceMethodName(), stackTraceElement.getSourceMethodId()); + long methodId = SubstrateJVM.getMethodRepo().getMethodId(stackTraceElement.getSourceClass(), stackTraceElement.getSourceMethodName(), + stackTraceElement.getSourceMethodSignature(), stackTraceElement.getSourceMethodId(), stackTraceElement.getSourceMethodModifiers()); JfrNativeEventWriter.putLong(data, methodId); JfrNativeEventWriter.putInt(data, stackTraceElement.getSourceLineNumber()); JfrNativeEventWriter.putInt(data, stackTraceElement.getBci()); diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestStackTraceEvent.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestStackTraceEvent.java index 67fa08c04b7c..920eae40c387 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestStackTraceEvent.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestStackTraceEvent.java @@ -26,20 +26,35 @@ package com.oracle.svm.test.jfr; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import jdk.jfr.consumer.RecordedThread; +import org.junit.Assert; import org.junit.Test; import com.oracle.svm.test.jfr.events.StackTraceEvent; import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedFrame; +import jdk.jfr.consumer.RecordedMethod; +import jdk.jfr.consumer.RecordedStackTrace; /** * Test if event ({@link StackTraceEvent}) with stacktrace payload is working. */ public class TestStackTraceEvent extends JfrRecordingTest { + + private static final JfrSeenMethod junitTest = new JfrSeenMethod("test", "()V", 1); + private static final JfrSeenMethod svmJunitMain = new JfrSeenMethod("main", "([Ljava/lang/String;)V", 9); + private static final JfrSeenMethod javaMainRun = new JfrSeenMethod("doRun", "(ILorg/graalvm/nativeimage/c/type/CCharPointerPointer;)I", 10); + @Test public void test() throws Throwable { String[] events = new String[]{StackTraceEvent.class.getName()}; @@ -57,5 +72,42 @@ public void test() throws Throwable { private static void validateEvents(List events) { assertEquals(1, events.size()); + RecordedEvent event = events.getFirst(); + + long sampledThreadId = event. getValue("eventThread").getJavaThreadId(); + assertTrue(sampledThreadId > 0); + + RecordedStackTrace stackTrace = event.getStackTrace(); + assertNotNull(stackTrace); + + List frames = stackTrace.getFrames(); + assertFalse(frames.isEmpty()); + + Set seenMethod = new HashSet<>(); + for (RecordedFrame frame : frames) { + RecordedMethod method = frame.getMethod(); + assertNotNull(method); + + String methodName = method.getName(); + assertNotNull(methodName); + assertFalse(methodName.isEmpty()); + + String methodDescriptor = method.getDescriptor(); + assertNotNull(methodDescriptor); + assertFalse(methodDescriptor.isEmpty()); + + int methodModifiers = method.getModifiers(); + assertTrue(methodModifiers >= 0); + + seenMethod.add(new JfrSeenMethod(methodName, methodDescriptor, methodModifiers)); + } + + Assert.assertTrue(seenMethod.contains(junitTest)); + Assert.assertTrue(seenMethod.contains(javaMainRun)); + Assert.assertTrue(seenMethod.contains(svmJunitMain)); + } + + private record JfrSeenMethod(String name, String descriptor, int modifier) { + } }