8293979: Resolve JVM_CONSTANT_Class references at CDS dump time
Reviewed-by: coleenp, ccheung
This commit is contained in:
parent
7cbf6721dc
commit
aad81f2eba
202
src/hotspot/share/cds/classPrelinker.cpp
Normal file
202
src/hotspot/share/cds/classPrelinker.cpp
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "cds/classPrelinker.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmClasses.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/constantPool.inline.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/klass.inline.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
|
||||
ClassPrelinker::ClassesTable* ClassPrelinker::_processed_classes = NULL;
|
||||
ClassPrelinker::ClassesTable* ClassPrelinker::_vm_classes = NULL;
|
||||
|
||||
bool ClassPrelinker::is_vm_class(InstanceKlass* ik) {
|
||||
return (_vm_classes->get(ik) != NULL);
|
||||
}
|
||||
|
||||
void ClassPrelinker::add_one_vm_class(InstanceKlass* ik) {
|
||||
bool created;
|
||||
_vm_classes->put_if_absent(ik, &created);
|
||||
if (created) {
|
||||
InstanceKlass* super = ik->java_super();
|
||||
if (super != NULL) {
|
||||
add_one_vm_class(super);
|
||||
}
|
||||
Array<InstanceKlass*>* ifs = ik->local_interfaces();
|
||||
for (int i = 0; i < ifs->length(); i++) {
|
||||
add_one_vm_class(ifs->at(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClassPrelinker::initialize() {
|
||||
assert(_vm_classes == NULL, "must be");
|
||||
_vm_classes = new (ResourceObj::C_HEAP, mtClass)ClassesTable();
|
||||
_processed_classes = new (ResourceObj::C_HEAP, mtClass)ClassesTable();
|
||||
for (auto id : EnumRange<vmClassID>{}) {
|
||||
add_one_vm_class(vmClasses::klass_at(id));
|
||||
}
|
||||
}
|
||||
|
||||
void ClassPrelinker::dispose() {
|
||||
assert(_vm_classes != NULL, "must be");
|
||||
delete _vm_classes;
|
||||
delete _processed_classes;
|
||||
_vm_classes = NULL;
|
||||
_processed_classes = NULL;
|
||||
}
|
||||
|
||||
bool ClassPrelinker::can_archive_resolved_klass(ConstantPool* cp, int cp_index) {
|
||||
assert(!is_in_archivebuilder_buffer(cp), "sanity");
|
||||
assert(cp->tag_at(cp_index).is_klass(), "must be resolved");
|
||||
|
||||
Klass* resolved_klass = cp->resolved_klass_at(cp_index);
|
||||
assert(resolved_klass != NULL, "must be");
|
||||
|
||||
return can_archive_resolved_klass(cp->pool_holder(), resolved_klass);
|
||||
}
|
||||
|
||||
bool ClassPrelinker::can_archive_resolved_klass(InstanceKlass* cp_holder, Klass* resolved_klass) {
|
||||
assert(!is_in_archivebuilder_buffer(cp_holder), "sanity");
|
||||
assert(!is_in_archivebuilder_buffer(resolved_klass), "sanity");
|
||||
|
||||
if (resolved_klass->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(resolved_klass);
|
||||
if (is_vm_class(ik)) { // These are safe to resolve. See is_vm_class declaration.
|
||||
assert(ik->is_shared_boot_class(), "vmClasses must be loaded by boot loader");
|
||||
if (cp_holder->is_shared_boot_class()) {
|
||||
// For now, do this for boot loader only. Other loaders
|
||||
// must go through ConstantPool::klass_at_impl at runtime
|
||||
// to put this class in their directory.
|
||||
|
||||
// TODO: we can support the platform and app loaders as well, if we
|
||||
// preload the vmClasses into these two loaders during VM bootstrap.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (cp_holder->is_subtype_of(ik)) {
|
||||
// All super types of ik will be resolved in ik->class_loader() before
|
||||
// ik is defined in this loader, so it's safe to archive the resolved klass reference.
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO -- allow objArray classes, too
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClassPrelinker::dumptime_resolve_constants(InstanceKlass* ik, TRAPS) {
|
||||
constantPoolHandle cp(THREAD, ik->constants());
|
||||
if (cp->cache() == NULL || cp->reference_map() == NULL) {
|
||||
// The cache may be NULL if the pool_holder klass fails verification
|
||||
// at dump time due to missing dependencies.
|
||||
return;
|
||||
}
|
||||
|
||||
bool first_time;
|
||||
_processed_classes->put_if_absent(ik, &first_time);
|
||||
if (!first_time) {
|
||||
// We have already resolved the constants in class, so no need to do it again.
|
||||
return;
|
||||
}
|
||||
|
||||
for (int cp_index = 1; cp_index < cp->length(); cp_index++) { // Index 0 is unused
|
||||
switch (cp->tag_at(cp_index).value()) {
|
||||
case JVM_CONSTANT_UnresolvedClass:
|
||||
maybe_resolve_class(cp, cp_index, CHECK);
|
||||
break;
|
||||
|
||||
case JVM_CONSTANT_String:
|
||||
resolve_string(cp, cp_index, CHECK); // may throw OOM when interning strings.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Klass* ClassPrelinker::find_loaded_class(JavaThread* THREAD, oop class_loader, Symbol* name) {
|
||||
Handle h_loader(THREAD, class_loader);
|
||||
Klass* k = SystemDictionary::find_instance_or_array_klass(THREAD, name,
|
||||
h_loader,
|
||||
Handle());
|
||||
if (k != NULL) {
|
||||
return k;
|
||||
}
|
||||
if (class_loader == SystemDictionary::java_system_loader()) {
|
||||
return find_loaded_class(THREAD, SystemDictionary::java_platform_loader(), name);
|
||||
} else if (class_loader == SystemDictionary::java_platform_loader()) {
|
||||
return find_loaded_class(THREAD, NULL, name);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Klass* ClassPrelinker::maybe_resolve_class(constantPoolHandle cp, int cp_index, TRAPS) {
|
||||
assert(!is_in_archivebuilder_buffer(cp()), "sanity");
|
||||
InstanceKlass* cp_holder = cp->pool_holder();
|
||||
if (!cp_holder->is_shared_boot_class() &&
|
||||
!cp_holder->is_shared_platform_class() &&
|
||||
!cp_holder->is_shared_app_class()) {
|
||||
// Don't trust custom loaders, as they may not be well-behaved
|
||||
// when resolving classes.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Symbol* name = cp->klass_name_at(cp_index);
|
||||
Klass* resolved_klass = find_loaded_class(THREAD, cp_holder->class_loader(), name);
|
||||
if (resolved_klass != NULL && can_archive_resolved_klass(cp_holder, resolved_klass)) {
|
||||
Klass* k = cp->klass_at(cp_index, CHECK_NULL); // Should fail only with OOM
|
||||
assert(k == resolved_klass, "must be");
|
||||
}
|
||||
|
||||
return resolved_klass;
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
void ClassPrelinker::resolve_string(constantPoolHandle cp, int cp_index, TRAPS) {
|
||||
if (!DumpSharedSpaces) {
|
||||
// The archive heap is not supported for the dynamic archive.
|
||||
return;
|
||||
}
|
||||
|
||||
int cache_index = cp->cp_to_object_index(cp_index);
|
||||
ConstantPool::string_at_impl(cp, cp_index, cache_index, CHECK);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ASSERT
|
||||
bool ClassPrelinker::is_in_archivebuilder_buffer(address p) {
|
||||
if (!Thread::current()->is_VM_thread() || ArchiveBuilder::current() == NULL) {
|
||||
return false;
|
||||
} else {
|
||||
return ArchiveBuilder::current()->is_in_buffer_space(p);
|
||||
}
|
||||
}
|
||||
#endif
|
91
src/hotspot/share/cds/classPrelinker.hpp
Normal file
91
src/hotspot/share/cds/classPrelinker.hpp
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_CDS_CLASSPRELINKER_HPP
|
||||
#define SHARE_CDS_CLASSPRELINKER_HPP
|
||||
|
||||
#include "oops/oopsHierarchy.hpp"
|
||||
#include "memory/allStatic.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "runtime/handles.hpp"
|
||||
#include "utilities/exceptions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/resourceHash.hpp"
|
||||
|
||||
class ConstantPool;
|
||||
class constantPoolHandle;
|
||||
class InstanceKlass;
|
||||
class Klass;
|
||||
|
||||
// ClassPrelinker is used to perform ahead-of-time linking of ConstantPool entries
|
||||
// for archived InstanceKlasses.
|
||||
//
|
||||
// At run time, Java classes are loaded dynamically and may be replaced with JVMTI.
|
||||
// Therefore, we take care to prelink only the ConstantPool entries that are
|
||||
// guatanteed to resolve to the same results at both dump time and run time.
|
||||
//
|
||||
// For example, a JVM_CONSTANT_Class reference to a supertype can be safely resolved
|
||||
// at dump time, because at run time we will load a class from the CDS archive only
|
||||
// if all of its supertypes are loaded from the CDS archive.
|
||||
class ClassPrelinker : AllStatic {
|
||||
using ClassesTable = ResourceHashtable<InstanceKlass*, bool, 15889, ResourceObj::C_HEAP, mtClassShared> ;
|
||||
static ClassesTable* _processed_classes;
|
||||
static ClassesTable* _vm_classes;
|
||||
|
||||
static void add_one_vm_class(InstanceKlass* ik);
|
||||
|
||||
#ifdef ASSERT
|
||||
static bool is_in_archivebuilder_buffer(address p);
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
static bool is_in_archivebuilder_buffer(T p) {
|
||||
return is_in_archivebuilder_buffer((address)(p));
|
||||
}
|
||||
static void resolve_string(constantPoolHandle cp, int cp_index, TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static Klass* maybe_resolve_class(constantPoolHandle cp, int cp_index, TRAPS);
|
||||
static bool can_archive_resolved_klass(InstanceKlass* cp_holder, Klass* resolved_klass);
|
||||
static Klass* find_loaded_class(JavaThread* THREAD, oop class_loader, Symbol* name);
|
||||
|
||||
public:
|
||||
static void initialize();
|
||||
static void dispose();
|
||||
|
||||
// Is this class resolved as part of vmClasses::resolve_all()? If so, these
|
||||
// classes are guatanteed to be loaded at runtime (and cannot be replaced by JVMTI)
|
||||
// when CDS is enabled. Therefore, we can safely keep a direct reference to these
|
||||
// classes.
|
||||
static bool is_vm_class(InstanceKlass* ik);
|
||||
|
||||
// Resolve all constant pool entries that are safe to be stored in the
|
||||
// CDS archive.
|
||||
static void dumptime_resolve_constants(InstanceKlass* ik, TRAPS);
|
||||
|
||||
// Can we resolve the klass entry at cp_index in this constant pool, and store
|
||||
// the result in the CDS archive? Returns true if cp_index is guaranteed to
|
||||
// resolve to the same InstanceKlass* at both dump time and run time.
|
||||
static bool can_archive_resolved_klass(ConstantPool* cp, int cp_index);
|
||||
};
|
||||
|
||||
#endif // SHARE_CDS_CLASSPRELINKER_HPP
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -101,4 +101,9 @@ void DumpAllocStats::print_stats(int ro_all, int rw_all) {
|
||||
ro_all, all_ro_bytes, rw_all, all_rw_bytes);
|
||||
|
||||
#undef fmt_stats
|
||||
|
||||
msg.debug("Class CP entries = %d, archived = %d (%3.1f%%)",
|
||||
_num_klass_cp_entries, _num_klass_cp_entries_archived,
|
||||
percent_of(_num_klass_cp_entries_archived, _num_klass_cp_entries));
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -65,12 +65,17 @@ public:
|
||||
int _counts[2][_number_of_types];
|
||||
int _bytes [2][_number_of_types];
|
||||
|
||||
int _num_klass_cp_entries;
|
||||
int _num_klass_cp_entries_archived;
|
||||
|
||||
public:
|
||||
enum { RO = 0, RW = 1 };
|
||||
|
||||
DumpAllocStats() {
|
||||
memset(_counts, 0, sizeof(_counts));
|
||||
memset(_bytes, 0, sizeof(_bytes));
|
||||
_num_klass_cp_entries = 0;
|
||||
_num_klass_cp_entries_archived = 0;
|
||||
};
|
||||
|
||||
CompactHashtableStats* symbol_stats() { return &_symbol_stats; }
|
||||
@ -97,6 +102,11 @@ public:
|
||||
_bytes[RW][CppVTablesType] += byte_size;
|
||||
}
|
||||
|
||||
void record_klass_cp_entry(bool archived) {
|
||||
_num_klass_cp_entries ++;
|
||||
_num_klass_cp_entries_archived += archived ? 1 : 0;
|
||||
}
|
||||
|
||||
void print_stats(int ro_all, int rw_all);
|
||||
};
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "cds/archiveUtils.inline.hpp"
|
||||
#include "cds/cds_globals.hpp"
|
||||
#include "cds/classPrelinker.hpp"
|
||||
#include "cds/dynamicArchive.hpp"
|
||||
#include "cds/lambdaFormInvokers.hpp"
|
||||
#include "cds/metaspaceShared.hpp"
|
||||
@ -208,6 +209,7 @@ void DynamicArchiveBuilder::release_header() {
|
||||
|
||||
void DynamicArchiveBuilder::post_dump() {
|
||||
ArchivePtrMarker::reset_map_and_vs();
|
||||
ClassPrelinker::dispose();
|
||||
}
|
||||
|
||||
void DynamicArchiveBuilder::sort_methods() {
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "cds/cdsProtectionDomain.hpp"
|
||||
#include "cds/classListWriter.hpp"
|
||||
#include "cds/classListParser.hpp"
|
||||
#include "cds/classPrelinker.hpp"
|
||||
#include "cds/cppVtables.hpp"
|
||||
#include "cds/dumpAllocStats.hpp"
|
||||
#include "cds/filemap.hpp"
|
||||
@ -634,17 +635,13 @@ bool MetaspaceShared::link_class_for_cds(InstanceKlass* ik, TRAPS) {
|
||||
// cpcache to be created. Class verification is done according
|
||||
// to -Xverify setting.
|
||||
bool res = MetaspaceShared::try_link_class(THREAD, ik);
|
||||
|
||||
if (DumpSharedSpaces) {
|
||||
// The following function is used to resolve all Strings in the statically
|
||||
// dumped classes to archive all the Strings. The archive heap is not supported
|
||||
// for the dynamic archive.
|
||||
ik->constants()->resolve_class_constants(CHECK_(false)); // may throw OOM when interning strings.
|
||||
}
|
||||
ClassPrelinker::dumptime_resolve_constants(ik, CHECK_(false));
|
||||
return res;
|
||||
}
|
||||
|
||||
void MetaspaceShared::link_shared_classes(bool jcmd_request, TRAPS) {
|
||||
ClassPrelinker::initialize();
|
||||
|
||||
if (!jcmd_request) {
|
||||
LambdaFormInvokers::regenerate_holder_classes(CHECK);
|
||||
}
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "jvm.h"
|
||||
#include "cds/archiveHeapLoader.hpp"
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "cds/classPrelinker.hpp"
|
||||
#include "cds/heapShared.hpp"
|
||||
#include "classfile/classLoaderData.hpp"
|
||||
#include "classfile/javaClasses.inline.hpp"
|
||||
@ -299,23 +301,6 @@ void ConstantPool::archive_resolved_references() {
|
||||
}
|
||||
}
|
||||
|
||||
void ConstantPool::resolve_class_constants(TRAPS) {
|
||||
assert(DumpSharedSpaces, "used during dump time only");
|
||||
// The _cache may be NULL if the _pool_holder klass fails verification
|
||||
// at dump time due to missing dependencies.
|
||||
if (cache() == NULL || reference_map() == NULL) {
|
||||
return; // nothing to do
|
||||
}
|
||||
|
||||
constantPoolHandle cp(THREAD, this);
|
||||
for (int index = 1; index < length(); index++) { // Index 0 is unused
|
||||
if (tag_at(index).is_string()) {
|
||||
int cache_index = cp->cp_to_object_index(index);
|
||||
string_at_impl(cp, index, cache_index, CHECK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConstantPool::add_dumped_interned_strings() {
|
||||
objArrayOop rr = resolved_references();
|
||||
if (rr != NULL) {
|
||||
@ -388,44 +373,69 @@ void ConstantPool::remove_unshareable_info() {
|
||||
resolved_references() != NULL ? resolved_references()->length() : 0);
|
||||
set_resolved_references(OopHandle());
|
||||
|
||||
int num_klasses = 0;
|
||||
bool archived = false;
|
||||
for (int index = 1; index < length(); index++) { // Index 0 is unused
|
||||
if (tag_at(index).is_unresolved_klass_in_error()) {
|
||||
switch (tag_at(index).value()) {
|
||||
case JVM_CONSTANT_UnresolvedClassInError:
|
||||
tag_at_put(index, JVM_CONSTANT_UnresolvedClass);
|
||||
} else if (tag_at(index).is_method_handle_in_error()) {
|
||||
break;
|
||||
case JVM_CONSTANT_MethodHandleInError:
|
||||
tag_at_put(index, JVM_CONSTANT_MethodHandle);
|
||||
} else if (tag_at(index).is_method_type_in_error()) {
|
||||
break;
|
||||
case JVM_CONSTANT_MethodTypeInError:
|
||||
tag_at_put(index, JVM_CONSTANT_MethodType);
|
||||
} else if (tag_at(index).is_dynamic_constant_in_error()) {
|
||||
break;
|
||||
case JVM_CONSTANT_DynamicInError:
|
||||
tag_at_put(index, JVM_CONSTANT_Dynamic);
|
||||
}
|
||||
if (tag_at(index).is_klass()) {
|
||||
// This class was resolved as a side effect of executing Java code
|
||||
// during dump time. We need to restore it back to an UnresolvedClass,
|
||||
// so that the proper class loading and initialization can happen
|
||||
// at runtime.
|
||||
bool clear_it = true;
|
||||
if (pool_holder()->is_hidden() && index == pool_holder()->this_class_index()) {
|
||||
// All references to a hidden class's own field/methods are through this
|
||||
// index. We cannot clear it. See comments in ClassFileParser::fill_instance_klass.
|
||||
clear_it = false;
|
||||
}
|
||||
if (clear_it) {
|
||||
CPKlassSlot kslot = klass_slot_at(index);
|
||||
int resolved_klass_index = kslot.resolved_klass_index();
|
||||
int name_index = kslot.name_index();
|
||||
assert(tag_at(name_index).is_symbol(), "sanity");
|
||||
resolved_klasses()->at_put(resolved_klass_index, NULL);
|
||||
tag_at_put(index, JVM_CONSTANT_UnresolvedClass);
|
||||
assert(klass_name_at(index) == symbol_at(name_index), "sanity");
|
||||
}
|
||||
break;
|
||||
case JVM_CONSTANT_Class:
|
||||
archived = maybe_archive_resolved_klass_at(index);
|
||||
ArchiveBuilder::alloc_stats()->record_klass_cp_entry(archived);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cache() != NULL) {
|
||||
// cache() is NULL if this class is not yet linked.
|
||||
cache()->remove_unshareable_info();
|
||||
}
|
||||
}
|
||||
|
||||
bool ConstantPool::maybe_archive_resolved_klass_at(int cp_index) {
|
||||
assert(ArchiveBuilder::current()->is_in_buffer_space(this), "must be");
|
||||
assert(tag_at(cp_index).is_klass(), "must be resolved");
|
||||
|
||||
if (pool_holder()->is_hidden() && cp_index == pool_holder()->this_class_index()) {
|
||||
// All references to a hidden class's own field/methods are through this
|
||||
// index, which was resolved in ClassFileParser::fill_instance_klass. We
|
||||
// must preserve it.
|
||||
return true;
|
||||
}
|
||||
|
||||
CPKlassSlot kslot = klass_slot_at(cp_index);
|
||||
int resolved_klass_index = kslot.resolved_klass_index();
|
||||
Klass* k = resolved_klasses()->at(resolved_klass_index);
|
||||
// k could be NULL if the referenced class has been excluded via
|
||||
// SystemDictionaryShared::is_excluded_class().
|
||||
|
||||
if (k != NULL) {
|
||||
ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(this);
|
||||
if (ClassPrelinker::can_archive_resolved_klass(src_cp, cp_index)) {
|
||||
if (log_is_enabled(Debug, cds, resolve)) {
|
||||
ResourceMark rm;
|
||||
log_debug(cds, resolve)("Resolved klass CP entry [%d]: %s => %s", cp_index,
|
||||
pool_holder()->external_name(), k->external_name());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// This referenced class cannot be archived. Revert the tag to UnresolvedClass,
|
||||
// so that the proper class loading and initialization can happen at runtime.
|
||||
resolved_klasses()->at_put(resolved_klass_index, NULL);
|
||||
tag_at_put(cp_index, JVM_CONSTANT_UnresolvedClass);
|
||||
return false;
|
||||
}
|
||||
#endif // INCLUDE_CDS
|
||||
|
||||
int ConstantPool::cp_to_object_index(int cp_index) {
|
||||
|
@ -81,6 +81,7 @@ class ConstantPool : public Metadata {
|
||||
friend class JVMCIVMStructs;
|
||||
friend class BytecodeInterpreter; // Directly extracts a klass in the pool for fast instanceof/checkcast
|
||||
friend class Universe; // For null constructor
|
||||
friend class ClassPrelinker; // CDS
|
||||
private:
|
||||
// If you add a new field that points to any metaspace object, you
|
||||
// must add this field to ConstantPool::metaspace_pointers_do().
|
||||
@ -695,7 +696,7 @@ class ConstantPool : public Metadata {
|
||||
// CDS support
|
||||
void archive_resolved_references() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
void add_dumped_interned_strings() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
void resolve_class_constants(TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
bool maybe_archive_resolved_klass_at(int cp_index);
|
||||
void remove_unshareable_info();
|
||||
void restore_unshareable_info(TRAPS);
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user