< prev index next >

src/hotspot/share/oops/cpCache.cpp

Print this page
*** 21,11 ***
   * 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"
--- 21,10 ---

*** 47,10 ***
--- 46,11 ---
  #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"

*** 174,11 ***
          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
--- 174,12 ---
          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

*** 399,13 ***
  #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) {
--- 400,11 ---
  #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) {

*** 418,11 ***
    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 {
--- 417,13 ---
    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 && ClassPrelinker::is_resolution_deterministic(src_cp, cp_index)) {
        rfi->mark_and_relocate();
        archived = true;
      } else {

*** 455,17 ***
      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();
      }
--- 456,14 ---
      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();
      }

*** 493,11 ***
        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.
--- 491,61 ---
        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 && 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 = 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.

*** 518,26 ***
        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");
--- 566,31 ---
        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 (!ClassPrelinker::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 >