Skip to content

Commit

Permalink
Allowing JFR to get J9Class of hidden and anonymous classes
Browse files Browse the repository at this point in the history
Signed-off-by: Gengchen Tuo <[email protected]>
  • Loading branch information
thallium committed Jan 21, 2025
1 parent a61d849 commit 9bb00d2
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 24 deletions.
2 changes: 1 addition & 1 deletion runtime/oti/j9nonbuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -4873,7 +4873,7 @@ typedef struct J9InternalVMFunctions {
struct J9Class* ( *internalFindClassUTF8)(struct J9VMThread *currentThread, U_8 *className, UDATA classNameLength, struct J9ClassLoader *classLoader, UDATA options) ;
struct J9Class* ( *internalFindClassInModule)(struct J9VMThread *currentThread, struct J9Module *j9module, U_8 *className, UDATA classNameLength, struct J9ClassLoader *classLoader, UDATA options) ;
struct J9Class* ( *internalFindClassString)(struct J9VMThread* currentThread, j9object_t moduleName, j9object_t className, struct J9ClassLoader* classLoader, UDATA options, UDATA allowedBitsForClassName) ;
struct J9Class* ( *hashClassTableAt)(struct J9ClassLoader *classLoader, U_8 *className, UDATA classNameLength) ;
struct J9Class * (*hashClassTableAt)(struct J9ClassLoader *classLoader, U_8 *className, UDATA classNameLength);
UDATA ( *hashClassTableAtPut)(struct J9VMThread *vmThread, struct J9ClassLoader *classLoader, U_8 *className, UDATA classNameLength, struct J9Class *value) ;
UDATA ( *hashClassTableDelete)(struct J9ClassLoader *classLoader, U_8 *className, UDATA classNameLength) ;
void ( *hashClassTableReplace)(struct J9VMThread* vmThread, struct J9ClassLoader *classLoader, struct J9Class *originalClass, struct J9Class *replacementClass) ;
Expand Down
13 changes: 12 additions & 1 deletion runtime/oti/vm_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -871,10 +871,11 @@ iterateStackTrace(J9VMThread * vmThread, j9object_t* exception, UDATA (*callba
* @param skipHiddenFrames
* @param sizeOfWalkstateCache
* @param exceptionIsJavaObject
* @param revealAnonAndHiddenClass
* @return UDATA
*/
UDATA
iterateStackTraceImpl(J9VMThread * vmThread, j9object_t* exception, UDATA (*callback) (J9VMThread * vmThread, void * userData, UDATA bytecodeOffset, J9ROMClass * romClass, J9ROMMethod * romMethod, J9UTF8 * fileName, UDATA lineNumber, J9ClassLoader* classLoader, J9Class* ramClass, UDATA frameType), void * userData, UDATA pruneConstructors, UDATA skipHiddenFrames, UDATA sizeOfWalkstateCache, BOOLEAN exceptionIsJavaObject);
iterateStackTraceImpl(J9VMThread * vmThread, j9object_t* exception, UDATA (*callback) (J9VMThread * vmThread, void * userData, UDATA bytecodeOffset, J9ROMClass * romClass, J9ROMMethod * romMethod, J9UTF8 * fileName, UDATA lineNumber, J9ClassLoader* classLoader, J9Class* ramClass, UDATA frameType), void * userData, UDATA pruneConstructors, UDATA skipHiddenFrames, UDATA sizeOfWalkstateCache, BOOLEAN exceptionIsJavaObject, BOOLEAN revealAnonAndHiddenClass);


/* ---------------- exceptionsupport.c ---------------- */
Expand Down Expand Up @@ -2080,6 +2081,16 @@ isAnyClassLoadedFromPackage(J9ClassLoader* classLoader, U_8 *pkgName, UDATA pkgN
void
hashClassTableFree(J9ClassLoader* classLoader);

/**
* @brief
* @param *classLoader
* @param *className
* @param classNameLength
* @param ignoreAnonAndHiddenClass
* @return J9Class *
*/
J9Class *
hashClassTableAtImpl(J9ClassLoader *classLoader, U_8 *className, UDATA classNameLength, BOOLEAN ignoreAnonAndHiddenClass);

/**
* @brief
Expand Down
4 changes: 2 additions & 2 deletions runtime/vm/JFRConstantPoolTypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,7 @@ class VM_JFRConstantPoolTypes {
goto done;
}

expandedStackTraceCount = iterateStackTraceImpl(_currentThread, (j9object_t*)walkStateCache, NULL, NULL, FALSE, FALSE, numberOfFrames, FALSE);
expandedStackTraceCount = iterateStackTraceImpl(_currentThread, (j9object_t*)walkStateCache, NULL, NULL, FALSE, FALSE, numberOfFrames, FALSE, TRUE);

_currentStackFrameBuffer = (StackFrame*) j9mem_allocate_memory(sizeof(StackFrame) * expandedStackTraceCount, J9MEM_CATEGORY_CLASSES);
_currentFrameCount = 0;
Expand All @@ -915,7 +915,7 @@ class VM_JFRConstantPoolTypes {
goto done;
}

iterateStackTraceImpl(_currentThread, (j9object_t*)walkStateCache, &stackTraceCallback, this, FALSE, FALSE, numberOfFrames, FALSE);
iterateStackTraceImpl(_currentThread, (j9object_t*)walkStateCache, &stackTraceCallback, this, FALSE, FALSE, numberOfFrames, FALSE, TRUE);

index = addStackTraceEntry(walkThread, j9time_nano_time(), _currentFrameCount);
_stackFrameCount += expandedStackTraceCount;
Expand Down
26 changes: 16 additions & 10 deletions runtime/vm/KeyHashTable.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,12 @@ classHashEqualFn(void *tableNode, void *queryNode, void *userData)
UDATA tableNodeType = classHashGetName(tableNode, &tableNodeName, &tableNodeLength);
UDATA queryNodeType = classHashGetName(queryNode, &queryNodeName, &queryNodeLength);
UDATA tableNodeTag = ((KeyHashTableClassEntry *)tableNode)->tag;
BOOLEAN isTableNodeHiddenClass = (TYPE_CLASS == tableNodeType)
BOOLEAN isTableNodeAnonOrHiddenClass = (TYPE_CLASS == tableNodeType)
&& (TAG_RAM_CLASS == (tableNodeTag & MASK_RAM_CLASS))
&& J9ROMCLASS_IS_HIDDEN(((KeyHashTableClassEntry *)tableNode)->ramClass->romClass);
&& J9ROMCLASS_IS_ANON_OR_HIDDEN(((KeyHashTableClassEntry *)tableNode)->ramClass->romClass);

if (isTableNodeHiddenClass) {
/* Hidden class is keyed on its rom address, not on its name. */
if (isTableNodeAnonOrHiddenClass) {
/* Anon and Hidden class is keyed on its rom address, not on its name. */
PORT_ACCESS_FROM_JAVAVM(javaVM);
j9str_printf(PORTLIB, buf, ROM_ADDRESS_LENGTH + 1, ROM_ADDRESS_FORMAT, (UDATA)((KeyHashTableClassEntry *)tableNode)->ramClass->romClass);
tableNodeName = (const U_8 *)buf;
Expand Down Expand Up @@ -225,12 +225,12 @@ classHashFn(void *key, void *userData)
UDATA type = classHashGetName(key, &name, &length);
UDATA keyTag = ((KeyHashTableClassEntry *)key)->tag;
char buf[ROM_ADDRESS_LENGTH + 1] = {0};
BOOLEAN isTableNodeHiddenClass = (TYPE_CLASS == type)
BOOLEAN isTableNodeHiddenOrAnonClass = (TYPE_CLASS == type)
&& (TAG_RAM_CLASS == (keyTag & MASK_RAM_CLASS))
&& J9ROMCLASS_IS_HIDDEN(((KeyHashTableClassEntry *)key)->ramClass->romClass);
&& J9ROMCLASS_IS_ANON_OR_HIDDEN(((KeyHashTableClassEntry *)key)->ramClass->romClass);

if (isTableNodeHiddenClass) {
/* for hidden class, do not key on its name, key on its rom address */
if (isTableNodeHiddenOrAnonClass) {
/* For anon or hidden class, do not key on its name, key on its rom address */
PORT_ACCESS_FROM_JAVAVM(javaVM);
j9str_printf(PORTLIB, buf, ROM_ADDRESS_LENGTH + 1, ROM_ADDRESS_FORMAT, (UDATA)((KeyHashTableClassEntry *)key)->ramClass->romClass);
name = (const U_8 *)buf;
Expand Down Expand Up @@ -333,7 +333,7 @@ hashClassTableNew(J9JavaVM *javaVM, U_32 initialSize)
}

J9Class *
hashClassTableAt(J9ClassLoader *classLoader, U_8 *className, UDATA classNameLength)
hashClassTableAtImpl(J9ClassLoader *classLoader, U_8 *className, UDATA classNameLength, BOOLEAN ignoreAnonAndHiddenClass)
{
J9HashTable *table = classLoader->classHashTable;
KeyHashTableClassQueryEntry key;
Expand All @@ -346,7 +346,7 @@ hashClassTableAt(J9ClassLoader *classLoader, U_8 *className, UDATA classNameLeng
if (NULL != result) {
J9Class *clazz = result->ramClass;
checkClassAlignment(clazz, "hashClassTableAt");
if (J9ROMCLASS_IS_HIDDEN(clazz->romClass)) {
if ((TRUE == ignoreAnonAndHiddenClass) && J9ROMCLASS_IS_ANON_OR_HIDDEN(clazz->romClass)) {
return NULL;
}
return clazz;
Expand All @@ -355,6 +355,12 @@ hashClassTableAt(J9ClassLoader *classLoader, U_8 *className, UDATA classNameLeng
}
}

J9Class *
hashClassTableAt(J9ClassLoader *classLoader, U_8 *className, UDATA classNameLength)
{
return hashClassTableAtImpl(classLoader, className, classNameLength, TRUE);
}

BOOLEAN
isAnyClassLoadedFromPackage(J9ClassLoader *classLoader, U_8 *pkgName, UDATA pkgNameLength)
{
Expand Down
1 change: 0 additions & 1 deletion runtime/vm/createramclass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2392,7 +2392,6 @@ internalCreateRAMClassDone(J9VMThread *vmThread, J9ClassLoader *classLoader, J9C
/* Put the new class in the table or arrayClass field. */
if ((!fastHCR)
&& (0 == J9ROMCLASS_IS_PRIMITIVE_OR_ARRAY(romClass))
&& J9_ARE_NO_BITS_SET(options, J9_FINDCLASS_FLAG_ANON)
) {
if (hashClassTableAtPut(vmThread, classLoader, J9UTF8_DATA(className), J9UTF8_LENGTH(className), state->ramClass)) {
if (hotswapping) {
Expand Down
36 changes: 29 additions & 7 deletions runtime/vm/exceptiondescribe.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ typedef UDATA (*callback_func_t) (J9VMThread * vmThread, void * userData, UDATA
static void printExceptionInThread (J9VMThread* vmThread);
static UDATA isSubclassOfThreadDeath (J9VMThread *vmThread, j9object_t exception);
static void printExceptionMessage (J9VMThread* vmThread, j9object_t exception);
static J9Class* findJ9ClassForROMClass(J9VMThread *vmThread, J9ROMClass *romClass, J9ClassLoader **resultClassLoader);
static J9Class* findJ9ClassForROMClass(J9VMThread *vmThread, J9ROMClass *romClass, J9ClassLoader **resultClassLoader, BOOLEAN revealAnonAndHiddenClass);


/* assumes VM access */
Expand Down Expand Up @@ -220,18 +220,19 @@ printStackTraceEntry(J9VMThread * vmThread, void * voidUserData, UDATA bytecodeO
* @param[in] ROMClass The J9ROMClass from which the J9Class is created.
* @param[in, out] resultClassLoader This is the classLoader that owns the memory segment that the ROMClass was found in.
* The romclass memory segment in the shared cache always belongs to vm->systemClassLoader. Set it to the actual class loader which loaded the class in this case.
* @param[in] revealAnonAndHiddenClass Whether to return the J9Class of a hidden or anonymous class.
*
* @return The J9class, or NULL on failure.
*/
static J9Class*
findJ9ClassForROMClass(J9VMThread *vmThread, J9ROMClass *romClass, J9ClassLoader **resultClassLoader)
findJ9ClassForROMClass(J9VMThread *vmThread, J9ROMClass *romClass, J9ClassLoader **resultClassLoader, BOOLEAN revealAnonAndHiddenClass)
{
J9UTF8 const *utfClassName = J9ROMCLASS_CLASSNAME(romClass);
J9JavaVM *vm = vmThread->javaVM;
J9SharedClassConfig *config = vm->sharedClassConfig;
J9Class* ret = NULL;

if (_J9ROMCLASS_J9MODIFIER_IS_SET(romClass, J9AccClassAnonClass)) {
if ((FALSE == revealAnonAndHiddenClass) && _J9ROMCLASS_J9MODIFIER_IS_SET(romClass, J9AccClassAnonClass)) {
/* Anonymous classes are not allowed in any class loader hash table. */
return NULL;
}
Expand Down Expand Up @@ -332,7 +333,27 @@ findJ9ClassForROMClass(J9VMThread *vmThread, J9ROMClass *romClass, J9ClassLoader
omrthread_rwmutex_exit_write(config->romToRamHashTableMutex);
}
} else {
ret = peekClassHashTable(vmThread, *resultClassLoader, J9UTF8_DATA(utfClassName), J9UTF8_LENGTH(utfClassName));
if ((TRUE == revealAnonAndHiddenClass) && J9ROMCLASS_IS_ANON_OR_HIDDEN(romClass)) {
PORT_ACCESS_FROM_JAVAVM(vmThread->javaVM);
char buf[ROM_ADDRESS_LENGTH + 1] = {0};
BOOLEAN fastMode = J9_ARE_ALL_BITS_SET(vm->extendedRuntimeFlags, J9_EXTENDED_RUNTIME_FAST_CLASS_HASH_TABLE);

/* A hidden or anonymous class is keyed on its address */
j9str_printf(PORTLIB, buf, ROM_ADDRESS_LENGTH + 1, ROM_ADDRESS_FORMAT, romClass);
if (!fastMode) {
omrthread_monitor_enter(vm->classTableMutex);
}
if (_J9ROMCLASS_J9MODIFIER_IS_SET(romClass, J9AccClassAnonClass)) {
ret = hashClassTableAtImpl(vm->anonClassLoader, (U_8 *)buf, ROM_ADDRESS_LENGTH, FALSE);
} else {
ret = hashClassTableAtImpl(*resultClassLoader, (U_8 *)buf, ROM_ADDRESS_LENGTH, FALSE);
}
if (!fastMode) {
omrthread_monitor_exit(vm->classTableMutex);
}
} else {
ret = peekClassHashTable(vmThread, *resultClassLoader, J9UTF8_DATA(utfClassName), J9UTF8_LENGTH(utfClassName));
}
}
done:
return ret;
Expand All @@ -349,12 +370,13 @@ findJ9ClassForROMClass(J9VMThread *vmThread, J9ROMClass *romClass, J9ClassLoader
* @param pruneConstructors Non-zero if constructors should be pruned from the stack trace.
* @param sizeOfWalkstateCache Non-zero if exception is walkstate cache instead of exception object.
* Indicatest the size of cache.
* @param revealAnonAndHiddenClass Whether to show methods of hidden and anonymous classes.
* @return The number of times the callback function was invoked.
*
* @note Assumes VM access
**/
UDATA
iterateStackTraceImpl(J9VMThread * vmThread, j9object_t* exception, callback_func_t callback, void * userData, UDATA pruneConstructors, UDATA skipHiddenFrames, UDATA sizeOfWalkstateCache, BOOLEAN exceptionIsJavaObject)
iterateStackTraceImpl(J9VMThread * vmThread, j9object_t* exception, callback_func_t callback, void * userData, UDATA pruneConstructors, UDATA skipHiddenFrames, UDATA sizeOfWalkstateCache, BOOLEAN exceptionIsJavaObject, BOOLEAN revealAnonAndHiddenClass)
{
J9JavaVM * vm = vmThread->javaVM;
UDATA totalEntries = 0;
Expand Down Expand Up @@ -473,7 +495,7 @@ iterateStackTraceImpl(J9VMThread * vmThread, j9object_t* exception, callback_fun
#endif
romClass = findROMClassFromPC(vmThread, methodPC, &classLoader);
if (NULL != romClass) {
ramClass = findJ9ClassForROMClass(vmThread, romClass, &classLoader);
ramClass = findJ9ClassForROMClass(vmThread, romClass, &classLoader, revealAnonAndHiddenClass);
while (NULL != ramClass) {
U_32 i = 0;
J9Method *methods = ramClass->ramMethods;
Expand Down Expand Up @@ -582,7 +604,7 @@ foundROMMethod: ;
UDATA
iterateStackTrace(J9VMThread * vmThread, j9object_t* exception, callback_func_t callback, void * userData, UDATA pruneConstructors, UDATA skipHiddenFrames)
{
return iterateStackTraceImpl(vmThread, exception, callback, userData, pruneConstructors, skipHiddenFrames, 0, TRUE);
return iterateStackTraceImpl(vmThread, exception, callback, userData, pruneConstructors, skipHiddenFrames, 0, TRUE, FALSE);
}

/**
Expand Down
6 changes: 4 additions & 2 deletions runtime/vm/jvminit.c
Original file line number Diff line number Diff line change
Expand Up @@ -8322,10 +8322,11 @@ freeClassNativeMemory(J9HookInterface** hook, UDATA eventNum, void* eventData, v
static void
vmHookAnonClassesUnload(J9HookInterface** hook, UDATA eventNum, void* eventData, void* userData)
{
J9VMAnonymousClassesUnloadEvent * unloadedEvent = (J9VMAnonymousClassesUnloadEvent *)eventData;
J9VMThread * vmThread = unloadedEvent->currentThread;
J9VMAnonymousClassesUnloadEvent *unloadedEvent = (J9VMAnonymousClassesUnloadEvent *)eventData;
J9VMThread *vmThread = unloadedEvent->currentThread;
J9JavaVM *vm = vmThread->javaVM;
for (J9Class* j9clazz = unloadedEvent->anonymousClassesToUnload; j9clazz; j9clazz = j9clazz->gcLink) {
J9UTF8 const *className = J9ROMCLASS_CLASSNAME(j9clazz->romClass);
/* AnonClass->classLoader points to the hostclass->classLoader not the anonClassLoader. */
if (J9VM_SHOULD_CLEAR_JNIIDS_FOR_ASGCT(vm, j9clazz->classLoader)) {
void **jniIDs = j9clazz->jniIDs;
Expand All @@ -8337,6 +8338,7 @@ vmHookAnonClassesUnload(J9HookInterface** hook, UDATA eventNum, void* eventData,
}
}
}
hashClassTableDelete(vm->anonClassLoader, J9UTF8_DATA(className), J9UTF8_LENGTH(className));
#if JAVA_SPEC_VERSION >= 22
hashClassTablePackageDelete(vmThread, j9clazz->classLoader, j9clazz->romClass);
#endif /* JAVA_SPEC_VERSION >= 22 */
Expand Down

0 comments on commit 9bb00d2

Please sign in to comment.