hotspot/src/share/vm/oops/objArrayKlass.cpp
changeset 13728 882756847a04
parent 12379 2cf45b79ce3a
child 13952 e3cf184080bc
child 13922 ab7d352debe6
--- a/hotspot/src/share/vm/oops/objArrayKlass.cpp	Fri Aug 31 16:39:35 2012 -0700
+++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp	Sat Sep 01 13:25:18 2012 -0400
@@ -23,17 +23,19 @@
  */
 
 #include "precompiled.hpp"
+#include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "gc_implementation/shared/markSweep.inline.hpp"
 #include "gc_interface/collectedHeap.inline.hpp"
 #include "memory/genOopClosures.inline.hpp"
+#include "memory/metadataFactory.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.inline.hpp"
 #include "oops/instanceKlass.hpp"
+#include "oops/klass.inline.hpp"
 #include "oops/objArrayKlass.hpp"
 #include "oops/objArrayKlass.inline.hpp"
-#include "oops/objArrayKlassKlass.hpp"
 #include "oops/objArrayOop.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/oop.inline2.hpp"
@@ -42,6 +44,7 @@
 #include "runtime/mutexLocker.hpp"
 #include "utilities/copy.hpp"
 #ifndef SERIALGC
+#include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp"
 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
 #include "gc_implementation/g1/g1OopClosures.inline.hpp"
 #include "gc_implementation/g1/g1RemSet.inline.hpp"
@@ -53,6 +56,131 @@
 #include "oops/oop.pcgc.inline.hpp"
 #endif
 
+objArrayKlass* objArrayKlass::allocate(ClassLoaderData* loader_data, int n, KlassHandle klass_handle, Symbol* name, TRAPS) {
+  assert(objArrayKlass::header_size() <= InstanceKlass::header_size(),
+      "array klasses must be same size as InstanceKlass");
+
+  int size = arrayKlass::static_size(objArrayKlass::header_size());
+
+  return new (loader_data, size, THREAD) objArrayKlass(n, klass_handle, name);
+}
+
+Klass* objArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_data,
+                                                int n, KlassHandle element_klass, TRAPS) {
+
+  // Eagerly allocate the direct array supertype.
+  KlassHandle super_klass = KlassHandle();
+  if (!Universe::is_bootstrapping() || SystemDictionary::Object_klass_loaded()) {
+    KlassHandle element_super (THREAD, element_klass->super());
+    if (element_super.not_null()) {
+      // The element type has a direct super.  E.g., String[] has direct super of Object[].
+      super_klass = KlassHandle(THREAD, element_super->array_klass_or_null());
+      bool supers_exist = super_klass.not_null();
+      // Also, see if the element has secondary supertypes.
+      // We need an array type for each.
+      Array<Klass*>* element_supers = element_klass->secondary_supers();
+      for( int i = element_supers->length()-1; i >= 0; i-- ) {
+        Klass* elem_super = element_supers->at(i);
+        if (Klass::cast(elem_super)->array_klass_or_null() == NULL) {
+          supers_exist = false;
+          break;
+        }
+      }
+      if (!supers_exist) {
+        // Oops.  Not allocated yet.  Back out, allocate it, and retry.
+#ifndef PRODUCT
+        if (WizardMode) {
+          tty->print_cr("Must retry array klass creation for depth %d",n);
+        }
+#endif
+        KlassHandle ek;
+        {
+          MutexUnlocker mu(MultiArray_lock);
+          MutexUnlocker mc(Compile_lock);   // for vtables
+          Klass* sk = element_super->array_klass(CHECK_0);
+          super_klass = KlassHandle(THREAD, sk);
+          for( int i = element_supers->length()-1; i >= 0; i-- ) {
+            KlassHandle elem_super (THREAD, element_supers->at(i));
+            elem_super->array_klass(CHECK_0);
+          }
+          // Now retry from the beginning
+          Klass* klass_oop = element_klass->array_klass(n, CHECK_0);
+          // Create a handle because the enclosing brace, when locking
+          // can cause a gc.  Better to have this function return a Handle.
+          ek = KlassHandle(THREAD, klass_oop);
+        }  // re-lock
+        return ek();
+      }
+    } else {
+      // The element type is already Object.  Object[] has direct super of Object.
+      super_klass = KlassHandle(THREAD, SystemDictionary::Object_klass());
+    }
+  }
+
+  // Create type name for klass.
+  Symbol* name = NULL;
+  if (!element_klass->oop_is_instance() ||
+      (name = InstanceKlass::cast(element_klass())->array_name()) == NULL) {
+
+    ResourceMark rm(THREAD);
+    char *name_str = element_klass->name()->as_C_string();
+    int len = element_klass->name()->utf8_length();
+    char *new_str = NEW_RESOURCE_ARRAY(char, len + 4);
+    int idx = 0;
+    new_str[idx++] = '[';
+    if (element_klass->oop_is_instance()) { // it could be an array or simple type
+      new_str[idx++] = 'L';
+    }
+    memcpy(&new_str[idx], name_str, len * sizeof(char));
+    idx += len;
+    if (element_klass->oop_is_instance()) {
+      new_str[idx++] = ';';
+    }
+    new_str[idx++] = '\0';
+    name = SymbolTable::new_permanent_symbol(new_str, CHECK_0);
+    if (element_klass->oop_is_instance()) {
+      InstanceKlass* ik = InstanceKlass::cast(element_klass());
+      ik->set_array_name(name);
+    }
+  }
+
+  // Initialize instance variables
+  objArrayKlass* oak = objArrayKlass::allocate(loader_data, n, element_klass, name, CHECK_0);
+
+  // Add all classes to our internal class loader list here,
+  // including classes in the bootstrap (NULL) class loader.
+  // GC walks these as strong roots.
+  loader_data->add_class(oak);
+
+  // Call complete_create_array_klass after all instance variables has been initialized.
+  arrayKlass::complete_create_array_klass(oak, super_klass, CHECK_0);
+
+  return oak;
+}
+
+objArrayKlass::objArrayKlass(int n, KlassHandle element_klass, Symbol* name) : arrayKlass(name) {
+  this->set_dimension(n);
+  this->set_element_klass(element_klass());
+  // decrement refcount because object arrays are not explicitly freed.  The
+  // InstanceKlass array_name() keeps the name counted while the klass is
+  // loaded.
+  name->decrement_refcount();
+
+  Klass* bk;
+  if (element_klass->oop_is_objArray()) {
+    bk = objArrayKlass::cast(element_klass())->bottom_klass();
+  } else {
+    bk = element_klass();
+  }
+  assert(bk != NULL && (Klass::cast(bk)->oop_is_instance() || Klass::cast(bk)->oop_is_typeArray()), "invalid bottom klass");
+  this->set_bottom_klass(bk);
+  this->set_class_loader_data(bk->class_loader_data());
+
+  this->set_layout_helper(array_layout_helper(T_OBJECT));
+  assert(this->oop_is_array(), "sanity");
+  assert(this->oop_is_objArray(), "sanity");
+}
+
 int objArrayKlass::oop_size(oop obj) const {
   assert(obj->is_objArray(), "must be object array");
   return objArrayOop(obj)->object_size();
@@ -62,10 +190,8 @@
   if (length >= 0) {
     if (length <= arrayOopDesc::max_array_length(T_OBJECT)) {
       int size = objArrayOopDesc::object_size(length);
-      KlassHandle h_k(THREAD, as_klassOop());
-      objArrayOop a = (objArrayOop)CollectedHeap::array_allocate(h_k, size, length, CHECK_NULL);
-      assert(a->is_parsable(), "Can't publish unless parsable");
-      return a;
+      KlassHandle h_k(THREAD, this);
+      return (objArrayOop)CollectedHeap::array_allocate(h_k, size, length, CHECK_NULL);
     } else {
       report_java_out_of_memory("Requested array size exceeds VM limit");
       JvmtiExport::post_array_size_exhausted();
@@ -85,14 +211,12 @@
   KlassHandle h_lower_dimension(THREAD, lower_dimension());
   // If length < 0 allocate will throw an exception.
   objArrayOop array = allocate(length, CHECK_NULL);
-  assert(array->is_parsable(), "Don't handlize unless parsable");
   objArrayHandle h_array (THREAD, array);
   if (rank > 1) {
     if (length != 0) {
       for (int index = 0; index < length; index++) {
         arrayKlass* ak = arrayKlass::cast(h_lower_dimension());
         oop sub_array = ak->multi_allocate(rank-1, &sizes[1], CHECK_NULL);
-        assert(sub_array->is_parsable(), "Don't publish until parsable");
         h_array->obj_at_put(index, sub_array);
       }
     } else {
@@ -128,8 +252,8 @@
     Copy::conjoint_oops_atomic(src, dst, length);
   } else {
     // We have to make sure all elements conform to the destination array
-    klassOop bound = objArrayKlass::cast(d->klass())->element_klass();
-    klassOop stype = objArrayKlass::cast(s->klass())->element_klass();
+    Klass* bound = objArrayKlass::cast(d->klass())->element_klass();
+    Klass* stype = objArrayKlass::cast(s->klass())->element_klass();
     if (stype == bound || Klass::cast(stype)->is_subtype_of(bound)) {
       // elements are guaranteed to be subtypes, so no check necessary
       bs->write_ref_array_pre(dst, length);
@@ -203,21 +327,13 @@
 }
 
 
-klassOop objArrayKlass::array_klass_impl(bool or_null, int n, TRAPS) {
-  objArrayKlassHandle h_this(THREAD, as_klassOop());
-  return array_klass_impl(h_this, or_null, n, CHECK_NULL);
-}
-
-
-klassOop objArrayKlass::array_klass_impl(objArrayKlassHandle this_oop, bool or_null, int n, TRAPS) {
+Klass* objArrayKlass::array_klass_impl(bool or_null, int n, TRAPS) {
 
-  assert(this_oop->dimension() <= n, "check order of chain");
-  int dimension = this_oop->dimension();
-  if (dimension == n)
-    return this_oop();
+  assert(dimension() <= n, "check order of chain");
+  int dim = dimension();
+  if (dim == n) return this;
 
-  objArrayKlassHandle ak (THREAD, this_oop->higher_dimension());
-  if (ak.is_null()) {
+  if (higher_dimension() == NULL) {
     if (or_null)  return NULL;
 
     ResourceMark rm;
@@ -228,17 +344,15 @@
       MutexLocker mu(MultiArray_lock, THREAD);
 
       // Check if another thread beat us
-      ak = objArrayKlassHandle(THREAD, this_oop->higher_dimension());
-      if( ak.is_null() ) {
+      if (higher_dimension() == NULL) {
 
         // Create multi-dim klass object and link them together
-        klassOop new_klass =
-          objArrayKlassKlass::cast(Universe::objArrayKlassKlassObj())->
-          allocate_objArray_klass(dimension + 1, this_oop, CHECK_NULL);
-        ak = objArrayKlassHandle(THREAD, new_klass);
-        ak->set_lower_dimension(this_oop());
+        Klass* k =
+          objArrayKlass::allocate_objArray_klass(class_loader_data(), dim + 1, this, CHECK_NULL);
+        objArrayKlass* ak = objArrayKlass::cast(k);
+        ak->set_lower_dimension(this);
         OrderAccess::storestore();
-        this_oop->set_higher_dimension(ak());
+        set_higher_dimension(ak);
         assert(ak->oop_is_objArray(), "incorrect initialization of objArrayKlass");
       }
     }
@@ -246,58 +360,58 @@
     CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
   }
 
+  objArrayKlass *ak = objArrayKlass::cast(higher_dimension());
   if (or_null) {
     return ak->array_klass_or_null(n);
   }
   return ak->array_klass(n, CHECK_NULL);
 }
 
-klassOop objArrayKlass::array_klass_impl(bool or_null, TRAPS) {
+Klass* objArrayKlass::array_klass_impl(bool or_null, TRAPS) {
   return array_klass_impl(or_null, dimension() +  1, CHECK_NULL);
 }
 
 bool objArrayKlass::can_be_primary_super_slow() const {
-  if (!bottom_klass()->klass_part()->can_be_primary_super())
+  if (!bottom_klass()->can_be_primary_super())
     // array of interfaces
     return false;
   else
     return Klass::can_be_primary_super_slow();
 }
 
-objArrayOop objArrayKlass::compute_secondary_supers(int num_extra_slots, TRAPS) {
+GrowableArray<Klass*>* objArrayKlass::compute_secondary_supers(int num_extra_slots) {
   // interfaces = { cloneable_klass, serializable_klass, elemSuper[], ... };
-  objArrayOop es = Klass::cast(element_klass())->secondary_supers();
-  objArrayHandle elem_supers (THREAD, es);
-  int num_elem_supers = elem_supers.is_null() ? 0 : elem_supers->length();
+  Array<Klass*>* elem_supers = Klass::cast(element_klass())->secondary_supers();
+  int num_elem_supers = elem_supers == NULL ? 0 : elem_supers->length();
   int num_secondaries = num_extra_slots + 2 + num_elem_supers;
   if (num_secondaries == 2) {
     // Must share this for correct bootstrapping!
-    return Universe::the_array_interfaces_array();
+    set_secondary_supers(Universe::the_array_interfaces_array());
+    return NULL;
   } else {
-    objArrayOop sec_oop = oopFactory::new_system_objArray(num_secondaries, CHECK_NULL);
-    objArrayHandle secondaries(THREAD, sec_oop);
-    secondaries->obj_at_put(num_extra_slots+0, SystemDictionary::Cloneable_klass());
-    secondaries->obj_at_put(num_extra_slots+1, SystemDictionary::Serializable_klass());
+    GrowableArray<Klass*>* secondaries = new GrowableArray<Klass*>(num_elem_supers+2);
+    secondaries->push(SystemDictionary::Cloneable_klass());
+    secondaries->push(SystemDictionary::Serializable_klass());
     for (int i = 0; i < num_elem_supers; i++) {
-      klassOop elem_super = (klassOop) elem_supers->obj_at(i);
-      klassOop array_super = elem_super->klass_part()->array_klass_or_null();
+      Klass* elem_super = (Klass*) elem_supers->at(i);
+      Klass* array_super = elem_super->array_klass_or_null();
       assert(array_super != NULL, "must already have been created");
-      secondaries->obj_at_put(num_extra_slots+2+i, array_super);
+      secondaries->push(array_super);
     }
-    return secondaries();
+    return secondaries;
   }
 }
 
-bool objArrayKlass::compute_is_subtype_of(klassOop k) {
-  if (!k->klass_part()->oop_is_objArray())
+bool objArrayKlass::compute_is_subtype_of(Klass* k) {
+  if (!k->oop_is_objArray())
     return arrayKlass::compute_is_subtype_of(k);
 
   objArrayKlass* oak = objArrayKlass::cast(k);
-  return element_klass()->klass_part()->is_subtype_of(oak->element_klass());
+  return element_klass()->is_subtype_of(oak->element_klass());
 }
 
 void objArrayKlass::initialize(TRAPS) {
-  Klass::cast(bottom_klass())->initialize(THREAD);  // dispatches to either instanceKlass or typeArrayKlass
+  Klass::cast(bottom_klass())->initialize(THREAD);  // dispatches to either InstanceKlass or typeArrayKlass
 }
 
 #define ObjArrayKlass_SPECIALIZED_OOP_ITERATE(T, a, p, do_oop) \
@@ -344,7 +458,7 @@
 
 void objArrayKlass::oop_follow_contents(oop obj) {
   assert (obj->is_array(), "obj must be array");
-  objArrayOop(obj)->follow_header();
+  MarkSweep::follow_klass(obj->klass());
   if (UseCompressedOops) {
     objarray_follow_contents<narrowOop>(obj, 0);
   } else {
@@ -356,7 +470,7 @@
 void objArrayKlass::oop_follow_contents(ParCompactionManager* cm,
                                         oop obj) {
   assert(obj->is_array(), "obj must be array");
-  objArrayOop(obj)->follow_header(cm);
+  PSParallelCompact::follow_klass(cm, obj->klass());
   if (UseCompressedOops) {
     objarray_follow_contents<narrowOop>(cm, obj, 0);
   } else {
@@ -365,6 +479,12 @@
 }
 #endif // SERIALGC
 
+#define if_do_metadata_checked(closure, nv_suffix)                    \
+  /* Make sure the non-virtual and the virtual versions match. */     \
+  assert(closure->do_metadata##nv_suffix() == closure->do_metadata(), \
+      "Inconsistency in do_metadata");                                \
+  if (closure->do_metadata##nv_suffix())
+
 #define ObjArrayKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)           \
                                                                                 \
 int objArrayKlass::oop_oop_iterate##nv_suffix(oop obj,                          \
@@ -375,8 +495,8 @@
   /* Get size before changing pointers. */                                      \
   /* Don't call size() or oop_size() since that is a virtual call. */           \
   int size = a->object_size();                                                  \
-  if (closure->do_header()) {                                                   \
-    a->oop_iterate_header(closure);                                             \
+  if_do_metadata_checked(closure, nv_suffix) {                                  \
+    closure->do_klass##nv_suffix(obj->klass());                                 \
   }                                                                             \
   ObjArrayKlass_OOP_ITERATE(a, p, (closure)->do_oop##nv_suffix(p))              \
   return size;                                                                  \
@@ -393,8 +513,9 @@
   /* Get size before changing pointers. */                                      \
   /* Don't call size() or oop_size() since that is a virtual call */            \
   int size = a->object_size();                                                  \
-  if (closure->do_header()) {                                                   \
-    a->oop_iterate_header(closure, mr);                                         \
+  if_do_metadata_checked(closure, nv_suffix) {                                  \
+    /* SSS: Do we need to pass down mr here? */                                 \
+    closure->do_klass##nv_suffix(a->klass());                                   \
   }                                                                             \
   ObjArrayKlass_BOUNDED_OOP_ITERATE(                                            \
     a, p, mr.start(), mr.end(), (closure)->do_oop##nv_suffix(p))                \
@@ -419,8 +540,9 @@
     /* this might be wierd if end needs to be aligned on HeapWord boundary */   \
     HeapWord* high = (HeapWord*)((narrowOop*)a->base() + end);                  \
     MemRegion mr(low, high);                                                    \
-    if (closure->do_header()) {                                                 \
-      a->oop_iterate_header(closure, mr);                                       \
+    if_do_metadata_checked(closure, nv_suffix) {                                \
+      /* SSS: Do we need to pass down mr here? */                               \
+      closure->do_klass##nv_suffix(a->klass());                                 \
     }                                                                           \
     ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop,                    \
       a, p, low, high, (closure)->do_oop##nv_suffix(p))                         \
@@ -428,8 +550,9 @@
     HeapWord* low = start == 0 ? (HeapWord*)a : (HeapWord*)a->obj_at_addr<oop>(start);  \
     HeapWord* high = (HeapWord*)((oop*)a->base() + end);                        \
     MemRegion mr(low, high);                                                    \
-    if (closure->do_header()) {                                                 \
-      a->oop_iterate_header(closure, mr);                                       \
+    if_do_metadata_checked(closure, nv_suffix) {                                \
+      /* SSS: Do we need to pass down mr here? */                               \
+      closure->do_klass##nv_suffix(a->klass());                                 \
     }                                                                           \
     ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop,                          \
       a, p, low, high, (closure)->do_oop##nv_suffix(p))                         \
@@ -450,7 +573,7 @@
   // Get size before changing pointers.
   // Don't call size() or oop_size() since that is a virtual call.
   int size = a->object_size();
-  a->adjust_header();
+  MarkSweep::adjust_klass(a->klass());
   ObjArrayKlass_OOP_ITERATE(a, p, MarkSweep::adjust_pointer(p))
   return size;
 }
@@ -468,8 +591,10 @@
 int objArrayKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) {
   assert (obj->is_objArray(), "obj must be obj array");
   objArrayOop a = objArrayOop(obj);
+  int size = a->object_size();
+  a->update_header(cm);
   ObjArrayKlass_OOP_ITERATE(a, p, PSParallelCompact::adjust_pointer(p))
-  return a->object_size();
+  return size;
 }
 #endif // SERIALGC
 
@@ -489,8 +614,25 @@
 }
 
 
+// Printing
+
+void objArrayKlass::print_on(outputStream* st) const {
 #ifndef PRODUCT
-// Printing
+  Klass::print_on(st);
+  st->print(" - instance klass: ");
+  element_klass()->print_value_on(st);
+  st->cr();
+#endif //PRODUCT
+}
+
+void objArrayKlass::print_value_on(outputStream* st) const {
+  assert(is_klass(), "must be klass");
+
+  element_klass()->print_value_on(st);
+  st->print("[]");
+}
+
+#ifndef PRODUCT
 
 void objArrayKlass::oop_print_on(oop obj, outputStream* st) {
   arrayKlass::oop_print_on(obj, st);
@@ -535,8 +677,19 @@
   return external_name();
 }
 
+
 // Verification
 
+void objArrayKlass::verify_on(outputStream* st) {
+  arrayKlass::verify_on(st);
+  guarantee(element_klass()->is_metadata(), "should be in metaspace");
+  guarantee(element_klass()->is_klass(), "should be klass");
+  guarantee(bottom_klass()->is_metadata(), "should be in metaspace");
+  guarantee(bottom_klass()->is_klass(), "should be klass");
+  Klass* bk = Klass::cast(bottom_klass());
+  guarantee(bk->oop_is_instance() || bk->oop_is_typeArray(),  "invalid bottom klass");
+}
+
 void objArrayKlass::oop_verify_on(oop obj, outputStream* st) {
   arrayKlass::oop_verify_on(obj, st);
   guarantee(obj->is_objArray(), "must be objArray");