Skip to content
Permalink
Browse files
8266973: Migrate to ClassHierarchyIterator when enumerating subclasses
Reviewed-by: kvn, coleenp
  • Loading branch information
Vladimir Ivanov committed May 18, 2021
1 parent 02507bc commit 9d168e25d1e2e8b662dc7aa6cda7516c423cef7d
@@ -1647,16 +1647,14 @@ bool Dependencies::is_concrete_method(Method* m, Klass* k) {
return true;
}

Klass* Dependencies::find_finalizable_subclass(Klass* k) {
if (k->is_interface()) return NULL;
if (k->has_finalizer()) return k;
k = k->subklass();
while (k != NULL) {
Klass* result = find_finalizable_subclass(k);
if (result != NULL) return result;
k = k->next_sibling();
Klass* Dependencies::find_finalizable_subclass(InstanceKlass* ik) {
for (ClassHierarchyIterator iter(ik); !iter.done(); iter.next()) {
Klass* sub = iter.klass();
if (sub->has_finalizer() && !sub->is_interface()) {
return sub;
}
}
return NULL;
return NULL; // not found
}

bool Dependencies::is_concrete_klass(ciInstanceKlass* k) {
@@ -1895,9 +1893,10 @@ Method* Dependencies::find_unique_concrete_method(InstanceKlass* ctxk, Method* m
}

Klass* Dependencies::check_has_no_finalizable_subclasses(InstanceKlass* ctxk, NewKlassDepChange* changes) {
Klass* search_at = ctxk;
if (changes != NULL)
InstanceKlass* search_at = ctxk;
if (changes != NULL) {
search_at = changes->new_type(); // just look at the new bit
}
return find_finalizable_subclass(search_at);
}

@@ -382,7 +382,7 @@ class Dependencies: public ResourceObj {
// and abstract (as defined by the Java language and VM).
static bool is_concrete_klass(Klass* k); // k is instantiable
static bool is_concrete_method(Method* m, Klass* k); // m is invocable
static Klass* find_finalizable_subclass(Klass* k);
static Klass* find_finalizable_subclass(InstanceKlass* ik);

// These versions of the concreteness queries work through the CI.
// The CI versions are allowed to skew sometimes from the VM
@@ -324,29 +324,12 @@ static bool is_classloader_klass_allowed(const Klass* k) {
}

static void do_classloaders() {
Stack<const Klass*, mtTracing> mark_stack;
mark_stack.push(vmClasses::ClassLoader_klass()->subklass());

while (!mark_stack.is_empty()) {
const Klass* const current = mark_stack.pop();
assert(current != NULL, "null element in stack!");
if (is_classloader_klass_allowed(current)) {
do_loader_klass(current);
}

// subclass (depth)
const Klass* next_klass = current->subklass();
if (next_klass != NULL) {
mark_stack.push(next_klass);
}

// siblings (breadth)
next_klass = current->next_sibling();
if (next_klass != NULL) {
mark_stack.push(next_klass);
for (ClassHierarchyIterator iter(vmClasses::ClassLoader_klass()); !iter.done(); iter.next()) {
Klass* subk = iter.klass();
if (is_classloader_klass_allowed(subk)) {
do_loader_klass(subk);
}
}
assert(mark_stack.is_empty(), "invariant");
}

static int primitives_count = 9;
@@ -76,35 +76,17 @@ 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 Klass* event_klass, JavaThread* thread) {
static void fill_klasses(GrowableArray<const void*>& event_subklasses, const InstanceKlass* event_klass, JavaThread* thread) {
assert(event_subklasses.length() == 0, "invariant");
assert(event_klass != NULL, "invariant");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));

Stack<const Klass*, mtTracing> mark_stack;
mark_stack.push(event_klass->subklass());

while (!mark_stack.is_empty()) {
const Klass* const current = mark_stack.pop();
assert(current != NULL, "null element in stack!");

if (is_allowed(current)) {
event_subklasses.append(current);
}

// subclass (depth)
const Klass* next_klass = current->subklass();
if (next_klass != NULL) {
mark_stack.push(next_klass);
}

// siblings (breadth)
next_klass = current->next_sibling();
if (next_klass != NULL) {
mark_stack.push(next_klass);
for (ClassHierarchyIterator iter(const_cast<InstanceKlass*>(event_klass)); !iter.done(); iter.next()) {
Klass* subk = iter.klass();
if (is_allowed(subk)) {
event_subklasses.append(subk);
}
}
assert(mark_stack.is_empty(), "invariant");
}

static void transform_klasses_to_local_jni_handles(GrowableArray<const void*>& event_subklasses, JavaThread* thread) {
@@ -132,6 +114,7 @@ jobject JdkJfrEvent::get_all_klasses(TRAPS) {

const Klass* const klass = SystemDictionary::resolve_or_null(event_klass_name, THREAD);
assert(klass != NULL, "invariant");
assert(klass->is_instance_klass(), "invariant");
assert(JdkJfrEvent::is(klass), "invariant");

if (klass->subklass() == NULL) {
@@ -140,7 +123,7 @@ jobject JdkJfrEvent::get_all_klasses(TRAPS) {

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

if (event_subklasses.is_empty()) {
return empty_java_util_arraylist;
@@ -827,7 +827,11 @@ C2V_END
C2V_VMENTRY_0(jboolean, hasFinalizableSubclass,(JNIEnv* env, jobject, jobject jvmci_type))
Klass* klass = JVMCIENV->asKlass(jvmci_type);
assert(klass != NULL, "method must not be called for primitive types");
return Dependencies::find_finalizable_subclass(klass) != NULL;
if (!klass->is_instance_klass()) {
return false;
}
InstanceKlass* iklass = InstanceKlass::cast(klass);
return Dependencies::find_finalizable_subclass(iklass) != NULL;
C2V_END

C2V_VMENTRY_NULL(jobject, getClassInitializer, (JNIEnv* env, jobject, jobject jvmci_type))
@@ -514,24 +514,14 @@ oop Universe::swap_reference_pending_list(oop list) {
#undef assert_pll_locked
#undef assert_pll_ownership

static void reinitialize_vtable_of(Klass* ko) {
// init vtable of k and all subclasses
ko->vtable().initialize_vtable();
if (ko->is_instance_klass()) {
for (Klass* sk = ko->subklass();
sk != NULL;
sk = sk->next_sibling()) {
reinitialize_vtable_of(sk);
}
}
}

static void reinitialize_vtables() {
// The vtables are initialized by starting at java.lang.Object and
// initializing through the subclass links, so that the super
// classes are always initialized first.
Klass* ok = vmClasses::Object_klass();
reinitialize_vtable_of(ok);
for (ClassHierarchyIterator iter(vmClasses::Object_klass()); !iter.done(); iter.next()) {
Klass* sub = iter.klass();
sub->vtable().initialize_vtable();
}
}


@@ -1406,7 +1406,6 @@ class ClassHierarchyIterator : public StackObj {

public:
ClassHierarchyIterator(InstanceKlass* root) : _root(root), _current(root), _visit_subclasses(true) {
assert(!root->is_interface(), "no subclasses");
assert(_root == _current, "required"); // initial state
}

@@ -4420,7 +4420,7 @@ void VM_RedefineClasses::redefine_single_class(Thread* current, jclass the_jclas
the_class->oop_map_cache()->flush_obsolete_entries();
}

increment_class_counter((InstanceKlass *)the_class);
increment_class_counter(the_class);

if (EventClassRedefinition::is_enabled()) {
EventClassRedefinition event;
@@ -4449,24 +4449,20 @@ void VM_RedefineClasses::redefine_single_class(Thread* current, jclass the_jclas

// Increment the classRedefinedCount field in the specific InstanceKlass
// and in all direct and indirect subclasses.
void VM_RedefineClasses::increment_class_counter(InstanceKlass *ik) {
oop class_mirror = ik->java_mirror();
Klass* class_oop = java_lang_Class::as_Klass(class_mirror);
int new_count = java_lang_Class::classRedefinedCount(class_mirror) + 1;
java_lang_Class::set_classRedefinedCount(class_mirror, new_count);

if (class_oop != _the_class) {
// _the_class count is printed at end of redefine_single_class()
log_debug(redefine, class, subclass)("updated count in subclass=%s to %d", ik->external_name(), new_count);
}

for (Klass *subk = ik->subklass(); subk != NULL;
subk = subk->next_sibling()) {
if (subk->is_instance_klass()) {
// Only update instanceKlasses
InstanceKlass *subik = InstanceKlass::cast(subk);
// recursively do subclasses of the current subclass
increment_class_counter(subik);
void VM_RedefineClasses::increment_class_counter(InstanceKlass* ik) {
for (ClassHierarchyIterator iter(ik); !iter.done(); iter.next()) {
// Only update instanceKlasses
Klass* sub = iter.klass();
if (sub->is_instance_klass()) {
oop class_mirror = InstanceKlass::cast(sub)->java_mirror();
Klass* class_oop = java_lang_Class::as_Klass(class_mirror);
int new_count = java_lang_Class::classRedefinedCount(class_mirror) + 1;
java_lang_Class::set_classRedefinedCount(class_mirror, new_count);

if (class_oop != _the_class) {
// _the_class count is printed at end of redefine_single_class()
log_debug(redefine, class, subclass)("updated count in subclass=%s to %d", ik->external_name(), new_count);
}
}
}
}
@@ -423,7 +423,7 @@ class VM_RedefineClasses: public VM_Operation {

// Increment the classRedefinedCount field in the specific InstanceKlass
// and in all direct and indirect subclasses.
void increment_class_counter(InstanceKlass *ik);
void increment_class_counter(InstanceKlass* ik);

// Support for constant pool merging (these routines are in alpha order):
void append_entry(const constantPoolHandle& scratch_cp, int scratch_i,

0 comments on commit 9d168e2

Please sign in to comment.