Skip to content

Commit e9bb3b9

Browse files
Extend JNI ID retention to JVMTI GetStackTrace stack walks
JVMTI GetStackTrace and GetAllStackTracesExtended hand out jmethodIDs during stack collection. If classes are unloaded before resolution, passing a stale jmethodID to GetMethodName, GetMethodDeclaringClass, or GetClassSignature causes a segfault instead of an error code. - Rename J9ClassLoader.asyncGetCallTraceUsed to keepJNIIDs to generalize the retention mechanism beyond ASGCT - Rename macro J9VM_SHOULD_CLEAR_JNIIDS_FOR_ASGCT to J9VM_SHOULD_KEEP_JNIIDS - Set classLoader->keepJNIIDs = 1 in GetStackTrace and GetAllStackTracesExtended iterators when handing out a method ID - Invalidate pool entries in freeClassNativeMemory before freeing the per-class table, covering anonymous/hidden classes (e.g. LambdaForms) missed by vmHookAnonClassesUnload Signed-off-by: Tomal Majumder <tomal.majumder@ibm.com>
1 parent 3f41d4c commit e9bb3b9

7 files changed

Lines changed: 25 additions & 7 deletions

File tree

runtime/j9vm/asgct.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ asyncFrameIterator(J9VMThread * currentThread, J9StackWalkState * walkState)
123123
frame->lineno = (jint)walkState->bytecodePCOffset;
124124
}
125125
walkState->userData1 = (void*)(frame + 1);
126-
declaringClass->classLoader->asyncGetCallTraceUsed = 1;
126+
declaringClass->classLoader->keepJNIIDs = 1;
127127
return J9_STACKWALK_KEEP_ITERATING;
128128
}
129129

runtime/jvmti/jvmtiExtensionMechanism.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2076,6 +2076,7 @@ jvmtiInternalGetStackTraceIteratorExtended(J9VMThread *currentThread, J9StackWal
20762076
UDATA frameCount = 0;
20772077
J9JVMTIStackTraceType type = (J9JVMTIStackTraceType)(UDATA)walkState->userData2;
20782078
J9Method *method = walkState->method;
2079+
J9Class *declaringClass = J9_CLASS_FROM_METHOD(method);
20792080

20802081
#if JAVA_SPEC_VERSION >= 20
20812082
J9ROMMethod *romMethod = NULL;
@@ -2118,7 +2119,9 @@ jvmtiInternalGetStackTraceIteratorExtended(J9VMThread *currentThread, J9StackWal
21182119
}
21192120

21202121
frame_buffer->method = methodID;
2121-
2122+
2123+
declaringClass->classLoader->keepJNIIDs = 1;
2124+
21222125
if (J9_ARE_ANY_BITS_SET(type, J9JVMTI_STACK_TRACE_EXTRA_FRAME_INFO)) {
21232126
/* Fill in the extended data. */
21242127
#if defined(J9VM_INTERP_NATIVE_SUPPORT)

runtime/jvmti/jvmtiStackFrame.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,7 @@ jvmtiInternalGetStackTraceIterator(J9VMThread *currentThread, J9StackWalkState *
709709
jmethodID methodID = NULL;
710710
UDATA rc = J9_STACKWALK_KEEP_ITERATING;
711711
J9Method *method = walkState->method;
712+
J9Class *declaringClass = J9_CLASS_FROM_METHOD(method);
712713

713714
#if JAVA_SPEC_VERSION >= 20
714715
J9ROMMethod *romMethod = NULL;
@@ -747,6 +748,7 @@ jvmtiInternalGetStackTraceIterator(J9VMThread *currentThread, J9StackWalkState *
747748
}
748749
}
749750

751+
declaringClass->classLoader->keepJNIIDs = 1;
750752
walkState->userData1 = frame_buffer + 1;
751753
}
752754

runtime/oti/j9.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,8 +434,8 @@ static_assert((LITERAL_STRLEN(J9_UNMODIFIABLE_CLASS_ANNOTATION) < (size_t)'/'),
434434

435435
#define J9VM_NUM_OF_ENTRIES_IN_CLASS_JNIID_TABLE(romclass) ((romclass)->romMethodCount + (romclass)->romFieldCount)
436436

437-
#define J9VM_SHOULD_CLEAR_JNIIDS_FOR_ASGCT(vm, classLoader) (J9_ARE_NO_BITS_SET((vm)->extendedRuntimeFlags2, J9_EXTENDED_RUNTIME2_NEVER_KEEP_JNI_IDS) \
438-
&& ((classLoader)->asyncGetCallTraceUsed || J9_ARE_ANY_BITS_SET((vm)->extendedRuntimeFlags2, J9_EXTENDED_RUNTIME2_ALWAYS_KEEP_JNI_IDS)))
437+
#define J9VM_SHOULD_KEEP_JNIIDS(vm, classLoader) (J9_ARE_NO_BITS_SET((vm)->extendedRuntimeFlags2, J9_EXTENDED_RUNTIME2_NEVER_KEEP_JNI_IDS) \
438+
&& ((classLoader)->keepJNIIDs || J9_ARE_ANY_BITS_SET((vm)->extendedRuntimeFlags2, J9_EXTENDED_RUNTIME2_ALWAYS_KEEP_JNI_IDS)))
439439

440440
#define J9_IS_GCCONTAINERHEURISTICS(vm) \
441441
J9_ARE_ANY_BITS_SET((vm)->extendedRuntimeFlags3, J9_EXTENDED_RUNTIME3_GCCONTAINERHEURISTICS)

runtime/oti/j9nonbuilder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3893,7 +3893,7 @@ typedef struct J9ClassLoader {
38933893
omrthread_monitor_t hotFieldPoolMutex;
38943894
omrthread_rwmutex_t cpEntriesMutex;
38953895
UDATA initClassPathEntryCount;
3896-
UDATA asyncGetCallTraceUsed;
3896+
UDATA keepJNIIDs;
38973897
omrthread_monitor_t mapCacheMutex;
38983898
struct J9HashTable* localmapCache;
38993899
struct J9HashTable* argsbitsCache;

runtime/vm/classallocation.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ freeClassLoader(J9ClassLoader *classLoader, J9JavaVM *javaVM, J9VMThread *vmThre
430430
}
431431

432432
if (NULL != classLoader->jniIDs) {
433-
if (J9VM_SHOULD_CLEAR_JNIIDS_FOR_ASGCT(javaVM, classLoader)) {
433+
if (J9VM_SHOULD_KEEP_JNIIDS(javaVM, classLoader)) {
434434
pool_state idWalkState;
435435
J9GenericJNIID *jniID = pool_startDo(classLoader->jniIDs, &idWalkState);
436436

runtime/vm/jvminit.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8777,6 +8777,19 @@ freeClassNativeMemory(J9HookInterface** hook, UDATA eventNum, void* eventData, v
87778777
J9Class * clazz = data->clazz;
87788778
PORT_ACCESS_FROM_JAVAVM(vm);
87798779

8780+
if (NULL != clazz->jniIDs) {
8781+
J9ClassLoader *classLoader = clazz->classLoader;
8782+
if (J9VM_SHOULD_KEEP_JNIIDS(vm, classLoader)) {
8783+
UDATA size = J9VM_NUM_OF_ENTRIES_IN_CLASS_JNIID_TABLE(clazz->romClass);
8784+
for (UDATA i = 0; i < size; i++) {
8785+
J9GenericJNIID *id = (J9GenericJNIID *)(clazz->jniIDs[i]);
8786+
if (NULL != id) {
8787+
memset(id, -1, sizeof(J9GenericJNIID));
8788+
}
8789+
}
8790+
}
8791+
}
8792+
87808793
/* Free the ID table for this class, but do not free any of the IDs. They will be freed by killing their
87818794
pools when the class loader is unloaded.
87828795
*/
@@ -8870,7 +8883,7 @@ vmHookAnonClassesUnload(J9HookInterface** hook, UDATA eventNum, void* eventData,
88708883
J9ClassLoader *classLoader = j9clazz->classLoader;
88718884
/* Anon classes are unloaded piecemeal, so clear the map cache where the anon maps may be cached */
88728885
freeMapCaches(classLoader);
8873-
if (J9VM_SHOULD_CLEAR_JNIIDS_FOR_ASGCT(vm, classLoader)) {
8886+
if (J9VM_SHOULD_KEEP_JNIIDS(vm, classLoader)) {
88748887
void **jniIDs = j9clazz->jniIDs;
88758888
if (NULL != jniIDs) {
88768889
UDATA size = J9VM_NUM_OF_ENTRIES_IN_CLASS_JNIID_TABLE(j9clazz->romClass);

0 commit comments

Comments
 (0)