From 1ee62064346392b8ed38f22983221be71b86e53f Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Mon, 10 Nov 2025 12:29:29 -0800 Subject: [PATCH] fix --- src/hotspot/share/prims/jvmtiTagMap.cpp | 39 +++++- .../KindSystemClass/KindSystemClass.java | 62 ++++++++++ .../KindSystemClass/libKindSystemClass.cpp | 113 ++++++++++++++++++ 3 files changed, 211 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/serviceability/jvmti/FollowReferences/KindSystemClass/KindSystemClass.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/FollowReferences/KindSystemClass/libKindSystemClass.cpp diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index a69c7cb714249..6431a748fde7f 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -2190,6 +2190,39 @@ class SimpleRootsClosure : public OopClosure { virtual void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); } }; +// A supporting closure used to process ClassLoaderData roots +class CLDRootsClosure: public OopClosure { +private: + bool _continue; +public: + CLDRootsClosure(): _continue(true) {} + + inline bool stopped() { + return !_continue; + } + + void do_oop(oop* obj_p) { + if (stopped()) { + return; + } + + oop o = NativeAccess::oop_load(obj_p); + // ignore null + if (o == nullptr) { + return; + } + + jvmtiHeapReferenceKind kind = JVMTI_HEAP_REFERENCE_OTHER; + if (o->klass() == vmClasses::Class_klass()) { + kind = JVMTI_HEAP_REFERENCE_SYSTEM_CLASS; + } + + // invoke the callback + _continue = CallbackInvoker::report_simple_root(kind, o); + } + virtual void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); } +}; + // A supporting closure used to process JNI locals class JNILocalRootsClosure : public OopClosure { private: @@ -2776,10 +2809,10 @@ inline bool VM_HeapWalkOperation::collect_simple_roots() { } // Preloaded classes and loader from the system dictionary - blk.set_kind(JVMTI_HEAP_REFERENCE_SYSTEM_CLASS); - CLDToOopClosure cld_closure(&blk, ClassLoaderData::_claim_none); + CLDRootsClosure cld_roots_closure; + CLDToOopClosure cld_closure(&cld_roots_closure, ClassLoaderData::_claim_none); ClassLoaderDataGraph::always_strong_cld_do(&cld_closure); - if (blk.stopped()) { + if (cld_roots_closure.stopped()) { return false; } diff --git a/test/hotspot/jtreg/serviceability/jvmti/FollowReferences/KindSystemClass/KindSystemClass.java b/test/hotspot/jtreg/serviceability/jvmti/FollowReferences/KindSystemClass/KindSystemClass.java new file mode 100644 index 0000000000000..d02364d2b8f12 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/FollowReferences/KindSystemClass/KindSystemClass.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8371083 + * @summary Verify FollowReferences does not report non-classes roots as JVMTI_HEAP_REFERENCE_SYSTEM_CLASS + * @requires vm.jvmti + * @run main/othervm/native -agentlib:KindSystemClass + * KindSystemClass + */ + +public class KindSystemClass { + + static native int tagSysClasses(); + static native Object[] getObjectsWithTags(); + + public static void main(String[] args) throws Exception { + System.loadLibrary("KindSystemClass"); + + int tagged = tagSysClasses(); + System.out.println("Tagged " + tagged + " classes"); + + Object[] objs = getObjectsWithTags(); + System.out.println("Tagged objects (total " + objs.length + "):"); + int nonClassesCnt = 0; + for (int i = 0; i < objs.length; i++) { + Object obj = objs[i]; + String s; + if (obj instanceof Class cls) { + s = "OK: " + cls; + } else { + nonClassesCnt++; + s = "ERROR, not a class: " + obj; + } + System.out.println("[" + i + "] " + s); + } + if (nonClassesCnt != 0) { + throw new RuntimeException("Found " + nonClassesCnt + " non-classes"); + } + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/FollowReferences/KindSystemClass/libKindSystemClass.cpp b/test/hotspot/jtreg/serviceability/jvmti/FollowReferences/KindSystemClass/libKindSystemClass.cpp new file mode 100644 index 0000000000000..2d4d949461d69 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/FollowReferences/KindSystemClass/libKindSystemClass.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include "jvmti_common.hpp" + +static jvmtiEnv *jvmti = nullptr; +static int class_counter = 0; +static int other_counter = 0; + +static jint JNICALL +heap_reference_callback(jvmtiHeapReferenceKind reference_kind, + const jvmtiHeapReferenceInfo* reference_info, + jlong class_tag, + jlong referrer_class_tag, + jlong size, + jlong* tag_ptr, + jlong* referrer_tag_ptr, + jint length, + void* user_data) { + switch (reference_kind) { + case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS: + *tag_ptr = ++class_counter; + break; + case JVMTI_HEAP_REFERENCE_OTHER: + ++other_counter; + break; + default: + break; + } + return JVMTI_VISIT_OBJECTS; +} + +extern "C" JNIEXPORT jint JNICALL +Java_KindSystemClass_tagSysClasses(JNIEnv* jni, jclass clazz) { + jvmtiHeapCallbacks callbacks = {}; + callbacks.heap_reference_callback = heap_reference_callback; + + jvmtiError err = jvmti->FollowReferences(0 /* filter nothing */, + nullptr /* no class filter */, + nullptr /* no initial object, follow roots */, + &callbacks, + nullptr); + check_jvmti_error(err, "FollowReferences failed"); + + LOG("JVMTI_HEAP_REFERENCE_SYSTEM_CLASS: %d, JVMTI_HEAP_REFERENCE_OTHER: %d\n", class_counter, other_counter); + + return class_counter; +} + +extern "C" JNIEXPORT jobjectArray JNICALL +Java_KindSystemClass_getObjectsWithTags(JNIEnv* jni, jclass clazz) { + // request tagged objects with tags 1..class_counter + jlong* tags = nullptr; + jvmtiError err = jvmti->Allocate(class_counter * sizeof(jlong), (unsigned char**)&tags); + check_jvmti_error(err, "Allocate failed"); + + for (int i = 0; i < class_counter; i++) { + tags[i] = i+1; + } + + jint count = 0; + jobject* objects = nullptr; + + err = jvmti->GetObjectsWithTags(class_counter, tags, + &count, &objects, nullptr); + check_jvmti_error(err, "GetObjectsWithTags failed"); + + jclass object_klass = jni->FindClass("java/lang/Object"); + jobjectArray array = jni->NewObjectArray(count, object_klass, nullptr); + + for (jint i = 0; i < count; i++) { + jni->SetObjectArrayElement(array, i, objects[i]); + } + + deallocate(jvmti, jni, objects); + + return array; +} + + +extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { + if (vm->GetEnv(reinterpret_cast(&jvmti), JVMTI_VERSION) != JNI_OK || !jvmti) { + LOG("Could not initialize JVMTI\n"); + abort(); + } + jvmtiCapabilities capabilities; + memset(&capabilities, 0, sizeof(capabilities)); + capabilities.can_tag_objects = 1; + check_jvmti_error(jvmti->AddCapabilities(&capabilities), "adding capabilities"); + return JVMTI_ERROR_NONE; +} +