-
Notifications
You must be signed in to change notification settings - Fork 6k
8358680: AOT cache creation fails: no strings should have been added #25816
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,7 @@ | |
#include "classfile/javaClasses.inline.hpp" | ||
#include "classfile/stringTable.hpp" | ||
#include "classfile/vmClasses.hpp" | ||
#include "compiler/compileBroker.hpp" | ||
#include "gc/shared/collectedHeap.hpp" | ||
#include "gc/shared/oopStorage.inline.hpp" | ||
#include "gc/shared/oopStorageSet.hpp" | ||
|
@@ -115,6 +116,7 @@ OopStorage* StringTable::_oop_storage; | |
|
||
static size_t _current_size = 0; | ||
static volatile size_t _items_count = 0; | ||
DEBUG_ONLY(static int _disable_interning_during_cds_dump = 0); | ||
|
||
volatile bool _alt_hash = false; | ||
|
||
|
@@ -346,6 +348,10 @@ bool StringTable::has_work() { | |
return Atomic::load_acquire(&_has_work); | ||
} | ||
|
||
size_t StringTable::items_count() { | ||
return Atomic::load_acquire(&_items_count); | ||
} | ||
|
||
void StringTable::trigger_concurrent_work() { | ||
// Avoid churn on ServiceThread | ||
if (!has_work()) { | ||
|
@@ -504,6 +510,9 @@ oop StringTable::intern(const char* utf8_string, TRAPS) { | |
} | ||
|
||
oop StringTable::intern(const StringWrapper& name, TRAPS) { | ||
assert(!Atomic::load_acquire(&_disable_interning_during_cds_dump), | ||
"All threads that may intern strings should have been stopped before CDS starts copying the interned string table"); | ||
|
||
// shared table always uses java_lang_String::hash_code | ||
unsigned int hash = hash_wrapped_string(name); | ||
oop found_string = lookup_shared(name, hash); | ||
|
@@ -793,7 +802,7 @@ void StringTable::verify() { | |
} | ||
|
||
// Verification and comp | ||
class VerifyCompStrings : StackObj { | ||
class StringTable::VerifyCompStrings : StackObj { | ||
static unsigned string_hash(oop const& str) { | ||
return java_lang_String::hash_code_noupdate(str); | ||
} | ||
|
@@ -805,7 +814,7 @@ class VerifyCompStrings : StackObj { | |
string_hash, string_equals> _table; | ||
public: | ||
size_t _errors; | ||
VerifyCompStrings() : _table(unsigned(_items_count / 8) + 1, 0 /* do not resize */), _errors(0) {} | ||
VerifyCompStrings() : _table(unsigned(items_count() / 8) + 1, 0 /* do not resize */), _errors(0) {} | ||
bool operator()(WeakHandle* val) { | ||
oop s = val->resolve(); | ||
if (s == nullptr) { | ||
|
@@ -939,20 +948,32 @@ oop StringTable::lookup_shared(const jchar* name, int len) { | |
return _shared_table.lookup(wrapped_name, java_lang_String::hash_code(name, len), 0); | ||
} | ||
|
||
// This is called BEFORE we enter the CDS safepoint. We can allocate heap objects. | ||
// This should be called when we know no more strings will be added (which will be easy | ||
// to guarantee because CDS runs with a single Java thread. See JDK-8253495.) | ||
// This is called BEFORE we enter the CDS safepoint. We can allocate still Java object arrays to | ||
// be used by the shared strings table. | ||
void StringTable::allocate_shared_strings_array(TRAPS) { | ||
if (!CDSConfig::is_dumping_heap()) { | ||
return; | ||
} | ||
assert(CDSConfig::allow_only_single_java_thread(), "No more interned strings can be added"); | ||
|
||
if (_items_count > (size_t)max_jint) { | ||
fatal("Too many strings to be archived: %zu", _items_count); | ||
CompileBroker::wait_for_no_active_tasks(); | ||
|
||
precond(THREAD->is_Java_thread()); | ||
precond(CDSConfig::allow_only_single_java_thread()); | ||
|
||
// At this point, no more strings will be added: | ||
// - There's only a single Java thread (this thread). It no longer executes Java bytecodes | ||
// so JIT compilation will eventually stop. | ||
// - CompileBroker has no more active tasks, so all JIT requests have been processed. | ||
|
||
// This flag will be cleared after intern table dumping has completed, so we can run the | ||
// compiler again (for future AOT method compilation, etc). | ||
DEBUG_ONLY(Atomic::release_store(&_disable_interning_during_cds_dump, 1)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think atomics work with bool or is this a refcount ? |
||
|
||
if (items_count() > (size_t)max_jint) { | ||
fatal("Too many strings to be archived: %zu", items_count()); | ||
} | ||
|
||
int total = (int)_items_count; | ||
int total = (int)items_count(); | ||
size_t single_array_size = objArrayOopDesc::object_size(total); | ||
|
||
log_info(aot)("allocated string table for %d strings", total); | ||
|
@@ -972,7 +993,7 @@ void StringTable::allocate_shared_strings_array(TRAPS) { | |
// This can only happen if you have an extremely large number of classes that | ||
// refer to more than 16384 * 16384 = 26M interned strings! Not a practical concern | ||
// but bail out for safety. | ||
log_error(aot)("Too many strings to be archived: %zu", _items_count); | ||
log_error(aot)("Too many strings to be archived: %zu", items_count()); | ||
MetaspaceShared::unrecoverable_writing_error(); | ||
} | ||
|
||
|
@@ -1070,7 +1091,7 @@ oop StringTable::init_shared_strings_array() { | |
|
||
void StringTable::write_shared_table() { | ||
_shared_table.reset(); | ||
CompactHashtableWriter writer((int)_items_count, ArchiveBuilder::string_stats()); | ||
CompactHashtableWriter writer((int)items_count(), ArchiveBuilder::string_stats()); | ||
|
||
int index = 0; | ||
auto copy_into_shared_table = [&] (WeakHandle* val) { | ||
|
@@ -1084,6 +1105,8 @@ void StringTable::write_shared_table() { | |
}; | ||
_local_table->do_safepoint_scan(copy_into_shared_table); | ||
writer.dump(&_shared_table, "string"); | ||
|
||
DEBUG_ONLY(Atomic::release_store(&_disable_interning_during_cds_dump, 0)); | ||
} | ||
|
||
void StringTable::set_shared_strings_array_index(int root_index) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,12 +37,13 @@ | |
#include "runtime/mutexLocker.hpp" | ||
|
||
CompileTask* CompileTask::_task_free_list = nullptr; | ||
int CompileTask::_active_tasks = 0; | ||
|
||
/** | ||
* Allocate a CompileTask, from the free list if possible. | ||
*/ | ||
CompileTask* CompileTask::allocate() { | ||
MutexLocker locker(CompileTaskAlloc_lock); | ||
MonitorLocker locker(CompileTaskAlloc_lock); | ||
CompileTask* task = nullptr; | ||
|
||
if (_task_free_list != nullptr) { | ||
|
@@ -56,14 +57,15 @@ CompileTask* CompileTask::allocate() { | |
} | ||
assert(task->is_free(), "Task must be free."); | ||
task->set_is_free(false); | ||
_active_tasks++; | ||
return task; | ||
} | ||
|
||
/** | ||
* Add a task to the free list. | ||
*/ | ||
void CompileTask::free(CompileTask* task) { | ||
MutexLocker locker(CompileTaskAlloc_lock); | ||
MonitorLocker locker(CompileTaskAlloc_lock); | ||
if (!task->is_free()) { | ||
if ((task->_method_holder != nullptr && JNIHandles::is_weak_global_handle(task->_method_holder))) { | ||
JNIHandles::destroy_weak_global(task->_method_holder); | ||
|
@@ -79,6 +81,17 @@ void CompileTask::free(CompileTask* task) { | |
task->set_is_free(true); | ||
task->set_next(_task_free_list); | ||
_task_free_list = task; | ||
_active_tasks--; | ||
if (_active_tasks == 0) { | ||
locker.notify_all(); | ||
} | ||
} | ||
} | ||
|
||
void CompileTask::wait_for_no_active_tasks() { | ||
MonitorLocker locker(CompileTaskAlloc_lock); | ||
while (_active_tasks > 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't this have to have an Atomic::load() to make it re-read in the loop? Even though it's after we reacquire the lock. |
||
locker.wait(); | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there's a convention to make accessor functions that use acquire semantics to be named items_count_acquire().