Skip to content

Commit 7d5370d

Browse files
committed
JVM_getAllEventClasses support
Signed-off-by: Gengchen Tuo <gengchen.tuo@ibm.com>
1 parent f8b93be commit 7d5370d

3 files changed

Lines changed: 218 additions & 26 deletions

File tree

runtime/jcl/common/jdk_jfr_internal_JVM_common.cpp

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "j9.h"
2424
#include "jni.h"
2525
#include "jclprots.h"
26+
#include "ut_j9jcl.h"
2627

2728
#include "ObjectAccessBarrierAPI.hpp"
2829
#include "VMHelpers.hpp"
@@ -100,10 +101,86 @@ Java_jdk_jfr_internal_JVM_getAllEventClasses(JNIEnv *env, jobject obj)
100101
J9VMThread *currentThread = (J9VMThread*) env;
101102
J9JavaVM *vm = currentThread->javaVM;
102103
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
104+
J9MemoryManagerFunctions *mmFuncs = vm->memoryManagerFunctions;
103105
jobject result = NULL;
104106

105107
vmFuncs->internalEnterVMFromJNI(currentThread);
106-
result = vmFuncs->j9jni_createLocalRef(env, vmFuncs->jvmUpcallTransformArrayToList(currentThread, NULL));
108+
109+
omrthread_monitor_enter(vm->jfrState.typeIDMonitor);
110+
111+
/* First pass: count event classes with valid eventClass pointers across all classloaders. */
112+
UDATA eventCount = 0;
113+
J9ClassLoaderWalkState walkState;
114+
J9ClassLoader *classLoader = vmFuncs->allClassLoadersStartDo(&walkState, vm, 0);
115+
116+
while (NULL != classLoader) {
117+
J9HashTable *typeIDTable = classLoader->typeIDs;
118+
if (NULL != typeIDTable) {
119+
J9HashTableState hashTableState = {0};
120+
J9JFRTypeID *entry = (J9JFRTypeID *)hashTableStartDo(typeIDTable, &hashTableState);
121+
122+
while (NULL != entry) {
123+
if (entry->isEvent && (NULL != entry->eventClass)) {
124+
eventCount += 1;
125+
}
126+
entry = (J9JFRTypeID *)hashTableNextDo(&hashTableState);
127+
}
128+
}
129+
classLoader = vmFuncs->allClassLoadersNextDo(&walkState);
130+
}
131+
vmFuncs->allClassLoadersEndDo(&walkState);
132+
133+
/* Get the Class class and create Class[] array class. */
134+
J9Class *javaLangClass = J9VMJAVALANGCLASS_OR_NULL(vm);
135+
UDATA arrayIndex = 0;
136+
j9array_t classArray = NULL;
137+
Assert_JCL_notNull(javaLangClass);
138+
139+
J9Class *classArrayClass = javaLangClass->arrayClass;
140+
if (NULL == classArrayClass) {
141+
J9ROMArrayClass *arrayOfObjectsROMClass = (J9ROMArrayClass*)J9ROMIMAGEHEADER_FIRSTCLASS(vm->arrayROMClasses);
142+
classArrayClass = vmFuncs->internalCreateArrayClass(currentThread, arrayOfObjectsROMClass, javaLangClass);
143+
if (NULL == classArrayClass) {
144+
goto done;
145+
}
146+
}
147+
148+
/* Allocate the Class[] array. */
149+
classArray = (j9array_t)mmFuncs->J9AllocateIndexableObject(
150+
currentThread, classArrayClass, (U_32)eventCount, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
151+
if (NULL == classArray) {
152+
vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
153+
goto done;
154+
}
155+
156+
/* Second pass: populate the array with event classes from all classloaders */
157+
classLoader = vmFuncs->allClassLoadersStartDo(&walkState, vm, 0);
158+
159+
while (NULL != classLoader) {
160+
J9HashTable *typeIDTable = classLoader->typeIDs;
161+
if (NULL != typeIDTable) {
162+
J9HashTableState hashTableState = {0};
163+
J9JFRTypeID *entry = (J9JFRTypeID *)hashTableStartDo(typeIDTable, &hashTableState);
164+
165+
while (NULL != entry) {
166+
if (entry->isEvent && (NULL != entry->eventClass)) {
167+
/* Use the stored eventClass pointer directly */
168+
j9object_t classObject = J9VM_J9CLASS_TO_HEAPCLASS(entry->eventClass);
169+
J9JAVAARRAYOFOBJECT_STORE(currentThread, classArray, arrayIndex, classObject);
170+
arrayIndex += 1;
171+
}
172+
entry = (J9JFRTypeID *)hashTableNextDo(&hashTableState);
173+
}
174+
}
175+
classLoader = vmFuncs->allClassLoadersNextDo(&walkState);
176+
}
177+
vmFuncs->allClassLoadersEndDo(&walkState);
178+
179+
/* Convert array to list and create local ref */
180+
result = vmFuncs->j9jni_createLocalRef(env, vmFuncs->jvmUpcallTransformArrayToList(currentThread, (j9object_t)classArray));
181+
182+
done:
183+
omrthread_monitor_exit(vm->jfrState.typeIDMonitor);
107184
vmFuncs->internalExitVMToJNI(currentThread);
108185

109186
return result;

runtime/oti/j9nonbuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,8 @@ typedef struct J9JFRTypeID {
554554
jlong id;
555555
struct J9UTF8 *className;
556556
BOOLEAN free;
557+
BOOLEAN isEvent;
558+
struct J9Class *eventClass;
557559
} J9JFRTypeID;
558560

559561
typedef struct J9JFRNetworkUtilization {

runtime/vm/jfr.cpp

Lines changed: 138 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ static bool addEventIds(J9JavaVM *vm);
7575
static bool addTypeIds(J9JavaVM *vm);
7676
#endif /* JAVA_SPEC_VERSION >= 17 */
7777
static void jfrShutdownInternalStructures(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);
78+
static void addEventClass(J9VMThread *currentThread, J9Class *clazz);
79+
static void jfrClassInitialize(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);
7880

7981
static void
8082
freeThreadIDs(J9VMThread *currentThread)
@@ -1152,6 +1154,7 @@ stopJFRRecording(J9JavaVM *vm)
11521154
(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_MONITOR_CONTENDED_ENTERED, jfrVMMonitorEntered, NULL);
11531155
(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_UNPARKED, jfrVMThreadParked, NULL);
11541156
(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_SYSTEM_GC_CALLED, jfrSystemGC, NULL);
1157+
11551158
/* Deregister GC-related hooks via gc_base */
11561159
vm->memoryManagerFunctions->j9gc_deregister_jfr_hooks(vm);
11571160
}
@@ -1706,24 +1709,21 @@ getTypeId(J9VMThread *currentThread, J9Class *clazz)
17061709
return getTypeIdImpl(currentThread, clazz->classLoader, J9ROMCLASS_CLASSNAME(clazz->romClass), FALSE);
17071710
}
17081711

1709-
static jlong
1710-
getTypeIdImpl(J9VMThread *currentThread, J9ClassLoader *classLoader, J9UTF8 *className, BOOLEAN freeName)
1711-
{
1712-
J9JavaVM *vm = currentThread->javaVM;
1713-
jlong result = INVALID_TYPE_ID;
1714-
J9JFRTypeID entry = {0};
1715-
J9JFRTypeID *jfrTypeID = &entry;
1716-
1717-
Assert_VM_mustHaveVMAccess(currentThread);
1718-
1719-
omrthread_monitor_enter(vm->jfrState.typeIDMonitor);
1720-
1721-
J9HashTable *typeIDTable = classLoader->typeIDs;
1722-
1723-
if (NULL == typeIDTable) {
1724-
PORT_ACCESS_FROM_JAVAVM(vm);
1712+
/**
1713+
* Create and initialize a JFR TypeID hash table for the given class loader.
1714+
* Caller must hold vm->jfrState.typeIDMonitor.
1715+
*
1716+
* @param vm[in] Java VM
1717+
* @param classLoader[in] the class loader whose TypeID hash table will be created
1718+
*
1719+
* @returns the created hash table, NULL if error happened during table creation and/or initialization
1720+
*/
17251721

1726-
typeIDTable = hashTableNew(OMRPORT_FROM_J9PORT(privatePortLibrary),
1722+
static J9HashTable *
1723+
createJFRTypeIDHashTable(J9JavaVM *vm, J9ClassLoader *classLoader)
1724+
{
1725+
PORT_ACCESS_FROM_JAVAVM(vm);
1726+
J9HashTable *typeIDTable = hashTableNew(OMRPORT_FROM_J9PORT(privatePortLibrary),
17271727
J9_GET_CALLSITE(),
17281728
0,
17291729
sizeof(J9JFRTypeID),
@@ -1734,32 +1734,54 @@ getTypeIdImpl(J9VMThread *currentThread, J9ClassLoader *classLoader, J9UTF8 *cla
17341734
jfrTypeIDHashEqualFn,
17351735
NULL,
17361736
NULL);
1737-
1738-
if (NULL == typeIDTable) {
1739-
setNativeOutOfMemoryError(currentThread, 0, 0);
1740-
goto done;
1741-
}
1742-
classLoader->typeIDs = typeIDTable;
1737+
if (NULL == typeIDTable) {
1738+
goto done;
1739+
}
17431740

17441741
#if JAVA_SPEC_VERSION >= 17
17451742
if (vm->systemClassLoader == classLoader) {
17461743
/* Pre-populate table with known JFR event IDs */
17471744
if (!addEventIds(vm)) {
17481745
hashTableFree(typeIDTable);
17491746
classLoader->typeIDs = NULL;
1750-
setNativeOutOfMemoryError(currentThread, 0, 0);
17511747
goto done;
17521748
}
17531749

17541750
/* Pre-populate table with known JFR type IDs */
17551751
if (!addTypeIds(vm)) {
17561752
hashTableFree(typeIDTable);
17571753
classLoader->typeIDs = NULL;
1758-
setNativeOutOfMemoryError(currentThread, 0, 0);
17591754
goto done;
17601755
}
17611756
}
17621757
#endif /* JAVA_SPEC_VERSION >= 17 */
1758+
1759+
classLoader->typeIDs = typeIDTable;
1760+
done:
1761+
return typeIDTable;
1762+
}
1763+
1764+
static jlong
1765+
getTypeIdImpl(J9VMThread *currentThread, J9ClassLoader *classLoader, J9UTF8 *className, BOOLEAN freeName)
1766+
{
1767+
J9JavaVM *vm = currentThread->javaVM;
1768+
jlong result = INVALID_TYPE_ID;
1769+
J9JFRTypeID entry = {0};
1770+
J9JFRTypeID *jfrTypeID = &entry;
1771+
1772+
Assert_VM_mustHaveVMAccess(currentThread);
1773+
1774+
omrthread_monitor_enter(vm->jfrState.typeIDMonitor);
1775+
1776+
J9HashTable *typeIDTable = classLoader->typeIDs;
1777+
1778+
if (NULL == typeIDTable) {
1779+
typeIDTable = createJFRTypeIDHashTable(vm, classLoader);
1780+
1781+
if (NULL == typeIDTable) {
1782+
setNativeOutOfMemoryError(currentThread, 0, 0);
1783+
goto done;
1784+
}
17631785
}
17641786

17651787
jfrTypeID->className = className;
@@ -1770,6 +1792,8 @@ getTypeIdImpl(J9VMThread *currentThread, J9ClassLoader *classLoader, J9UTF8 *cla
17701792
jfrTypeID = &entry;
17711793
jfrTypeID->id = vm->jfrState.typeIDcount;
17721794
jfrTypeID->free = freeName;
1795+
jfrTypeID->isEvent = FALSE;
1796+
jfrTypeID->eventClass = NULL;
17731797

17741798
vm->jfrState.typeIDcount += 1;
17751799
Assert_VM_true(vm->jfrState.typeIDcount > 0);
@@ -1802,6 +1826,12 @@ initializeJFRv2(J9JavaVM *vm)
18021826
goto done;
18031827
}
18041828

1829+
if (J9_ARE_ALL_BITS_SET(vm->extendedRuntimeFlags3, J9_EXTENDED_RUNTIME3_JFR_V2_SUPPORT)) {
1830+
if ((*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_CLASS_INITIALIZE, jfrClassInitialize, OMR_GET_CALLSITE(), NULL)) {
1831+
goto done;
1832+
}
1833+
}
1834+
18051835
if (0 != initializeJFRIDs(vm)) {
18061836
goto done;
18071837
}
@@ -1853,6 +1883,9 @@ jfrShutdownInternalStructures(J9HookInterface **hook, UDATA eventNum, void *even
18531883
internalReleaseVMAccess(currentThread);
18541884
vm->jfrState.jfrEventClassRef = NULL;
18551885
vm->jfrState.jfrInternalEventClassRef = NULL;
1886+
if (J9_ARE_ALL_BITS_SET(vm->extendedRuntimeFlags3, J9_EXTENDED_RUNTIME3_JFR_V2_SUPPORT)) {
1887+
(*hook)->J9HookUnregister(hook, J9HOOK_VM_CLASS_INITIALIZE, jfrClassInitialize, NULL);
1888+
}
18561889
}
18571890

18581891
static void
@@ -2017,6 +2050,8 @@ addType(J9JavaVM *vm, const char *eventOrTypeName, UDATA id, bool isEvent)
20172050
entry.id = id;
20182051
entry.className = className;
20192052
entry.free = TRUE;
2053+
entry.isEvent = isEvent;
2054+
entry.eventClass = NULL;
20202055

20212056
/* Add to hash table */
20222057
if (NULL == hashTableAdd(typeIDTable, &entry)) {
@@ -2332,6 +2367,84 @@ requestJFREvent(J9VMThread *currentThread, jlong id)
23322367
#endif /* JAVA_SPEC_VERSION >= 17 */
23332368
}
23342369

2370+
void
2371+
jfrClassInitialize(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData)
2372+
{
2373+
J9VMClassInitializeEvent *event = (J9VMClassInitializeEvent *)eventData;
2374+
J9VMThread *currentThread = event->currentThread;
2375+
J9Class *clazz = event->clazz;
2376+
2377+
addEventClass(currentThread, clazz);
2378+
}
2379+
2380+
/**
2381+
* Add an event class to the typeIDs table after it has been loaded.
2382+
* This function is called from the class loading hook to register event classes.
2383+
*
2384+
* @param currentThread[in] the current J9VMThread
2385+
* @param clazz[in] the loaded class to check and potentially add
2386+
*/
2387+
static void
2388+
addEventClass(J9VMThread *currentThread, J9Class *clazz)
2389+
{
2390+
J9JavaVM *vm = currentThread->javaVM;
2391+
J9UTF8 *className = J9ROMCLASS_CLASSNAME(clazz->romClass);
2392+
J9ClassLoader *classLoader = clazz->classLoader;
2393+
2394+
if (NULL == vm->jfrState.jfrEventClassRef) {
2395+
return;
2396+
}
2397+
2398+
/* Check if this class is a subclass of jdk.jfr.Event and not an abstract class */
2399+
J9Class *eventClass = J9VMJAVALANGCLASS_VMREF(currentThread, J9_JNI_UNWRAP_REFERENCE(vm->jfrState.jfrEventClassRef));
2400+
if (isSameOrSuperClassOf(eventClass, clazz)
2401+
&& J9_ARE_NO_BITS_SET(clazz->romClass->modifiers, J9AccAbstract)
2402+
) {
2403+
omrthread_monitor_enter(vm->jfrState.typeIDMonitor);
2404+
2405+
J9HashTable *typeIDTable = classLoader->typeIDs;
2406+
J9JFRTypeID query = {0};
2407+
J9JFRTypeID *existingEntry = NULL;
2408+
2409+
/* Create typeIDs table if it doesn't exist */
2410+
if (NULL == typeIDTable) {
2411+
typeIDTable = createJFRTypeIDHashTable(vm, classLoader);
2412+
2413+
if (NULL == typeIDTable) {
2414+
goto done;
2415+
}
2416+
}
2417+
2418+
/* Check if entry already exists */
2419+
query.className = className;
2420+
existingEntry = (J9JFRTypeID *)hashTableFind(typeIDTable, &query);
2421+
2422+
if (NULL != existingEntry) {
2423+
/* Update existing entry with event class pointer */
2424+
existingEntry->isEvent = TRUE;
2425+
existingEntry->eventClass = clazz;
2426+
} else {
2427+
/* Create new entry */
2428+
J9JFRTypeID newEntry = {0};
2429+
newEntry.id = vm->jfrState.typeIDcount;
2430+
newEntry.className = className;
2431+
newEntry.free = FALSE;
2432+
newEntry.isEvent = TRUE;
2433+
newEntry.eventClass = clazz;
2434+
2435+
vm->jfrState.typeIDcount += 1;
2436+
Assert_VM_true(vm->jfrState.typeIDcount > 0);
2437+
2438+
if (NULL == hashTableAdd(typeIDTable, &newEntry)) {
2439+
setNativeOutOfMemoryError(currentThread, 0, 0);
2440+
goto done;
2441+
}
2442+
}
2443+
done:
2444+
omrthread_monitor_exit(vm->jfrState.typeIDMonitor);
2445+
}
2446+
}
2447+
23352448
} /* extern "C" */
23362449

23372450
#endif /* defined(J9VM_OPT_JFR) */

0 commit comments

Comments
 (0)