Skip to content

Skip methods with JvmtiMountTransition annotation #18016

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

Merged
merged 1 commit into from
Aug 26, 2023
Merged
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
94 changes: 56 additions & 38 deletions runtime/jvmti/jvmtiExtensionMechanism.c
Original file line number Diff line number Diff line change
@@ -1864,89 +1864,107 @@ jvmtiInternalGetStackTraceExtended(jvmtiEnv* env,


static UDATA
jvmtiInternalGetStackTraceIteratorExtended(J9VMThread * currentThread, J9StackWalkState * walkState)
jvmtiInternalGetStackTraceIteratorExtended(J9VMThread *currentThread, J9StackWalkState *walkState)
{
J9JVMTIStackTraceType type;
jmethodID methodID;
jvmtiFrameInfoExtended * frame_buffer;
UDATA frameCount;
jmethodID methodID = NULL;
jvmtiFrameInfoExtended *frame_buffer = NULL;
UDATA frameCount = 0;
J9JVMTIStackTraceType type = (J9JVMTIStackTraceType)(UDATA)walkState->userData2;
J9Method *method = walkState->method;

/* In extra info mode when method enter is enabled, exclude natives which have not had method enter reported for them */
#if JAVA_SPEC_VERSION >= 20
J9ROMMethod *romMethod = NULL;
U_32 extendedModifiers = 0;

type = (J9JVMTIStackTraceType) (UDATA) walkState->userData2;
if (type & J9JVMTI_STACK_TRACE_PRUNE_UNREPORTED_METHODS) {
if ((UDATA)walkState->pc == J9SF_FRAME_TYPE_NATIVE_METHOD) {
/* INL natives never have enter/exit reported */
/* walkState->method can never be NULL since the J9_STACKWALK_VISIBLE_ONLY flag is set. */
Assert_JVMTI_true(NULL != method);

romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(method);
extendedModifiers = getExtendedModifiersDataFromROMMethod(romMethod);

if (J9_ARE_ANY_BITS_SET(extendedModifiers, CFR_METHOD_EXT_JVMTIMOUNTTRANSITION_ANNOTATION)) {
goto skip;
}
#endif /* JAVA_SPEC_VERSION >= 20 */

/* In extra info mode when method enter is enabled, exclude natives which have not had method enter reported for them. */
if (J9_ARE_ANY_BITS_SET(type, J9JVMTI_STACK_TRACE_PRUNE_UNREPORTED_METHODS)) {
if (J9SF_FRAME_TYPE_NATIVE_METHOD == (UDATA)walkState->pc) {
/* INL natives never have enter/exit reported. */
return J9_STACKWALK_KEEP_ITERATING;
}
#if defined(J9VM_INTERP_NATIVE_SUPPORT)
if ((UDATA)walkState->pc == J9SF_FRAME_TYPE_JNI_NATIVE_METHOD) {
if (walkState->frameFlags & J9_STACK_FLAGS_JIT_JNI_CALL_OUT_FRAME) {
/* Direct JNI inlined into JIT method */
if (J9SF_FRAME_TYPE_JNI_NATIVE_METHOD == (UDATA)walkState->pc) {
if (J9_ARE_ANY_BITS_SET(walkState->frameFlags, J9_STACK_FLAGS_JIT_JNI_CALL_OUT_FRAME)) {
/* Direct JNI inlined into JIT method. */
return J9_STACKWALK_KEEP_ITERATING;
}
}
/* Direct JNI thunks (method is native, jitInfo != NULL) do have enter/exit reported */
#endif
/* Direct JNI thunks (method is native, jitInfo != NULL) do have enter/exit reported. */
#endif /* defined(J9VM_INTERP_NATIVE_SUPPORT) */
}

frame_buffer = walkState->userData1;
if (frame_buffer != NULL) {
methodID = getCurrentMethodID(currentThread, walkState->method);
if (methodID == NULL) {
if (NULL != frame_buffer) {
methodID = getCurrentMethodID(currentThread, method);
if (NULL == methodID) {
walkState->userData1 = NULL;
return J9_STACKWALK_STOP_ITERATING;
}

frame_buffer->method = methodID;

if (type & J9JVMTI_STACK_TRACE_EXTRA_FRAME_INFO) {
/* Fill in the extended data */
#ifdef J9VM_INTERP_NATIVE_SUPPORT
if (walkState->jitInfo == NULL) {
if (J9_ARE_ANY_BITS_SET(type, J9JVMTI_STACK_TRACE_EXTRA_FRAME_INFO)) {
/* Fill in the extended data. */
#if defined(J9VM_INTERP_NATIVE_SUPPORT)
if (NULL == walkState->jitInfo) {
frame_buffer->type = COM_IBM_STACK_FRAME_EXTENDED_NOT_JITTED;
} else if (J9_ARE_ANY_BITS_SET(type, J9JVMTI_STACK_TRACE_MARK_INLINED_FRAMES) && (walkState->inlineDepth > 0)) {
frame_buffer->type = COM_IBM_STACK_FRAME_EXTENDED_INLINED;
} else {
frame_buffer->type = COM_IBM_STACK_FRAME_EXTENDED_JITTED;
}
#else
#else /* defined(J9VM_INTERP_NATIVE_SUPPORT) */
frame_buffer->type = COM_IBM_STACK_FRAME_EXTENDED_NOT_JITTED;
#endif
#endif /* defined(J9VM_INTERP_NATIVE_SUPPORT) */
frame_buffer->machinepc = -1; /* not supported yet */
}
}

if (type & J9JVMTI_STACK_TRACE_ENTRY_LOCAL_STORAGE) {
#ifdef J9VM_INTERP_NATIVE_SUPPORT
if ((jlocation) walkState->bytecodePCOffset == -1) {
frame_buffer->nativeFrameAddress = (void *) walkState->walkedEntryLocalStorage;
if (J9_ARE_ANY_BITS_SET(type, J9JVMTI_STACK_TRACE_ENTRY_LOCAL_STORAGE)) {
#if defined(J9VM_INTERP_NATIVE_SUPPORT)
if (-1 == (jlocation)walkState->bytecodePCOffset) {
frame_buffer->nativeFrameAddress = (void *)walkState->walkedEntryLocalStorage;
} else {
frame_buffer->nativeFrameAddress = NULL;
}
#else
#else /* defined(J9VM_INTERP_NATIVE_SUPPORT) */
frame_buffer->nativeFrameAddress = NULL;
#endif
#endif /* defined(J9VM_INTERP_NATIVE_SUPPORT) */
}

/* The location = -1 for native method case is handled in the stack walker */
frame_buffer->location = (jlocation) walkState->bytecodePCOffset;
/* The location = -1 for native method case is handled in the stack walker. */
frame_buffer->location = (jlocation)walkState->bytecodePCOffset;

/* If the location specifies a JBinvokeinterface, back it up to the JBinvokeinterface2 */
/* If the location specifies a JBinvokeinterface, back it up to the JBinvokeinterface2. */
if (!IS_SPECIAL_FRAME_PC(walkState->pc)) {
if (*(walkState->pc) == JBinvokeinterface) {
if (JBinvokeinterface == *(walkState->pc)) {
frame_buffer->location -= 2;
}
}

walkState->userData1 = frame_buffer + 1;
}

frameCount = (UDATA) walkState->userData3;
frameCount = (UDATA)walkState->userData3;
++frameCount;
walkState->userData3 = (void *) frameCount;
if (frameCount == (UDATA) walkState->userData4) {
walkState->userData3 = (void *)frameCount;
if (frameCount == (UDATA)walkState->userData4) {
return J9_STACKWALK_STOP_ITERATING;
}

#if JAVA_SPEC_VERSION >= 20
skip:
#endif /* JAVA_SPEC_VERSION >= 20 */
return J9_STACKWALK_KEEP_ITERATING;
}

24 changes: 24 additions & 0 deletions runtime/jvmti/jvmtiHelpers.c
Original file line number Diff line number Diff line change
@@ -1974,6 +1974,30 @@ jvmtiTLSGet(J9VMThread *vmThread, j9object_t thread, UDATA key)
#endif /* JAVA_SPEC_VERSION >= 19 */
}

#if JAVA_SPEC_VERSION >= 20
UDATA
genericFrameIterator(J9VMThread *currentThread, J9StackWalkState *walkState)
{
J9Method *method = walkState->method;
J9ROMMethod *romMethod = NULL;
U_32 extendedModifiers = 0;

/* walkState->method can never be NULL since the J9_STACKWALK_VISIBLE_ONLY flag is set. */
Assert_JVMTI_true(NULL != method);

romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(method);
extendedModifiers = getExtendedModifiersDataFromROMMethod(romMethod);

if (J9_ARE_ANY_BITS_SET(extendedModifiers, CFR_METHOD_EXT_JVMTIMOUNTTRANSITION_ANNOTATION)) {
/* The number of frames skipped is stored in userData1. */
UDATA framesSkipped = (UDATA)walkState->userData1;
walkState->userData1 = (void *)(framesSkipped + 1);
}

return J9_STACKWALK_KEEP_ITERATING;
}
#endif /* JAVA_SPEC_VERSION >= 20 */

UDATA
genericWalkStackFramesHelper(J9VMThread *currentThread, J9VMThread *targetThread, j9object_t threadObject, J9StackWalkState *walkState)
{
74 changes: 56 additions & 18 deletions runtime/jvmti/jvmtiStackFrame.c
Original file line number Diff line number Diff line change
@@ -383,6 +383,11 @@ jvmtiGetFrameCount(jvmtiEnv* env,
J9StackWalkState walkState;
walkState.flags = J9_STACKWALK_INCLUDE_NATIVES | J9_STACKWALK_VISIBLE_ONLY;
walkState.skipCount = 0;
/* The number of frames skipped is stored in userData1. */
walkState.userData1 = (void *)0;
#if JAVA_SPEC_VERSION >= 20
walkState.frameWalkFunction = genericFrameIterator;
#endif /* JAVA_SPEC_VERSION >= 20 */

#if JAVA_SPEC_VERSION >= 19
if (NULL != targetThread)
@@ -398,7 +403,7 @@ jvmtiGetFrameCount(jvmtiEnv* env,
vmFuncs->resumeThreadForInspection(currentThread, targetThread);
}

rv_count = (jint) walkState.framesWalked;
rv_count = (jint)(walkState.framesWalked - (UDATA)walkState.userData1);

releaseVMThread(currentThread, targetThread, thread);
}
@@ -683,32 +688,56 @@ jvmtiNotifyFramePop(jvmtiEnv *env,


static UDATA
jvmtiInternalGetStackTraceIterator(J9VMThread * currentThread, J9StackWalkState * walkState)
jvmtiInternalGetStackTraceIterator(J9VMThread *currentThread, J9StackWalkState *walkState)
{
jmethodID methodID;
jmethodID methodID = NULL;
UDATA rc = J9_STACKWALK_KEEP_ITERATING;
J9Method *method = walkState->method;

#if JAVA_SPEC_VERSION >= 20
J9ROMMethod *romMethod = NULL;
U_32 extendedModifiers = 0;

/* walkState->method can never be NULL since the J9_STACKWALK_VISIBLE_ONLY flag is set. */
Assert_JVMTI_true(NULL != method);

romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(method);
extendedModifiers = getExtendedModifiersDataFromROMMethod(romMethod);

if (J9_ARE_ANY_BITS_SET(extendedModifiers, CFR_METHOD_EXT_JVMTIMOUNTTRANSITION_ANNOTATION)) {
/* The number of frames skipped is stored in userData2. */
UDATA framesSkipped = (UDATA)walkState->userData2;
walkState->userData2 = (void *)(framesSkipped + 1);
goto skip;
}
#endif /* JAVA_SPEC_VERSION >= 20 */

methodID = getCurrentMethodID(currentThread, walkState->method);
if (methodID == NULL) {
methodID = getCurrentMethodID(currentThread, method);
if (NULL == methodID) {
walkState->userData1 = NULL;
return J9_STACKWALK_STOP_ITERATING;
rc = J9_STACKWALK_STOP_ITERATING;
} else {
jvmtiFrameInfo * frame_buffer = walkState->userData1;
jvmtiFrameInfo *frame_buffer = walkState->userData1;

frame_buffer->method = methodID;
/* The location = -1 for native method case is handled in the stack walker */
frame_buffer->location = (jlocation) walkState->bytecodePCOffset;
/* The location = -1 for native method case is handled in the stack walker. */
frame_buffer->location = (jlocation)walkState->bytecodePCOffset;

/* If the location specifies a JBinvokeinterface, back it up to the JBinvokeinterface2 */
/* If the location specifies a JBinvokeinterface, back it up to the JBinvokeinterface2. */

if (!IS_SPECIAL_FRAME_PC(walkState->pc)) {
if (*(walkState->pc) == JBinvokeinterface) {
if (JBinvokeinterface == *(walkState->pc)) {
frame_buffer->location -= 2;
}
}

walkState->userData1 = frame_buffer + 1;
return J9_STACKWALK_KEEP_ITERATING;
}

#if JAVA_SPEC_VERSION >= 20
skip:
#endif /* JAVA_SPEC_VERSION >= 20 */
return rc;
}


@@ -780,36 +809,45 @@ jvmtiInternalGetStackTrace(
jint *count_ptr)
{
J9StackWalkState walkState = {0};

UDATA framesWalked = 0;
walkState.flags = J9_STACKWALK_INCLUDE_NATIVES | J9_STACKWALK_VISIBLE_ONLY;
walkState.skipCount = 0;

/* The number of frames skipped is stored in userData1. */
walkState.userData1 = (void *)0;
#if JAVA_SPEC_VERSION >= 20
walkState.frameWalkFunction = genericFrameIterator;
#endif /* JAVA_SPEC_VERSION >= 20 */
genericWalkStackFramesHelper(currentThread, targetThread, threadObject, &walkState);
framesWalked = walkState.framesWalked - (UDATA)walkState.userData1;
if (start_depth == 0) {
/* This violates the spec, but matches JDK behaviour - allows querying an empty stack with start_depth == 0 */
walkState.skipCount = 0;
} else if (start_depth > 0) {
if (((UDATA) start_depth) >= walkState.framesWalked) {
if (((UDATA)start_depth) >= framesWalked) {
return JVMTI_ERROR_ILLEGAL_ARGUMENT;
}
walkState.skipCount = (UDATA) start_depth;
} else {
if (((UDATA) -start_depth) > walkState.framesWalked) {
if (((UDATA)-start_depth) > framesWalked) {
return JVMTI_ERROR_ILLEGAL_ARGUMENT;
}
walkState.skipCount = walkState.framesWalked + start_depth;
walkState.skipCount = framesWalked + start_depth;
}
walkState.maxFrames = max_frame_count;
walkState.flags = J9_STACKWALK_INCLUDE_NATIVES | J9_STACKWALK_VISIBLE_ONLY
| J9_STACKWALK_RECORD_BYTECODE_PC_OFFSET | J9_STACKWALK_COUNT_SPECIFIED
| J9_STACKWALK_ITERATE_FRAMES;
walkState.userData1 = frame_buffer;
/* The number of frames skipped is stored in userData2. */
walkState.userData2 = (void *)0;
walkState.frameWalkFunction = jvmtiInternalGetStackTraceIterator;

genericWalkStackFramesHelper(currentThread, targetThread, threadObject, &walkState);
framesWalked = walkState.framesWalked - (UDATA)walkState.userData2;

if (NULL == walkState.userData1) {
return JVMTI_ERROR_OUT_OF_MEMORY;
}
*count_ptr = (jint) walkState.framesWalked;
*count_ptr = (jint)framesWalked;
return JVMTI_ERROR_NONE;
}
11 changes: 11 additions & 0 deletions runtime/jvmti/jvmti_internal.h
Original file line number Diff line number Diff line change
@@ -1352,6 +1352,17 @@ suspendAgentBreakpoint(J9VMThread * currentThread, J9JVMTIAgentBreakpoint * agen
UDATA
findDecompileInfo(J9VMThread *currentThread, J9VMThread *targetThread, UDATA depth, J9StackWalkState *walkState);

#if JAVA_SPEC_VERSION >= 20
/**
* A helper to iterate through the frames of a thread.
* @param[in] currentThread current thread
* @param[in] walkState a stack walk state
* @return 0 on success and non-zero on failure
*/
UDATA
genericFrameIterator(J9VMThread *currentThread, J9StackWalkState *walkState);
#endif /* JAVA_SPEC_VERSION >= 20 */

/**
* A helper to walk a platform thread or virtual thread
* @param[in] currentThread current thread