8297914: Remove java_lang_Class::process_archived_mirror()
Reviewed-by: ccheung
This commit is contained in:
parent
4be94e4350
commit
7bcd5f418c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -55,6 +55,7 @@
|
||||
#include "runtime/fieldDescriptor.inline.hpp"
|
||||
#include "runtime/init.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "runtime/safepointVerifiers.hpp"
|
||||
#include "utilities/bitMap.inline.hpp"
|
||||
#include "utilities/copy.hpp"
|
||||
@ -135,8 +136,11 @@ static ArchivableStaticFieldInfo fmg_open_archive_subgraph_entry_fields[] = {
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
KlassSubGraphInfo* HeapShared::_default_subgraph_info;
|
||||
GrowableArrayCHeap<oop, mtClassShared>* HeapShared::_pending_roots = NULL;
|
||||
OopHandle HeapShared::_roots;
|
||||
OopHandle HeapShared::_scratch_basic_type_mirrors[T_VOID+1];
|
||||
KlassToOopHandleTable* HeapShared::_scratch_java_mirror_table = NULL;
|
||||
|
||||
#ifdef ASSERT
|
||||
bool HeapShared::is_archived_object_during_dumptime(oop p) {
|
||||
@ -343,21 +347,108 @@ oop HeapShared::archive_object(oop obj) {
|
||||
return archived_oop;
|
||||
}
|
||||
|
||||
void HeapShared::archive_klass_objects() {
|
||||
class KlassToOopHandleTable: public ResourceHashtable<Klass*, OopHandle,
|
||||
36137, // prime number
|
||||
AnyObj::C_HEAP,
|
||||
mtClassShared> {
|
||||
public:
|
||||
oop get_oop(Klass* k) {
|
||||
MutexLocker ml(ScratchObjects_lock, Mutex::_no_safepoint_check_flag);
|
||||
OopHandle* handle = get(k);
|
||||
if (handle != NULL) {
|
||||
return handle->resolve();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
void set_oop(Klass* k, oop o) {
|
||||
MutexLocker ml(ScratchObjects_lock, Mutex::_no_safepoint_check_flag);
|
||||
OopHandle handle(Universe::vm_global(), o);
|
||||
bool is_new = put(k, handle);
|
||||
assert(is_new, "cannot set twice");
|
||||
}
|
||||
void remove_oop(Klass* k) {
|
||||
MutexLocker ml(ScratchObjects_lock, Mutex::_no_safepoint_check_flag);
|
||||
OopHandle* handle = get(k);
|
||||
if (handle != NULL) {
|
||||
handle->release(Universe::vm_global());
|
||||
remove(k);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void HeapShared::init_scratch_objects(TRAPS) {
|
||||
for (int i = T_BOOLEAN; i < T_VOID+1; i++) {
|
||||
BasicType bt = (BasicType)i;
|
||||
if (!is_reference_type(bt)) {
|
||||
oop m = java_lang_Class::create_basic_type_mirror(type2name(bt), bt, CHECK);
|
||||
_scratch_basic_type_mirrors[i] = OopHandle(Universe::vm_global(), m);
|
||||
}
|
||||
}
|
||||
_scratch_java_mirror_table = new (mtClass)KlassToOopHandleTable();
|
||||
}
|
||||
|
||||
oop HeapShared::scratch_java_mirror(BasicType t) {
|
||||
assert((uint)t < T_VOID+1, "range check");
|
||||
assert(!is_reference_type(t), "sanity");
|
||||
return _scratch_basic_type_mirrors[t].resolve();
|
||||
}
|
||||
|
||||
oop HeapShared::scratch_java_mirror(Klass* k) {
|
||||
return _scratch_java_mirror_table->get_oop(k);
|
||||
}
|
||||
|
||||
void HeapShared::set_scratch_java_mirror(Klass* k, oop mirror) {
|
||||
_scratch_java_mirror_table->set_oop(k, mirror);
|
||||
}
|
||||
|
||||
void HeapShared::remove_scratch_objects(Klass* k) {
|
||||
_scratch_java_mirror_table->remove_oop(k);
|
||||
}
|
||||
|
||||
void HeapShared::archive_java_mirrors() {
|
||||
init_seen_objects_table();
|
||||
|
||||
for (int i = T_BOOLEAN; i < T_VOID+1; i++) {
|
||||
BasicType bt = (BasicType)i;
|
||||
if (!is_reference_type(bt)) {
|
||||
oop m = _scratch_basic_type_mirrors[i].resolve();
|
||||
assert(m != NULL, "sanity");
|
||||
oop archived_m = archive_reachable_objects_from(1, _default_subgraph_info, m, /*is_closed_archive=*/ false);
|
||||
assert(archived_m != NULL, "sanity");
|
||||
|
||||
log_trace(cds, heap, mirror)(
|
||||
"Archived %s mirror object from " PTR_FORMAT " ==> " PTR_FORMAT,
|
||||
type2name(bt), p2i(m), p2i(archived_m));
|
||||
|
||||
Universe::set_archived_basic_type_mirror_index(bt, append_root(archived_m));
|
||||
}
|
||||
}
|
||||
|
||||
GrowableArray<Klass*>* klasses = ArchiveBuilder::current()->klasses();
|
||||
assert(klasses != NULL, "sanity");
|
||||
for (int i = 0; i < klasses->length(); i++) {
|
||||
Klass* k = ArchiveBuilder::get_buffered_klass(klasses->at(i));
|
||||
Klass* orig_k = klasses->at(i);
|
||||
oop m = scratch_java_mirror(orig_k);
|
||||
if (m != NULL) {
|
||||
Klass* buffered_k = ArchiveBuilder::get_buffered_klass(orig_k);
|
||||
oop archived_m = archive_reachable_objects_from(1, _default_subgraph_info, m, /*is_closed_archive=*/ false);
|
||||
guarantee(archived_m != NULL, "scratch mirrors should not point to any unachivable objects");
|
||||
buffered_k->set_archived_java_mirror(append_root(archived_m));
|
||||
ResourceMark rm;
|
||||
log_trace(cds, heap, mirror)(
|
||||
"Archived %s mirror object from " PTR_FORMAT " ==> " PTR_FORMAT,
|
||||
buffered_k->external_name(), p2i(m), p2i(archived_m));
|
||||
|
||||
// archive mirror object
|
||||
java_lang_Class::archive_mirror(k);
|
||||
|
||||
// archive the resolved_referenes array
|
||||
if (k->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
ik->constants()->archive_resolved_references();
|
||||
// archive the resolved_referenes array
|
||||
if (buffered_k->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(buffered_k);
|
||||
ik->constants()->archive_resolved_references();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete_seen_objects_table();
|
||||
}
|
||||
|
||||
void HeapShared::mark_native_pointers(oop orig_obj, oop archived_obj) {
|
||||
@ -501,6 +592,8 @@ void HeapShared::archive_objects(GrowableArray<MemRegion>* closed_regions,
|
||||
{
|
||||
NoSafepointVerifier nsv;
|
||||
|
||||
_default_subgraph_info = init_subgraph_info(vmClasses::Object_klass(), false);
|
||||
|
||||
// Cache for recording where the archived objects are copied to
|
||||
create_archived_object_cache(log_is_enabled(Info, cds, map));
|
||||
|
||||
@ -516,6 +609,7 @@ void HeapShared::archive_objects(GrowableArray<MemRegion>* closed_regions,
|
||||
copy_open_objects(open_regions);
|
||||
|
||||
CDSHeapVerifier::verify();
|
||||
check_default_subgraph_classes();
|
||||
}
|
||||
|
||||
G1HeapVerifier::verify_archive_regions();
|
||||
@ -542,9 +636,7 @@ void HeapShared::copy_open_objects(GrowableArray<MemRegion>* open_regions) {
|
||||
|
||||
G1CollectedHeap::heap()->begin_archive_alloc_range(true /* open */);
|
||||
|
||||
java_lang_Class::archive_basic_type_mirrors();
|
||||
|
||||
archive_klass_objects();
|
||||
archive_java_mirrors();
|
||||
|
||||
archive_object_subgraphs(open_archive_subgraph_entry_fields,
|
||||
false /* is_closed_archive */,
|
||||
@ -1134,9 +1226,11 @@ class WalkOopAndArchiveClosure: public BasicOopIterateClosure {
|
||||
log_debug(cds, heap)("(%d) %s[" SIZE_FORMAT "] ==> " PTR_FORMAT " size " SIZE_FORMAT " %s", _level,
|
||||
_orig_referencing_obj->klass()->external_name(), field_delta,
|
||||
p2i(obj), obj->size() * HeapWordSize, obj->klass()->external_name());
|
||||
LogTarget(Trace, cds, heap) log;
|
||||
LogStream out(log);
|
||||
obj->print_on(&out);
|
||||
if (log_is_enabled(Trace, cds, heap)) {
|
||||
LogTarget(Trace, cds, heap) log;
|
||||
LogStream out(log);
|
||||
obj->print_on(&out);
|
||||
}
|
||||
}
|
||||
|
||||
oop archived = HeapShared::archive_reachable_objects_from(
|
||||
@ -1213,7 +1307,7 @@ oop HeapShared::archive_reachable_objects_from(int level,
|
||||
//
|
||||
// If you get an error here, you probably made a change in the JDK library that has added a Class
|
||||
// object that is referenced (directly or indirectly) by static fields.
|
||||
if (java_lang_Class::is_instance(orig_obj)) {
|
||||
if (java_lang_Class::is_instance(orig_obj) && subgraph_info != _default_subgraph_info) {
|
||||
log_error(cds, heap)("(%d) Unknown java.lang.Class object is in the archived sub-graph", level);
|
||||
os::_exit(1);
|
||||
}
|
||||
@ -1431,6 +1525,31 @@ void HeapShared::verify_reachable_objects_from(oop obj, bool is_archived) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// The "default subgraph" contains special objects (see heapShared.hpp) that
|
||||
// can be accessed before we load any Java classes (including java/lang/Class).
|
||||
// Make sure that these are only instances of the very few specific types
|
||||
// that we can handle.
|
||||
void HeapShared::check_default_subgraph_classes() {
|
||||
GrowableArray<Klass*>* klasses = _default_subgraph_info->subgraph_object_klasses();
|
||||
int num = klasses->length();
|
||||
for (int i = 0; i < num; i++) {
|
||||
Klass* subgraph_k = klasses->at(i);
|
||||
if (log_is_enabled(Info, cds, heap)) {
|
||||
ResourceMark rm;
|
||||
log_info(cds, heap)(
|
||||
"Archived object klass (default subgraph %d) => %s",
|
||||
i, subgraph_k->external_name());
|
||||
}
|
||||
|
||||
guarantee(subgraph_k->name()->equals("java/lang/Class") ||
|
||||
subgraph_k->name()->equals("java/lang/String") ||
|
||||
subgraph_k->name()->equals("[Ljava/lang/Object;") ||
|
||||
subgraph_k->name()->equals("[C") ||
|
||||
subgraph_k->name()->equals("[B"),
|
||||
"default subgraph can have only these objects");
|
||||
}
|
||||
}
|
||||
|
||||
HeapShared::SeenObjectsTable* HeapShared::_seen_objects_table = NULL;
|
||||
int HeapShared::_num_new_walked_objs;
|
||||
int HeapShared::_num_new_archived_objs;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -43,6 +43,7 @@
|
||||
class DumpedInternedStrings;
|
||||
class FileMapInfo;
|
||||
class KlassSubGraphInfo;
|
||||
class KlassToOopHandleTable;
|
||||
class ResourceBitMap;
|
||||
|
||||
struct ArchivableStaticFieldInfo;
|
||||
@ -156,6 +157,11 @@ public:
|
||||
}
|
||||
|
||||
static bool is_subgraph_root_class(InstanceKlass* ik);
|
||||
|
||||
// Scratch objects for archiving Klass::java_mirror()
|
||||
static oop scratch_java_mirror(BasicType t) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
|
||||
static oop scratch_java_mirror(Klass* k) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
|
||||
|
||||
private:
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
static bool _disable_writing;
|
||||
@ -247,6 +253,7 @@ private:
|
||||
InstanceKlass* k, int field_offset) PRODUCT_RETURN;
|
||||
static void verify_reachable_objects_from(oop obj, bool is_archived) PRODUCT_RETURN;
|
||||
static void verify_subgraph_from(oop orig_obj) PRODUCT_RETURN;
|
||||
static void check_default_subgraph_classes();
|
||||
|
||||
static KlassSubGraphInfo* init_subgraph_info(Klass *k, bool is_full_module_graph);
|
||||
static KlassSubGraphInfo* get_subgraph_info(Klass *k);
|
||||
@ -269,8 +276,17 @@ private:
|
||||
|
||||
static SeenObjectsTable *_seen_objects_table;
|
||||
|
||||
// The "default subgraph" is the root of all archived objects that do not belong to any
|
||||
// of the classes defined in the <xxx>_archive_subgraph_entry_fields[] arrays:
|
||||
// - interned strings
|
||||
// - Klass::java_mirror()
|
||||
// - ConstantPool::resolved_references()
|
||||
static KlassSubGraphInfo* _default_subgraph_info;
|
||||
|
||||
static GrowableArrayCHeap<oop, mtClassShared>* _pending_roots;
|
||||
static OopHandle _roots;
|
||||
static OopHandle _scratch_basic_type_mirrors[T_VOID+1];
|
||||
static KlassToOopHandleTable* _scratch_java_mirror_table;
|
||||
|
||||
static void init_seen_objects_table() {
|
||||
assert(_seen_objects_table == NULL, "must be");
|
||||
@ -358,7 +374,7 @@ private:
|
||||
static oop find_archived_heap_object(oop obj);
|
||||
static oop archive_object(oop obj);
|
||||
|
||||
static void archive_klass_objects();
|
||||
static void archive_java_mirrors();
|
||||
|
||||
static void archive_objects(GrowableArray<MemRegion>* closed_regions,
|
||||
GrowableArray<MemRegion>* open_regions);
|
||||
@ -374,6 +390,10 @@ private:
|
||||
static ResourceBitMap calculate_ptrmap(MemRegion region); // marks all the native pointers
|
||||
static void add_to_dumped_interned_strings(oop string);
|
||||
|
||||
// Scratch objects for archiving Klass::java_mirror()
|
||||
static void set_scratch_java_mirror(Klass* k, oop mirror);
|
||||
static void remove_scratch_objects(Klass* k);
|
||||
|
||||
// We use the HeapShared::roots() array to make sure that objects stored in the
|
||||
// archived heap regions are not prematurely collected. These roots include:
|
||||
//
|
||||
@ -403,6 +423,7 @@ private:
|
||||
#endif // INCLUDE_CDS_JAVA_HEAP
|
||||
|
||||
public:
|
||||
static void init_scratch_objects(TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void run_full_gc_in_vm_thread() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
static bool is_heap_region(int idx) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -806,18 +806,6 @@ static void initialize_static_string_field(fieldDescriptor* fd, Handle mirror, T
|
||||
mirror()->obj_field_put(fd->offset(), string);
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
static void initialize_static_string_field_for_dump(fieldDescriptor* fd, Handle mirror) {
|
||||
DEBUG_ONLY(assert_valid_static_string_field(fd);)
|
||||
assert(DumpSharedSpaces, "must be");
|
||||
assert(HeapShared::is_archived_object_during_dumptime(mirror()), "must be");
|
||||
// Archive the String field and update the pointer.
|
||||
oop s = mirror()->obj_field(fd->offset());
|
||||
oop archived_s = StringTable::create_archived_string(s);
|
||||
mirror()->obj_field_put(fd->offset(), archived_s);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void initialize_static_primitive_field(fieldDescriptor* fd, Handle mirror) {
|
||||
assert(fd->has_initial_value(), "caller should have checked this");
|
||||
BasicType t = fd->field_type();
|
||||
@ -864,19 +852,6 @@ static void initialize_static_field(fieldDescriptor* fd, Handle mirror, TRAPS) {
|
||||
}
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
static void initialize_static_field_for_dump(fieldDescriptor* fd, Handle mirror) {
|
||||
assert(mirror.not_null() && fd->is_static(), "just checking");
|
||||
if (fd->has_initial_value()) {
|
||||
if (fd->field_type() != T_OBJECT) {
|
||||
initialize_static_primitive_field(fd, mirror);
|
||||
} else {
|
||||
initialize_static_string_field_for_dump(fd, mirror);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void java_lang_Class::fixup_mirror(Klass* k, TRAPS) {
|
||||
assert(InstanceMirrorKlass::offset_of_static_fields() != 0, "must have been computed already");
|
||||
|
||||
@ -973,6 +948,61 @@ void java_lang_Class::allocate_fixup_lists() {
|
||||
set_fixup_module_field_list(module_list);
|
||||
}
|
||||
|
||||
void java_lang_Class::allocate_mirror(Klass* k, bool is_scratch, Handle protection_domain, Handle classData,
|
||||
Handle& mirror, Handle& comp_mirror, TRAPS) {
|
||||
// Allocate mirror (java.lang.Class instance)
|
||||
oop mirror_oop = InstanceMirrorKlass::cast(vmClasses::Class_klass())->allocate_instance(k, CHECK);
|
||||
mirror = Handle(THREAD, mirror_oop);
|
||||
|
||||
// Setup indirection from mirror->klass
|
||||
set_klass(mirror(), k);
|
||||
|
||||
InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(mirror->klass());
|
||||
assert(oop_size(mirror()) == mk->instance_size(k), "should have been set");
|
||||
|
||||
set_static_oop_field_count(mirror(), mk->compute_static_oop_field_count(mirror()));
|
||||
|
||||
// It might also have a component mirror. This mirror must already exist.
|
||||
if (k->is_array_klass()) {
|
||||
if (k->is_typeArray_klass()) {
|
||||
BasicType type = TypeArrayKlass::cast(k)->element_type();
|
||||
if (is_scratch) {
|
||||
comp_mirror = Handle(THREAD, HeapShared::scratch_java_mirror(type));
|
||||
} else {
|
||||
comp_mirror = Handle(THREAD, Universe::java_mirror(type));
|
||||
}
|
||||
} else {
|
||||
assert(k->is_objArray_klass(), "Must be");
|
||||
Klass* element_klass = ObjArrayKlass::cast(k)->element_klass();
|
||||
assert(element_klass != NULL, "Must have an element klass");
|
||||
if (is_scratch) {
|
||||
comp_mirror = Handle(THREAD, HeapShared::scratch_java_mirror(element_klass));
|
||||
} else {
|
||||
comp_mirror = Handle(THREAD, element_klass->java_mirror());
|
||||
}
|
||||
}
|
||||
assert(comp_mirror() != NULL, "must have a mirror");
|
||||
|
||||
// Two-way link between the array klass and its component mirror:
|
||||
// (array_klass) k -> mirror -> component_mirror -> array_klass -> k
|
||||
set_component_mirror(mirror(), comp_mirror());
|
||||
// See below for ordering dependencies between field array_klass in component mirror
|
||||
// and java_mirror in this klass.
|
||||
} else {
|
||||
assert(k->is_instance_klass(), "Must be");
|
||||
|
||||
initialize_mirror_fields(k, mirror, protection_domain, classData, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
// If any of the fields throws an exception like OOM remove the klass field
|
||||
// from the mirror so GC doesn't follow it after the klass has been deallocated.
|
||||
// This mirror looks like a primitive type, which logically it is because it
|
||||
// it represents no class.
|
||||
set_klass(mirror(), NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void java_lang_Class::create_mirror(Klass* k, Handle class_loader,
|
||||
Handle module, Handle protection_domain,
|
||||
Handle classData, TRAPS) {
|
||||
@ -988,50 +1018,10 @@ void java_lang_Class::create_mirror(Klass* k, Handle class_loader,
|
||||
// Class_klass has to be loaded because it is used to allocate
|
||||
// the mirror.
|
||||
if (vmClasses::Class_klass_loaded()) {
|
||||
// Allocate mirror (java.lang.Class instance)
|
||||
oop mirror_oop = InstanceMirrorKlass::cast(vmClasses::Class_klass())->allocate_instance(k, CHECK);
|
||||
Handle mirror(THREAD, mirror_oop);
|
||||
Handle mirror;
|
||||
Handle comp_mirror;
|
||||
|
||||
// Setup indirection from mirror->klass
|
||||
set_klass(mirror(), k);
|
||||
|
||||
InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(mirror->klass());
|
||||
assert(oop_size(mirror()) == mk->instance_size(k), "should have been set");
|
||||
|
||||
set_static_oop_field_count(mirror(), mk->compute_static_oop_field_count(mirror()));
|
||||
|
||||
// It might also have a component mirror. This mirror must already exist.
|
||||
if (k->is_array_klass()) {
|
||||
if (k->is_typeArray_klass()) {
|
||||
BasicType type = TypeArrayKlass::cast(k)->element_type();
|
||||
comp_mirror = Handle(THREAD, Universe::java_mirror(type));
|
||||
} else {
|
||||
assert(k->is_objArray_klass(), "Must be");
|
||||
Klass* element_klass = ObjArrayKlass::cast(k)->element_klass();
|
||||
assert(element_klass != NULL, "Must have an element klass");
|
||||
comp_mirror = Handle(THREAD, element_klass->java_mirror());
|
||||
}
|
||||
assert(comp_mirror() != NULL, "must have a mirror");
|
||||
|
||||
// Two-way link between the array klass and its component mirror:
|
||||
// (array_klass) k -> mirror -> component_mirror -> array_klass -> k
|
||||
set_component_mirror(mirror(), comp_mirror());
|
||||
// See below for ordering dependencies between field array_klass in component mirror
|
||||
// and java_mirror in this klass.
|
||||
} else {
|
||||
assert(k->is_instance_klass(), "Must be");
|
||||
|
||||
initialize_mirror_fields(k, mirror, protection_domain, classData, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
// If any of the fields throws an exception like OOM remove the klass field
|
||||
// from the mirror so GC doesn't follow it after the klass has been deallocated.
|
||||
// This mirror looks like a primitive type, which logically it is because it
|
||||
// it represents no class.
|
||||
set_klass(mirror(), NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
allocate_mirror(k, /*is_scratch=*/false, protection_domain, classData, mirror, comp_mirror, CHECK);
|
||||
|
||||
// set the classLoader field in the java_lang_Class instance
|
||||
assert(class_loader() == k->class_loader(), "should be same");
|
||||
@ -1050,6 +1040,9 @@ void java_lang_Class::create_mirror(Klass* k, Handle class_loader,
|
||||
// concurrently doesn't expect a k to have a null java_mirror.
|
||||
release_set_array_klass(comp_mirror(), k);
|
||||
}
|
||||
if (DumpSharedSpaces) {
|
||||
create_scratch_mirror(k, CHECK);
|
||||
}
|
||||
} else {
|
||||
assert(fixup_mirror_list() != NULL, "fixup_mirror_list not initialized");
|
||||
fixup_mirror_list()->push(k);
|
||||
@ -1057,191 +1050,35 @@ void java_lang_Class::create_mirror(Klass* k, Handle class_loader,
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
// Clears mirror fields. Static final fields with initial values are reloaded
|
||||
// from constant pool. The object identity hash is in the object header and is
|
||||
// not affected.
|
||||
class ResetMirrorField: public FieldClosure {
|
||||
private:
|
||||
Handle _m;
|
||||
|
||||
public:
|
||||
ResetMirrorField(Handle mirror) : _m(mirror) {}
|
||||
|
||||
void do_field(fieldDescriptor* fd) {
|
||||
assert(DumpSharedSpaces, "dump time only");
|
||||
assert(_m.not_null(), "Mirror cannot be NULL");
|
||||
|
||||
if (fd->is_static() && fd->has_initial_value()) {
|
||||
initialize_static_field_for_dump(fd, _m);
|
||||
return;
|
||||
}
|
||||
|
||||
BasicType ft = fd->field_type();
|
||||
switch (ft) {
|
||||
case T_BYTE:
|
||||
_m()->byte_field_put(fd->offset(), 0);
|
||||
break;
|
||||
case T_CHAR:
|
||||
_m()->char_field_put(fd->offset(), 0);
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
_m()->double_field_put(fd->offset(), 0);
|
||||
break;
|
||||
case T_FLOAT:
|
||||
_m()->float_field_put(fd->offset(), 0);
|
||||
break;
|
||||
case T_INT:
|
||||
_m()->int_field_put(fd->offset(), 0);
|
||||
break;
|
||||
case T_LONG:
|
||||
_m()->long_field_put(fd->offset(), 0);
|
||||
break;
|
||||
case T_SHORT:
|
||||
_m()->short_field_put(fd->offset(), 0);
|
||||
break;
|
||||
case T_BOOLEAN:
|
||||
_m()->bool_field_put(fd->offset(), false);
|
||||
break;
|
||||
case T_ARRAY:
|
||||
case T_OBJECT: {
|
||||
// It might be useful to cache the String field, but
|
||||
// for now just clear out any reference field
|
||||
oop o = _m()->obj_field(fd->offset());
|
||||
_m()->obj_field_put(fd->offset(), NULL);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void java_lang_Class::archive_basic_type_mirrors() {
|
||||
assert(HeapShared::can_write(), "must be");
|
||||
|
||||
for (int t = T_BOOLEAN; t < T_VOID+1; t++) {
|
||||
BasicType bt = (BasicType)t;
|
||||
if (!is_reference_type(bt)) {
|
||||
oop m = Universe::java_mirror(bt);
|
||||
assert(m != NULL, "sanity");
|
||||
// Update the field at _array_klass_offset to point to the relocated array klass.
|
||||
oop archived_m = HeapShared::archive_object(m);
|
||||
assert(archived_m != NULL, "sanity");
|
||||
|
||||
// Clear the fields. Just to be safe
|
||||
Klass *k = m->klass();
|
||||
Handle archived_mirror_h(Thread::current(), archived_m);
|
||||
ResetMirrorField reset(archived_mirror_h);
|
||||
InstanceKlass::cast(k)->do_nonstatic_fields(&reset);
|
||||
|
||||
log_trace(cds, heap, mirror)(
|
||||
"Archived %s mirror object from " PTR_FORMAT " ==> " PTR_FORMAT,
|
||||
type2name(bt), p2i(m), p2i(archived_m));
|
||||
|
||||
Universe::set_archived_basic_type_mirror_index(bt, HeapShared::append_root(archived_m));
|
||||
}
|
||||
}
|
||||
}
|
||||
// The "scratch mirror" stores the states of the mirror object that can be
|
||||
// decided at dump time (such as the initial values of the static fields, the
|
||||
// component mirror, etc). At runtime, more information is added to it by
|
||||
// java_lang_Class::restore_archived_mirror().
|
||||
//
|
||||
// After the mirror object is successfully archived, the archived
|
||||
// klass is set with _has_archived_raw_mirror flag.
|
||||
// Essentially, /*dumptime*/create_scratch_mirror() + /*runtime*/restore_archived_mirror()
|
||||
// produces the same result as /*runtime*/create_mirror().
|
||||
//
|
||||
// The _has_archived_raw_mirror flag is cleared at runtime when the
|
||||
// archived mirror is restored. If archived java heap data cannot
|
||||
// be used at runtime, new mirror object is created for the shared
|
||||
// class. The _has_archived_raw_mirror is cleared also during the process.
|
||||
oop java_lang_Class::archive_mirror(Klass* k) {
|
||||
assert(HeapShared::can_write(), "must be");
|
||||
|
||||
// Mirror is already archived
|
||||
if (k->has_archived_mirror_index()) {
|
||||
assert(k->archived_java_mirror() != NULL, "no archived mirror");
|
||||
return k->archived_java_mirror();
|
||||
// Note: we archive the "scratch mirror" instead of k->java_mirror(), because the
|
||||
// latter may contain dumptime-specific information that cannot be archived
|
||||
// (e.g., ClassLoaderData*, or static fields that are modified by Java code execution).
|
||||
void java_lang_Class::create_scratch_mirror(Klass* k, TRAPS) {
|
||||
if (k->class_loader() != NULL &&
|
||||
k->class_loader() != SystemDictionary::java_platform_loader() &&
|
||||
k->class_loader() != SystemDictionary::java_system_loader()) {
|
||||
// We only archive the mirrors of classes loaded by the built-in loaders
|
||||
return;
|
||||
}
|
||||
|
||||
// No mirror
|
||||
oop mirror = k->java_mirror();
|
||||
if (mirror == NULL) {
|
||||
return NULL;
|
||||
Handle protection_domain, classData; // set to NULL. Will be reinitialized at runtime
|
||||
Handle mirror;
|
||||
Handle comp_mirror;
|
||||
allocate_mirror(k, /*is_scratch=*/true, protection_domain, classData, mirror, comp_mirror, CHECK);
|
||||
|
||||
if (comp_mirror() != NULL) {
|
||||
release_set_array_klass(comp_mirror(), k);
|
||||
}
|
||||
|
||||
if (k->is_instance_klass()) {
|
||||
InstanceKlass *ik = InstanceKlass::cast(k);
|
||||
assert(ik->signers() == NULL, "class with signer should have been excluded");
|
||||
|
||||
if (!(ik->is_shared_boot_class() || ik->is_shared_platform_class() ||
|
||||
ik->is_shared_app_class())) {
|
||||
// Archiving mirror for classes from non-builtin loaders is not
|
||||
// supported.
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Now start archiving the mirror object
|
||||
oop archived_mirror = HeapShared::archive_object(mirror);
|
||||
if (archived_mirror == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
archived_mirror = process_archived_mirror(k, mirror, archived_mirror);
|
||||
if (archived_mirror == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
k->set_archived_java_mirror(archived_mirror);
|
||||
|
||||
ResourceMark rm;
|
||||
log_trace(cds, heap, mirror)(
|
||||
"Archived %s mirror object from " PTR_FORMAT " ==> " PTR_FORMAT,
|
||||
k->external_name(), p2i(mirror), p2i(archived_mirror));
|
||||
|
||||
return archived_mirror;
|
||||
}
|
||||
|
||||
// The process is based on create_mirror().
|
||||
oop java_lang_Class::process_archived_mirror(Klass* k, oop mirror,
|
||||
oop archived_mirror) {
|
||||
// Clear nonstatic fields in archived mirror. Some of the fields will be set
|
||||
// to archived metadata and objects below.
|
||||
Klass *c = archived_mirror->klass();
|
||||
Handle archived_mirror_h(Thread::current(), archived_mirror);
|
||||
ResetMirrorField reset(archived_mirror_h);
|
||||
InstanceKlass::cast(c)->do_nonstatic_fields(&reset);
|
||||
|
||||
if (k->is_array_klass()) {
|
||||
oop archived_comp_mirror;
|
||||
if (k->is_typeArray_klass()) {
|
||||
// The primitive type mirrors are already archived. Get the archived mirror.
|
||||
oop comp_mirror = component_mirror(mirror);
|
||||
archived_comp_mirror = HeapShared::find_archived_heap_object(comp_mirror);
|
||||
assert(archived_comp_mirror != NULL, "Must be");
|
||||
} else {
|
||||
assert(k->is_objArray_klass(), "Must be");
|
||||
Klass* element_klass = ObjArrayKlass::cast(k)->element_klass();
|
||||
assert(element_klass != NULL, "Must have an element klass");
|
||||
archived_comp_mirror = archive_mirror(element_klass);
|
||||
if (archived_comp_mirror == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
set_component_mirror(archived_mirror, archived_comp_mirror);
|
||||
} else {
|
||||
assert(k->is_instance_klass(), "Must be");
|
||||
|
||||
// Reset local static fields in the mirror
|
||||
InstanceKlass::cast(k)->do_local_static_fields(&reset);
|
||||
|
||||
set_protection_domain(archived_mirror, NULL);
|
||||
set_signers(archived_mirror, NULL);
|
||||
set_source_file(archived_mirror, NULL);
|
||||
}
|
||||
|
||||
// clear class loader and mirror_module_field
|
||||
set_class_loader(archived_mirror, NULL);
|
||||
set_module(archived_mirror, NULL);
|
||||
|
||||
return archived_mirror;
|
||||
HeapShared::set_scratch_java_mirror(k, mirror());
|
||||
}
|
||||
|
||||
// Returns true if the mirror is updated, false if no archived mirror
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -249,6 +249,8 @@ class java_lang_Class : AllStatic {
|
||||
static void compute_offsets();
|
||||
|
||||
// Instance creation
|
||||
static void allocate_mirror(Klass* k, bool is_scratch, Handle protection_domain, Handle classData,
|
||||
Handle& mirror, Handle& comp_mirror, TRAPS); // returns mirror and comp_mirror
|
||||
static void create_mirror(Klass* k, Handle class_loader, Handle module,
|
||||
Handle protection_domain, Handle classData, TRAPS);
|
||||
static void fixup_mirror(Klass* k, TRAPS);
|
||||
@ -256,10 +258,7 @@ class java_lang_Class : AllStatic {
|
||||
|
||||
// Archiving
|
||||
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
|
||||
static void archive_basic_type_mirrors() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static oop archive_mirror(Klass* k) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
|
||||
static oop process_archived_mirror(Klass* k, oop mirror, oop archived_mirror)
|
||||
NOT_CDS_JAVA_HEAP_RETURN_(NULL);
|
||||
static void create_scratch_mirror(Klass* k, TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static bool restore_archived_mirror(Klass *k, Handle class_loader, Handle module,
|
||||
Handle protection_domain,
|
||||
TRAPS) NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -478,6 +478,9 @@ void Universe::initialize_basic_type_mirrors(TRAPS) {
|
||||
CDS_JAVA_HEAP_ONLY(_archived_basic_type_mirror_indices[i] = -1);
|
||||
}
|
||||
}
|
||||
if (DumpSharedSpaces) {
|
||||
HeapShared::init_scratch_objects(CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
void Universe::fixup_mirrors(TRAPS) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -692,6 +692,12 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
|
||||
set_annotations(NULL);
|
||||
|
||||
SystemDictionaryShared::handle_class_unloading(this);
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
if (DumpSharedSpaces) {
|
||||
HeapShared::remove_scratch_objects(this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool InstanceKlass::is_record() const {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -642,9 +642,9 @@ void Klass::clear_archived_mirror_index() {
|
||||
}
|
||||
|
||||
// No GC barrier
|
||||
void Klass::set_archived_java_mirror(oop m) {
|
||||
assert(DumpSharedSpaces, "called only during runtime");
|
||||
_archived_mirror_index = HeapShared::append_root(m);
|
||||
void Klass::set_archived_java_mirror(int mirror_index) {
|
||||
assert(DumpSharedSpaces, "called only during dumptime");
|
||||
_archived_mirror_index = mirror_index;
|
||||
}
|
||||
#endif // INCLUDE_CDS_JAVA_HEAP
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -266,7 +266,7 @@ protected:
|
||||
void set_java_mirror(Handle m);
|
||||
|
||||
oop archived_java_mirror() NOT_CDS_JAVA_HEAP_RETURN_(NULL);
|
||||
void set_archived_java_mirror(oop m) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
void set_archived_java_mirror(int mirror_index) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
// Temporary mirror switch used by RedefineClasses
|
||||
OopHandle java_mirror_handle() const { return _java_mirror; }
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -155,6 +155,7 @@ Mutex* DumpRegion_lock = NULL;
|
||||
Mutex* ClassListFile_lock = NULL;
|
||||
Mutex* UnregisteredClassesTable_lock= NULL;
|
||||
Mutex* LambdaFormInvokers_lock = NULL;
|
||||
Mutex* ScratchObjects_lock = NULL;
|
||||
#endif // INCLUDE_CDS
|
||||
Mutex* Bootclasspath_lock = NULL;
|
||||
|
||||
@ -329,6 +330,7 @@ void mutex_init() {
|
||||
def(DumpRegion_lock , PaddedMutex , nosafepoint);
|
||||
def(ClassListFile_lock , PaddedMutex , nosafepoint);
|
||||
def(LambdaFormInvokers_lock , PaddedMutex , safepoint);
|
||||
def(ScratchObjects_lock , PaddedMutex , nosafepoint-1); // Holds DumpTimeTable_lock
|
||||
#endif // INCLUDE_CDS
|
||||
def(Bootclasspath_lock , PaddedMutex , nosafepoint);
|
||||
def(Zip_lock , PaddedMonitor, nosafepoint-1); // Holds DumpTimeTable_lock
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -126,6 +126,7 @@ extern Mutex* DumpRegion_lock; // Symbol::operator new(size_t
|
||||
extern Mutex* ClassListFile_lock; // ClassListWriter()
|
||||
extern Mutex* UnregisteredClassesTable_lock; // UnregisteredClassesTableTable
|
||||
extern Mutex* LambdaFormInvokers_lock; // Protecting LambdaFormInvokers::_lambdaform_lines
|
||||
extern Mutex* ScratchObjects_lock; // Protecting _scratch_xxx_table in heapShared.cpp
|
||||
#endif // INCLUDE_CDS
|
||||
#if INCLUDE_JFR
|
||||
extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table
|
||||
|
Loading…
Reference in New Issue
Block a user