< prev index next > src/hotspot/share/oops/constantPool.cpp
Print this page
* questions.
*
*/
#include "precompiled.hpp"
#include "cds/archiveHeapWriter.hpp"
#include "cds/archiveHeapLoader.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/cdsConfig.hpp"
- #include "cds/classPrelinker.hpp"
#include "cds/heapShared.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmClasses.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/codeCache.hpp"
#include "interpreter/bootstrapInfo.hpp"
#include "interpreter/linkResolver.hpp"
* questions.
*
*/
#include "precompiled.hpp"
+ #include "cds/aotConstantPoolResolver.hpp"
#include "cds/archiveHeapWriter.hpp"
#include "cds/archiveHeapLoader.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/heapShared.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/systemDictionary.hpp"
+ #include "classfile/systemDictionaryShared.hpp"
#include "classfile/vmClasses.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/codeCache.hpp"
#include "interpreter/bootstrapInfo.hpp"
#include "interpreter/linkResolver.hpp"
// and the Klass* non-null, so we need hardware store ordering here.
release_tag_at_put(class_index, JVM_CONSTANT_Class);
}
#if INCLUDE_CDS_JAVA_HEAP
+ template <typename Function>
+ void ConstantPool::iterate_archivable_resolved_references(Function function) {
+ objArrayOop rr = resolved_references();
+ if (rr != nullptr && cache() != nullptr && CDSConfig::is_dumping_invokedynamic()) {
+ Array<ResolvedIndyEntry>* indy_entries = cache()->resolved_indy_entries();
+ if (indy_entries != nullptr) {
+ for (int i = 0; i < indy_entries->length(); i++) {
+ ResolvedIndyEntry *rie = indy_entries->adr_at(i);
+ if (rie->is_resolved() && AOTConstantPoolResolver::is_resolution_deterministic(this, rie->constant_pool_index())) {
+ int rr_index = rie->resolved_references_index();
+ function(rr_index);
+ }
+ }
+ }
+
+ Array<ResolvedMethodEntry>* method_entries = cache()->resolved_method_entries();
+ if (method_entries != nullptr) {
+ for (int i = 0; i < method_entries->length(); i++) {
+ ResolvedMethodEntry* rme = method_entries->adr_at(i);
+ if (rme->is_resolved(Bytecodes::_invokehandle) && rme->has_appendix() &&
+ cache()->can_archive_resolved_method(this, rme)) {
+ int rr_index = rme->resolved_references_index();
+ function(rr_index);
+ }
+ }
+ }
+ }
+ }
+
// Returns the _resolved_reference array after removing unarchivable items from it.
// Returns null if this class is not supported, or _resolved_reference doesn't exist.
objArrayOop ConstantPool::prepare_resolved_references_for_archiving() {
if (_cache == nullptr) {
return nullptr; // nothing to do
return nullptr;
}
objArrayOop rr = resolved_references();
if (rr != nullptr) {
+ ResourceMark rm;
int rr_len = rr->length();
+ GrowableArray<bool> keep_resolved_refs(rr_len, rr_len, false);
+
ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(this);
+ src_cp->iterate_archivable_resolved_references([&](int rr_index) {
+ keep_resolved_refs.at_put(rr_index, true);
+ });
+
objArrayOop scratch_rr = HeapShared::scratch_resolved_references(src_cp);
Array<u2>* ref_map = reference_map();
int ref_map_len = ref_map == nullptr ? 0 : ref_map->length();
for (int i = 0; i < rr_len; i++) {
oop obj = rr->obj_at(i);
assert(java_lang_String::is_instance(obj), "must be");
if (!ArchiveHeapWriter::is_string_too_large_to_archive(obj)) {
scratch_rr->obj_at_put(i, obj);
}
}
+ } else if (keep_resolved_refs.at(i)) {
+ scratch_rr->obj_at_put(i, obj);
}
}
}
return scratch_rr;
}
return rr;
}
+ void ConstantPool::find_archivable_hidden_classes() {
+ if (_cache == nullptr) {
+ return;
+ }
+
+ ClassLoaderData* loader_data = pool_holder()->class_loader_data();
+ if (loader_data == nullptr) {
+ // These are custom loader classes from the preimage
+ return;
+ }
+
+ if (!SystemDictionaryShared::is_builtin_loader(loader_data)) {
+ // Archiving resolved references for classes from non-builtin loaders
+ // is not yet supported.
+ return;
+ }
+
+ objArrayOop rr = resolved_references();
+ if (rr != nullptr) {
+ iterate_archivable_resolved_references([&](int rr_index) {
+ oop obj = rr->obj_at(rr_index);
+ HeapShared::find_archivable_hidden_classes_in_object(obj);
+ });
+ }
+ }
+
void ConstantPool::add_dumped_interned_strings() {
objArrayOop rr = resolved_references();
if (rr != nullptr) {
int rr_len = rr->length();
for (int i = 0; i < rr_len; i++) {
return;
}
assert(is_constantPool(), "ensure C++ vtable is restored");
assert(on_stack(), "should always be set for shared constant pools");
assert(is_shared(), "should always be set for shared constant pools");
+ if (is_for_method_handle_intrinsic()) {
+ return;
+ }
assert(_cache != nullptr, "constant pool _cache should not be null");
// Only create the new resolved references array if it hasn't been attempted before
if (resolved_references() != nullptr) return;
Handle refs_handle(THREAD, stom); // must handleize.
set_resolved_references(loader_data->add_handle(refs_handle));
}
}
}
+
+ if (CDSConfig::is_dumping_final_static_archive() && resolved_references() != nullptr) {
+ objArrayOop scratch_references = oopFactory::new_objArray(vmClasses::Object_klass(), resolved_references()->length(), CHECK);
+ HeapShared::add_scratch_resolved_references(this, scratch_references);
+ }
}
void ConstantPool::remove_unshareable_info() {
// Shared ConstantPools are in the RO region, so the _flags cannot be modified.
// The _on_stack flag is used to prevent ConstantPools from deallocation during
// class redefinition. Since shared ConstantPools cannot be deallocated anyway,
// we always set _on_stack to true to avoid having to change _flags during runtime.
_flags |= (_on_stack | _is_shared);
+ if (!ArchiveBuilder::current()->get_source_addr(_pool_holder)->is_linked()) {
+ return;
+ }
+
+ if (is_for_method_handle_intrinsic()) {
+ // This CP was created by Method::make_method_handle_intrinsic() and has nothing
+ // that need to be removed/restored. It has no cpCache since the intrinsic methods
+ // don't have any bytecodes.
+ assert(cache() == NULL, "must not have cpCache");
+ return;
+ }
+
// resolved_references(): remember its length. If it cannot be restored
// from the archived heap objects at run time, we need to dynamically allocate it.
if (cache() != nullptr) {
set_resolved_reference_length(
resolved_references() != nullptr ? resolved_references()->length() : 0);
// has cleared the resolved_klasses()->at(...) pointer to NULL. Thus, we
// need to revert the tag to JVM_CONSTANT_UnresolvedClass.
can_archive = false;
} else {
ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(this);
! can_archive = ClassPrelinker::is_resolution_deterministic(src_cp, cp_index);
}
if (!can_archive) {
int resolved_klass_index = klass_slot_at(cp_index).resolved_klass_index();
resolved_klasses()->at_put(resolved_klass_index, nullptr);
// has cleared the resolved_klasses()->at(...) pointer to NULL. Thus, we
// need to revert the tag to JVM_CONSTANT_UnresolvedClass.
can_archive = false;
} else {
ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(this);
! can_archive = AOTConstantPoolResolver::is_resolution_deterministic(src_cp, cp_index);
}
if (!can_archive) {
int resolved_klass_index = klass_slot_at(cp_index).resolved_klass_index();
resolved_klasses()->at_put(resolved_klass_index, nullptr);
if (can_archive) {
log.print(" => %s %s%s", k->name()->as_C_string(), get_type(k),
(!k->is_instance_klass() || pool_holder()->is_subtype_of(k)) ? "" : " (not supertype)");
} else {
Symbol* name = klass_name_at(cp_index);
! log.print(" %s", name->as_C_string());
}
}
ArchiveBuilder::alloc_stats()->record_klass_cp_entry(can_archive, /*reverted=*/!can_archive);
}
if (can_archive) {
log.print(" => %s %s%s", k->name()->as_C_string(), get_type(k),
(!k->is_instance_klass() || pool_holder()->is_subtype_of(k)) ? "" : " (not supertype)");
} else {
Symbol* name = klass_name_at(cp_index);
! log.print(" => %s", name->as_C_string());
}
}
ArchiveBuilder::alloc_stats()->record_klass_cp_entry(can_archive, /*reverted=*/!can_archive);
}
case Bytecodes::_invokestatic:
case Bytecodes::_invokevirtual:
case Bytecodes::_fast_invokevfinal: // Bytecode interpreter uses this
return resolved_method_entry_at(index)->constant_pool_index();
default:
! tty->print_cr("Unexpected bytecode: %d", code);
- ShouldNotReachHere(); // All cases should have been handled
- return -1;
}
}
bool ConstantPool::is_resolved(int index, Bytecodes::Code code) {
assert(cache() != nullptr, "'index' is a rewritten index so this class must have been rewritten");
case Bytecodes::_invokestatic:
case Bytecodes::_invokevirtual:
case Bytecodes::_fast_invokevfinal: // Bytecode interpreter uses this
return resolved_method_entry_at(index)->constant_pool_index();
default:
! fatal("Unexpected bytecode: %s", Bytecodes::name(code));
}
}
bool ConstantPool::is_resolved(int index, Bytecodes::Code code) {
assert(cache() != nullptr, "'index' is a rewritten index so this class must have been rewritten");
< prev index next >