@@ -75,6 +75,8 @@ static bool addEventIds(J9JavaVM *vm);
7575static bool addTypeIds (J9JavaVM *vm);
7676#endif /* JAVA_SPEC_VERSION >= 17 */
7777static 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
7981static void
8082freeThreadIDs (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
18581891static 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