blob: 6ee18c17a57da8be83f241e50b2bc48b7070edb9 [file] [log] [blame]
/*
* Copyright (c) 2021, 2023, 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 "precompiled.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/dumpTimeClassInfo.inline.hpp"
#include "cds/runTimeClassInfo.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "memory/resourceArea.hpp"
DumpTimeClassInfo::~DumpTimeClassInfo() {
if (_verifier_constraints != nullptr) {
assert(_verifier_constraint_flags != nullptr, "must be");
delete _verifier_constraints;
delete _verifier_constraint_flags;
}
if (_loader_constraints != nullptr) {
delete _loader_constraints;
}
}
size_t DumpTimeClassInfo::runtime_info_bytesize() const {
return RunTimeClassInfo::byte_size(_klass, num_verifier_constraints(),
num_loader_constraints(),
num_enum_klass_static_fields());
}
void DumpTimeClassInfo::add_verification_constraint(InstanceKlass* k, Symbol* name,
Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) {
if (_verifier_constraints == nullptr) {
_verifier_constraints = new (mtClass) GrowableArray<DTVerifierConstraint>(4, mtClass);
}
if (_verifier_constraint_flags == nullptr) {
_verifier_constraint_flags = new (mtClass) GrowableArray<char>(4, mtClass);
}
GrowableArray<DTVerifierConstraint>* vc_array = _verifier_constraints;
for (int i = 0; i < vc_array->length(); i++) {
if (vc_array->at(i).equals(name, from_name)) {
return;
}
}
DTVerifierConstraint cons(name, from_name);
vc_array->append(cons);
GrowableArray<char>* vcflags_array = _verifier_constraint_flags;
char c = 0;
c |= from_field_is_protected ? SystemDictionaryShared::FROM_FIELD_IS_PROTECTED : 0;
c |= from_is_array ? SystemDictionaryShared::FROM_IS_ARRAY : 0;
c |= from_is_object ? SystemDictionaryShared::FROM_IS_OBJECT : 0;
vcflags_array->append(c);
if (log_is_enabled(Trace, cds, verification)) {
ResourceMark rm;
log_trace(cds, verification)("add_verification_constraint: %s: %s must be subclass of %s [0x%x] array len %d flags len %d",
k->external_name(), from_name->as_klass_external_name(),
name->as_klass_external_name(), c, vc_array->length(), vcflags_array->length());
}
}
static char get_loader_type_by(oop loader) {
assert(SystemDictionary::is_builtin_class_loader(loader), "Must be built-in loader");
if (SystemDictionary::is_boot_class_loader(loader)) {
return (char)ClassLoader::BOOT_LOADER;
} else if (SystemDictionary::is_platform_class_loader(loader)) {
return (char)ClassLoader::PLATFORM_LOADER;
} else {
assert(SystemDictionary::is_system_class_loader(loader), "Class loader mismatch");
return (char)ClassLoader::APP_LOADER;
}
}
void DumpTimeClassInfo::record_linking_constraint(Symbol* name, Handle loader1, Handle loader2) {
assert(loader1 != loader2, "sanity");
LogTarget(Info, class, loader, constraints) log;
if (_loader_constraints == nullptr) {
_loader_constraints = new (mtClass) GrowableArray<DTLoaderConstraint>(4, mtClass);
}
char lt1 = get_loader_type_by(loader1());
char lt2 = get_loader_type_by(loader2());
DTLoaderConstraint lc(name, lt1, lt2);
for (int i = 0; i < _loader_constraints->length(); i++) {
if (lc.equals(_loader_constraints->at(i))) {
if (log.is_enabled()) {
ResourceMark rm;
// Use loader[0]/loader[1] to be consistent with the logs in loaderConstraints.cpp
log.print("[CDS record loader constraint for class: %s constraint_name: %s loader[0]: %s loader[1]: %s already added]",
_klass->external_name(), name->as_C_string(),
ClassLoaderData::class_loader_data(loader1())->loader_name_and_id(),
ClassLoaderData::class_loader_data(loader2())->loader_name_and_id());
}
return;
}
}
_loader_constraints->append(lc);
if (log.is_enabled()) {
ResourceMark rm;
// Use loader[0]/loader[1] to be consistent with the logs in loaderConstraints.cpp
log.print("[CDS record loader constraint for class: %s constraint_name: %s loader[0]: %s loader[1]: %s total %d]",
_klass->external_name(), name->as_C_string(),
ClassLoaderData::class_loader_data(loader1())->loader_name_and_id(),
ClassLoaderData::class_loader_data(loader2())->loader_name_and_id(),
_loader_constraints->length());
}
}
void DumpTimeClassInfo::add_enum_klass_static_field(int archived_heap_root_index) {
if (_enum_klass_static_fields == nullptr) {
_enum_klass_static_fields = new (mtClass) GrowableArray<int>(20, mtClass);
}
_enum_klass_static_fields->append(archived_heap_root_index);
}
int DumpTimeClassInfo::enum_klass_static_field(int which_field) {
assert(_enum_klass_static_fields != nullptr, "must be");
return _enum_klass_static_fields->at(which_field);
}
bool DumpTimeClassInfo::is_builtin() {
return SystemDictionaryShared::is_builtin(_klass);
}
DumpTimeClassInfo* DumpTimeSharedClassTable::allocate_info(InstanceKlass* k) {
assert(!k->is_shared(), "Do not call with shared classes");
bool created;
DumpTimeClassInfo* p = put_if_absent(k, &created);
assert(created, "must not exist in table");
p->_klass = k;
return p;
}
DumpTimeClassInfo* DumpTimeSharedClassTable::get_info(InstanceKlass* k) {
assert(!k->is_shared(), "Do not call with shared classes");
DumpTimeClassInfo* p = get(k);
assert(p != nullptr, "we must not see any non-shared InstanceKlass* that's "
"not stored with SystemDictionaryShared::init_dumptime_info");
assert(p->_klass == k, "Sanity");
return p;
}
class CountClassByCategory : StackObj {
DumpTimeSharedClassTable* _table;
public:
CountClassByCategory(DumpTimeSharedClassTable* table) : _table(table) {}
void do_entry(InstanceKlass* k, DumpTimeClassInfo& info) {
if (!info.is_excluded()) {
if (info.is_builtin()) {
_table->inc_builtin_count();
} else {
_table->inc_unregistered_count();
}
}
}
};
void DumpTimeSharedClassTable::update_counts() {
_builtin_count = 0;
_unregistered_count = 0;
CountClassByCategory counter(this);
iterate_all_live_classes(&counter);
}