Set array length before fence in allocation code path.

Could not delete SetLength since it is required by
space_test.

Bug: 11747779

Change-Id: Icf1ead216b6ff1b519240ab0d0ca30d68429d5b6
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index fcc07a0..9b28555 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -32,10 +32,11 @@
 namespace art {
 namespace gc {
 
-template <const bool kInstrumented>
-inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, mirror::Class* c,
-                                                      size_t byte_count, AllocatorType allocator) {
-  DebugCheckPreconditionsForAllocObject(c, byte_count);
+template <bool kInstrumented, typename PreFenceVisitor>
+inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, mirror::Class* klass,
+                                                      size_t byte_count, AllocatorType allocator,
+                                                      const PreFenceVisitor& pre_fence_visitor) {
+  DebugCheckPreconditionsForAllocObject(klass, byte_count);
   // Since allocation can cause a GC which will need to SuspendAll, make sure all allocations are
   // done in the runnable state where suspension is expected.
   DCHECK_EQ(self->GetState(), kRunnable);
@@ -43,7 +44,7 @@
   mirror::Object* obj;
   size_t bytes_allocated;
   AllocationTimer alloc_timer(this, &obj);
-  if (UNLIKELY(ShouldAllocLargeObject(c, byte_count))) {
+  if (UNLIKELY(ShouldAllocLargeObject(klass, byte_count))) {
     obj = TryToAllocate<kInstrumented>(self, kAllocatorTypeLOS, byte_count, false,
                                        &bytes_allocated);
     allocator = kAllocatorTypeLOS;
@@ -52,16 +53,16 @@
   }
 
   if (UNLIKELY(obj == nullptr)) {
-    SirtRef<mirror::Class> sirt_c(self, c);
+    SirtRef<mirror::Class> sirt_c(self, klass);
     obj = AllocateInternalWithGc(self, allocator, byte_count, &bytes_allocated);
     if (obj == nullptr) {
       return nullptr;
     } else {
-      c = sirt_c.get();
+      klass = sirt_c.get();
     }
   }
-  obj->SetClass(c);
-  // TODO: Set array length here.
+  obj->SetClass(klass);
+  pre_fence_visitor(obj);
   DCHECK_GT(bytes_allocated, 0u);
   const size_t new_num_bytes_allocated =
       static_cast<size_t>(num_bytes_allocated_.fetch_add(bytes_allocated)) + bytes_allocated;
@@ -87,7 +88,7 @@
   }
   if (kInstrumented) {
     if (Dbg::IsAllocTrackingEnabled()) {
-      Dbg::RecordAllocation(c, bytes_allocated);
+      Dbg::RecordAllocation(klass, bytes_allocated);
     }
   } else {
     DCHECK(!Dbg::IsAllocTrackingEnabled());
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 5a0372a..470bacd 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -162,9 +162,10 @@
     return AllocObjectWithAllocator<kInstrumented>(self, klass, num_bytes,
                                                    GetCurrentNonMovingAllocator());
   }
-  template <bool kInstrumented>
-  ALWAYS_INLINE mirror::Object* AllocObjectWithAllocator(Thread* self, mirror::Class* klass,
-                                                         size_t num_bytes, AllocatorType allocator)
+  template <bool kInstrumented, typename PreFenceVisitor = VoidFunctor>
+  ALWAYS_INLINE mirror::Object* AllocObjectWithAllocator(
+      Thread* self, mirror::Class* klass, size_t byte_count, AllocatorType allocator,
+      const PreFenceVisitor& pre_fence_visitor = VoidFunctor())
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   AllocatorType GetCurrentAllocator() const {
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index 2955faa..46ffaae 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -58,13 +58,20 @@
   return size;
 }
 
-static inline Array* SetArrayLength(Array* array, size_t length) {
-  if (LIKELY(array != nullptr)) {
-    DCHECK(array->IsArrayInstance());
-    array->SetLength(length);
+class SetLengthVisitor {
+ public:
+  explicit SetLengthVisitor(int32_t length) : length_(length) {
   }
-  return array;
-}
+
+  void operator()(mirror::Object* obj) const {
+    mirror::Array* array = obj->AsArray();
+    DCHECK(array->IsArrayInstance());
+    array->SetLength(length_);
+  }
+
+ private:
+  const int32_t length_;
+};
 
 template <bool kIsInstrumented>
 inline Array* Array::Alloc(Thread* self, Class* array_class, int32_t component_count,
@@ -74,9 +81,10 @@
     return nullptr;
   }
   gc::Heap* heap = Runtime::Current()->GetHeap();
-  Array* array = down_cast<Array*>(
-      heap->AllocObjectWithAllocator<kIsInstrumented>(self, array_class, size, allocator_type));
-  return SetArrayLength(array, component_count);
+  SetLengthVisitor visitor(component_count);
+  return down_cast<Array*>(
+      heap->AllocObjectWithAllocator<kIsInstrumented>(self, array_class, size, allocator_type,
+                                                      visitor));
 }
 
 template <bool kIsInstrumented>