Guard entrypoint changing by runtime shutdown lock.

There was a race when we changed the allocation entrypoints where a
new thread would be starting (Thread::Init) and initialize to the
wrong entrypoints. Guarding allocation entrypoint changing
with the runtime shutdown lock fixes this race condition since
Thread::Init is only called with the runtime shutdown lock held.

Bug: 13250963

Change-Id: I8eb209c124b6bf17020de874e1b0083f158b8200
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 9ad21cf..89601ff 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -45,6 +45,7 @@
 #include "gc/space/rosalloc_space-inl.h"
 #include "gc/space/space-inl.h"
 #include "gc/space/zygote_space.h"
+#include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "heap-inl.h"
 #include "image.h"
 #include "invoke_arg_array_builder.h"
@@ -65,8 +66,6 @@
 
 namespace art {
 
-extern void SetQuickAllocEntryPointsAllocator(gc::AllocatorType allocator);
-
 namespace gc {
 
 static constexpr bool kGCALotMode = false;
@@ -308,11 +307,12 @@
 }
 
 void Heap::ChangeAllocator(AllocatorType allocator) {
-  // These two allocators are only used internally and don't have any entrypoints.
-  DCHECK_NE(allocator, kAllocatorTypeLOS);
-  DCHECK_NE(allocator, kAllocatorTypeNonMoving);
   if (current_allocator_ != allocator) {
+    // These two allocators are only used internally and don't have any entrypoints.
+    CHECK_NE(allocator, kAllocatorTypeLOS);
+    CHECK_NE(allocator, kAllocatorTypeNonMoving);
     current_allocator_ = allocator;
+    MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_);
     SetQuickAllocEntryPointsAllocator(current_allocator_);
     Runtime::Current()->GetInstrumentation()->ResetQuickAllocEntryPoints();
   }
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index b194d8d..88adf81 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -197,13 +197,16 @@
   void RegisterNativeFree(JNIEnv* env, int bytes);
 
   // Change the allocator, updates entrypoints.
-  void ChangeAllocator(AllocatorType allocator);
+  void ChangeAllocator(AllocatorType allocator)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
+      LOCKS_EXCLUDED(Locks::runtime_shutdown_lock_);
 
   // Transition the garbage collector during runtime, may copy objects from one space to another.
   void TransitionCollector(CollectorType collector_type);
 
   // Change the collector to be one of the possible options (MS, CMS, SS).
-  void ChangeCollector(CollectorType collector_type);
+  void ChangeCollector(CollectorType collector_type)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // The given reference is believed to be to an object in the Java heap, check the soundness of it.
   // TODO: NO_THREAD_SAFETY_ANALYSIS since we call this everywhere and it is impossible to find a
@@ -465,7 +468,8 @@
 
   // Revoke all the thread-local allocation stacks.
   void RevokeAllThreadLocalAllocationStacks(Thread* self)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
+      LOCKS_EXCLUDED(Locks::runtime_shutdown_lock_, Locks::thread_list_lock_);
 
   // Mark all the objects in the allocation stack in the specified bitmap.
   void MarkAllocStack(accounting::SpaceBitmap* bitmap1, accounting::SpaceBitmap* bitmap2,