< prev index next >

src/hotspot/share/oops/constantPool.cpp

Print this page
@@ -21,22 +21,23 @@
   * 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/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/systemDictionaryShared.hpp"
  #include "classfile/vmClasses.hpp"
  #include "classfile/vmSymbols.hpp"
  #include "code/codeCache.hpp"
  #include "interpreter/bootstrapInfo.hpp"
  #include "interpreter/linkResolver.hpp"

@@ -281,10 +282,39 @@
    // 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

@@ -298,12 +328,19 @@
      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);

@@ -315,18 +352,46 @@
              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++) {

@@ -347,10 +412,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;
  

@@ -377,19 +445,36 @@
          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);

@@ -480,11 +565,11 @@
      // 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);
+     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);

@@ -500,11 +585,11 @@
      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());
+       log.print(" => %s", name->as_C_string());
      }
    }
  
    ArchiveBuilder::alloc_stats()->record_klass_cp_entry(can_archive, /*reverted=*/!can_archive);
  }

@@ -746,13 +831,11 @@
      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");
< prev index next >