jvmtiError tagClassAndItsInheritors()

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;
}