mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
Co-authored-by: John R Rose <jrose@openjdk.org> Co-authored-by: Vladimir Ivanov <vlivanov@openjdk.org> Co-authored-by: Ioi Lam <iklam@openjdk.org> Co-authored-by: Vladimir Kozlov <kvn@openjdk.org> Co-authored-by: Aleksey Shipilev <shade@openjdk.org> Reviewed-by: kvn, ihse, cjplummer, iklam
303 lines
10 KiB
C++
303 lines
10 KiB
C++
/*
|
|
* 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 "cds/aotArtifactFinder.hpp"
|
|
#include "cds/aotClassInitializer.hpp"
|
|
#include "cds/aotClassLinker.hpp"
|
|
#include "cds/aotLogging.hpp"
|
|
#include "cds/aotReferenceObjSupport.hpp"
|
|
#include "cds/dumpTimeClassInfo.inline.hpp"
|
|
#include "cds/heapShared.hpp"
|
|
#include "cds/lambdaProxyClassDictionary.hpp"
|
|
#include "classfile/systemDictionaryShared.hpp"
|
|
#include "logging/log.hpp"
|
|
#include "memory/metaspaceClosure.hpp"
|
|
#include "oops/instanceKlass.hpp"
|
|
#include "oops/objArrayKlass.hpp"
|
|
#include "oops/trainingData.hpp"
|
|
#include "utilities/resourceHash.hpp"
|
|
|
|
// All the classes that should be included in the AOT cache (in at least the "allocated" state)
|
|
static GrowableArrayCHeap<Klass*, mtClassShared>* _all_cached_classes = nullptr;
|
|
|
|
// This is a stack that tracks all the AOT-inited classes that are waiting to be passed
|
|
// to HeapShared::copy_and_rescan_aot_inited_mirror().
|
|
static GrowableArrayCHeap<InstanceKlass*, mtClassShared>* _pending_aot_inited_classes = nullptr;
|
|
|
|
static const int TABLE_SIZE = 15889; // prime number
|
|
using ClassesTable = ResourceHashtable<Klass*, bool, TABLE_SIZE, AnyObj::C_HEAP, mtClassShared>;
|
|
static ClassesTable* _seen_classes; // all classes that have been seen by AOTArtifactFinder
|
|
static ClassesTable* _aot_inited_classes; // all classes that need to be AOT-initialized.
|
|
|
|
void AOTArtifactFinder::initialize() {
|
|
_all_cached_classes = new GrowableArrayCHeap<Klass*, mtClassShared>();
|
|
_pending_aot_inited_classes = new GrowableArrayCHeap<InstanceKlass*, mtClassShared>();
|
|
_seen_classes = new (mtClass)ClassesTable();
|
|
_aot_inited_classes = new (mtClass)ClassesTable();
|
|
}
|
|
|
|
void AOTArtifactFinder::dispose() {
|
|
delete _all_cached_classes;
|
|
delete _seen_classes;
|
|
delete _aot_inited_classes;
|
|
delete _pending_aot_inited_classes;
|
|
_all_cached_classes = nullptr;
|
|
_seen_classes = nullptr;
|
|
_aot_inited_classes = nullptr;
|
|
_pending_aot_inited_classes = nullptr;
|
|
}
|
|
|
|
// Find all Klasses and oops that should be included in the AOT cache. See aotArtifactFinder.hpp
|
|
void AOTArtifactFinder::find_artifacts() {
|
|
// Some classes might have been marked as excluded as a side effect of running
|
|
// AOTConstantPoolResolver. Make sure we check all the remaining ones.
|
|
//
|
|
// Note, if a class is not excluded, it does NOT mean it will be automatically included
|
|
// into the AOT cache -- that will be decided by the code below.
|
|
SystemDictionaryShared::finish_exclusion_checks();
|
|
AOTReferenceObjSupport::init_keep_alive_objs_table();
|
|
|
|
start_scanning_for_oops();
|
|
|
|
// Add the primitive array classes
|
|
for (int i = T_BOOLEAN; i < T_VOID+1; i++) {
|
|
BasicType bt = (BasicType)i;
|
|
if (is_java_primitive(bt)) {
|
|
add_cached_type_array_class(Universe::typeArrayKlass(bt));
|
|
}
|
|
}
|
|
|
|
#if INCLUDE_CDS_JAVA_HEAP
|
|
// Add the mirrors that aren't associated with a Klass
|
|
// - primitive mirrors (E.g., "int.class" in Java code)
|
|
// - mirror of fillerArrayKlass
|
|
if (CDSConfig::is_dumping_heap()) {
|
|
for (int i = T_BOOLEAN; i < T_VOID+1; i++) {
|
|
BasicType bt = (BasicType)i;
|
|
if (!is_reference_type(bt)) {
|
|
oop orig_mirror = Universe::java_mirror(bt);
|
|
oop scratch_mirror = HeapShared::scratch_java_mirror(bt);
|
|
HeapShared::scan_java_mirror(orig_mirror);
|
|
log_trace(aot, heap, mirror)(
|
|
"Archived %s mirror object from " PTR_FORMAT,
|
|
type2name(bt), p2i(scratch_mirror));
|
|
Universe::set_archived_basic_type_mirror_index(bt, HeapShared::append_root(scratch_mirror));
|
|
}
|
|
}
|
|
|
|
// Universe::fillerArrayKlass() isn't in the class hierarchy, so handle it specially.
|
|
HeapShared::scan_java_mirror(Universe::fillerArrayKlass()->java_mirror());
|
|
}
|
|
#endif
|
|
|
|
// Add all the InstanceKlasses (and their array classes) that are always included.
|
|
SystemDictionaryShared::dumptime_table()->iterate_all_live_classes([&] (InstanceKlass* ik, DumpTimeClassInfo& info) {
|
|
// Skip "AOT tooling classes" in this block. They will be included in the AOT cache only if
|
|
// - One of their subtypes is included
|
|
// - One of their instances is found by HeapShared.
|
|
if (!info.is_excluded() && !info.is_aot_tooling_class()) {
|
|
bool add = false;
|
|
if (!ik->is_hidden()) {
|
|
// All non-hidden classes are always included into the AOT cache
|
|
add = true;
|
|
} else {
|
|
if (CDSConfig::is_dumping_lambdas_in_legacy_mode()) {
|
|
// Legacy support of lambda proxies -- these are always included into the AOT cache
|
|
if (LambdaProxyClassDictionary::is_registered_lambda_proxy_class(ik)) {
|
|
add = true;
|
|
}
|
|
} else {
|
|
assert(!LambdaProxyClassDictionary::is_registered_lambda_proxy_class(ik),
|
|
"registered lambda proxies are only for legacy lambda proxy support");
|
|
}
|
|
}
|
|
|
|
if (add) {
|
|
add_cached_instance_class(ik);
|
|
if (AOTClassInitializer::can_archive_initialized_mirror(ik)) {
|
|
add_aot_inited_class(ik);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
#if INCLUDE_CDS_JAVA_HEAP
|
|
// Keep scanning until we discover no more class that need to be AOT-initialized.
|
|
if (CDSConfig::is_initing_classes_at_dump_time()) {
|
|
while (_pending_aot_inited_classes->length() > 0) {
|
|
InstanceKlass* ik = _pending_aot_inited_classes->pop();
|
|
HeapShared::copy_and_rescan_aot_inited_mirror(ik);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Exclude all the (hidden) classes that have not been discovered by the code above.
|
|
SystemDictionaryShared::dumptime_table()->iterate_all_live_classes([&] (InstanceKlass* k, DumpTimeClassInfo& info) {
|
|
if (!info.is_excluded() && _seen_classes->get(k) == nullptr) {
|
|
info.set_excluded();
|
|
info.set_has_checked_exclusion();
|
|
if (aot_log_is_enabled(Debug, aot)) {
|
|
ResourceMark rm;
|
|
aot_log_debug(aot)("Skipping %s: %s class", k->name()->as_C_string(),
|
|
k->is_hidden() ? "Unreferenced hidden" : "AOT tooling");
|
|
}
|
|
}
|
|
});
|
|
|
|
end_scanning_for_oops();
|
|
|
|
TrainingData::cleanup_training_data();
|
|
}
|
|
|
|
void AOTArtifactFinder::start_scanning_for_oops() {
|
|
#if INCLUDE_CDS_JAVA_HEAP
|
|
if (CDSConfig::is_dumping_heap()) {
|
|
HeapShared::start_scanning_for_oops();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void AOTArtifactFinder::end_scanning_for_oops() {
|
|
#if INCLUDE_CDS_JAVA_HEAP
|
|
if (CDSConfig::is_dumping_heap()) {
|
|
HeapShared::end_scanning_for_oops();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void AOTArtifactFinder::add_aot_inited_class(InstanceKlass* ik) {
|
|
if (CDSConfig::is_initing_classes_at_dump_time()) {
|
|
assert(ik->is_initialized(), "must be");
|
|
add_cached_instance_class(ik);
|
|
|
|
bool created;
|
|
_aot_inited_classes->put_if_absent(ik, &created);
|
|
if (created) {
|
|
_pending_aot_inited_classes->push(ik);
|
|
|
|
InstanceKlass* s = ik->java_super();
|
|
if (s != nullptr) {
|
|
add_aot_inited_class(s);
|
|
}
|
|
|
|
Array<InstanceKlass*>* interfaces = ik->local_interfaces();
|
|
int len = interfaces->length();
|
|
for (int i = 0; i < len; i++) {
|
|
InstanceKlass* intf = interfaces->at(i);
|
|
if (intf->is_initialized()) {
|
|
add_aot_inited_class(intf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void AOTArtifactFinder::append_to_all_cached_classes(Klass* k) {
|
|
precond(!SystemDictionaryShared::should_be_excluded(k));
|
|
_all_cached_classes->append(k);
|
|
}
|
|
|
|
void AOTArtifactFinder::add_cached_instance_class(InstanceKlass* ik) {
|
|
if (CDSConfig::is_dumping_dynamic_archive() && ik->is_shared()) {
|
|
// This class is already included in the base archive. No need to cache
|
|
// it again in the dynamic archive.
|
|
return;
|
|
}
|
|
|
|
bool created;
|
|
_seen_classes->put_if_absent(ik, &created);
|
|
if (created) {
|
|
append_to_all_cached_classes(ik);
|
|
|
|
// All super types must be added.
|
|
InstanceKlass* s = ik->java_super();
|
|
if (s != nullptr) {
|
|
add_cached_instance_class(s);
|
|
}
|
|
|
|
Array<InstanceKlass*>* interfaces = ik->local_interfaces();
|
|
int len = interfaces->length();
|
|
for (int i = 0; i < len; i++) {
|
|
InstanceKlass* intf = interfaces->at(i);
|
|
add_cached_instance_class(intf);
|
|
}
|
|
|
|
if (CDSConfig::is_dumping_final_static_archive() && ik->defined_by_other_loaders()) {
|
|
// The following are not appliable to unregistered classes
|
|
return;
|
|
}
|
|
scan_oops_in_instance_class(ik);
|
|
if (ik->is_hidden() && CDSConfig::is_initing_classes_at_dump_time()) {
|
|
bool succeed = AOTClassLinker::try_add_candidate(ik);
|
|
guarantee(succeed, "All cached hidden classes must be aot-linkable");
|
|
add_aot_inited_class(ik);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AOTArtifactFinder::add_cached_type_array_class(TypeArrayKlass* tak) {
|
|
bool created;
|
|
_seen_classes->put_if_absent(tak, &created);
|
|
if (created) {
|
|
append_to_all_cached_classes(tak);
|
|
scan_oops_in_array_class(tak);
|
|
}
|
|
}
|
|
|
|
void AOTArtifactFinder::add_cached_class(Klass* k) {
|
|
if (k->is_typeArray_klass()) {
|
|
add_cached_type_array_class(TypeArrayKlass::cast(k));
|
|
} else if (k->is_objArray_klass()) {
|
|
add_cached_class(ObjArrayKlass::cast(k)->element_klass());
|
|
} else {
|
|
add_cached_instance_class(InstanceKlass::cast(k));
|
|
}
|
|
}
|
|
|
|
void AOTArtifactFinder::scan_oops_in_instance_class(InstanceKlass* ik) {
|
|
#if INCLUDE_CDS_JAVA_HEAP
|
|
if (CDSConfig::is_dumping_heap()) {
|
|
HeapShared::scan_java_class(ik);
|
|
scan_oops_in_array_class(ik->array_klasses());
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void AOTArtifactFinder::scan_oops_in_array_class(ArrayKlass* ak) {
|
|
#if INCLUDE_CDS_JAVA_HEAP
|
|
if (CDSConfig::is_dumping_heap()) {
|
|
while (ak != nullptr) {
|
|
HeapShared::scan_java_class(ak);
|
|
ak = ak->array_klass_or_null();
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void AOTArtifactFinder::all_cached_classes_do(MetaspaceClosure* it) {
|
|
for (int i = 0; i < _all_cached_classes->length(); i++) {
|
|
it->push(_all_cached_classes->adr_at(i));
|
|
}
|
|
}
|