diff --git a/runtime/jvmti/jvmtiExtensionMechanism.c b/runtime/jvmti/jvmtiExtensionMechanism.c index 591fec5fab2..c1bebb55a3b 100644 --- a/runtime/jvmti/jvmtiExtensionMechanism.c +++ b/runtime/jvmti/jvmtiExtensionMechanism.c @@ -1864,76 +1864,90 @@ 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; } } @@ -1941,12 +1955,16 @@ jvmtiInternalGetStackTraceIteratorExtended(J9VMThread * currentThread, J9StackWa 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; } diff --git a/runtime/jvmti/jvmtiHelpers.c b/runtime/jvmti/jvmtiHelpers.c index 911c5634a4a..ca8da16d990 100644 --- a/runtime/jvmti/jvmtiHelpers.c +++ b/runtime/jvmti/jvmtiHelpers.c @@ -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) { diff --git a/runtime/jvmti/jvmtiStackFrame.c b/runtime/jvmti/jvmtiStackFrame.c index ab18f8a4337..0d170177f2d 100644 --- a/runtime/jvmti/jvmtiStackFrame.c +++ b/runtime/jvmti/jvmtiStackFrame.c @@ -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; } diff --git a/runtime/jvmti/jvmti_internal.h b/runtime/jvmti/jvmti_internal.h index 04556e893c2..94346d41d51 100644 --- a/runtime/jvmti/jvmti_internal.h +++ b/runtime/jvmti/jvmti_internal.h @@ -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