< prev index next >

src/hotspot/share/oops/constantPool.cpp

Print this page
@@ -26,16 +26,19 @@
  #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"

@@ -57,14 +60,16 @@
  #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"
  

@@ -296,25 +301,57 @@
      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;
    }

@@ -343,10 +380,13 @@
      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;
  

@@ -373,36 +413,93 @@
          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:

@@ -410,56 +507,248 @@
        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.

@@ -697,13 +986,36 @@
      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()) {

@@ -1012,11 +1324,13 @@
        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

@@ -1070,11 +1384,13 @@
      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));

@@ -1118,11 +1434,13 @@
        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 >