src/reachability/objects_of_class_in_heap.cpp (71 lines of code) (raw):
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
#include "../roots/paths_to_closest_gc_roots.h"
#include "objects_of_class_in_heap.h"
#define CLASS_TAG 1
#define REFERENCE_CLASS_TAG 2
#define WEAK_SOFT_REACHABLE_TAG 3
#define STRONG_REACHABLE_TAG 4
#define OBJECT_OF_CLASS_TAG 5
jint JNICALL findReachableObjectsOfClass(jvmtiHeapReferenceKind refKind, const jvmtiHeapReferenceInfo *refInfo, jlong classTag,
jlong referrerClassTag, jlong size, jlong *tagPtr,
jlong *referrerTagPtr, jint length, void *userData) {
if (*tagPtr == REFERENCE_CLASS_TAG || *tagPtr == CLASS_TAG) {
return JVMTI_VISIT_OBJECTS;
} else if (classTag == REFERENCE_CLASS_TAG) {
*tagPtr = WEAK_SOFT_REACHABLE_TAG; // tag soft/weak/phantom reference
} else if (*tagPtr == 0) {
if (referrerTagPtr != nullptr && *referrerTagPtr == WEAK_SOFT_REACHABLE_TAG) {
*tagPtr = WEAK_SOFT_REACHABLE_TAG;
} else {
*tagPtr = STRONG_REACHABLE_TAG;
}
} else if (*tagPtr == WEAK_SOFT_REACHABLE_TAG) {
if (referrerTagPtr == nullptr || *referrerTagPtr != WEAK_SOFT_REACHABLE_TAG) {
*tagPtr = STRONG_REACHABLE_TAG;
}
}
if (classTag == CLASS_TAG && *tagPtr == STRONG_REACHABLE_TAG) {
*tagPtr = OBJECT_OF_CLASS_TAG;
if (*reinterpret_cast<bool *>(userData)) {
return JVMTI_VISIT_ABORT;
}
}
return JVMTI_VISIT_OBJECTS;
}
static jvmtiError getReachableObjectsOfClass(JNIEnv *env, jvmtiEnv *jvmti, jobject startObject, jobject classObject, std::vector<jobject> &result, bool findFirst) {
setTagsForReferences(env, jvmti, REFERENCE_CLASS_TAG);
jvmtiError err = tagClassAndItsInheritors(env, jvmti, classObject, [](jlong oldTag) -> jlong { return CLASS_TAG; });
if (err != JVMTI_ERROR_NONE) return err;
jvmtiHeapCallbacks cb;
std::memset(&cb, 0, sizeof(jvmtiHeapCallbacks));
cb.heap_reference_callback = findReachableObjectsOfClass;
err = jvmti->FollowReferences(0, nullptr, startObject, &cb, &findFirst);
if (err != JVMTI_ERROR_NONE) return err;
return getObjectsByTags(jvmti, std::vector<jlong>{OBJECT_OF_CLASS_TAG}, result);
}
GetFirstReachableObjectOfClassAction::GetFirstReachableObjectOfClassAction(JNIEnv *env, jvmtiEnv *jvmti, jobject object) : MemoryAgentAction(env, jvmti, object) {
}
jobject GetFirstReachableObjectOfClassAction::executeOperation(jobject startObject, jobject classObject) {
std::vector<jobject> result;
jvmtiError err = getReachableObjectsOfClass(env, jvmti, startObject, classObject, result, true);
handleError(jvmti, err, "Couldn't check class reachability");
return result.empty() ? nullptr : result[0];
}
jvmtiError GetFirstReachableObjectOfClassAction::cleanHeap() {
return removeAllTagsFromHeap(jvmti, nullptr);
}
GetAllReachableObjectsOfClassAction::GetAllReachableObjectsOfClassAction(JNIEnv *env, jvmtiEnv *jvmti, jobject object) : MemoryAgentAction(env, jvmti, object) {
}
jobjectArray GetAllReachableObjectsOfClassAction::executeOperation(jobject startObject, jobject classObject) {
std::vector<jobject> reachableObjects;
jvmtiError err = getReachableObjectsOfClass(env, jvmti, startObject, classObject, reachableObjects, false);
handleError(jvmti, err, "Couldn't get reachable objects of class");
jclass langObject = env->FindClass("java/lang/Object");
jobjectArray resultArray = env->NewObjectArray(reachableObjects.size(), langObject, nullptr);
for (jsize i = 0; i < reachableObjects.size(); ++i) {
env->SetObjectArrayElement(resultArray, i, reachableObjects[i]);
}
return resultArray;
}
jvmtiError GetAllReachableObjectsOfClassAction::cleanHeap() {
return removeAllTagsFromHeap(jvmti, nullptr);
}