# HG changeset patch
# User kbarrett
# Date 1473955843 14400
#      Thu Sep 15 12:10:43 2016 -0400
# Node ID f008248d98dd625b62b5f3f5ca9b24956d33c18d
# Parent  7767224562139a10efca0575c28a62be7895d5b3
8165808: Add release barriers when allocating objects with concurrent collection
Summary: Add release_set_klass, use in slow-path allocators.
Reviewed-by: jmasa, dholmes

diff --git a/src/share/vm/gc_interface/collectedHeap.hpp b/src/share/vm/gc_interface/collectedHeap.hpp
--- a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp
+++ b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp
@@ -320,9 +320,6 @@
   inline static oop array_allocate(KlassHandle klass, int size, int length, TRAPS);
   inline static oop array_allocate_nozero(KlassHandle klass, int size, int length, TRAPS);
 
-  inline static void post_allocation_install_obj_klass(KlassHandle klass,
-                                                       oop obj);
-
   // Raw memory allocation facilities
   // The obj and array allocate methods are covers for these methods.
   // mem_allocate() should never be
diff --git a/src/share/vm/gc_interface/collectedHeap.inline.hpp b/src/share/vm/gc_interface/collectedHeap.inline.hpp
--- a/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp
+++ b/hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp
@@ -39,14 +39,22 @@
 // Inline allocation implementations.
 
 void CollectedHeap::post_allocation_setup_common(KlassHandle klass,
-                                                 HeapWord* obj) {
-  post_allocation_setup_no_klass_install(klass, obj);
-  post_allocation_install_obj_klass(klass, oop(obj));
+                                                 HeapWord* obj_ptr) {
+  post_allocation_setup_no_klass_install(klass, obj_ptr);
+  oop obj = (oop)obj_ptr;
+#if ! INCLUDE_ALL_GCS
+  obj->set_klass(klass());
+#else
+  // Need a release store to ensure array/class length, mark word, and
+  // object zeroing are visible before setting the klass non-NULL, for
+  // concurrent collectors.
+  obj->release_set_klass(klass());
+#endif
 }
 
 void CollectedHeap::post_allocation_setup_no_klass_install(KlassHandle klass,
-                                                           HeapWord* objPtr) {
-  oop obj = (oop)objPtr;
+                                                           HeapWord* obj_ptr) {
+  oop obj = (oop)obj_ptr;
 
   assert(obj != NULL, "NULL object pointer");
   if (UseBiasedLocking && (klass() != NULL)) {
@@ -57,18 +65,6 @@
   }
 }
 
-void CollectedHeap::post_allocation_install_obj_klass(KlassHandle klass,
-                                                   oop obj) {
-  // These asserts are kind of complicated because of klassKlass
-  // and the beginning of the world.
-  assert(klass() != NULL || !Universe::is_fully_initialized(), "NULL klass");
-  assert(klass() == NULL || klass()->is_klass(), "not a klass");
-  assert(obj != NULL, "NULL object pointer");
-  obj->set_klass(klass());
-  assert(!Universe::is_fully_initialized() || obj->klass() != NULL,
-         "missing klass");
-}
-
 // Support for jvmti and dtrace
 inline void post_allocation_notify(KlassHandle klass, oop obj, int size) {
   // support low memory notifications (no-op if not enabled)
@@ -86,25 +82,26 @@
 }
 
 void CollectedHeap::post_allocation_setup_obj(KlassHandle klass,
-                                              HeapWord* obj,
+                                              HeapWord* obj_ptr,
                                               int size) {
-  post_allocation_setup_common(klass, obj);
+  post_allocation_setup_common(klass, obj_ptr);
+  oop obj = (oop)obj_ptr;
   assert(Universe::is_bootstrapping() ||
-         !((oop)obj)->is_array(), "must not be an array");
+         !obj->is_array(), "must not be an array");
   // notify jvmti and dtrace
-  post_allocation_notify(klass, (oop)obj, size);
+  post_allocation_notify(klass, obj, size);
 }
 
 void CollectedHeap::post_allocation_setup_array(KlassHandle klass,
-                                                HeapWord* obj,
+                                                HeapWord* obj_ptr,
                                                 int length) {
-  // Set array length before setting the _klass field
-  // in post_allocation_setup_common() because the klass field
-  // indicates that the object is parsable by concurrent GC.
+  // Set array length before setting the _klass field because a
+  // non-NULL klass field indicates that the object is parsable by
+  // concurrent GC.
   assert(length >= 0, "length should be non-negative");
-  ((arrayOop)obj)->set_length(length);
-  post_allocation_setup_common(klass, obj);
-  oop new_obj = (oop)obj;
+  ((arrayOop)obj_ptr)->set_length(length);
+  post_allocation_setup_common(klass, obj_ptr);
+  oop new_obj = (oop)obj_ptr;
   assert(new_obj->is_array(), "must be an array");
   // notify jvmti and dtrace (must be after length is set for dtrace)
   post_allocation_notify(klass, new_obj, new_obj->size());
diff --git a/src/share/vm/oops/oop.hpp b/src/share/vm/oops/oop.hpp
--- a/hotspot/src/share/vm/oops/oop.hpp
+++ b/hotspot/src/share/vm/oops/oop.hpp
@@ -87,6 +87,7 @@
   narrowKlass* compressed_klass_addr();
 
   void set_klass(Klass* k);
+  void release_set_klass(Klass* k);
 
   // For klass field compression
   int klass_gap() const;
diff --git a/src/share/vm/oops/oop.inline.hpp b/src/share/vm/oops/oop.inline.hpp
--- a/hotspot/src/share/vm/oops/oop.inline.hpp
+++ b/hotspot/src/share/vm/oops/oop.inline.hpp
@@ -103,10 +103,14 @@
   return &_metadata._compressed_klass;
 }
 
+#define CHECK_SET_KLASS(k)                                                \
+  do {                                                                    \
+    assert(Universe::is_bootstrapping() || k != NULL, "NULL Klass");      \
+    assert(Universe::is_bootstrapping() || k->is_klass(), "not a Klass"); \
+  } while (0)
+
 inline void oopDesc::set_klass(Klass* k) {
-  // since klasses are promoted no store check is needed
-  assert(Universe::is_bootstrapping() || k != NULL, "must be a real Klass*");
-  assert(Universe::is_bootstrapping() || k->is_klass(), "not a Klass*");
+  CHECK_SET_KLASS(k);
   if (UseCompressedClassPointers) {
     *compressed_klass_addr() = Klass::encode_klass_not_null(k);
   } else {
@@ -114,6 +118,18 @@
   }
 }
 
+inline void oopDesc::release_set_klass(Klass* k) {
+  CHECK_SET_KLASS(k);
+  if (UseCompressedClassPointers) {
+    OrderAccess::release_store(compressed_klass_addr(),
+                               Klass::encode_klass_not_null(k));
+  } else {
+    OrderAccess::release_store_ptr(klass_addr(), k);
+  }
+}
+
+#undef CHECK_SET_KLASS
+
 inline int oopDesc::klass_gap() const {
   return *(int*)(((intptr_t)this) + klass_gap_offset_in_bytes());
 }
