Skip to content
Permalink
Browse files
8276789: Support C++ lambda in ResourceHashtable::iterate
Reviewed-by: stefank, coleenp
  • Loading branch information
iklam committed Jun 3, 2022
1 parent ba9ee8c commit b544b8b7d43907e93263db31ba3cc6d5951bcaee
Showing 5 changed files with 74 additions and 83 deletions.
@@ -193,21 +193,20 @@ class CountClassByCategory : StackObj {
DumpTimeSharedClassTable* _table;
public:
CountClassByCategory(DumpTimeSharedClassTable* table) : _table(table) {}
bool do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
void do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
if (!info.is_excluded()) {
if (info.is_builtin()) {
_table->inc_builtin_count();
} else {
_table->inc_unregistered_count();
}
}
return true; // keep on iterating
}
};

void DumpTimeSharedClassTable::update_counts() {
_builtin_count = 0;
_unregistered_count = 0;
CountClassByCategory counter(this);
iterate(&counter);
iterate_all_live_classes(&counter);
}
@@ -1,4 +1,3 @@

/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -209,10 +208,17 @@ class DumpTimeSharedClassTable: public DumpTimeSharedClassTableBaseType
}
}

// Overrides ResourceHashtable<>::iterate(ITER*)
template<class ITER> void iterate(ITER* iter) const;
template<class ITER> void iterate_all_live_classes(ITER* iter) const;
template<typename Function> void iterate_all_live_classes(Function function) const;

private:
template<class ITER> class IterationHelper;
// It's unsafe to iterate on classes whose loader is dead.
// Declare these private and don't implement them. This forces users of
// DumpTimeSharedClassTable to use the iterate_all_live_classes() methods
// instead.
template<class ITER> void iterate(ITER* iter) const;
template<typename Function> void iterate(Function function) const;
template<typename Function> void iterate_all(Function function) const;
};

#endif // SHARED_CDS_DUMPTIMESHAREDCLASSINFO_HPP
@@ -1,6 +1,6 @@

/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@@ -35,38 +35,34 @@

#if INCLUDE_CDS

// For safety, only iterate over a class if it loader is alive.
// IterationHelper and DumpTimeSharedClassTable::iterate
// must be used only inside a safepoint, where the value of
// For safety, only iterate over a class if its loader is alive.
// This function must be called only inside a safepoint, where the value of
// k->is_loader_alive() will not change.
template<class ITER>
class DumpTimeSharedClassTable::IterationHelper {
ITER* _iter;
public:
IterationHelper(ITER* iter) {
_iter = iter;
}
bool do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
template<typename Function>
void DumpTimeSharedClassTable::iterate_all_live_classes(Function function) const {
auto wrapper = [&] (InstanceKlass* k, DumpTimeClassInfo& info) {
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
assert_lock_strong(DumpTimeTable_lock);
if (k->is_loader_alive()) {
bool result = _iter->do_entry(k, info);
function(k, info);
assert(k->is_loader_alive(), "must not change");
return result;
} else {
if (!SystemDictionaryShared::is_excluded_class(k)) {
SystemDictionaryShared::warn_excluded(k, "Class loader not alive");
SystemDictionaryShared::set_excluded_locked(k);
}
return true;
}
}
};
};
DumpTimeSharedClassTableBaseType::iterate_all(wrapper);
}


template<class ITER>
void DumpTimeSharedClassTable::iterate(ITER* iter) const {
IterationHelper<ITER> helper(iter);
DumpTimeSharedClassTableBaseType::iterate(&helper);
void DumpTimeSharedClassTable::iterate_all_live_classes(ITER* iter) const {
auto function = [&] (InstanceKlass* k, DumpTimeClassInfo& v) {
iter->do_entry(k, v);
};
iterate_all_live_classes(function);
}

#endif // INCLUDE_CDS
@@ -617,11 +617,10 @@ class UnregisteredClassesDuplicationChecker : StackObj {
public:
UnregisteredClassesDuplicationChecker() : _thread(Thread::current()) {}

bool do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
void do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
if (!SystemDictionaryShared::is_builtin(k)) {
_list.append(k);
}
return true; // keep on iterating
}

static int compare_by_loader(InstanceKlass** a, InstanceKlass** b) {
@@ -653,29 +652,23 @@ class UnregisteredClassesDuplicationChecker : StackObj {
}
};

class ExcludeDumpTimeSharedClasses : StackObj {
public:
bool do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
SystemDictionaryShared::check_for_exclusion(k, &info);
return true; // keep on iterating
}
};

void SystemDictionaryShared::check_excluded_classes() {
assert(no_class_loading_should_happen(), "sanity");
assert_lock_strong(DumpTimeTable_lock);

if (DynamicDumpSharedSpaces) {
// Do this first -- if a base class is excluded due to duplication,
// all of its subclasses will also be excluded by ExcludeDumpTimeSharedClasses
// all of its subclasses will also be excluded.
ResourceMark rm;
UnregisteredClassesDuplicationChecker dup_checker;
_dumptime_table->iterate(&dup_checker);
_dumptime_table->iterate_all_live_classes(&dup_checker);
dup_checker.mark_duplicated_classes();
}

ExcludeDumpTimeSharedClasses excl;
_dumptime_table->iterate(&excl);
auto check_for_exclusion = [&] (InstanceKlass* k, DumpTimeClassInfo& info) {
SystemDictionaryShared::check_for_exclusion(k, &info);
};
_dumptime_table->iterate_all_live_classes(check_for_exclusion);
_dumptime_table->update_counts();

cleanup_lambda_proxy_class_dictionary();
@@ -725,42 +718,24 @@ bool SystemDictionaryShared::has_class_failed_verification(InstanceKlass* ik) {
return (p == NULL) ? false : p->failed_verification();
}

class IterateDumpTimeSharedClassTable : StackObj {
MetaspaceClosure *_it;
public:
IterateDumpTimeSharedClassTable(MetaspaceClosure* it) : _it(it) {}
void SystemDictionaryShared::dumptime_classes_do(class MetaspaceClosure* it) {
assert_lock_strong(DumpTimeTable_lock);

bool do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
assert_lock_strong(DumpTimeTable_lock);
auto do_klass = [&] (InstanceKlass* k, DumpTimeClassInfo& info) {
if (k->is_loader_alive() && !info.is_excluded()) {
info.metaspace_pointers_do(_it);
info.metaspace_pointers_do(it);
}
return true; // keep on iterating
}
};
};
_dumptime_table->iterate_all_live_classes(do_klass);

class IterateDumpTimeLambdaProxyClassDictionary : StackObj {
MetaspaceClosure *_it;
public:
IterateDumpTimeLambdaProxyClassDictionary(MetaspaceClosure* it) : _it(it) {}

bool do_entry(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) {
assert_lock_strong(DumpTimeTable_lock);
if (key.caller_ik()->is_loader_alive()) {
info.metaspace_pointers_do(_it);
key.metaspace_pointers_do(_it);
}
return true; // keep on iterating
}
};

void SystemDictionaryShared::dumptime_classes_do(class MetaspaceClosure* it) {
assert_lock_strong(DumpTimeTable_lock);
IterateDumpTimeSharedClassTable iter(it);
_dumptime_table->iterate(&iter);
if (_dumptime_lambda_proxy_class_dictionary != NULL) {
IterateDumpTimeLambdaProxyClassDictionary iter_lambda(it);
_dumptime_lambda_proxy_class_dictionary->iterate(&iter_lambda);
auto do_lambda = [&] (LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) {
if (key.caller_ik()->is_loader_alive()) {
info.metaspace_pointers_do(it);
key.metaspace_pointers_do(it);
}
};
_dumptime_lambda_proxy_class_dictionary->iterate_all(do_lambda);
}
}

@@ -1172,12 +1147,11 @@ class EstimateSizeForArchive : StackObj {
_num_unregistered_klasses = 0;
}

bool do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
void do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
if (!info.is_excluded()) {
size_t byte_size = info.runtime_info_bytesize();
_shared_class_info_size += align_up(byte_size, SharedSpaceObjectAlignment);
}
return true; // keep on iterating
}

size_t total() {
@@ -1187,7 +1161,7 @@ class EstimateSizeForArchive : StackObj {

size_t SystemDictionaryShared::estimate_size_for_archive() {
EstimateSizeForArchive est;
_dumptime_table->iterate(&est);
_dumptime_table->iterate_all_live_classes(&est);
size_t total_size = est.total() +
CompactHashtableWriter::estimate_size(_dumptime_table->count_of(true)) +
CompactHashtableWriter::estimate_size(_dumptime_table->count_of(false));
@@ -1281,7 +1255,7 @@ class CopySharedClassInfoToArchive : StackObj {
bool is_builtin)
: _writer(writer), _is_builtin(is_builtin), _builder(ArchiveBuilder::current()) {}

bool do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
void do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
if (!info.is_excluded() && info.is_builtin() == _is_builtin) {
size_t byte_size = info.runtime_info_bytesize();
RunTimeClassInfo* record;
@@ -1305,7 +1279,6 @@ class CopySharedClassInfoToArchive : StackObj {
// Save this for quick runtime lookup of InstanceKlass* -> RunTimeClassInfo*
RunTimeClassInfo::set_for(info._klass, record);
}
return true; // keep on iterating
}
};

@@ -1325,7 +1298,7 @@ void SystemDictionaryShared::write_dictionary(RunTimeSharedDictionary* dictionar
CompactHashtableWriter writer(_dumptime_table->count_of(is_builtin), &stats);
CopySharedClassInfoToArchive copy(&writer, is_builtin);
assert_lock_strong(DumpTimeTable_lock);
_dumptime_table->iterate(&copy);
_dumptime_table->iterate_all_live_classes(&copy);
writer.dump(dictionary, is_builtin ? "builtin dictionary" : "unregistered dictionary");
}

@@ -1558,12 +1531,11 @@ class CloneDumpTimeClassTable: public StackObj {
assert(_table != NULL, "_dumptime_table is NULL");
assert(_cloned_table != NULL, "_cloned_table is NULL");
}
bool do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
void do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
if (!info.is_excluded()) {
bool created;
_cloned_table->put_if_absent(k, info.clone(), &created);
}
return true; // keep on iterating
}
};

@@ -1596,7 +1568,7 @@ void SystemDictionaryShared::clone_dumptime_tables() {
assert(_cloned_dumptime_table == NULL, "_cloned_dumptime_table must be cleaned");
_cloned_dumptime_table = new (ResourceObj::C_HEAP, mtClass) DumpTimeSharedClassTable;
CloneDumpTimeClassTable copy_classes(_dumptime_table, _cloned_dumptime_table);
_dumptime_table->iterate(&copy_classes);
_dumptime_table->iterate_all_live_classes(&copy_classes);
_cloned_dumptime_table->update_counts();
}
if (_dumptime_lambda_proxy_class_dictionary != NULL) {
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2022, 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
@@ -203,19 +203,37 @@ class ResourceHashtableBase : public STORAGE {
// the iteration is cancelled.
template<class ITER>
void iterate(ITER* iter) const {
auto function = [&] (K& k, V& v) {
return iter->do_entry(k, v);
};
iterate(function);
}

template<typename Function>
void iterate(Function function) const { // lambda enabled API
Node* const* bucket = table();
const unsigned sz = table_size();
while (bucket < bucket_at(sz)) {
Node* node = *bucket;
while (node != NULL) {
bool cont = iter->do_entry(node->_key, node->_value);
bool cont = function(node->_key, node->_value);
if (!cont) { return; }
node = node->_next;
}
++bucket;
}
}

// same as above, but unconditionally iterate all entries
template<typename Function>
void iterate_all(Function function) const { // lambda enabled API
auto wrapper = [&] (K& k, V& v) {
function(k, v);
return true;
};
iterate(wrapper);
}

// ITER contains bool do_entry(K const&, V const&), which will be
// called for each entry in the table. If do_entry() returns true,
// the entry is deleted.

1 comment on commit b544b8b

@openjdk-notifier
Copy link

@openjdk-notifier openjdk-notifier bot commented on b544b8b Jun 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.