mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-21 21:33:07 +00:00
8276789: Support C++ lambda in ResourceHashtable::iterate
Reviewed-by: stefank, coleenp
This commit is contained in:
parent
ba9ee8cb28
commit
b544b8b7d4
@ -193,7 +193,7 @@ 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();
|
||||
@ -201,7 +201,6 @@ public:
|
||||
_table->inc_unregistered_count();
|
||||
}
|
||||
}
|
||||
return true; // keep on iterating
|
||||
}
|
||||
};
|
||||
|
||||
@ -209,5 +208,5 @@ 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 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// 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 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
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) {}
|
||||
|
||||
bool do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
|
||||
assert_lock_strong(DumpTimeTable_lock);
|
||||
if (k->is_loader_alive() && !info.is_excluded()) {
|
||||
info.metaspace_pointers_do(_it);
|
||||
}
|
||||
return true; // keep on iterating
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
auto do_klass = [&] (InstanceKlass* k, DumpTimeClassInfo& info) {
|
||||
if (k->is_loader_alive() && !info.is_excluded()) {
|
||||
info.metaspace_pointers_do(it);
|
||||
}
|
||||
};
|
||||
_dumptime_table->iterate_all_live_classes(do_klass);
|
||||
|
||||
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 @@ public:
|
||||
_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 @@ public:
|
||||
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
// 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(©);
|
||||
_dumptime_table->iterate_all_live_classes(©);
|
||||
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(©_classes);
|
||||
_dumptime_table->iterate_all_live_classes(©_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,12 +203,20 @@ 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;
|
||||
}
|
||||
@ -216,6 +224,16 @@ class ResourceHashtableBase : public STORAGE {
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user