mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-17 01:24:33 +02:00
8266764: [REDO] JDK-8255493 Support for pre-generated java.lang.invoke classes in CDS dynamic archive
Reviewed-by: ccheung, iklam
This commit is contained in:
parent
8c71144a23
commit
2066f497b9
16 changed files with 407 additions and 75 deletions
|
@ -259,6 +259,7 @@ void ArchiveBuilder::gather_klasses_and_symbols() {
|
||||||
log_info(cds)(" instance classes = %5d", _num_instance_klasses);
|
log_info(cds)(" instance classes = %5d", _num_instance_klasses);
|
||||||
log_info(cds)(" obj array classes = %5d", _num_obj_array_klasses);
|
log_info(cds)(" obj array classes = %5d", _num_obj_array_klasses);
|
||||||
log_info(cds)(" type array classes = %5d", _num_type_array_klasses);
|
log_info(cds)(" type array classes = %5d", _num_type_array_klasses);
|
||||||
|
log_info(cds)(" symbols = %5d", _symbols->length());
|
||||||
|
|
||||||
if (DumpSharedSpaces) {
|
if (DumpSharedSpaces) {
|
||||||
// To ensure deterministic contents in the static archive, we need to ensure that
|
// To ensure deterministic contents in the static archive, we need to ensure that
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "cds/archiveBuilder.hpp"
|
#include "cds/archiveBuilder.hpp"
|
||||||
#include "cds/archiveUtils.inline.hpp"
|
#include "cds/archiveUtils.inline.hpp"
|
||||||
#include "cds/dynamicArchive.hpp"
|
#include "cds/dynamicArchive.hpp"
|
||||||
|
#include "cds/lambdaFormInvokers.hpp"
|
||||||
#include "cds/metaspaceShared.hpp"
|
#include "cds/metaspaceShared.hpp"
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
#include "classfile/symbolTable.hpp"
|
#include "classfile/symbolTable.hpp"
|
||||||
|
@ -169,7 +170,6 @@ void DynamicArchiveBuilder::init_header() {
|
||||||
assert(FileMapInfo::dynamic_info() == mapinfo, "must be");
|
assert(FileMapInfo::dynamic_info() == mapinfo, "must be");
|
||||||
_header = mapinfo->dynamic_header();
|
_header = mapinfo->dynamic_header();
|
||||||
|
|
||||||
Thread* THREAD = Thread::current();
|
|
||||||
FileMapInfo* base_info = FileMapInfo::current_info();
|
FileMapInfo* base_info = FileMapInfo::current_info();
|
||||||
_header->set_base_header_crc(base_info->crc());
|
_header->set_base_header_crc(base_info->crc());
|
||||||
for (int i = 0; i < MetaspaceShared::n_regions; i++) {
|
for (int i = 0; i < MetaspaceShared::n_regions; i++) {
|
||||||
|
@ -250,7 +250,6 @@ void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Thread* THREAD = Thread::current();
|
|
||||||
Method::sort_methods(ik->methods(), /*set_idnums=*/true, dynamic_dump_method_comparator);
|
Method::sort_methods(ik->methods(), /*set_idnums=*/true, dynamic_dump_method_comparator);
|
||||||
if (ik->default_methods() != NULL) {
|
if (ik->default_methods() != NULL) {
|
||||||
Method::sort_methods(ik->default_methods(), /*set_idnums=*/false, dynamic_dump_method_comparator);
|
Method::sort_methods(ik->default_methods(), /*set_idnums=*/false, dynamic_dump_method_comparator);
|
||||||
|
@ -331,6 +330,20 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void DynamicArchive::prepare_for_dynamic_dumping_at_exit() {
|
||||||
|
EXCEPTION_MARK;
|
||||||
|
ResourceMark rm(THREAD);
|
||||||
|
MetaspaceShared::link_and_cleanup_shared_classes(THREAD);
|
||||||
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
|
log_error(cds)("ArchiveClassesAtExit has failed");
|
||||||
|
log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(),
|
||||||
|
java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION)));
|
||||||
|
// We cannot continue to dump the archive anymore.
|
||||||
|
DynamicDumpSharedSpaces = false;
|
||||||
|
CLEAR_PENDING_EXCEPTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool DynamicArchive::_has_been_dumped_once = false;
|
bool DynamicArchive::_has_been_dumped_once = false;
|
||||||
|
|
||||||
void DynamicArchive::dump(const char* archive_name, TRAPS) {
|
void DynamicArchive::dump(const char* archive_name, TRAPS) {
|
||||||
|
@ -344,20 +357,20 @@ void DynamicArchive::dump(const char* archive_name, TRAPS) {
|
||||||
} else {
|
} else {
|
||||||
// prevent multiple dumps.
|
// prevent multiple dumps.
|
||||||
set_has_been_dumped_once();
|
set_has_been_dumped_once();
|
||||||
}
|
ArchiveClassesAtExit = archive_name;
|
||||||
ArchiveClassesAtExit = archive_name;
|
if (Arguments::init_shared_archive_paths()) {
|
||||||
if (Arguments::init_shared_archive_paths()) {
|
dump();
|
||||||
dump();
|
} else {
|
||||||
} else {
|
ArchiveClassesAtExit = nullptr;
|
||||||
ArchiveClassesAtExit = nullptr;
|
THROW_MSG(vmSymbols::java_lang_RuntimeException(),
|
||||||
THROW_MSG(vmSymbols::java_lang_RuntimeException(),
|
|
||||||
"Could not setup SharedDynamicArchivePath");
|
"Could not setup SharedDynamicArchivePath");
|
||||||
}
|
}
|
||||||
// prevent do dynamic dump at exit.
|
// prevent do dynamic dump at exit.
|
||||||
ArchiveClassesAtExit = nullptr;
|
ArchiveClassesAtExit = nullptr;
|
||||||
if (!Arguments::init_shared_archive_paths()) {
|
if (!Arguments::init_shared_archive_paths()) {
|
||||||
THROW_MSG(vmSymbols::java_lang_RuntimeException(),
|
THROW_MSG(vmSymbols::java_lang_RuntimeException(),
|
||||||
"Could not restore SharedDynamicArchivePath");
|
"Could not restore SharedDynamicArchivePath");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
class DynamicArchive : AllStatic {
|
class DynamicArchive : AllStatic {
|
||||||
static bool _has_been_dumped_once;
|
static bool _has_been_dumped_once;
|
||||||
public:
|
public:
|
||||||
|
static void prepare_for_dynamic_dumping_at_exit();
|
||||||
static void dump(const char* archive_name, TRAPS);
|
static void dump(const char* archive_name, TRAPS);
|
||||||
static void dump();
|
static void dump();
|
||||||
static bool has_been_dumped_once() { return _has_been_dumped_once; }
|
static bool has_been_dumped_once() { return _has_been_dumped_once; }
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "cds/archiveBuilder.hpp"
|
||||||
#include "cds/lambdaFormInvokers.hpp"
|
#include "cds/lambdaFormInvokers.hpp"
|
||||||
#include "cds/metaspaceShared.hpp"
|
#include "cds/metaspaceShared.hpp"
|
||||||
#include "classfile/classLoadInfo.hpp"
|
#include "classfile/classLoadInfo.hpp"
|
||||||
|
@ -45,31 +46,76 @@
|
||||||
#include "oops/typeArrayOop.inline.hpp"
|
#include "oops/typeArrayOop.inline.hpp"
|
||||||
#include "runtime/handles.inline.hpp"
|
#include "runtime/handles.inline.hpp"
|
||||||
#include "runtime/javaCalls.hpp"
|
#include "runtime/javaCalls.hpp"
|
||||||
|
#include "runtime/mutexLocker.hpp"
|
||||||
|
|
||||||
GrowableArray<char*>* LambdaFormInvokers::_lambdaform_lines = NULL;
|
GrowableArrayCHeap<char*, mtClassShared>* LambdaFormInvokers::_lambdaform_lines = nullptr;
|
||||||
|
Array<Array<char>*>* LambdaFormInvokers::_static_archive_invokers = nullptr;
|
||||||
|
|
||||||
|
#define NUM_FILTER 4
|
||||||
|
static const char* filter[NUM_FILTER] = {"java.lang.invoke.Invokers$Holder",
|
||||||
|
"java.lang.invoke.DirectMethodHandle$Holder",
|
||||||
|
"java.lang.invoke.DelegatingMethodHandle$Holder",
|
||||||
|
"java.lang.invoke.LambdaForm$Holder"};
|
||||||
|
|
||||||
|
static bool should_be_archived(char* line) {
|
||||||
|
for (int k = 0; k < NUM_FILTER; k++) {
|
||||||
|
if (strstr(line, filter[k]) != nullptr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LambdaFormInvokers::append_filtered(char* line) {
|
||||||
|
if (should_be_archived(line)) {
|
||||||
|
append(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#undef NUM_FILTER
|
||||||
|
|
||||||
void LambdaFormInvokers::append(char* line) {
|
void LambdaFormInvokers::append(char* line) {
|
||||||
|
MutexLocker ml(Thread::current(), LambdaFormInvokers_lock);
|
||||||
if (_lambdaform_lines == NULL) {
|
if (_lambdaform_lines == NULL) {
|
||||||
_lambdaform_lines = new GrowableArray<char*>(100);
|
_lambdaform_lines = new GrowableArrayCHeap<char*, mtClassShared>(150);
|
||||||
}
|
}
|
||||||
_lambdaform_lines->append(line);
|
_lambdaform_lines->append(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convenient output
|
||||||
|
class PrintLambdaFormMessage {
|
||||||
|
public:
|
||||||
|
PrintLambdaFormMessage() {
|
||||||
|
log_info(cds)("Regenerate MethodHandle Holder classes...");
|
||||||
|
}
|
||||||
|
~PrintLambdaFormMessage() {
|
||||||
|
log_info(cds)("Regenerate MethodHandle Holder classes...done");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void LambdaFormInvokers::regenerate_holder_classes(TRAPS) {
|
void LambdaFormInvokers::regenerate_holder_classes(TRAPS) {
|
||||||
assert(_lambdaform_lines != NULL, "Bad List");
|
PrintLambdaFormMessage plm;
|
||||||
|
if (_lambdaform_lines == nullptr || _lambdaform_lines->length() == 0) {
|
||||||
|
log_info(cds)("Nothing to regenerate for holder classes");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
|
|
||||||
Symbol* cds_name = vmSymbols::jdk_internal_misc_CDS();
|
Symbol* cds_name = vmSymbols::jdk_internal_misc_CDS();
|
||||||
Klass* cds_klass = SystemDictionary::resolve_or_null(cds_name, THREAD);
|
Klass* cds_klass = SystemDictionary::resolve_or_null(cds_name, THREAD);
|
||||||
guarantee(cds_klass != NULL, "jdk/internal/misc/CDS must exist!");
|
guarantee(cds_klass != NULL, "jdk/internal/misc/CDS must exist!");
|
||||||
|
|
||||||
|
HandleMark hm(THREAD);
|
||||||
int len = _lambdaform_lines->length();
|
int len = _lambdaform_lines->length();
|
||||||
objArrayHandle list_lines = oopFactory::new_objArray_handle(vmClasses::String_klass(), len, CHECK);
|
objArrayHandle list_lines;
|
||||||
for (int i = 0; i < len; i++) {
|
{
|
||||||
Handle h_line = java_lang_String::create_from_str(_lambdaform_lines->at(i), CHECK);
|
MutexLocker ml(Thread::current(), LambdaFormInvokers_lock);
|
||||||
list_lines->obj_at_put(i, h_line());
|
list_lines = oopFactory::new_objArray_handle(vmClasses::String_klass(), len, CHECK);
|
||||||
}
|
for (int i = 0; i < len; i++) {
|
||||||
|
Handle h_line = java_lang_String::create_from_str(_lambdaform_lines->at(i), CHECK);
|
||||||
|
list_lines->obj_at_put(i, h_line());
|
||||||
|
}
|
||||||
|
} // Before calling into java, release vm lock.
|
||||||
//
|
//
|
||||||
// Object[] CDS.generateLambdaFormHolderClasses(String[] lines)
|
// Object[] CDS.generateLambdaFormHolderClasses(String[] lines)
|
||||||
// the returned Object[] layout:
|
// the returned Object[] layout:
|
||||||
|
@ -81,9 +127,16 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) {
|
||||||
JavaCalls::call_static(&result, cds_klass, method, signrs, list_lines, THREAD);
|
JavaCalls::call_static(&result, cds_klass, method, signrs, list_lines, THREAD);
|
||||||
|
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
log_info(cds)("%s: %s", THREAD->pending_exception()->klass()->external_name(),
|
if (!PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) {
|
||||||
java_lang_String::as_utf8_string(java_lang_Throwable::message(THREAD->pending_exception())));
|
log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(),
|
||||||
CLEAR_PENDING_EXCEPTION;
|
java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION)));
|
||||||
|
if (DumpSharedSpaces) {
|
||||||
|
log_error(cds)("Failed to generate LambdaForm holder classes. Is your classlist out of date?");
|
||||||
|
} else {
|
||||||
|
log_error(cds)("Failed to generate LambdaForm holder classes. Was the base archive generated with an outdated classlist?");
|
||||||
|
}
|
||||||
|
CLEAR_PENDING_EXCEPTION;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,20 +152,10 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) {
|
||||||
char *class_name = java_lang_String::as_utf8_string(h_name());
|
char *class_name = java_lang_String::as_utf8_string(h_name());
|
||||||
int len = h_bytes->length();
|
int len = h_bytes->length();
|
||||||
// make a copy of class bytes so GC will not affect us.
|
// make a copy of class bytes so GC will not affect us.
|
||||||
char *buf = resource_allocate_bytes(THREAD, len);
|
char *buf = NEW_RESOURCE_ARRAY(char, len);
|
||||||
memcpy(buf, (char*)h_bytes->byte_at_addr(0), len);
|
memcpy(buf, (char*)h_bytes->byte_at_addr(0), len);
|
||||||
ClassFileStream st((u1*)buf, len, NULL, ClassFileStream::verify);
|
ClassFileStream st((u1*)buf, len, NULL, ClassFileStream::verify);
|
||||||
|
reload_class(class_name, st, CHECK);
|
||||||
reload_class(class_name, st, THREAD);
|
|
||||||
// free buf
|
|
||||||
resource_free_bytes(buf, len);
|
|
||||||
|
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
|
||||||
log_info(cds)("Exception happened: %s", PENDING_EXCEPTION->klass()->name()->as_C_string());
|
|
||||||
log_info(cds)("Could not create InstanceKlass for class %s", class_name);
|
|
||||||
CLEAR_PENDING_EXCEPTION;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,5 +190,53 @@ void LambdaFormInvokers::reload_class(char* name, ClassFileStream& st, TRAPS) {
|
||||||
|
|
||||||
// exclude the existing class from dump
|
// exclude the existing class from dump
|
||||||
SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass));
|
SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass));
|
||||||
log_info(cds, lambda)("Replaced class %s, old: %p new: %p", name, klass, result);
|
SystemDictionaryShared::init_dumptime_info(result);
|
||||||
|
log_info(cds, lambda)("Replaced class %s, old: " INTPTR_FORMAT " new: " INTPTR_FORMAT,
|
||||||
|
name, p2i(klass), p2i(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LambdaFormInvokers::dump_static_archive_invokers() {
|
||||||
|
if (_lambdaform_lines != nullptr && _lambdaform_lines->length() > 0) {
|
||||||
|
int count = 0;
|
||||||
|
int len = _lambdaform_lines->length();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
char* str = _lambdaform_lines->at(i);
|
||||||
|
if (should_be_archived(str)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count > 0) {
|
||||||
|
_static_archive_invokers = ArchiveBuilder::new_ro_array<Array<char>*>(count);
|
||||||
|
int index = 0;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
char* str = _lambdaform_lines->at(i);
|
||||||
|
if (should_be_archived(str)) {
|
||||||
|
size_t str_len = strlen(str) + 1; // including terminating zero
|
||||||
|
Array<char>* line = ArchiveBuilder::new_ro_array<char>((int)str_len);
|
||||||
|
strncpy(line->adr_at(0), str, str_len);
|
||||||
|
|
||||||
|
_static_archive_invokers->at_put(index, line);
|
||||||
|
ArchivePtrMarker::mark_pointer(_static_archive_invokers->adr_at(index));
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(index == count, "Should match");
|
||||||
|
}
|
||||||
|
log_debug(cds)("Total LF lines stored into static archive: %d", count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LambdaFormInvokers::read_static_archive_invokers() {
|
||||||
|
if (_static_archive_invokers != nullptr) {
|
||||||
|
for (int i = 0; i < _static_archive_invokers->length(); i++) {
|
||||||
|
Array<char>* line = _static_archive_invokers->at(i);
|
||||||
|
char* str = line->adr_at(0);
|
||||||
|
append(str);
|
||||||
|
}
|
||||||
|
log_debug(cds)("Total LF lines read from static archive: %d", _static_archive_invokers->length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LambdaFormInvokers::serialize(SerializeClosure* soc) {
|
||||||
|
soc->do_ptr((void**)&_static_archive_invokers);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,21 +26,24 @@
|
||||||
#define SHARE_CDS_LAMBDAFORMINVOKERS_HPP
|
#define SHARE_CDS_LAMBDAFORMINVOKERS_HPP
|
||||||
#include "memory/allStatic.hpp"
|
#include "memory/allStatic.hpp"
|
||||||
#include "runtime/handles.hpp"
|
#include "runtime/handles.hpp"
|
||||||
|
#include "utilities/growableArray.hpp"
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class GrowableArray;
|
|
||||||
class ClassFileStream;
|
class ClassFileStream;
|
||||||
|
template <class T>
|
||||||
|
class Array;
|
||||||
|
|
||||||
class LambdaFormInvokers : public AllStatic {
|
class LambdaFormInvokers : public AllStatic {
|
||||||
private:
|
private:
|
||||||
static GrowableArray<char*>* _lambdaform_lines;
|
static GrowableArrayCHeap<char*, mtClassShared>* _lambdaform_lines;
|
||||||
|
// For storing LF form lines (LF_RESOLVE only) in read only table.
|
||||||
|
static Array<Array<char>*>* _static_archive_invokers;
|
||||||
static void reload_class(char* name, ClassFileStream& st, TRAPS);
|
static void reload_class(char* name, ClassFileStream& st, TRAPS);
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static void append(char* line);
|
static void append(char* line);
|
||||||
|
static void append_filtered(char* line);
|
||||||
|
static void dump_static_archive_invokers();
|
||||||
|
static void read_static_archive_invokers();
|
||||||
static void regenerate_holder_classes(TRAPS);
|
static void regenerate_holder_classes(TRAPS);
|
||||||
static GrowableArray<char*>* lambdaform_lines() {
|
static void serialize(SerializeClosure* soc);
|
||||||
return _lambdaform_lines;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
#endif // SHARE_CDS_LAMBDAFORMINVOKERS_HPP
|
#endif // SHARE_CDS_LAMBDAFORMINVOKERS_HPP
|
||||||
|
|
|
@ -361,6 +361,7 @@ void MetaspaceShared::serialize(SerializeClosure* soc) {
|
||||||
|
|
||||||
CDS_JAVA_HEAP_ONLY(ClassLoaderDataShared::serialize(soc);)
|
CDS_JAVA_HEAP_ONLY(ClassLoaderDataShared::serialize(soc);)
|
||||||
|
|
||||||
|
LambdaFormInvokers::serialize(soc);
|
||||||
soc->do_tag(666);
|
soc->do_tag(666);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,6 +461,8 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
|
||||||
|
|
||||||
SystemDictionaryShared::write_to_archive();
|
SystemDictionaryShared::write_to_archive();
|
||||||
|
|
||||||
|
// Write lambform lines into archive
|
||||||
|
LambdaFormInvokers::dump_static_archive_invokers();
|
||||||
// Write the other data to the output array.
|
// Write the other data to the output array.
|
||||||
DumpRegion* ro_region = ArchiveBuilder::current()->ro_region();
|
DumpRegion* ro_region = ArchiveBuilder::current()->ro_region();
|
||||||
char* start = ro_region->top();
|
char* start = ro_region->top();
|
||||||
|
@ -598,6 +601,8 @@ bool MetaspaceShared::link_class_for_cds(InstanceKlass* ik, TRAPS) {
|
||||||
void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) {
|
void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) {
|
||||||
// Collect all loaded ClassLoaderData.
|
// Collect all loaded ClassLoaderData.
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
|
|
||||||
|
LambdaFormInvokers::regenerate_holder_classes(CHECK);
|
||||||
CollectCLDClosure collect_cld;
|
CollectCLDClosure collect_cld;
|
||||||
{
|
{
|
||||||
// ClassLoaderDataGraph::loaded_cld_do requires ClassLoaderDataGraph_lock.
|
// ClassLoaderDataGraph::loaded_cld_do requires ClassLoaderDataGraph_lock.
|
||||||
|
@ -718,12 +723,6 @@ void MetaspaceShared::preload_and_dump_impl(TRAPS) {
|
||||||
log_info(cds)("Reading extra data: done.");
|
log_info(cds)("Reading extra data: done.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LambdaFormInvokers::lambdaform_lines() != NULL) {
|
|
||||||
log_info(cds)("Regenerate MethodHandle Holder classes...");
|
|
||||||
LambdaFormInvokers::regenerate_holder_classes(CHECK);
|
|
||||||
log_info(cds)("Regenerate MethodHandle Holder classes done.");
|
|
||||||
}
|
|
||||||
|
|
||||||
HeapShared::init_for_dumping(CHECK);
|
HeapShared::init_for_dumping(CHECK);
|
||||||
|
|
||||||
// Rewrite and link classes
|
// Rewrite and link classes
|
||||||
|
@ -904,12 +903,12 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
|
||||||
char* cds_end = dynamic_mapped ? dynamic_mapinfo->mapped_end() : static_mapinfo->mapped_end();
|
char* cds_end = dynamic_mapped ? dynamic_mapinfo->mapped_end() : static_mapinfo->mapped_end();
|
||||||
set_shared_metaspace_range(cds_base, static_mapinfo->mapped_end(), cds_end);
|
set_shared_metaspace_range(cds_base, static_mapinfo->mapped_end(), cds_end);
|
||||||
_relocation_delta = static_mapinfo->relocation_delta();
|
_relocation_delta = static_mapinfo->relocation_delta();
|
||||||
|
_requested_base_address = static_mapinfo->requested_base_address();
|
||||||
if (dynamic_mapped) {
|
if (dynamic_mapped) {
|
||||||
FileMapInfo::set_shared_path_table(dynamic_mapinfo);
|
FileMapInfo::set_shared_path_table(dynamic_mapinfo);
|
||||||
} else {
|
} else {
|
||||||
FileMapInfo::set_shared_path_table(static_mapinfo);
|
FileMapInfo::set_shared_path_table(static_mapinfo);
|
||||||
}
|
}
|
||||||
_requested_base_address = static_mapinfo->requested_base_address();
|
|
||||||
} else {
|
} else {
|
||||||
set_shared_metaspace_range(NULL, NULL, NULL);
|
set_shared_metaspace_range(NULL, NULL, NULL);
|
||||||
UseSharedSpaces = false;
|
UseSharedSpaces = false;
|
||||||
|
@ -1408,6 +1407,12 @@ void MetaspaceShared::initialize_shared_spaces() {
|
||||||
dynamic_mapinfo->unmap_region(MetaspaceShared::bm);
|
dynamic_mapinfo->unmap_region(MetaspaceShared::bm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up LambdaFormInvokers::_lambdaform_lines for dynamic dump
|
||||||
|
if (DynamicDumpSharedSpaces) {
|
||||||
|
// Read stored LF format lines stored in static archive
|
||||||
|
LambdaFormInvokers::read_static_archive_invokers();
|
||||||
|
}
|
||||||
|
|
||||||
if (PrintSharedArchiveAndExit) {
|
if (PrintSharedArchiveAndExit) {
|
||||||
// Print archive names
|
// Print archive names
|
||||||
if (dynamic_mapinfo != nullptr) {
|
if (dynamic_mapinfo != nullptr) {
|
||||||
|
|
|
@ -2200,6 +2200,19 @@ SystemDictionaryShared::find_record(RunTimeSharedDictionary* static_dict, RunTim
|
||||||
|
|
||||||
unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary_quick(name);
|
unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary_quick(name);
|
||||||
const RunTimeSharedClassInfo* record = NULL;
|
const RunTimeSharedClassInfo* record = NULL;
|
||||||
|
if (DynamicArchive::is_mapped()) {
|
||||||
|
// Those regenerated holder classes are in dynamic archive
|
||||||
|
if (name == vmSymbols::java_lang_invoke_Invokers_Holder() ||
|
||||||
|
name == vmSymbols::java_lang_invoke_DirectMethodHandle_Holder() ||
|
||||||
|
name == vmSymbols::java_lang_invoke_LambdaForm_Holder() ||
|
||||||
|
name == vmSymbols::java_lang_invoke_DelegatingMethodHandle_Holder()) {
|
||||||
|
record = dynamic_dict->lookup(name, hash, 0);
|
||||||
|
if (record != nullptr) {
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!MetaspaceShared::is_shared_dynamic(name)) {
|
if (!MetaspaceShared::is_shared_dynamic(name)) {
|
||||||
// The names of all shared classes in the static dict must also be in the
|
// The names of all shared classes in the static dict must also be in the
|
||||||
// static archive
|
// static archive
|
||||||
|
@ -2256,7 +2269,7 @@ public:
|
||||||
|
|
||||||
void do_value(const RunTimeSharedClassInfo* record) {
|
void do_value(const RunTimeSharedClassInfo* record) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
_st->print_cr("%4d: %s %s", (_index++), record->_klass->external_name(),
|
_st->print_cr("%4d: %s %s", _index++, record->_klass->external_name(),
|
||||||
class_loader_name_for_shared(record->_klass));
|
class_loader_name_for_shared(record->_klass));
|
||||||
}
|
}
|
||||||
int index() const { return _index; }
|
int index() const { return _index; }
|
||||||
|
@ -2273,7 +2286,7 @@ public:
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
Klass* k = record->proxy_klass_head();
|
Klass* k = record->proxy_klass_head();
|
||||||
while (k != nullptr) {
|
while (k != nullptr) {
|
||||||
_st->print_cr("%4d: %s %s", (++_index), k->external_name(),
|
_st->print_cr("%4d: %s %s", _index++, k->external_name(),
|
||||||
class_loader_name_for_shared(k));
|
class_loader_name_for_shared(k));
|
||||||
k = k->next_link();
|
k = k->next_link();
|
||||||
}
|
}
|
||||||
|
|
|
@ -297,12 +297,6 @@
|
||||||
template(base_name, "base") \
|
template(base_name, "base") \
|
||||||
/* Type Annotations (JDK 8 and above) */ \
|
/* Type Annotations (JDK 8 and above) */ \
|
||||||
template(type_annotations_name, "typeAnnotations") \
|
template(type_annotations_name, "typeAnnotations") \
|
||||||
/* used by CDS */ \
|
|
||||||
template(jdk_internal_misc_CDS, "jdk/internal/misc/CDS") \
|
|
||||||
template(generateLambdaFormHolderClasses, "generateLambdaFormHolderClasses") \
|
|
||||||
template(generateLambdaFormHolderClasses_signature, "([Ljava/lang/String;)[Ljava/lang/Object;") \
|
|
||||||
template(dumpSharedArchive, "dumpSharedArchive") \
|
|
||||||
template(dumpSharedArchive_signature, "(ZLjava/lang/String;)V") \
|
|
||||||
\
|
\
|
||||||
/* Intrinsic Annotation (JDK 9 and above) */ \
|
/* Intrinsic Annotation (JDK 9 and above) */ \
|
||||||
template(jdk_internal_vm_annotation_DontInline_signature, "Ljdk/internal/vm/annotation/DontInline;") \
|
template(jdk_internal_vm_annotation_DontInline_signature, "Ljdk/internal/vm/annotation/DontInline;") \
|
||||||
|
@ -694,13 +688,22 @@
|
||||||
/* jfr signatures */ \
|
/* jfr signatures */ \
|
||||||
JFR_TEMPLATES(template) \
|
JFR_TEMPLATES(template) \
|
||||||
\
|
\
|
||||||
/* cds */ \
|
/* CDS */ \
|
||||||
template(jdk_internal_loader_ClassLoaders, "jdk/internal/loader/ClassLoaders") \
|
template(dumpSharedArchive, "dumpSharedArchive") \
|
||||||
template(java_util_concurrent_ConcurrentHashMap, "java/util/concurrent/ConcurrentHashMap") \
|
template(dumpSharedArchive_signature, "(ZLjava/lang/String;)V") \
|
||||||
template(java_util_ArrayList, "java/util/ArrayList") \
|
template(generateLambdaFormHolderClasses, "generateLambdaFormHolderClasses") \
|
||||||
template(toFileURL_name, "toFileURL") \
|
template(generateLambdaFormHolderClasses_signature, "([Ljava/lang/String;)[Ljava/lang/Object;") \
|
||||||
template(toFileURL_signature, "(Ljava/lang/String;)Ljava/net/URL;") \
|
template(java_lang_invoke_Invokers_Holder, "java/lang/invoke/Invokers$Holder") \
|
||||||
template(url_void_signature, "(Ljava/net/URL;)V") \
|
template(java_lang_invoke_DirectMethodHandle_Holder, "java/lang/invoke/DirectMethodHandle$Holder") \
|
||||||
|
template(java_lang_invoke_LambdaForm_Holder, "java/lang/invoke/LambdaForm$Holder") \
|
||||||
|
template(java_lang_invoke_DelegatingMethodHandle_Holder, "java/lang/invoke/DelegatingMethodHandle$Holder") \
|
||||||
|
template(jdk_internal_loader_ClassLoaders, "jdk/internal/loader/ClassLoaders") \
|
||||||
|
template(jdk_internal_misc_CDS, "jdk/internal/misc/CDS") \
|
||||||
|
template(java_util_concurrent_ConcurrentHashMap, "java/util/concurrent/ConcurrentHashMap") \
|
||||||
|
template(java_util_ArrayList, "java/util/ArrayList") \
|
||||||
|
template(toFileURL_name, "toFileURL") \
|
||||||
|
template(toFileURL_signature, "(Ljava/lang/String;)Ljava/net/URL;") \
|
||||||
|
template(url_void_signature, "(Ljava/net/URL;)V") \
|
||||||
\
|
\
|
||||||
/*end*/
|
/*end*/
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "cds/classListWriter.hpp"
|
#include "cds/classListWriter.hpp"
|
||||||
#include "cds/dynamicArchive.hpp"
|
#include "cds/dynamicArchive.hpp"
|
||||||
#include "cds/heapShared.hpp"
|
#include "cds/heapShared.hpp"
|
||||||
|
#include "cds/lambdaFormInvokers.hpp"
|
||||||
#include "classfile/classFileStream.hpp"
|
#include "classfile/classFileStream.hpp"
|
||||||
#include "classfile/classLoader.hpp"
|
#include "classfile/classLoader.hpp"
|
||||||
#include "classfile/classLoaderData.hpp"
|
#include "classfile/classLoaderData.hpp"
|
||||||
|
@ -420,10 +421,12 @@ JVM_END
|
||||||
extern volatile jint vm_created;
|
extern volatile jint vm_created;
|
||||||
|
|
||||||
JVM_ENTRY_NO_ENV(void, JVM_BeforeHalt())
|
JVM_ENTRY_NO_ENV(void, JVM_BeforeHalt())
|
||||||
|
#if INCLUDE_CDS
|
||||||
// Link all classes for dynamic CDS dumping before vm exit.
|
// Link all classes for dynamic CDS dumping before vm exit.
|
||||||
if (DynamicDumpSharedSpaces) {
|
if (DynamicDumpSharedSpaces) {
|
||||||
MetaspaceShared::link_and_cleanup_shared_classes(THREAD);
|
DynamicArchive::prepare_for_dynamic_dumping_at_exit();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
EventShutdown event;
|
EventShutdown event;
|
||||||
if (event.should_commit()) {
|
if (event.should_commit()) {
|
||||||
event.set_reason("Shutdown requested from Java");
|
event.set_reason("Shutdown requested from Java");
|
||||||
|
@ -3643,7 +3646,7 @@ JVM_END
|
||||||
|
|
||||||
JVM_ENTRY(jboolean, JVM_IsDumpingClassList(JNIEnv *env))
|
JVM_ENTRY(jboolean, JVM_IsDumpingClassList(JNIEnv *env))
|
||||||
#if INCLUDE_CDS
|
#if INCLUDE_CDS
|
||||||
return ClassListWriter::is_enabled();
|
return ClassListWriter::is_enabled() || DynamicDumpSharedSpaces;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif // INCLUDE_CDS
|
#endif // INCLUDE_CDS
|
||||||
|
@ -3651,13 +3654,20 @@ JVM_END
|
||||||
|
|
||||||
JVM_ENTRY(void, JVM_LogLambdaFormInvoker(JNIEnv *env, jstring line))
|
JVM_ENTRY(void, JVM_LogLambdaFormInvoker(JNIEnv *env, jstring line))
|
||||||
#if INCLUDE_CDS
|
#if INCLUDE_CDS
|
||||||
assert(ClassListWriter::is_enabled(), "Should be set and open");
|
assert(ClassListWriter::is_enabled() || DynamicDumpSharedSpaces, "Should be set and open or do dynamic dump");
|
||||||
if (line != NULL) {
|
if (line != NULL) {
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
Handle h_line (THREAD, JNIHandles::resolve_non_null(line));
|
Handle h_line (THREAD, JNIHandles::resolve_non_null(line));
|
||||||
char* c_line = java_lang_String::as_utf8_string(h_line());
|
char* c_line = java_lang_String::as_utf8_string(h_line());
|
||||||
ClassListWriter w;
|
if (DynamicDumpSharedSpaces) {
|
||||||
w.stream()->print_cr("%s %s", LAMBDA_FORM_TAG, c_line);
|
// Note: LambdaFormInvokers::append_filtered and LambdaFormInvokers::append take same format which is not
|
||||||
|
// same as below the print format. The line does not include LAMBDA_FORM_TAG.
|
||||||
|
LambdaFormInvokers::append_filtered(os::strdup((const char*)c_line, mtInternal));
|
||||||
|
}
|
||||||
|
if (ClassListWriter::is_enabled()) {
|
||||||
|
ClassListWriter w;
|
||||||
|
w.stream()->print_cr("%s %s", LAMBDA_FORM_TAG, c_line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif // INCLUDE_CDS
|
#endif // INCLUDE_CDS
|
||||||
JVM_END
|
JVM_END
|
||||||
|
@ -3676,7 +3686,7 @@ JVM_ENTRY(void, JVM_DumpDynamicArchive(JNIEnv *env, jstring archiveName))
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
Handle file_handle(THREAD, JNIHandles::resolve_non_null(archiveName));
|
Handle file_handle(THREAD, JNIHandles::resolve_non_null(archiveName));
|
||||||
char* archive_name = java_lang_String::as_utf8_string(file_handle());
|
char* archive_name = java_lang_String::as_utf8_string(file_handle());
|
||||||
DynamicArchive::dump(archive_name, THREAD);
|
DynamicArchive::dump(archive_name, CHECK);
|
||||||
#endif // INCLUDE_CDS
|
#endif // INCLUDE_CDS
|
||||||
JVM_END
|
JVM_END
|
||||||
|
|
||||||
|
|
|
@ -509,7 +509,15 @@ void before_exit(JavaThread* thread) {
|
||||||
|
|
||||||
#if INCLUDE_CDS
|
#if INCLUDE_CDS
|
||||||
if (DynamicDumpSharedSpaces) {
|
if (DynamicDumpSharedSpaces) {
|
||||||
|
ExceptionMark em(thread);
|
||||||
DynamicArchive::dump();
|
DynamicArchive::dump();
|
||||||
|
if (thread->has_pending_exception()) {
|
||||||
|
ResourceMark rm(thread);
|
||||||
|
oop pending_exception = thread->pending_exception();
|
||||||
|
log_error(cds)("ArchiveClassesAtExit has failed %s: %s", pending_exception->klass()->external_name(),
|
||||||
|
java_lang_String::as_utf8_string(java_lang_Throwable::message(pending_exception)));
|
||||||
|
thread->clear_pending_exception();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -154,6 +154,7 @@ Mutex* DumpTimeTable_lock = NULL;
|
||||||
Mutex* CDSLambda_lock = NULL;
|
Mutex* CDSLambda_lock = NULL;
|
||||||
Mutex* DumpRegion_lock = NULL;
|
Mutex* DumpRegion_lock = NULL;
|
||||||
Mutex* ClassListFile_lock = NULL;
|
Mutex* ClassListFile_lock = NULL;
|
||||||
|
Mutex* LambdaFormInvokers_lock = NULL;
|
||||||
#endif // INCLUDE_CDS
|
#endif // INCLUDE_CDS
|
||||||
Mutex* Bootclasspath_lock = NULL;
|
Mutex* Bootclasspath_lock = NULL;
|
||||||
|
|
||||||
|
@ -344,6 +345,7 @@ void mutex_init() {
|
||||||
def(CDSLambda_lock , PaddedMutex , leaf, true, _safepoint_check_never);
|
def(CDSLambda_lock , PaddedMutex , leaf, true, _safepoint_check_never);
|
||||||
def(DumpRegion_lock , PaddedMutex , leaf, true, _safepoint_check_never);
|
def(DumpRegion_lock , PaddedMutex , leaf, true, _safepoint_check_never);
|
||||||
def(ClassListFile_lock , PaddedMutex , leaf, true, _safepoint_check_never);
|
def(ClassListFile_lock , PaddedMutex , leaf, true, _safepoint_check_never);
|
||||||
|
def(LambdaFormInvokers_lock , PaddedMutex , nonleaf+2, false, _safepoint_check_always);
|
||||||
#endif // INCLUDE_CDS
|
#endif // INCLUDE_CDS
|
||||||
def(Bootclasspath_lock , PaddedMutex , leaf, false, _safepoint_check_never);
|
def(Bootclasspath_lock , PaddedMutex , leaf, false, _safepoint_check_never);
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,7 @@ extern Mutex* DumpTimeTable_lock; // SystemDictionaryShared::find
|
||||||
extern Mutex* CDSLambda_lock; // SystemDictionaryShared::get_shared_lambda_proxy_class
|
extern Mutex* CDSLambda_lock; // SystemDictionaryShared::get_shared_lambda_proxy_class
|
||||||
extern Mutex* DumpRegion_lock; // Symbol::operator new(size_t sz, int len)
|
extern Mutex* DumpRegion_lock; // Symbol::operator new(size_t sz, int len)
|
||||||
extern Mutex* ClassListFile_lock; // ClassListWriter()
|
extern Mutex* ClassListFile_lock; // ClassListWriter()
|
||||||
|
extern Mutex* LambdaFormInvokers_lock; // Protecting LambdaFormInvokers::_lambdaform_lines
|
||||||
#endif // INCLUDE_CDS
|
#endif // INCLUDE_CDS
|
||||||
#if INCLUDE_JFR
|
#if INCLUDE_JFR
|
||||||
extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table
|
extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "jvm.h"
|
#include "jvm.h"
|
||||||
|
#include "cds/dynamicArchive.hpp"
|
||||||
#include "cds/metaspaceShared.hpp"
|
#include "cds/metaspaceShared.hpp"
|
||||||
#include "classfile/classLoader.hpp"
|
#include "classfile/classLoader.hpp"
|
||||||
#include "classfile/javaClasses.hpp"
|
#include "classfile/javaClasses.hpp"
|
||||||
|
@ -3300,12 +3301,14 @@ void JavaThread::invoke_shutdown_hooks() {
|
||||||
this->clear_pending_exception();
|
this->clear_pending_exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if INCLUDE_CDS
|
||||||
// Link all classes for dynamic CDS dumping before vm exit.
|
// Link all classes for dynamic CDS dumping before vm exit.
|
||||||
// Same operation is being done in JVM_BeforeHalt for handling the
|
// Same operation is being done in JVM_BeforeHalt for handling the
|
||||||
// case where the application calls System.exit().
|
// case where the application calls System.exit().
|
||||||
if (DynamicDumpSharedSpaces) {
|
if (DynamicDumpSharedSpaces) {
|
||||||
MetaspaceShared::link_and_cleanup_shared_classes(this);
|
DynamicArchive::prepare_for_dynamic_dumping_at_exit();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
EXCEPTION_MARK;
|
EXCEPTION_MARK;
|
||||||
Klass* shutdown_klass =
|
Klass* shutdown_klass =
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8266764
|
||||||
|
* @summary test dynamic dump with OOM
|
||||||
|
* @requires vm.cds
|
||||||
|
* @requires vm.gc.Serial & vm.gc == null
|
||||||
|
* @comment Test dynamic dump at OOM, currently only works with SerialGC
|
||||||
|
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes
|
||||||
|
* @compile ./test-classes/MiniStoreOom.java
|
||||||
|
* @build LambHello sun.hotspot.WhiteBox
|
||||||
|
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar ministore.jar MiniStoreOom
|
||||||
|
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
|
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. TestDynamicDumpAtOom
|
||||||
|
*/
|
||||||
|
|
||||||
|
import jdk.test.lib.helpers.ClassFileInstaller;
|
||||||
|
import jdk.test.lib.cds.CDSTestUtils.Result;
|
||||||
|
|
||||||
|
public class TestDynamicDumpAtOom extends DynamicArchiveTestBase {
|
||||||
|
private static final String mainClass = "MiniStoreOom";
|
||||||
|
private static final String jarFile = "ministore.jar";
|
||||||
|
private static void doTest(String topArchiveName) throws Exception {
|
||||||
|
dump(topArchiveName,
|
||||||
|
"-Xmx64M",
|
||||||
|
"-XX:+UseSerialGC",
|
||||||
|
"-Xlog:cds",
|
||||||
|
"-Xlog:cds+dynamic=debug",
|
||||||
|
"-cp",
|
||||||
|
jarFile,
|
||||||
|
mainClass,
|
||||||
|
"1024").assertAbnormalExit(output -> {
|
||||||
|
output.shouldContain("ArchiveClassesAtExit has failed")
|
||||||
|
.shouldContain("java.lang.OutOfMemoryError: Java heap space");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testDefaultBase() throws Exception {
|
||||||
|
String topArchiveName = getNewArchiveName("top");
|
||||||
|
doTest(topArchiveName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
runTest(TestDynamicDumpAtOom::testDefaultBase);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8255493
|
||||||
|
* @summary LambHello World test for regenerate lambda holder classes in dynamic archive
|
||||||
|
* @requires vm.cds
|
||||||
|
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes
|
||||||
|
* @build LambHello sun.hotspot.WhiteBox
|
||||||
|
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar lambhello.jar LambHello
|
||||||
|
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
|
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. TestDynamicRegenerateHolderClasses
|
||||||
|
*/
|
||||||
|
|
||||||
|
import jdk.test.lib.helpers.ClassFileInstaller;
|
||||||
|
|
||||||
|
public class TestDynamicRegenerateHolderClasses extends DynamicArchiveTestBase {
|
||||||
|
static String CHECK_MESSAGES[] = {"java.lang.invoke.Invokers$Holder source: shared objects file (top)",
|
||||||
|
"java.lang.invoke.DirectMethodHandle$Holder source: shared objects file (top)",
|
||||||
|
"java.lang.invoke.DelegatingMethodHandle$Holder source: shared objects file (top)",
|
||||||
|
"java.lang.invoke.LambdaForm$Holder source: shared objects file (top)"};
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
runTest(TestDynamicRegenerateHolderClasses::testDefaultBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testDefaultBase() throws Exception {
|
||||||
|
String topArchiveName = getNewArchiveName("top");
|
||||||
|
doTest(topArchiveName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void doTest(String topArchiveName) throws Exception {
|
||||||
|
String appJar = ClassFileInstaller.getJarPath("lambhello.jar");
|
||||||
|
String mainClass = "LambHello";
|
||||||
|
dump(topArchiveName,
|
||||||
|
"-Xlog:cds",
|
||||||
|
"-Xlog:cds+dynamic=debug",
|
||||||
|
"-cp", appJar, mainClass)
|
||||||
|
.assertNormalExit(output -> {
|
||||||
|
output.shouldContain("Written dynamic archive 0x");
|
||||||
|
});
|
||||||
|
run(topArchiveName,
|
||||||
|
"-Xlog:class+load",
|
||||||
|
"-Xlog:cds+dynamic=debug,cds=debug,class+load",
|
||||||
|
"-cp", appJar, mainClass)
|
||||||
|
.assertNormalExit(output -> {
|
||||||
|
output.shouldContain("LambHello source: shared objects file (top)")
|
||||||
|
.shouldHaveExitValue(0);
|
||||||
|
for (String s : CHECK_MESSAGES) {
|
||||||
|
output.shouldContain(s);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import java.util.HashMap;
|
||||||
|
public class MiniStoreOom {
|
||||||
|
private static HashMap<Integer, Byte[]> store = new HashMap<Integer, Byte[]>();
|
||||||
|
public static void main(String... args) throws Exception {
|
||||||
|
int size = Integer.valueOf(args[0]);
|
||||||
|
int i = 0;
|
||||||
|
while (i++ < Integer.MAX_VALUE) {
|
||||||
|
store.put(i, new Byte[size]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue