8290833: Remove ConstantPoolCache::walk_entries_for_initialization()

Reviewed-by: coleenp, ccheung
This commit is contained in:
Ioi Lam 2022-08-11 21:48:34 +00:00
parent 755ecf6b73
commit bd5855337c
9 changed files with 124 additions and 85 deletions

View File

@ -159,6 +159,7 @@ ArchiveBuilder::ArchiveBuilder() :
_rw_src_objs(),
_ro_src_objs(),
_src_obj_table(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE),
_dumped_to_src_obj_table(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE),
_total_closed_heap_region_size(0),
_total_open_heap_region_size(0),
_estimated_metaspaceobj_bytes(0),
@ -630,6 +631,14 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s
newtop = dump_region->top();
memcpy(dest, src, bytes);
{
bool created;
_dumped_to_src_obj_table.put_if_absent((address)dest, src, &created);
assert(created, "must be");
if (_dumped_to_src_obj_table.maybe_grow()) {
log_info(cds, hashtables)("Expanded _dumped_to_src_obj_table table to %d", _dumped_to_src_obj_table.table_size());
}
}
intptr_t* archived_vtable = CppVtables::get_archived_vtable(ref->msotype(), (address)dest);
if (archived_vtable != NULL) {
@ -650,6 +659,13 @@ address ArchiveBuilder::get_dumped_addr(address src_obj) const {
return p->dumped_addr();
}
address ArchiveBuilder::get_src_obj(address dumped_addr) const {
assert(is_in_buffer_space(dumped_addr), "must be");
address* src_obj = _dumped_to_src_obj_table.get(dumped_addr);
assert(src_obj != NULL && *src_obj != NULL, "must be");
return *src_obj;
}
void ArchiveBuilder::relocate_embedded_pointers(ArchiveBuilder::SourceObjList* src_objs) {
for (int i = 0; i < src_objs->objs()->length(); i++) {
src_objs->relocate(i, this);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@ -200,6 +200,7 @@ private:
SourceObjList _rw_src_objs; // objs to put in rw region
SourceObjList _ro_src_objs; // objs to put in ro region
ResizeableResourceHashtable<address, SourceObjInfo, ResourceObj::C_HEAP, mtClassShared> _src_obj_table;
ResizeableResourceHashtable<address, address, ResourceObj::C_HEAP, mtClassShared> _dumped_to_src_obj_table;
GrowableArray<Klass*>* _klasses;
GrowableArray<Symbol*>* _symbols;
GrowableArray<SpecialRefInfo>* _special_refs;
@ -383,7 +384,17 @@ public:
void write_region(FileMapInfo* mapinfo, int region_idx, DumpRegion* dump_region,
bool read_only, bool allow_exec);
// + When creating a CDS archive, we first load Java classes and create metadata
// objects as usual. These are call "source" objects.
// + We then copy the source objects into the output buffer at "dumped addresses".
//
// The following functions translate between these two (non-overlapping) spaces.
// (The API should be renamed to be less confusing!)
address get_dumped_addr(address src_obj) const;
address get_src_obj(address dumped_addr) const;
template <typename T> T get_src_obj(T dumped_addr) const {
return (T)get_src_obj((address)dumped_addr);
}
// All klasses and symbols that will be copied into the archive
GrowableArray<Klass*>* klasses() const { return _klasses; }

View File

@ -80,6 +80,7 @@ DumpTimeSharedClassTable* SystemDictionaryShared::_dumptime_table = NULL;
DumpTimeSharedClassTable* SystemDictionaryShared::_cloned_dumptime_table = NULL;
DumpTimeLambdaProxyClassDictionary* SystemDictionaryShared::_dumptime_lambda_proxy_class_dictionary = NULL;
DumpTimeLambdaProxyClassDictionary* SystemDictionaryShared::_cloned_dumptime_lambda_proxy_class_dictionary = NULL;
SystemDictionaryShared::SavedCpCacheEntriesTable* SystemDictionaryShared::_saved_cpcache_entries_table = NULL;
// Used by NoClassLoadingMark
DEBUG_ONLY(bool SystemDictionaryShared::_class_loading_may_happen = true;)
@ -504,6 +505,7 @@ void SystemDictionaryShared::initialize() {
_dumptime_table = new (ResourceObj::C_HEAP, mtClass) DumpTimeSharedClassTable;
_dumptime_lambda_proxy_class_dictionary =
new (ResourceObj::C_HEAP, mtClass) DumpTimeLambdaProxyClassDictionary;
_saved_cpcache_entries_table = new (ResourceObj::C_HEAP, mtClass) SavedCpCacheEntriesTable;
}
}
@ -516,6 +518,11 @@ void SystemDictionaryShared::init_dumptime_info(InstanceKlass* k) {
void SystemDictionaryShared::remove_dumptime_info(InstanceKlass* k) {
MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
_dumptime_table->remove(k);
ConstantPoolCache* cpc = k->constants()->cache();
if (cpc != NULL) {
remove_saved_cpcache_entries_locked(cpc);
}
}
void SystemDictionaryShared::handle_class_unloading(InstanceKlass* klass) {
@ -1329,6 +1336,36 @@ void SystemDictionaryShared::update_shared_entry(InstanceKlass* k, int id) {
info->_id = id;
}
void SystemDictionaryShared::set_saved_cpcache_entries(ConstantPoolCache* cpc, ConstantPoolCacheEntry* entries) {
MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
bool is_new = _saved_cpcache_entries_table->put(cpc, entries);
assert(is_new, "saved entries must never changed");
}
ConstantPoolCacheEntry* SystemDictionaryShared::get_saved_cpcache_entries_locked(ConstantPoolCache* cpc) {
assert_lock_strong(DumpTimeTable_lock);
ConstantPoolCacheEntry** p = _saved_cpcache_entries_table->get(cpc);
if (p != nullptr) {
return *p;
} else {
return nullptr;
}
}
void SystemDictionaryShared::remove_saved_cpcache_entries(ConstantPoolCache* cpc) {
MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
remove_saved_cpcache_entries_locked(cpc);
}
void SystemDictionaryShared::remove_saved_cpcache_entries_locked(ConstantPoolCache* cpc) {
assert_lock_strong(DumpTimeTable_lock);
ConstantPoolCacheEntry** p = _saved_cpcache_entries_table->get(cpc);
if (p != nullptr) {
_saved_cpcache_entries_table->remove(cpc);
FREE_C_HEAP_ARRAY(ConstantPoolCacheEntry, *p);
}
}
const char* class_loader_name_for_shared(Klass* k) {
assert(k != nullptr, "Sanity");
assert(k->is_shared(), "Must be");

View File

@ -34,6 +34,7 @@
#include "classfile/systemDictionary.hpp"
#include "oops/klass.hpp"
#include "oops/oopHandle.hpp"
#include "utilities/resourceHash.hpp"
/*===============================================================================
@ -108,6 +109,8 @@
class BootstrapInfo;
class ClassFileStream;
class ConstantPoolCache;
class ConstantPoolCacheEntry;
class Dictionary;
class DumpTimeClassInfo;
class DumpTimeSharedClassTable;
@ -165,6 +168,15 @@ private:
static DumpTimeLambdaProxyClassDictionary* _dumptime_lambda_proxy_class_dictionary;
static DumpTimeLambdaProxyClassDictionary* _cloned_dumptime_lambda_proxy_class_dictionary;
// Doesn't need to be cloned as it's not modified during dump time.
using SavedCpCacheEntriesTable = ResourceHashtable<
ConstantPoolCache*,
ConstantPoolCacheEntry*,
15889, // prime number
ResourceObj::C_HEAP,
mtClassShared>;
static SavedCpCacheEntriesTable* _saved_cpcache_entries_table;
static ArchiveInfo _static_archive;
static ArchiveInfo _dynamic_archive;
@ -236,6 +248,11 @@ public:
return ClassLoaderData::the_null_class_loader_data()->dictionary();
}
static void set_saved_cpcache_entries(ConstantPoolCache* cpc, ConstantPoolCacheEntry* entries);
static ConstantPoolCacheEntry* get_saved_cpcache_entries_locked(ConstantPoolCache* k);
static void remove_saved_cpcache_entries(ConstantPoolCache* cpc);
static void remove_saved_cpcache_entries_locked(ConstantPoolCache* cpc);
static void update_shared_entry(InstanceKlass* klass, int id);
static void set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 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
@ -33,6 +33,7 @@
#include "oops/constantPool.hpp"
#include "oops/generateOopMap.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/arguments.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/handles.inline.hpp"
@ -116,10 +117,16 @@ void Rewriter::make_constant_pool_cache(TRAPS) {
MetadataFactory::free_metadata(loader_data, cache);
_pool->set_cache(NULL); // so the verifier isn't confused
} else {
DEBUG_ONLY(
if (DumpSharedSpaces) {
cache->verify_just_initialized();
})
if (Arguments::is_dumping_archive()) {
if (_pool->pool_holder()->is_shared()) {
assert(DynamicDumpSharedSpaces, "must be");
// We are linking a shared class from the base archive. This
// class won't be written into the dynamic archive, so there's no
// need to save its CpCaches.
} else {
cache->save_for_archive();
}
}
}
}

View File

@ -423,6 +423,7 @@ void ConstantPool::remove_unshareable_info() {
}
}
if (cache() != NULL) {
// cache() is NULL if this class is not yet linked.
cache()->remove_unshareable_info();
}
}

View File

@ -26,6 +26,7 @@
#include "cds/heapShared.hpp"
#include "classfile/resolutionErrors.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/vmClasses.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "interpreter/bytecodes.hpp"
@ -62,24 +63,6 @@ void ConstantPoolCacheEntry::initialize_entry(int index) {
assert(constant_pool_index() == index, "");
}
void ConstantPoolCacheEntry::verify_just_initialized(bool f2_used) {
assert((_indices & (~cp_index_mask)) == 0, "sanity");
assert(_f1 == NULL, "sanity");
assert(_flags == 0, "sanity");
if (!f2_used) {
assert(_f2 == 0, "sanity");
}
}
void ConstantPoolCacheEntry::reinitialize(bool f2_used) {
_indices &= cp_index_mask;
_f1 = NULL;
_flags = 0;
if (!f2_used) {
_f2 = 0;
}
}
int ConstantPoolCacheEntry::make_flags(TosState state,
int option_bits,
int field_index_or_method_params) {
@ -700,66 +683,31 @@ void ConstantPoolCache::record_gc_epoch() {
_gc_epoch = Continuations::gc_epoch();
}
void ConstantPoolCache::verify_just_initialized() {
DEBUG_ONLY(walk_entries_for_initialization(/*check_only = */ true));
void ConstantPoolCache::save_for_archive() {
#if INCLUDE_CDS
ConstantPoolCacheEntry* copy = NEW_C_HEAP_ARRAY(ConstantPoolCacheEntry, length(), mtClassShared);
for (int i = 0; i < length(); i++) {
copy[i] = *entry_at(i);
}
SystemDictionaryShared::set_saved_cpcache_entries(this, copy);
#endif
}
void ConstantPoolCache::remove_unshareable_info() {
walk_entries_for_initialization(/*check_only = */ false);
}
void ConstantPoolCache::walk_entries_for_initialization(bool check_only) {
#if INCLUDE_CDS
Arguments::assert_is_dumping_archive();
// When dumping the archive, we want to clean up the ConstantPoolCache
// to remove any effect of linking due to the execution of Java code --
// each ConstantPoolCacheEntry will have the same contents as if
// ConstantPoolCache::initialize has just returned:
//
// - We keep the ConstantPoolCache::constant_pool_index() bits for all entries.
// - We keep the "f2" field for entries used by invokedynamic and invokehandle
// - All other bits in the entries are cleared to zero.
ResourceMark rm;
InstanceKlass* ik = constant_pool()->pool_holder();
bool* f2_used = NEW_RESOURCE_ARRAY(bool, length());
memset(f2_used, 0, sizeof(bool) * length());
Thread* current = Thread::current();
// Find all the slots that we need to preserve f2
for (int i = 0; i < ik->methods()->length(); i++) {
Method* m = ik->methods()->at(i);
RawBytecodeStream bcs(methodHandle(current, m));
while (!bcs.is_last_bytecode()) {
Bytecodes::Code opcode = bcs.raw_next();
switch (opcode) {
case Bytecodes::_invokedynamic: {
int index = Bytes::get_native_u4(bcs.bcp() + 1);
int cp_cache_index = constant_pool()->invokedynamic_cp_cache_index(index);
f2_used[cp_cache_index] = 1;
}
break;
case Bytecodes::_invokehandle: {
int cp_cache_index = Bytes::get_native_u2(bcs.bcp() + 1);
f2_used[cp_cache_index] = 1;
}
break;
default:
break;
}
}
}
if (check_only) {
DEBUG_ONLY(
for (int i=0; i<length(); i++) {
entry_at(i)->verify_just_initialized(f2_used[i]);
})
} else {
for (int i=0; i<length(); i++) {
entry_at(i)->reinitialize(f2_used[i]);
}
// <this> is the copy to be written into the archive. It's in
// the ArchiveBuilder's "buffer space". However, the saved_cpcache_entries
// are recorded with the original ConstantPoolCache object.
ConstantPoolCache* orig_cpc = ArchiveBuilder::current()->get_src_obj(this);
ConstantPoolCacheEntry* saved = SystemDictionaryShared::get_saved_cpcache_entries_locked(orig_cpc);
for (int i=0; i<length(); i++) {
// Restore each entry to the initial state -- just after Rewriter::make_constant_pool_cache()
// has finished.
*entry_at(i) = saved[i];
}
#endif
}
void ConstantPoolCache::deallocate_contents(ClassLoaderData* data) {
@ -768,6 +716,12 @@ void ConstantPoolCache::deallocate_contents(ClassLoaderData* data) {
set_resolved_references(OopHandle());
MetadataFactory::free_array<u2>(data, _reference_map);
set_reference_map(NULL);
#if INCLUDE_CDS
if (Arguments::is_dumping_archive()) {
SystemDictionaryShared::remove_saved_cpcache_entries(this);
}
#endif
}
#if INCLUDE_CDS_JAVA_HEAP

View File

@ -386,9 +386,6 @@ class ConstantPoolCacheEntry {
// When shifting flags as a 32-bit int, make sure we don't need an extra mask for tos_state:
assert((((u4)-1 >> tos_state_shift) & ~tos_state_mask) == 0, "no need for tos_state mask");
}
void verify_just_initialized(bool f2_used);
void reinitialize(bool f2_used);
};
@ -457,7 +454,7 @@ class ConstantPoolCache: public MetaspaceObj {
// CDS support
void remove_unshareable_info();
void verify_just_initialized();
void save_for_archive();
private:
void walk_entries_for_initialization(bool check_only);
void set_length(int length) { _length = length; }

View File

@ -576,6 +576,7 @@ void InstanceKlass::deallocate_record_components(ClassLoaderData* loader_data,
// This function deallocates the metadata and C heap pointers that the
// InstanceKlass points to.
void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
SystemDictionaryShared::handle_class_unloading(this);
// Orphan the mirror first, CMS thinks it's still live.
if (java_mirror() != NULL) {
@ -691,8 +692,6 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
MetadataFactory::free_metadata(loader_data, annotations());
}
set_annotations(NULL);
SystemDictionaryShared::handle_class_unloading(this);
}
bool InstanceKlass::is_record() const {