8297914: Remove java_lang_Class::process_archived_mirror()

Reviewed-by: ccheung
This commit is contained in:
Ioi Lam 2023-01-15 20:30:31 +00:00
parent 4be94e4350
commit 7bcd5f418c
10 changed files with 269 additions and 281 deletions

View File

@ -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;

View File

@ -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) {

View File

@ -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

View File

@ -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);

View File

@ -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) {

View File

@ -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 {

View File

@ -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

View File

@ -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; }

View File

@ -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

View File

@ -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