Skip to content

Commit

Permalink
8340586: JdkJfrEvent::get_all_klasses stores non-strong oops in JNI h…
Browse files Browse the repository at this point in the history
…andles

Reviewed-by: coleenp, stefank, mgronlun
  • Loading branch information
xmas92 committed Nov 7, 2024
1 parent f2316f6 commit 97b681e
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 17 deletions.
28 changes: 11 additions & 17 deletions src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "oops/klass.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "utilities/stack.inline.hpp"

static jobject empty_java_util_arraylist = nullptr;
Expand Down Expand Up @@ -80,30 +81,25 @@ static bool is_allowed(const Klass* k) {
return !(k->is_abstract() || k->should_be_initialized());
}

static void fill_klasses(GrowableArray<const void*>& event_subklasses, const InstanceKlass* event_klass, JavaThread* thread) {
static void fill_klasses(GrowableArray<jclass>& event_subklasses, const InstanceKlass* event_klass, JavaThread* thread) {
assert(event_subklasses.length() == 0, "invariant");
assert(event_klass != nullptr, "invariant");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
// Do not safepoint while walking the ClassHierarchy, keeping klasses alive and storing their mirrors in JNI handles.
NoSafepointVerifier nsv;

for (ClassHierarchyIterator iter(const_cast<InstanceKlass*>(event_klass)); !iter.done(); iter.next()) {
Klass* subk = iter.klass();
if (is_allowed(subk)) {
event_subklasses.append(subk);
// We are walking the class hierarchy and saving the relevant klasses in JNI handles.
// To be allowed to store the java mirror, we must ensure that the klass and its oops are kept alive,
// and perform the store before the next safepoint.
subk->keep_alive();
event_subklasses.append((jclass)JfrJavaSupport::local_jni_handle(subk->java_mirror(), thread));
}
}
}

static void transform_klasses_to_local_jni_handles(GrowableArray<const void*>& event_subklasses, JavaThread* thread) {
assert(event_subklasses.is_nonempty(), "invariant");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));

for (int i = 0; i < event_subklasses.length(); ++i) {
const InstanceKlass* k = static_cast<const InstanceKlass*>(event_subklasses.at(i));
assert(is_allowed(k), "invariant");
event_subklasses.at_put(i, JfrJavaSupport::local_jni_handle(k->java_mirror(), thread));
}
}

jobject JdkJfrEvent::get_all_klasses(TRAPS) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
initialize(THREAD);
Expand All @@ -126,15 +122,13 @@ jobject JdkJfrEvent::get_all_klasses(TRAPS) {
}

ResourceMark rm(THREAD);
GrowableArray<const void*> event_subklasses(initial_array_size);
GrowableArray<jclass> event_subklasses(initial_array_size);
fill_klasses(event_subklasses, InstanceKlass::cast(klass), THREAD);

if (event_subklasses.is_empty()) {
return empty_java_util_arraylist;
}

transform_klasses_to_local_jni_handles(event_subklasses, THREAD);

Handle h_array_list(THREAD, new_java_util_arraylist(THREAD));
if (h_array_list.is_null()) {
return empty_java_util_arraylist;
Expand All @@ -152,7 +146,7 @@ jobject JdkJfrEvent::get_all_klasses(TRAPS) {

JavaValue result(T_BOOLEAN);
for (int i = 0; i < event_subklasses.length(); ++i) {
const jclass clazz = (jclass)event_subklasses.at(i);
const jclass clazz = event_subklasses.at(i);
assert(JdkJfrEvent::is_subklass(clazz), "invariant");
JfrJavaArguments args(&result, array_list_klass, add_method_sym, add_method_sig_sym);
args.set_receiver(h_array_list());
Expand Down
2 changes: 2 additions & 0 deletions src/hotspot/share/oops/klass.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,8 @@ class Klass : public Metadata {

inline oop klass_holder() const;

inline void keep_alive() const;

protected:

// Error handling when length > max_length or length < 0
Expand Down
8 changes: 8 additions & 0 deletions src/hotspot/share/oops/klass.inline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ inline oop Klass::klass_holder() const {
return class_loader_data()->holder();
}

inline void Klass::keep_alive() const {
// Resolving the holder (a WeakHandle) will keep the klass alive until the next safepoint.
// Making the klass's CLD handle oops (e.g. the java_mirror), safe to store in the object
// graph and its roots (e.g. Handles).
static_cast<void>(klass_holder());
}

inline bool Klass::is_non_strong_hidden() const {
return is_hidden() && class_loader_data()->has_class_mirror_holder();
}
Expand All @@ -52,6 +59,7 @@ inline bool Klass::is_loader_alive() const {
return class_loader_data()->is_alive();
}

// Loading the java_mirror does not keep its holder alive. See Klass::keep_alive().
inline oop Klass::java_mirror() const {
return _java_mirror.resolve();
}
Expand Down

0 comments on commit 97b681e

Please sign in to comment.