From fb99d593ef659919084ce2e0add2ca3686b31baf Mon Sep 17 00:00:00 2001 From: jovsteva Date: Mon, 11 Mar 2024 11:06:39 +0100 Subject: [PATCH 1/3] Add method modifier to JfrMethod entry. --- .../com/oracle/svm/core/code/FrameInfoDecoder.java | 3 +++ .../com/oracle/svm/core/code/FrameInfoEncoder.java | 13 +++++++++---- .../oracle/svm/core/code/FrameInfoQueryResult.java | 11 +++++++++++ .../oracle/svm/core/jfr/JfrMethodRepository.java | 5 ++--- .../sampler/SamplerJfrStackTraceSerializer.java | 2 +- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java index 78c012ffca04..1a780a2f4f5d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java @@ -378,9 +378,11 @@ private static void decodeCompressedFrameData(ReusableTypeReader readBuffer, Fra int encodedSourceLineNumber = readBuffer.getSVInt(); long compressedBci = readBuffer.getSV(); + int sourceMethodModifier = readBuffer.getSVInt(); queryResult.sourceLineNumber = CompressedFrameDecoderHelper.decodeSourceLineNumber(encodedSourceLineNumber); queryResult.encodedBci = CompressedFrameDecoderHelper.decodeCompressedEncodedBci(compressedBci); + queryResult.sourceMethodModifier = sourceMethodModifier; if (CompressedFrameDecoderHelper.hasEncodedUniqueSharedFrameSuccessor(compressedBci)) { state.successorIndex = readBuffer.getSVInt(); @@ -462,6 +464,7 @@ private static FrameInfoQueryResult decodeUncompressedFrameInfo(boolean isDeoptE cur.sourceMethodId = readBuffer.getSVInt(); cur.sourceLineNumber = readBuffer.getSVInt(); + cur.sourceMethodModifier = readBuffer.getUVInt(); if (prev == null) { // first frame read during this invocation 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..6974c4228277 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 @@ -145,6 +145,7 @@ protected void fillSourceFields(ResolvedJavaMethod method, FrameInfoQueryResult */ String sourceMethodName = stringTable.deduplicate(source.getMethodName(), true); resultFrameInfo.setSourceClassAndMethodName(sourceClass, sourceMethodName); + resultFrameInfo.sourceMethodModifier = method.getModifiers(); } protected abstract Class getDeclaringJavaClass(ResolvedJavaMethod method); @@ -161,6 +162,7 @@ protected void fillSourceFields(ResolvedJavaMethod method, FrameInfoQueryResult FrameInfoQueryResult targetFrameInfo = targetCodeInfo.getFrameInfo(); resultFrameInfo.sourceMethodId = targetFrameInfo.sourceMethodId; resultFrameInfo.sourceLineNumber = targetFrameInfo.sourceLineNumber; + resultFrameInfo.sourceMethodModifier = targetFrameInfo.sourceMethodModifier; } } else { /* @@ -199,6 +201,7 @@ record CompressedFrameData( String sourceMethodName, int sourceLineNumber, long encodedBci, + int sourceMethodModifier, boolean isSliceEnd) { } @@ -407,6 +410,7 @@ private static void encodeCompressedFrame(UnsafeArrayTypeWriter encodingBuffer, boolean encodeUniqueSuccessor = uniqueSuccessorIndex != NO_SUCCESSOR_INDEX_MARKER; encodingBuffer.putSV(encodeCompressedSourceLineNumber(frame.sourceLineNumber, frame.isSliceEnd)); encodingBuffer.putSV(encodeCompressedEncodedBci(frame.encodedBci, encodeUniqueSuccessor)); + encodingBuffer.putSV(frame.sourceMethodModifier); if (encodeUniqueSuccessor) { encodingBuffer.putSV(uniqueSuccessorIndex); } @@ -428,13 +432,13 @@ 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.sourceMethodModifier, 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); + cur.getSourceMethodName(), cur.sourceLineNumber, cur.encodedBci, cur.sourceMethodModifier, isSliceEnd); assert expected.equals(slice.get(curIdx)) : expected; curIdx++; } @@ -494,7 +498,7 @@ protected FrameData addDebugInfo(ResolvedJavaMethod method, CompilationResult co 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)); + resultFrame.getSourceMethodName(), resultFrame.sourceLineNumber, resultFrame.encodedBci, resultFrame.sourceMethodModifier,, (resultFrame.caller == null)); frameSlice.add(frame); } @@ -522,7 +526,7 @@ protected FrameData addDefaultDebugInfo(ResolvedJavaMethod method, int totalFram // 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); + data.frame.getSourceMethodName(), data.frame.sourceLineNumber, data.frame.encodedBci, data.frame.sourceMethodModifier, true); frameMetadata.addFrameSlice(data, List.of(frame)); allDebugInfos.add(data); @@ -956,6 +960,7 @@ private void encodeUncompressedFrameData(FrameData data, UnsafeArrayTypeWriter e encodingBuffer.putSV(cur.sourceMethodId); encodingBuffer.putSV(cur.sourceLineNumber); + encodingBuffer.putUV(cur.sourceMethodModifier); } encodingBuffer.putUV(FrameInfoDecoder.ENCODED_BCI_NO_CALLER); } 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..08fe66b76335 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 @@ -172,6 +172,11 @@ public JavaConstant getValue() { protected ValueInfo[][] virtualObjects; protected int sourceMethodId; protected int sourceLineNumber; +<<<<<<< HEAD +======= + protected int methodId; + protected int sourceMethodModifier; +>>>>>>> 869b8ba04c4 (Add method modifier to JfrMethod entry.) /* These are used only for constructing/encoding the code and frame info, or as cache. */ private ResolvedJavaMethod sourceMethod; @@ -198,6 +203,7 @@ public void init() { virtualObjects = null; sourceMethodId = 0; sourceLineNumber = -1; + sourceMethodModifier = -1; sourceMethod = null; sourceClass = Encoders.INVALID_CLASS; @@ -393,6 +399,11 @@ public int getSourceMethodId() { return sourceMethodId; } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public int getSourceMethodModifier() { + return sourceMethodModifier; + } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public String getSourceFileName() { Class clazz = getSourceClass(); 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..da05ddd47f83 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, int methodId, int methodModifier) { assert clazz != null; assert methodName != null; assert methodId > 0; @@ -89,8 +89,7 @@ public long getMethodId(Class clazz, String methodName, int methodId) { 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.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..8fcbdf6bee5c 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,7 @@ 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.getSourceMethodId(), stackTraceElement.getSourceMethodModifier()); JfrNativeEventWriter.putLong(data, methodId); JfrNativeEventWriter.putInt(data, stackTraceElement.getSourceLineNumber()); JfrNativeEventWriter.putInt(data, stackTraceElement.getBci()); From 5d849ca464842a02c46dbdeb77b1263db5ad84fe Mon Sep 17 00:00:00 2001 From: jovsteva Date: Mon, 11 Mar 2024 11:36:10 +0100 Subject: [PATCH 2/3] Add method signature to a JfrMethod entry. --- .../oracle/svm/core/code/CodeInfoDecoder.java | 38 ++++++++++++-- .../oracle/svm/core/code/CodeInfoEncoder.java | 45 ++++++++++++---- .../svm/core/code/FrameInfoDecoder.java | 3 -- .../svm/core/code/FrameInfoEncoder.java | 38 ++++++++------ .../svm/core/code/FrameInfoQueryResult.java | 52 ++++++++++--------- .../svm/core/jfr/JfrMethodRepository.java | 5 +- .../SamplerJfrStackTraceSerializer.java | 3 +- 7 files changed, 122 insertions(+), 62 deletions(-) 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..c3d525c8fac8 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 = readSourceFieldOffset(p, shortClass, classOffset); Class sourceClass = NonmovableArrays.getObject(CodeInfoAccess.getClasses(info), classIndex); - int methodNameIndex = shortName ? (p.readShort(classBytes) & 0xffff) : p.readInt(classBytes); + int methodNameIndex = readSourceFieldOffset(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 = readSourceFieldOffset(p, shortSignature, signatureOffset); + sourceMethodSignature = NonmovableArrays.getObject(CodeInfoAccess.getOtherStrings(info), sourceSignatureIndex); + + sourceSignatureModifiers = readSourceFieldOffset(p, true, modifierOffset); + } + result.setSourceFields(sourceClass, sourceMethodName, sourceMethodSignature, sourceSignatureModifiers); + } + + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) + private static int readSourceFieldOffset(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/FrameInfoDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java index 1a780a2f4f5d..78c012ffca04 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java @@ -378,11 +378,9 @@ private static void decodeCompressedFrameData(ReusableTypeReader readBuffer, Fra int encodedSourceLineNumber = readBuffer.getSVInt(); long compressedBci = readBuffer.getSV(); - int sourceMethodModifier = readBuffer.getSVInt(); queryResult.sourceLineNumber = CompressedFrameDecoderHelper.decodeSourceLineNumber(encodedSourceLineNumber); queryResult.encodedBci = CompressedFrameDecoderHelper.decodeCompressedEncodedBci(compressedBci); - queryResult.sourceMethodModifier = sourceMethodModifier; if (CompressedFrameDecoderHelper.hasEncodedUniqueSharedFrameSuccessor(compressedBci)) { state.successorIndex = readBuffer.getSVInt(); @@ -464,7 +462,6 @@ private static FrameInfoQueryResult decodeUncompressedFrameInfo(boolean isDeoptE cur.sourceMethodId = readBuffer.getSVInt(); cur.sourceLineNumber = readBuffer.getSVInt(); - cur.sourceMethodModifier = readBuffer.getUVInt(); if (prev == null) { // first frame read during this invocation 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 6974c4228277..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,9 +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); - resultFrameInfo.sourceMethodModifier = method.getModifiers(); + String sourceMethodSignature = CodeInfoEncoder.shouldEncodeAllMethodMetadata() ? stringTable.deduplicate(methodSignature, true) : methodSignature; + resultFrameInfo.setSourceFields(sourceClass, sourceMethodName, sourceMethodSignature, sourceMethodModifiers); } protected abstract Class getDeclaringJavaClass(ResolvedJavaMethod method); @@ -162,7 +164,6 @@ protected void fillSourceFields(ResolvedJavaMethod method, FrameInfoQueryResult FrameInfoQueryResult targetFrameInfo = targetCodeInfo.getFrameInfo(); resultFrameInfo.sourceMethodId = targetFrameInfo.sourceMethodId; resultFrameInfo.sourceLineNumber = targetFrameInfo.sourceLineNumber; - resultFrameInfo.sourceMethodModifier = targetFrameInfo.sourceMethodModifier; } } else { /* @@ -199,9 +200,10 @@ record CompressedFrameData( ResolvedJavaMethod sourceMethod, // for when methodId is not yet known (== 0) Class sourceClass, String sourceMethodName, + String sourceMethodSignature, + int sourceMethodModifier, int sourceLineNumber, long encodedBci, - int sourceMethodModifier, boolean isSliceEnd) { } @@ -403,14 +405,13 @@ 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)); boolean encodeUniqueSuccessor = uniqueSuccessorIndex != NO_SUCCESSOR_INDEX_MARKER; encodingBuffer.putSV(encodeCompressedSourceLineNumber(frame.sourceLineNumber, frame.isSliceEnd)); encodingBuffer.putSV(encodeCompressedEncodedBci(frame.encodedBci, encodeUniqueSuccessor)); - encodingBuffer.putSV(frame.sourceMethodModifier); if (encodeUniqueSuccessor) { encodingBuffer.putSV(uniqueSuccessorIndex); } @@ -432,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(), cur.sourceMethodModifier, 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, cur.sourceMethodModifier, 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++; } @@ -491,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.sourceMethodModifier,, (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); } @@ -521,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, data.frame.sourceMethodModifier, 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); @@ -955,12 +959,12 @@ 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); encodingBuffer.putSV(cur.sourceLineNumber); - encodingBuffer.putUV(cur.sourceMethodModifier); } encodingBuffer.putUV(FrameInfoDecoder.ENCODED_BCI_NO_CALLER); } 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 08fe66b76335..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; @@ -172,16 +174,13 @@ public JavaConstant getValue() { protected ValueInfo[][] virtualObjects; protected int sourceMethodId; protected int sourceLineNumber; -<<<<<<< HEAD -======= - protected int methodId; - protected int sourceMethodModifier; ->>>>>>> 869b8ba04c4 (Add method modifier to JfrMethod entry.) /* These are used only for constructing/encoding the code and frame info, or as cache. */ private ResolvedJavaMethod sourceMethod; private Class sourceClass; private String sourceMethodName; + private int sourceMethodModifiers; + private String sourceMethodSignature; @SuppressWarnings("this-escape") public FrameInfoQueryResult() { @@ -203,11 +202,12 @@ public void init() { virtualObjects = null; sourceMethodId = 0; sourceLineNumber = -1; - sourceMethodModifier = -1; sourceMethod = null; sourceClass = Encoders.INVALID_CLASS; sourceMethodName = Encoders.INVALID_METHOD_NAME; + sourceMethodSignature = Encoders.INVALID_METHOD_SIGNATURE; + sourceMethodModifiers = Encoders.INVALID_METHOD_MODIFIERS; } /** @@ -342,7 +342,7 @@ public ValueInfo[][] getVirtualObjects() { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public Class getSourceClass() { - fillInSourceClassAndMethodNameIfMissing(); + fillSourceFieldsIfMissing(); return sourceClass; } @@ -353,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() { @@ -399,9 +396,16 @@ public int getSourceMethodId() { return sourceMethodId; } - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public int getSourceMethodModifier() { - return sourceMethodModifier; + @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) @@ -417,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); } @@ -447,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 da05ddd47f83..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, int methodModifier) { + public long getMethodId(Class clazz, String methodName, String methodSignature, int methodId, int methodModifier) { assert clazz != null; assert methodName != null; assert methodId > 0; @@ -87,8 +87,7 @@ public long getMethodId(Class clazz, String methodName, int methodId, int met 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)); + JfrNativeEventWriter.putLong(data, symbolRepo.getSymbolId(methodSignature, false)); JfrNativeEventWriter.putInt(data, methodModifier); JfrNativeEventWriter.putBoolean(data, !StackTraceUtils.shouldShowFrame(clazz, methodName)); if (!JfrNativeEventWriter.commit(data)) { 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 8fcbdf6bee5c..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(), stackTraceElement.getSourceMethodModifier()); + 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()); From ac9eab3120d8c992c06e37a6f128c59c71c0dcbc Mon Sep 17 00:00:00 2001 From: jovsteva Date: Wed, 22 May 2024 10:30:54 +0200 Subject: [PATCH 3/3] Extend TestStackTraceEvent to include method signature and modifiers checks. --- .../oracle/svm/core/code/CodeInfoDecoder.java | 10 ++-- .../svm/test/jfr/TestStackTraceEvent.java | 52 +++++++++++++++++++ 2 files changed, 57 insertions(+), 5 deletions(-) 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 c3d525c8fac8..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 @@ -458,24 +458,24 @@ static void fillSourceFields(FrameInfoQueryResult result) { VMError.guarantee(methodIndex >= 0 && methodIndex < NonmovableArrays.lengthOf(methodEncodings) / entryBytes); Pointer p = NonmovableArrays.addressOf(methodEncodings, methodIndex * entryBytes); - int classIndex = readSourceFieldOffset(p, shortClass, classOffset); + int classIndex = readIndex(p, shortClass, classOffset); Class sourceClass = NonmovableArrays.getObject(CodeInfoAccess.getClasses(info), classIndex); - int methodNameIndex = readSourceFieldOffset(p, shortName, nameOffset); + int methodNameIndex = readIndex(p, shortName, nameOffset); String sourceMethodName = NonmovableArrays.getObject(CodeInfoAccess.getMemberNames(info), methodNameIndex); String sourceMethodSignature = CodeInfoEncoder.Encoders.INVALID_METHOD_SIGNATURE; int sourceSignatureModifiers = CodeInfoEncoder.Encoders.INVALID_METHOD_MODIFIERS; if (CodeInfoEncoder.shouldEncodeAllMethodMetadata()) { - int sourceSignatureIndex = readSourceFieldOffset(p, shortSignature, signatureOffset); + int sourceSignatureIndex = readIndex(p, shortSignature, signatureOffset); sourceMethodSignature = NonmovableArrays.getObject(CodeInfoAccess.getOtherStrings(info), sourceSignatureIndex); - sourceSignatureModifiers = readSourceFieldOffset(p, true, modifierOffset); + sourceSignatureModifiers = readIndex(p, true, modifierOffset); } result.setSourceFields(sourceClass, sourceMethodName, sourceMethodSignature, sourceSignatureModifiers); } @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) - private static int readSourceFieldOffset(Pointer p, boolean isShort, int offset) { + private static int readIndex(Pointer p, boolean isShort, int offset) { return isShort ? (p.readShort(offset) & 0xffff) : p.readInt(offset); } 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) { + } }