in src/utils.cpp [234:279]
jvmtiError tagClassAndItsInheritors(JNIEnv *env, jvmtiEnv *jvmti, jobject classObject, std::function<jlong (jlong)> &&createTag) {
jclass *classes;
jint cnt;
jvmtiError err = jvmti->GetLoadedClasses(&cnt, &classes);
if (err != JVMTI_ERROR_NONE) return err;
jclass langClass = env->FindClass("java/lang/Class");
jmethodID isAssignableFrom = env->GetMethodID(langClass, "isAssignableFrom", "(Ljava/lang/Class;)Z");
for (int i = 0; i < cnt; i++) {
if (env->CallBooleanMethod(classObject, isAssignableFrom, classes[i])) {
jlong oldTag;
err = jvmti->GetTag(classes[i], &oldTag);
if (err != JVMTI_ERROR_NONE) return err;
char* sig;
if (jvmti->GetClassSignature(classes[i], &sig, nullptr) != JVMTI_ERROR_NONE) {
continue;
}
// jdk/internal/vm/FillerArray objects are used to mark dead heap areas
// see https://bugs.openjdk.org/browse/JDK-8284435
// These objects must not be accessible, so they are facultative for analysis.
//
// However, these objects are invisible for consecutive jvmti->IterateThroughHeap calls.
//
// Simple test: tag all objects with IterateThroughHeap, then remove tags with another IterateThroughHeap
// call. There will be 3 tags left.
//
// see https://youtrack.jetbrains.com/issue/IDEA-330128
if (strcmp(sig, "Ljdk/internal/vm/FillerArray;") == 0
|| strcmp(sig, "Ljdk/internal/vm/FillerObject;") == 0
|| strcmp(sig, "[Ljdk/internal/vm/FillerElement;") == 0) {
continue;
}
jlong newTag = createTag(oldTag);
if (newTag != 0) {
err = jvmti->SetTag(classes[i], newTag);
if (err != JVMTI_ERROR_NONE) return err;
}
}
}
return err;
}