< prev index next > src/hotspot/share/oops/cpCache.cpp
Print this page
* questions.
*
*/
#include "precompiled.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/cdsConfig.hpp"
- #include "cds/classPrelinker.hpp"
#include "cds/heapShared.hpp"
#include "classfile/resolutionErrors.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/vmClasses.hpp"
* questions.
*
*/
#include "precompiled.hpp"
+ #include "cds/aotConstantPoolResolver.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/heapShared.hpp"
#include "classfile/resolutionErrors.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/vmClasses.hpp"
#include "oops/constantPool.inline.hpp"
#include "oops/cpCache.inline.hpp"
#include "oops/method.inline.hpp"
#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp"
+ #include "oops/method.inline.hpp"
#include "oops/resolvedFieldEntry.hpp"
#include "oops/resolvedIndyEntry.hpp"
#include "oops/resolvedMethodEntry.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/arguments.hpp"
method->name() != vmSymbols::object_initializer_name()) {
do_resolve = false;
}
if (invoke_code == Bytecodes::_invokestatic) {
assert(method->method_holder()->is_initialized() ||
! method->method_holder()->is_reentrant_initialization(JavaThread::current()),
"invalid class initialization state for invoke_static");
if (!VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) {
// Don't mark invokestatic to method as resolved if the holder class has not yet completed
// initialization. An invokestatic must only proceed if the class is initialized, but if
method->name() != vmSymbols::object_initializer_name()) {
do_resolve = false;
}
if (invoke_code == Bytecodes::_invokestatic) {
assert(method->method_holder()->is_initialized() ||
! method->method_holder()->is_reentrant_initialization(JavaThread::current()) ||
+ (CDSConfig::is_dumping_archive() && VM_Version::supports_fast_class_init_checks()),
"invalid class initialization state for invoke_static");
if (!VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) {
// Don't mark invokestatic to method as resolved if the holder class has not yet completed
// initialization. An invokestatic must only proceed if the class is initialized, but if
#if INCLUDE_CDS
void ConstantPoolCache::remove_unshareable_info() {
assert(CDSConfig::is_dumping_archive(), "sanity");
if (_resolved_indy_entries != nullptr) {
! for (int i = 0; i < _resolved_indy_entries->length(); i++) {
- resolved_indy_entry_at(i)->remove_unshareable_info();
- }
}
if (_resolved_field_entries != nullptr) {
remove_resolved_field_entries_if_non_deterministic();
}
if (_resolved_method_entries != nullptr) {
#if INCLUDE_CDS
void ConstantPoolCache::remove_unshareable_info() {
assert(CDSConfig::is_dumping_archive(), "sanity");
if (_resolved_indy_entries != nullptr) {
! remove_resolved_indy_entries_if_non_deterministic();
}
if (_resolved_field_entries != nullptr) {
remove_resolved_field_entries_if_non_deterministic();
}
if (_resolved_method_entries != nullptr) {
ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(cp);
for (int i = 0; i < _resolved_field_entries->length(); i++) {
ResolvedFieldEntry* rfi = _resolved_field_entries->adr_at(i);
int cp_index = rfi->constant_pool_index();
bool archived = false;
! bool resolved = rfi->is_resolved(Bytecodes::_getfield) ||
rfi->is_resolved(Bytecodes::_putfield);
! if (resolved && ClassPrelinker::is_resolution_deterministic(src_cp, cp_index)) {
rfi->mark_and_relocate();
archived = true;
} else {
rfi->remove_unshareable_info();
}
ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(cp);
for (int i = 0; i < _resolved_field_entries->length(); i++) {
ResolvedFieldEntry* rfi = _resolved_field_entries->adr_at(i);
int cp_index = rfi->constant_pool_index();
bool archived = false;
! bool resolved = rfi->is_resolved(Bytecodes::_getstatic) ||
+ rfi->is_resolved(Bytecodes::_putstatic) ||
+ rfi->is_resolved(Bytecodes::_getfield) ||
rfi->is_resolved(Bytecodes::_putfield);
! if (resolved && AOTConstantPoolResolver::is_resolution_deterministic(src_cp, cp_index)) {
rfi->mark_and_relocate();
archived = true;
} else {
rfi->remove_unshareable_info();
}
ResourceMark rm;
int klass_cp_index = cp->uncached_klass_ref_index_at(cp_index);
Symbol* klass_name = cp->klass_name_at(klass_cp_index);
Symbol* name = cp->uncached_name_ref_at(cp_index);
Symbol* signature = cp->uncached_signature_ref_at(cp_index);
! log.print("%s field CP entry [%3d]: %s %s %s.%s:%s",
(archived ? "archived" : "reverted"),
cp_index,
cp->pool_holder()->name()->as_C_string(),
- (archived ? "=>" : " "),
klass_name->as_C_string(), name->as_C_string(), signature->as_C_string());
}
}
ArchiveBuilder::alloc_stats()->record_field_cp_entry(archived, resolved && !archived);
}
ResourceMark rm;
int klass_cp_index = cp->uncached_klass_ref_index_at(cp_index);
Symbol* klass_name = cp->klass_name_at(klass_cp_index);
Symbol* name = cp->uncached_name_ref_at(cp_index);
Symbol* signature = cp->uncached_signature_ref_at(cp_index);
! log.print("%s field CP entry [%3d]: %s => %s.%s:%s",
(archived ? "archived" : "reverted"),
cp_index,
cp->pool_holder()->name()->as_C_string(),
klass_name->as_C_string(), name->as_C_string(), signature->as_C_string());
}
}
ArchiveBuilder::alloc_stats()->record_field_cp_entry(archived, resolved && !archived);
}
ResolvedMethodEntry* rme = _resolved_method_entries->adr_at(i);
int cp_index = rme->constant_pool_index();
bool archived = false;
bool resolved = rme->is_resolved(Bytecodes::_invokevirtual) ||
rme->is_resolved(Bytecodes::_invokespecial) ||
! rme->is_resolved(Bytecodes::_invokeinterface);
!
! // Just for safety -- this should not happen, but do not archive if we ever see this.
! resolved &= !(rme->is_resolved(Bytecodes::_invokehandle) ||
- rme->is_resolved(Bytecodes::_invokestatic));
-
- if (resolved && can_archive_resolved_method(rme)) {
rme->mark_and_relocate(src_cp);
archived = true;
} else {
rme->remove_unshareable_info();
}
ResolvedMethodEntry* rme = _resolved_method_entries->adr_at(i);
int cp_index = rme->constant_pool_index();
bool archived = false;
bool resolved = rme->is_resolved(Bytecodes::_invokevirtual) ||
rme->is_resolved(Bytecodes::_invokespecial) ||
! rme->is_resolved(Bytecodes::_invokestatic) ||
! rme->is_resolved(Bytecodes::_invokeinterface) ||
! rme->is_resolved(Bytecodes::_invokehandle);
! if (resolved && can_archive_resolved_method(src_cp, rme)) {
rme->mark_and_relocate(src_cp);
archived = true;
} else {
rme->remove_unshareable_info();
}
ArchiveBuilder::alloc_stats()->record_method_cp_entry(archived, resolved && !archived);
}
}
}
! bool ConstantPoolCache::can_archive_resolved_method(ResolvedMethodEntry* method_entry) {
InstanceKlass* pool_holder = constant_pool()->pool_holder();
if (!(pool_holder->is_shared_boot_class() || pool_holder->is_shared_platform_class() ||
pool_holder->is_shared_app_class())) {
// Archiving resolved cp entries for classes from non-builtin loaders
// is not yet supported.
ArchiveBuilder::alloc_stats()->record_method_cp_entry(archived, resolved && !archived);
}
}
}
! void ConstantPoolCache::remove_resolved_indy_entries_if_non_deterministic() {
+ ConstantPool* cp = constant_pool();
+ ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(cp);
+ for (int i = 0; i < _resolved_indy_entries->length(); i++) {
+ ResolvedIndyEntry* rei = _resolved_indy_entries->adr_at(i);
+ int cp_index = rei->constant_pool_index();
+ bool archived = false;
+ bool resolved = rei->is_resolved();
+ if (resolved && AOTConstantPoolResolver::is_resolution_deterministic(src_cp, cp_index)) {
+ rei->mark_and_relocate();
+ archived = true;
+ } else {
+ rei->remove_unshareable_info();
+ }
+ if (resolved) {
+ LogStreamHandle(Trace, cds, resolve) log;
+ if (log.is_enabled()) {
+ ResourceMark rm;
+ int bsm = cp->bootstrap_method_ref_index_at(cp_index);
+ int bsm_ref = cp->method_handle_index_at(bsm);
+ Symbol* bsm_name = cp->uncached_name_ref_at(bsm_ref);
+ Symbol* bsm_signature = cp->uncached_signature_ref_at(bsm_ref);
+ Symbol* bsm_klass = cp->klass_name_at(cp->uncached_klass_ref_index_at(bsm_ref));
+ log.print("%s indy CP entry [%3d]: %s (%d)",
+ (archived ? "archived" : "reverted"),
+ cp_index, cp->pool_holder()->name()->as_C_string(), i);
+ log.print(" %s %s.%s:%s", (archived ? "=>" : " "), bsm_klass->as_C_string(),
+ bsm_name->as_C_string(), bsm_signature->as_C_string());
+ }
+ ArchiveBuilder::alloc_stats()->record_indy_cp_entry(archived, resolved && !archived);
+ }
+ }
+ }
+
+ bool ConstantPoolCache::can_archive_invokehandle(ResolvedMethodEntry* rme) {
+ ConstantPool* cp = constant_pool();
+ assert(rme->is_resolved(Bytecodes::_invokehandle), "sanity");
+
+ int cp_index = rme->constant_pool_index();
+ int klass_cp_index = cp->uncached_klass_ref_index_at(cp_index);
+ Klass* resolved_klass = cp->resolved_klass_at(klass_cp_index);
+ if (!resolved_klass->is_instance_klass()) {
+ // FIXME: can this ever happen?
+ return false;
+ }
+ // FIXME -- any class referenced by the archived CP entries should be added to ArchiveBuilder::classes, or should be
+ // filtered out.
+ return true;
+ }
+
+ bool ConstantPoolCache::can_archive_resolved_method(ConstantPool* src_cp, ResolvedMethodEntry* method_entry) {
InstanceKlass* pool_holder = constant_pool()->pool_holder();
if (!(pool_holder->is_shared_boot_class() || pool_holder->is_shared_platform_class() ||
pool_holder->is_shared_app_class())) {
// Archiving resolved cp entries for classes from non-builtin loaders
// is not yet supported.
return false; // FIXME: corresponding stub is generated on demand during method resolution (see LinkResolver::resolve_static_call).
}
}
int cp_index = method_entry->constant_pool_index();
- ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(constant_pool());
assert(src_cp->tag_at(cp_index).is_method() || src_cp->tag_at(cp_index).is_interface_method(), "sanity");
! if (!ClassPrelinker::is_resolution_deterministic(src_cp, cp_index)) {
return false;
}
! if (method_entry->is_resolved(Bytecodes::_invokeinterface) ||
method_entry->is_resolved(Bytecodes::_invokevirtual) ||
method_entry->is_resolved(Bytecodes::_invokespecial)) {
return true;
} else {
- // invokestatic and invokehandle are not supported yet.
return false;
}
-
}
#endif // INCLUDE_CDS
void ConstantPoolCache::deallocate_contents(ClassLoaderData* data) {
assert(!is_shared(), "shared caches are not deallocated");
return false; // FIXME: corresponding stub is generated on demand during method resolution (see LinkResolver::resolve_static_call).
}
}
int cp_index = method_entry->constant_pool_index();
assert(src_cp->tag_at(cp_index).is_method() || src_cp->tag_at(cp_index).is_interface_method(), "sanity");
! if (!AOTConstantPoolResolver::is_resolution_deterministic(src_cp, cp_index)) {
return false;
}
! if (method_entry->is_resolved(Bytecodes::_invokestatic) ||
+ method_entry->is_resolved(Bytecodes::_invokeinterface) ||
method_entry->is_resolved(Bytecodes::_invokevirtual) ||
method_entry->is_resolved(Bytecodes::_invokespecial)) {
return true;
+ } else if (method_entry->is_resolved(Bytecodes::_invokehandle)) {
+ if (CDSConfig::is_dumping_invokedynamic() && can_archive_invokehandle(method_entry)) {
+ // invokehandle depends on archived MethodType and LambdaForms.
+ return true;
+ } else {
+ return false;
+ }
} else {
return false;
}
}
#endif // INCLUDE_CDS
void ConstantPoolCache::deallocate_contents(ClassLoaderData* data) {
assert(!is_shared(), "shared caches are not deallocated");
< prev index next >