< prev index next > src/hotspot/share/oops/constantPool.cpp
Print this page
#include "cds/archiveHeapWriter.hpp"
#include "cds/archiveHeapLoader.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/classPrelinker.hpp"
+ #include "cds/lambdaFormInvokers.inline.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"
#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/typeArrayOop.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/atomic.hpp"
+ //#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/javaCalls.hpp"
- #include "runtime/javaThread.hpp"
+ #include "runtime/javaThread.inline.hpp"
+ #include "runtime/perfData.hpp"
#include "runtime/signature.hpp"
#include "runtime/vframe.inline.hpp"
#include "utilities/checkedCast.hpp"
#include "utilities/copy.hpp"
return nullptr;
}
objArrayOop rr = resolved_references();
if (rr != nullptr) {
- ConstantPool* orig_pool = ArchiveBuilder::current()->get_source_addr(this);
- objArrayOop scratch_rr = HeapShared::scratch_resolved_references(orig_pool);
+ 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);
+
+ if (cache() != nullptr && ArchiveInvokeDynamic) {
+ 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() && ClassPrelinker::is_resolution_deterministic(src_cp, rie->constant_pool_index())) {
+ int rr_index = rie->resolved_references_index();
+ keep_resolved_refs.at_put(rr_index, true);
+ }
+ }
+ }
+
+ 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() &&
+ can_archive_resolved_method(rme)) {
+ int rr_index = rme->resolved_references_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();
- int rr_len = rr->length();
for (int i = 0; i < rr_len; i++) {
oop obj = rr->obj_at(i);
scratch_rr->obj_at_put(i, nullptr);
- if (obj != nullptr && i < ref_map_len) {
- int index = object_to_cp_index(i);
- if (tag_at(index).is_string()) {
- 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);
+ if (obj != nullptr) {
+ if (i < ref_map_len) {
+ int index = object_to_cp_index(i);
+ if (tag_at(index).is_string()) {
+ 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;
}
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 (!_pool_holder->is_linked() && !_pool_holder->verified_at_dump_time()) {
+ 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 are not in the shared archive.
// Save the length for restoration. It is not necessarily the same length
// as reference_map.length() if invokedynamic is saved. It is needed when
// re-creating the resolved reference array if archived heap data cannot be map
// at runtime.
set_resolved_reference_length(
resolved_references() != nullptr ? resolved_references()->length() : 0);
set_resolved_references(OopHandle());
- bool archived = false;
+ remove_unshareable_entries();
+ }
+
+ static const char* get_type(Klass* k) {
+ const char* type;
+ Klass* src_k;
+ if (ArchiveBuilder::is_active() && ArchiveBuilder::current()->is_in_buffer_space(k)) {
+ src_k = ArchiveBuilder::current()->get_source_addr(k);
+ } else {
+ src_k = k;
+ }
+
+ if (src_k->is_objArray_klass()) {
+ src_k = ObjArrayKlass::cast(src_k)->bottom_klass();
+ assert(!src_k->is_objArray_klass(), "sanity");
+ }
+
+ if (src_k->is_typeArray_klass()) {
+ type = "prim";
+ } else {
+ InstanceKlass* src_ik = InstanceKlass::cast(src_k);
+ oop loader = src_ik->class_loader();
+ if (loader == nullptr) {
+ type = "boot";
+ } else if (loader == SystemDictionary::java_platform_loader()) {
+ type = "plat";
+ } else if (loader == SystemDictionary::java_system_loader()) {
+ type = "app";
+ } else {
+ type = "unreg";
+ }
+ }
+
+ return type;
+ }
+
+ void ConstantPool::remove_unshareable_entries() {
+ ResourceMark rm;
+ log_info(cds, resolve)("Archiving CP entries for %s", pool_holder()->name()->as_C_string());
for (int cp_index = 1; cp_index < length(); cp_index++) { // cp_index 0 is unused
- switch (tag_at(cp_index).value()) {
+ int cp_tag = tag_at(cp_index).value();
+ switch (cp_tag) {
+ case JVM_CONSTANT_UnresolvedClass:
+ ArchiveBuilder::alloc_stats()->record_klass_cp_entry(false);
+ break;
case JVM_CONSTANT_UnresolvedClassInError:
tag_at_put(cp_index, JVM_CONSTANT_UnresolvedClass);
+ ArchiveBuilder::alloc_stats()->record_klass_cp_entry(false);
break;
case JVM_CONSTANT_MethodHandleInError:
tag_at_put(cp_index, JVM_CONSTANT_MethodHandle);
break;
case JVM_CONSTANT_MethodTypeInError:
break;
case JVM_CONSTANT_DynamicInError:
tag_at_put(cp_index, JVM_CONSTANT_Dynamic);
break;
case JVM_CONSTANT_Class:
- archived = maybe_archive_resolved_klass_at(cp_index);
- ArchiveBuilder::alloc_stats()->record_klass_cp_entry(archived);
+ remove_resolved_klass_if_non_deterministic(cp_index);
+ break;
+ default:
break;
}
}
if (cache() != nullptr) {
// cache() is null if this class is not yet linked.
- cache()->remove_unshareable_info();
+ remove_resolved_field_entries_if_non_deterministic();
+ remove_resolved_method_entries_if_non_deterministic();
+ remove_resolved_indy_entries_if_non_deterministic();
}
}
- bool ConstantPool::maybe_archive_resolved_klass_at(int cp_index) {
+ void ConstantPool::remove_resolved_klass_if_non_deterministic(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().
-
+ Klass* k = resolved_klass_at(cp_index);
+ bool revert = true;
if (k != nullptr) {
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());
+ if (ClassPrelinker::is_resolution_deterministic(src_cp, cp_index)) {
+ revert = false;
+ }
+ }
+
+ if (revert) {
+ // This resolved klass entry cannot be archived. Revert the tag to UnresolvedClass,
+ // so that it will be resolved at runtime.
+ int resolved_klass_index = klass_slot_at(cp_index).resolved_klass_index();
+ resolved_klasses()->at_put(resolved_klass_index, nullptr);
+ tag_at_put(cp_index, JVM_CONSTANT_UnresolvedClass);
+ }
+
+ LogStreamHandle(Trace, cds, resolve) log;
+ if (log.is_enabled()) {
+ ResourceMark rm;
+ log.print("%s klass CP entry [%3d]: %s %s",
+ (revert ? "reverted" : "archived"),
+ cp_index, pool_holder()->name()->as_C_string(), get_type(pool_holder()));
+ if (revert) {
+ Symbol* name = klass_name_at(cp_index);
+ log.print(" \"%s\"", name->as_C_string());
+ } else {
+ 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)");
+ }
+ }
+ ArchiveBuilder::alloc_stats()->record_klass_cp_entry(!revert);
+ }
+
+ void ConstantPool::remove_resolved_field_entries_if_non_deterministic() {
+ ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(this);
+ Array<ResolvedFieldEntry>* field_entries = cache()->resolved_field_entries();
+ if (field_entries != nullptr) {
+ for (int i = 0; i < field_entries->length(); i++) {
+ ResolvedFieldEntry* rfi = 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::_putfield) ||
+ 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();
+ }
+ if (resolved) {
+ LogStreamHandle(Trace, cds, resolve) log;
+ if (log.is_enabled()) {
+ ResourceMark rm;
+ int klass_cp_index = uncached_klass_ref_index_at(cp_index);
+ Symbol* klass_name = klass_name_at(klass_cp_index);
+ Symbol* name = uncached_name_ref_at(cp_index);
+ Symbol* signature = uncached_signature_ref_at(cp_index);
+ log.print("%s field CP entry [%3d]: %s %s %s.%s:%s",
+ (archived ? "archived" : "excluded"),
+ cp_index,
+ 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);
+ }
+ }
+ }
+
+ void ConstantPool::remove_resolved_method_entries_if_non_deterministic() {
+ ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(this);
+ 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);
+ 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(rme)) {
+ rme->mark_and_relocate(src_cp);
+ archived = true;
+ } else {
+ rme->remove_unshareable_info();
+ }
+ if (resolved) {
+ LogStreamHandle(Trace, cds, resolve) log;
+ if (log.is_enabled()) {
+ ResourceMark rm;
+ int klass_cp_index = uncached_klass_ref_index_at(cp_index);
+ Symbol* klass_name = klass_name_at(klass_cp_index);
+ Symbol* name = uncached_name_ref_at(cp_index);
+ Symbol* signature = uncached_signature_ref_at(cp_index);
+ log.print("%s%s method CP entry [%3d]: %s %s.%s:%s",
+ (archived ? "archived" : "excluded"),
+ (rme->is_resolved(Bytecodes::_invokeinterface) ? " interface" : ""),
+ cp_index,
+ pool_holder()->name()->as_C_string(),
+ klass_name->as_C_string(), name->as_C_string(), signature->as_C_string());
+ if (archived) {
+ Klass* resolved_klass = resolved_klass_at(klass_cp_index);
+ log.print(" => %s%s",
+ resolved_klass->name()->as_C_string(),
+ (rme->is_resolved(Bytecodes::_invokestatic) ? " *** static" : ""));
+ }
+ }
}
- return true;
+ ArchiveBuilder::alloc_stats()->record_method_cp_entry(archived, resolved && !archived);
+ }
+ }
+ }
+
+ void ConstantPool::remove_resolved_indy_entries_if_non_deterministic() {
+ ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(this);
+ Array<ResolvedIndyEntry>* indy_entries = cache()->resolved_indy_entries();
+ if (indy_entries != nullptr) {
+ for (int i = 0; i < indy_entries->length(); i++) {
+ ResolvedIndyEntry* rei = indy_entries->adr_at(i);
+ int cp_index = rei->constant_pool_index();
+ bool archived = false;
+ bool resolved = rei->is_resolved();
+ if (resolved && ClassPrelinker::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 = bootstrap_method_ref_index_at(cp_index);
+ int bsm_ref = method_handle_index_at(bsm);
+ Symbol* bsm_name = uncached_name_ref_at(bsm_ref);
+ Symbol* bsm_signature = uncached_signature_ref_at(bsm_ref);
+ Symbol* bsm_klass = klass_name_at(uncached_klass_ref_index_at(bsm_ref));
+ log.print("%s indy CP entry [%3d]: %s (%d)",
+ (archived ? "archived" : "excluded"),
+ cp_index, 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 ConstantPool::can_archive_invokehandle(ResolvedMethodEntry* rme) {
+ assert(rme->is_resolved(Bytecodes::_invokehandle), "sanity");
+
+ int cp_index = rme->constant_pool_index();
+ int klass_cp_index = uncached_klass_ref_index_at(cp_index);
+ Klass* resolved_klass = 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 ConstantPool::can_archive_resolved_method(ResolvedMethodEntry* method_entry) {
+ 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;
+ }
+
+ if (CDSConfig::is_dumping_dynamic_archive()) {
+ // InstanceKlass::methods() is has been resorted. We need to
+ // update the vtable_index in method_entry (not implemented)
+ return false;
+ }
+
+ if (!method_entry->is_resolved(Bytecodes::_invokevirtual)) {
+ if (method_entry->method() == nullptr) {
+ return false;
+ }
+ if (method_entry->method()->is_continuation_native_intrinsic()) {
+ 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(this);
+ 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::_invokehandle)) {
+ if (!ArchiveInvokeDynamic) {
+ // invokehandle depends on archived MethodType and LambdaForms.
+ return false;
+ } else if (!can_archive_invokehandle(method_entry)) {
+ return false;
}
+ } else 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)) {
+ // OK
+ } else {
+ return false; // just to be safe.
}
- // 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, nullptr);
- tag_at_put(cp_index, JVM_CONSTANT_UnresolvedClass);
- return false;
+ return true;
}
#endif // INCLUDE_CDS
int ConstantPool::cp_to_object_index(int cp_index) {
// this is harder don't do this so much.
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;
+ 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");
+ switch(code) {
+ case Bytecodes::_invokedynamic:
+ return resolved_indy_entry_at(index)->is_resolved();
+
+ case Bytecodes::_getfield:
+ case Bytecodes::_getstatic:
+ case Bytecodes::_putfield:
+ case Bytecodes::_putstatic:
+ return resolved_field_entry_at(index)->is_resolved(code);
+
+ case Bytecodes::_invokeinterface:
+ case Bytecodes::_invokehandle:
+ case Bytecodes::_invokespecial:
+ case Bytecodes::_invokestatic:
+ case Bytecodes::_invokevirtual:
+ case Bytecodes::_fast_invokevfinal: // Bytecode interpreter uses this
+ return resolved_method_entry_at(index)->is_resolved(code);
+
+ default:
+ fatal("Unexpected bytecode: %s", Bytecodes::name(code));
}
}
u2 ConstantPool::uncached_name_and_type_ref_index_at(int cp_index) {
if (tag_at(cp_index).has_bootstrap()) {
result_oop = resolved->java_mirror();
break;
}
case JVM_CONSTANT_Dynamic:
- {
+ { PerfTraceTimedEvent timer(ClassLoader::perf_resolve_invokedynamic_time(),
+ ClassLoader::perf_resolve_invokedynamic_count(),
+ THREAD->class_being_initialized() == nullptr);
// Resolve the Dynamically-Computed constant to invoke the BSM in order to obtain the resulting oop.
BootstrapInfo bootstrap_specifier(this_cp, cp_index);
// The initial step in resolving an unresolved symbolic reference to a
// dynamically-computed constant is to resolve the symbolic reference to a
assert(cache_index != _no_index_sentinel, "should have been set");
result_oop = string_at_impl(this_cp, cp_index, cache_index, CHECK_NULL);
break;
case JVM_CONSTANT_MethodHandle:
- {
+ { PerfTraceTimedEvent timer(ClassLoader::perf_resolve_method_handle_time(),
+ ClassLoader::perf_resolve_method_handle_count(),
+ THREAD->class_being_initialized() == nullptr);
int ref_kind = this_cp->method_handle_ref_kind_at(cp_index);
int callee_index = this_cp->method_handle_klass_index_at(cp_index);
Symbol* name = this_cp->method_handle_name_ref_at(cp_index);
Symbol* signature = this_cp->method_handle_signature_ref_at(cp_index);
constantTag m_tag = this_cp->tag_at(this_cp->method_handle_index_at(cp_index));
result_oop = value();
break;
}
case JVM_CONSTANT_MethodType:
- {
+ { PerfTraceTimedEvent timer(ClassLoader::perf_resolve_method_type_time(),
+ ClassLoader::perf_resolve_method_type_count(),
+ THREAD->class_being_initialized() == nullptr);
Symbol* signature = this_cp->method_type_signature_at(cp_index);
{ ResourceMark rm(THREAD);
log_debug(class, resolve)("resolve JVM_CONSTANT_MethodType [%d/%d] %s",
cp_index, this_cp->method_type_index_at(cp_index),
signature->as_C_string());
< prev index next >