< prev index next >

src/share/vm/oops/constantPool.cpp

Print this page

@@ -45,22 +45,14 @@
 #include "runtime/signature.hpp"
 #include "runtime/vframe.hpp"
 #include "utilities/copy.hpp"
 
 ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, TRAPS) {
-  // Tags are RW but comment below applies to tags also.
-  Array<u1>* tags = MetadataFactory::new_writeable_array<u1>(loader_data, length, 0, CHECK_NULL);
-
+  // Add one extra element to tags for storing ConstantPool::flags().
+  Array<u1>* tags = MetadataFactory::new_writeable_array<u1>(loader_data, length+1, 0, CHECK_NULL);
   int size = ConstantPool::size(length);
-
-  // CDS considerations:
-  // Allocate read-write but may be able to move to read-only at dumping time
-  // if all the klasses are resolved.  The only other field that is writable is
-  // the resolved_references array, which is recreated at startup time.
-  // But that could be moved to InstanceKlass (although a pain to access from
-  // assembly code).  Maybe it could be moved to the cpCache which is RW.
-  return new (loader_data, size, false, MetaspaceObj::ConstantPoolType, THREAD) ConstantPool(tags);
+  return new (loader_data, size, true, MetaspaceObj::ConstantPoolType, THREAD) ConstantPool(tags);
 }
 
 #ifdef ASSERT
 
 // MetaspaceObj allocation invariant is calloc equivalent memory

@@ -78,26 +70,30 @@
 
 #endif
 
 ConstantPool::ConstantPool(Array<u1>* tags) :
   _tags(tags),
-  _length(tags->length()),
-  _flags(0) {
+  _length(tags->length()-1) {
 
     assert(_tags != NULL, "invariant");
-    assert(tags->length() == _length, "invariant");
+    assert(tags->length()-1 == _length, "invariant"); // tags->at(_length) is flags()
     assert(tag_array_is_zero_initialized(tags), "invariant");
-    assert(0 == _flags, "invariant");
+    assert(0 == flags(), "invariant");
     assert(0 == version(), "invariant");
     assert(NULL == _pool_holder, "invariant");
 }
 
 void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) {
-  MetadataFactory::free_metadata(loader_data, cache());
-  set_cache(NULL);
+  if (cache() != NULL) {
   MetadataFactory::free_array<u2>(loader_data, reference_map());
   set_reference_map(NULL);
+    MetadataFactory::free_metadata(loader_data, cache());
+    set_cache(NULL);
+  }
+
+  MetadataFactory::free_array<Klass*>(loader_data, resolved_klasses());
+  set_resolved_klasses(NULL);
 
   MetadataFactory::free_array<jushort>(loader_data, operands());
   set_operands(NULL);
 
   release_C_heap_structures();

@@ -111,11 +107,11 @@
   // walk constant pool and decrement symbol reference counts
   unreference_symbols();
 }
 
 objArrayOop ConstantPool::resolved_references() const {
-  return (objArrayOop)JNIHandles::resolve(_resolved_references);
+  return (objArrayOop)JNIHandles::resolve(_cache->resolved_references());
 }
 
 // Create resolved_references array and mapping array for original cp indexes
 // The ldc bytecode was rewritten to have the resolved reference array index so need a way
 // to map it back for resolving and some unlikely miscellaneous uses.

@@ -148,13 +144,72 @@
     Handle refs_handle (THREAD, (oop)stom);  // must handleize.
     set_resolved_references(loader_data->add_handle(refs_handle));
   }
 }
 
+void ConstantPool::allocate_resolved_klasses(ClassLoaderData* loader_data, int num_klasses, TRAPS) {
+  // A ConstantPool can't possibly have 0xffff valid class entries,
+  // because entry #0 must be CONSTANT_Invalid, and each class entry must refer to a UTF8
+  // entry for the class's name. So at most we will have 0xfffe class entries.
+  // This allows us to use 0xffff (ConstantPool::_invalid_resolved_klass_index) to indicate
+  // UnresolvedKlass entries that are temporarily created during class redefinition.
+  assert(num_klasses < _invalid_resolved_klass_index, "sanity");
+  assert(resolved_klasses() == NULL, "sanity");
+  Array<Klass*>* rk = MetadataFactory::new_writeable_array<Klass*>(loader_data, num_klasses, CHECK);
+  set_resolved_klasses(rk);
+}
+
+void ConstantPool::initialize_unresolved_klasses(ClassLoaderData* loader_data, TRAPS) {
+  int len = length();
+  int num_klasses = 0;
+  for (int i = 1; i <len; i++) {
+    switch (tag_at(i).value()) {
+    case JVM_CONSTANT_ClassIndex:
+      {
+        const int class_index = klass_index_at(i);
+        unresolved_klass_at_put(i, class_index, num_klasses++);
+      }
+      break;
+#ifndef PRODUCT
+    case JVM_CONSTANT_Class:
+    case JVM_CONSTANT_UnresolvedClass:
+    case JVM_CONSTANT_UnresolvedClassInError:
+      // All of these should have been reverted back to ClassIndex before calling
+      // this function.
+      ShouldNotReachHere();
+#endif
+    }
+  }
+  allocate_resolved_klasses(loader_data, num_klasses, THREAD);
+}
+
+void ConstantPool::klass_at_put(int which, int name_index, int resolved_klass_index, Klass* k, Symbol* name) {
+  assert(is_within_bounds(which), "index out of bounds");
+  assert(is_within_bounds(name_index), "index out of bounds");
+  assert((resolved_klass_index & 0xffff0000) == 0, "must be");
+  *int_at_addr(which) =
+    build_int_from_shorts((jushort)resolved_klass_index, (jushort)name_index);
+
+  symbol_at_put(name_index, name);
+  name->increment_refcount();
+  Klass** adr = resolved_klasses()->adr_at(resolved_klass_index);
+  OrderAccess::release_store_ptr((Klass* volatile *)adr, k);
+
+  // The interpreter assumes when the tag is stored, the klass is resolved
+  // and the Klass* non-NULL, so we need hardware store ordering here.
+  if (k != NULL) {
+    release_tag_at_put(which, JVM_CONSTANT_Class);
+  } else {
+    release_tag_at_put(which, JVM_CONSTANT_UnresolvedClass);
+  }
+}
+
 // CDS support. Create a new resolved_references array.
 void ConstantPool::restore_unshareable_info(TRAPS) {
   assert(is_constantPool(), "ensure C++ vtable is restored");
+  assert(on_stack(), "should always be set for shared constant pools");
+  assert(is_shared_quick(), "should always be set for shared constant pools");
 
   // Only create the new resolved references array if it hasn't been attempted before
   if (resolved_references() != NULL) return;
 
   // restore the C++ vtable from the shared archive

@@ -178,10 +233,16 @@
   // Save the length for restoration.  It is not necessarily the same length
   // as reference_map.length() if invokedynamic is saved.
   set_resolved_reference_length(
     resolved_references() != NULL ? resolved_references()->length() : 0);
   set_resolved_references(NULL);
+
+  // 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_quick);
 }
 
 int ConstantPool::cp_to_object_index(int cp_index) {
   // this is harder don't do this so much.
   int i = reference_map()->find(cp_index);

@@ -227,15 +288,18 @@
   assert(THREAD->is_Java_thread(), "must be a Java thread");
 
   // A resolved constantPool entry will contain a Klass*, otherwise a Symbol*.
   // It is not safe to rely on the tag bit's here, since we don't have a lock, and
   // the entry and tag is not updated atomicly.
-  CPSlot entry = this_cp->slot_at(which);
-  if (entry.is_resolved()) {
-    assert(entry.get_klass()->is_klass(), "must be");
-    // Already resolved - return entry.
-    return entry.get_klass();
+  int value = *this_cp->int_at_addr(which);
+  int resolved_klass_index = extract_low_short_from_int(value);
+  int name_index = extract_high_short_from_int(value);
+  assert(this_cp->tag_at(name_index).is_symbol(), "sanity");
+
+  Klass* klass = this_cp->resolved_klasses()->at(resolved_klass_index);
+  if (klass != NULL) {
+    return klass;
   }
 
   // This tag doesn't change back to unresolved class unless at a safepoint.
   if (this_cp->tag_at(which).is_unresolved_klass_in_error()) {
     // The original attempt to resolve this constant pool entry failed so find the

@@ -249,11 +313,11 @@
     throw_resolution_error(this_cp, which, CHECK_0);
     ShouldNotReachHere();
   }
 
   Handle mirror_handle;
-  Symbol* name = entry.get_symbol();
+  Symbol* name = this_cp->symbol_at(name_index);
   Handle loader (THREAD, this_cp->pool_holder()->class_loader());
   Handle protection_domain (THREAD, this_cp->pool_holder()->protection_domain());
   Klass* k = SystemDictionary::resolve_or_fail(name, loader, protection_domain, true, THREAD);
   if (!HAS_PENDING_EXCEPTION) {
     // preserve the resolved klass from unloading

@@ -268,14 +332,13 @@
     if (save_resolution_error) {
       save_and_throw_exception(this_cp, which, constantTag(JVM_CONSTANT_UnresolvedClass), CHECK_NULL);
       // If CHECK_NULL above doesn't return the exception, that means that
       // some other thread has beaten us and has resolved the class.
       // To preserve old behavior, we return the resolved class.
-      entry = this_cp->resolved_klass_at(which);
-      assert(entry.is_resolved(), "must be resolved if exception was cleared");
-      assert(entry.get_klass()->is_klass(), "must be resolved to a klass");
-      return entry.get_klass();
+      klass = this_cp->resolved_klasses()->at(resolved_klass_index);
+      assert(klass != NULL, "must be resolved if exception was cleared");
+      return klass;
     } else {
       return NULL;  // return the pending exception
     }
   }
 

@@ -285,30 +348,36 @@
 
   // logging for class+resolve.
   if (log_is_enabled(Debug, class, resolve)){
     trace_class_resolution(this_cp, k);
   }
-  this_cp->klass_at_put(which, k);
-  entry = this_cp->resolved_klass_at(which);
-  assert(entry.is_resolved() && entry.get_klass()->is_klass(), "must be resolved at this point");
-  return entry.get_klass();
+  Klass** adr = this_cp->resolved_klasses()->adr_at(resolved_klass_index);
+  OrderAccess::release_store_ptr((Klass* volatile *)adr, k);
+  // The interpreter assumes when the tag is stored, the klass is resolved
+  // and the Klass* is a klass rather than a Symbol*, so we need
+  // hardware store ordering here.
+  this_cp->release_tag_at_put(which, JVM_CONSTANT_Class);
+  return k;
 }
 
 
 // Does not update ConstantPool* - to avoid any exception throwing. Used
 // by compiler and exception handling.  Also used to avoid classloads for
 // instanceof operations. Returns NULL if the class has not been loaded or
 // if the verification of constant pool failed
 Klass* ConstantPool::klass_at_if_loaded(const constantPoolHandle& this_cp, int which) {
-  CPSlot entry = this_cp->slot_at(which);
-  if (entry.is_resolved()) {
-    assert(entry.get_klass()->is_klass(), "must be");
-    return entry.get_klass();
+  int value = *this_cp->int_at_addr(which);
+  int resolved_klass_index = extract_low_short_from_int(value);
+  int name_index = extract_high_short_from_int(value);
+  assert(this_cp->tag_at(name_index).is_symbol(), "sanity");
+
+  Klass* k = this_cp->resolved_klasses()->at(resolved_klass_index);
+  if (k != NULL) {
+    return k;
   } else {
-    assert(entry.is_unresolved(), "must be either symbol or klass");
     Thread *thread = Thread::current();
-    Symbol* name = entry.get_symbol();
+    Symbol* name = this_cp->symbol_at(name_index);
     oop loader = this_cp->pool_holder()->class_loader();
     oop protection_domain = this_cp->pool_holder()->protection_domain();
     Handle h_prot (thread, protection_domain);
     Handle h_loader (thread, loader);
     Klass* k = SystemDictionary::find(name, h_loader, h_prot, thread);

@@ -486,22 +555,19 @@
 
 
 Symbol* ConstantPool::klass_name_at(int which) const {
   assert(tag_at(which).is_unresolved_klass() || tag_at(which).is_klass(),
          "Corrupted constant pool");
-  // A resolved constantPool entry will contain a Klass*, otherwise a Symbol*.
-  // It is not safe to rely on the tag bit's here, since we don't have a lock, and the entry and
-  // tag is not updated atomicly.
-  CPSlot entry = slot_at(which);
-  if (entry.is_resolved()) {
-    // Already resolved - return entry's name.
-    assert(entry.get_klass()->is_klass(), "must be");
-    return entry.get_klass()->name();
-  } else {
-    assert(entry.is_unresolved(), "must be either symbol or klass");
-    return entry.get_symbol();
-  }
+  int name_index = extract_high_short_from_int(*int_at_addr(which));
+  return symbol_at(name_index);
+}
+
+int ConstantPool::klass_name_index_at(int which) const {
+  assert(tag_at(which).is_unresolved_klass() || tag_at(which).is_klass(),
+         "Corrupted constant pool");
+  int name_index = extract_high_short_from_int(*int_at_addr(which));
+  return name_index;
 }
 
 Symbol* ConstantPool::klass_ref_at_noresolve(int which) {
   jint ref_index = klass_ref_index_at(which);
   return klass_at_noresolve(ref_index);

@@ -848,11 +914,11 @@
 }
 
 
 // Iterate over symbols and decrement ones which are Symbol*s
 // This is done during GC.
-// Only decrement the UTF8 symbols. Unresolved classes and strings point to
+// Only decrement the UTF8 symbols. Strings point to
 // these symbols but didn't increment the reference count.
 void ConstantPool::unreference_symbols() {
   for (int index = 1; index < length(); index++) { // Index 0 is unused
     constantTag tag = tag_at(index);
     if (tag.is_symbol()) {

@@ -1229,16 +1295,10 @@
                                         const constantPoolHandle& to_cp, int to_i,
                                         TRAPS) {
 
   int tag = from_cp->tag_at(from_i).value();
   switch (tag) {
-  case JVM_CONSTANT_Class:
-  {
-    Klass* k = from_cp->klass_at(from_i, CHECK);
-    to_cp->klass_at_put(to_i, k);
-  } break;
-
   case JVM_CONSTANT_ClassIndex:
   {
     jint ki = from_cp->klass_index_at(from_i);
     to_cp->klass_index_at_put(to_i, ki);
   } break;

@@ -1303,22 +1363,18 @@
   {
     jint si = from_cp->string_index_at(from_i);
     to_cp->string_index_at_put(to_i, si);
   } break;
 
+  case JVM_CONSTANT_Class:
   case JVM_CONSTANT_UnresolvedClass:
   case JVM_CONSTANT_UnresolvedClassInError:
   {
-    // Can be resolved after checking tag, so check the slot first.
-    CPSlot entry = from_cp->slot_at(from_i);
-    if (entry.is_resolved()) {
-      assert(entry.get_klass()->is_klass(), "must be");
-      // Already resolved
-      to_cp->klass_at_put(to_i, entry.get_klass());
-    } else {
-      to_cp->unresolved_klass_at_put(to_i, entry.get_symbol());
-    }
+    // Revert to JVM_CONSTANT_ClassIndex
+    int name_index = extract_high_short_from_int(*from_cp->int_at_addr(from_i));
+    assert(from_cp->tag_at(name_index).is_symbol(), "sanity");
+    to_cp->klass_index_at_put(to_i, name_index);
   } break;
 
   case JVM_CONSTANT_String:
   {
     Symbol* s = from_cp->unresolved_string_at(from_i);

@@ -1366,11 +1422,10 @@
     ShouldNotReachHere();
   } break;
   }
 } // end copy_entry_to()
 
-
 // Search constant pool search_cp for an entry that matches this
 // constant pool's entry at pattern_i. Returns the index of a
 // matching entry or zero (0) if there is no matching entry.
 int ConstantPool::find_matching_entry(int pattern_i,
       const constantPoolHandle& search_cp, TRAPS) {

@@ -1822,17 +1877,20 @@
 
 void ConstantPool::set_on_stack(const bool value) {
   if (value) {
     // Only record if it's not already set.
     if (!on_stack()) {
+      assert(!is_shared_quick(), "should always be set for shared constant pools");
       _flags |= _on_stack;
       MetadataOnStackMark::record(this);
     }
   } else {
     // Clearing is done single-threadedly.
+    if (!is_shared_quick()) {
     _flags &= ~_on_stack;
   }
+  }
 }
 
 // JSR 292 support for patching constant pool oops after the class is linked and
 // the oop array for resolved references are created.
 // We can't do this during classfile parsing, which is how the other indexes are

@@ -1903,10 +1961,11 @@
     st->print_cr(" - holder: " INTPTR_FORMAT, p2i(pool_holder()));
   }
   st->print_cr(" - cache: " INTPTR_FORMAT, p2i(cache()));
   st->print_cr(" - resolved_references: " INTPTR_FORMAT, p2i(resolved_references()));
   st->print_cr(" - reference_map: " INTPTR_FORMAT, p2i(reference_map()));
+  st->print_cr(" - resolved_klasses: " INTPTR_FORMAT, p2i(resolved_klasses()));
 
   for (int index = 1; index < length(); index++) {      // Index 0 is unused
     ((ConstantPool*)this)->print_entry_on(index, st);
     switch (tag_at(index).value()) {
       case JVM_CONSTANT_Long :

@@ -1964,17 +2023,28 @@
       st->print(" signature_index=%d", signature_ref_index_at(index));
       break;
     case JVM_CONSTANT_Utf8 :
       symbol_at(index)->print_value_on(st);
       break;
+    case JVM_CONSTANT_ClassIndex: {
+        int name_index = *int_at_addr(index);
+        st->print("klass_index=%d ", name_index);
+        symbol_at(name_index)->print_value_on(st);
+      }
+      break;
     case JVM_CONSTANT_UnresolvedClass :               // fall-through
     case JVM_CONSTANT_UnresolvedClassInError: {
-      CPSlot entry = slot_at(index);
-      if (entry.is_resolved()) {
-        entry.get_klass()->print_value_on(st);
+        int value = *int_at_addr(index);
+        int resolved_klass_index = extract_low_short_from_int(value);
+        int name_index = extract_high_short_from_int(value);
+        assert(tag_at(name_index).is_symbol(), "sanity");
+
+        Klass* klass = resolved_klasses()->at(resolved_klass_index);
+        if (klass != NULL) {
+          klass->print_value_on(st);
       } else {
-        entry.get_symbol()->print_value_on(st);
+          symbol_at(name_index)->print_value_on(st);
       }
       }
       break;
     case JVM_CONSTANT_MethodHandle :
     case JVM_CONSTANT_MethodHandleInError :

@@ -2042,22 +2112,17 @@
 
 void ConstantPool::verify_on(outputStream* st) {
   guarantee(is_constantPool(), "object must be constant pool");
   for (int i = 0; i< length();  i++) {
     constantTag tag = tag_at(i);
-    CPSlot entry = slot_at(i);
-    if (tag.is_klass()) {
-      if (entry.is_resolved()) {
-        guarantee(entry.get_klass()->is_klass(),    "should be klass");
-      }
-    } else if (tag.is_unresolved_klass()) {
-      if (entry.is_resolved()) {
-        guarantee(entry.get_klass()->is_klass(),    "should be klass");
-      }
+    if (tag.is_klass() || tag.is_unresolved_klass()) {
+      guarantee(klass_name_at(i)->refcount() != 0, "should have nonzero reference count");
     } else if (tag.is_symbol()) {
+      CPSlot entry = slot_at(i);
       guarantee(entry.get_symbol()->refcount() != 0, "should have nonzero reference count");
     } else if (tag.is_string()) {
+      CPSlot entry = slot_at(i);
       guarantee(entry.get_symbol()->refcount() != 0, "should have nonzero reference count");
     }
   }
   if (cache() != NULL) {
     // Note: cache() can be NULL before a class is completely setup or
< prev index next >