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/Android.mk b/runtime/Android.mk
index 7a2fab9..fd9dc4c 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -154,7 +154,6 @@
 	arch/arm/registers_arm.cc \
 	arch/x86/registers_x86.cc \
 	arch/mips/registers_mips.cc \
-	arch/quick_alloc_entrypoints.cc \
 	entrypoints/entrypoint_utils.cc \
 	entrypoints/interpreter/interpreter_entrypoints.cc \
 	entrypoints/jni/jni_entrypoints.cc \
diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc
index fc85ae3..23e3433 100644
--- a/runtime/arch/arm/entrypoints_init_arm.cc
+++ b/runtime/arch/arm/entrypoints_init_arm.cc
@@ -16,6 +16,7 @@
 
 #include "entrypoints/interpreter/interpreter_entrypoints.h"
 #include "entrypoints/portable/portable_entrypoints.h"
+#include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "entrypoints/entrypoint_utils.h"
 #include "entrypoints/math_entrypoints.h"
@@ -130,8 +131,6 @@
 // Generic JNI downcall
 extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
 
-extern void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints);
-
 void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
                      PortableEntryPoints* ppoints, QuickEntryPoints* qpoints) {
   // Interpreter
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index 41d79c2..500a2eb 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -15,6 +15,7 @@
  */
 
 #include "entrypoints/portable/portable_entrypoints.h"
+#include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "entrypoints/entrypoint_utils.h"
 #include "entrypoints/math_entrypoints.h"
diff --git a/runtime/arch/quick_alloc_entrypoints.cc b/runtime/arch/quick_alloc_entrypoints.cc
deleted file mode 100644
index 9363f81..0000000
--- a/runtime/arch/quick_alloc_entrypoints.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "entrypoints/quick/quick_entrypoints.h"
-#include "gc/heap.h"
-
-#define GENERATE_ENTRYPOINTS(suffix) \
-extern "C" void* art_quick_alloc_array##suffix(uint32_t, void*, int32_t); \
-extern "C" void* art_quick_alloc_array_resolved##suffix(void* klass, void*, int32_t); \
-extern "C" void* art_quick_alloc_array_with_access_check##suffix(uint32_t, void*, int32_t); \
-extern "C" void* art_quick_alloc_object##suffix(uint32_t type_idx, void* method); \
-extern "C" void* art_quick_alloc_object_resolved##suffix(void* klass, void* method); \
-extern "C" void* art_quick_alloc_object_initialized##suffix(void* klass, void* method); \
-extern "C" void* art_quick_alloc_object_with_access_check##suffix(uint32_t type_idx, void* method); \
-extern "C" void* art_quick_check_and_alloc_array##suffix(uint32_t, void*, int32_t); \
-extern "C" void* art_quick_check_and_alloc_array_with_access_check##suffix(uint32_t, void*, int32_t); \
-extern "C" void* art_quick_alloc_array##suffix##_instrumented(uint32_t, void*, int32_t); \
-extern "C" void* art_quick_alloc_array_resolved##suffix##_instrumented(void* klass, void*, int32_t); \
-extern "C" void* art_quick_alloc_array_with_access_check##suffix##_instrumented(uint32_t, void*, int32_t); \
-extern "C" void* art_quick_alloc_object##suffix##_instrumented(uint32_t type_idx, void* method); \
-extern "C" void* art_quick_alloc_object_resolved##suffix##_instrumented(void* klass, void* method); \
-extern "C" void* art_quick_alloc_object_initialized##suffix##_instrumented(void* klass, void* method); \
-extern "C" void* art_quick_alloc_object_with_access_check##suffix##_instrumented(uint32_t type_idx, void* method); \
-extern "C" void* art_quick_check_and_alloc_array##suffix##_instrumented(uint32_t, void*, int32_t); \
-extern "C" void* art_quick_check_and_alloc_array_with_access_check##suffix##_instrumented(uint32_t, void*, int32_t); \
-void SetQuickAllocEntryPoints##suffix(QuickEntryPoints* qpoints, bool instrumented) { \
-  if (instrumented) { \
-    qpoints->pAllocArray = art_quick_alloc_array##suffix##_instrumented; \
-    qpoints->pAllocArrayResolved = art_quick_alloc_array_resolved##suffix##_instrumented; \
-    qpoints->pAllocArrayWithAccessCheck = art_quick_alloc_array_with_access_check##suffix##_instrumented; \
-    qpoints->pAllocObject = art_quick_alloc_object##suffix##_instrumented; \
-    qpoints->pAllocObjectResolved = art_quick_alloc_object_resolved##suffix##_instrumented; \
-    qpoints->pAllocObjectInitialized = art_quick_alloc_object_initialized##suffix##_instrumented; \
-    qpoints->pAllocObjectWithAccessCheck = art_quick_alloc_object_with_access_check##suffix##_instrumented; \
-    qpoints->pCheckAndAllocArray = art_quick_check_and_alloc_array##suffix##_instrumented; \
-    qpoints->pCheckAndAllocArrayWithAccessCheck = art_quick_check_and_alloc_array_with_access_check##suffix##_instrumented; \
-  } else { \
-    qpoints->pAllocArray = art_quick_alloc_array##suffix; \
-    qpoints->pAllocArrayResolved = art_quick_alloc_array_resolved##suffix; \
-    qpoints->pAllocArrayWithAccessCheck = art_quick_alloc_array_with_access_check##suffix; \
-    qpoints->pAllocObject = art_quick_alloc_object##suffix; \
-    qpoints->pAllocObjectResolved = art_quick_alloc_object_resolved##suffix; \
-    qpoints->pAllocObjectInitialized = art_quick_alloc_object_initialized##suffix; \
-    qpoints->pAllocObjectWithAccessCheck = art_quick_alloc_object_with_access_check##suffix; \
-    qpoints->pCheckAndAllocArray = art_quick_check_and_alloc_array##suffix; \
-    qpoints->pCheckAndAllocArrayWithAccessCheck = art_quick_check_and_alloc_array_with_access_check##suffix; \
-  } \
-}
-
-namespace art {
-
-// Generate the entrypoint functions.
-GENERATE_ENTRYPOINTS(_dlmalloc);
-GENERATE_ENTRYPOINTS(_rosalloc);
-GENERATE_ENTRYPOINTS(_bump_pointer);
-GENERATE_ENTRYPOINTS(_tlab);
-
-static bool entry_points_instrumented = false;
-static gc::AllocatorType entry_points_allocator = gc::kAllocatorTypeDlMalloc;
-
-void SetQuickAllocEntryPointsAllocator(gc::AllocatorType allocator) {
-  entry_points_allocator = allocator;
-}
-
-void SetQuickAllocEntryPointsInstrumented(bool instrumented) {
-  entry_points_instrumented = instrumented;
-}
-
-void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints) {
-  switch (entry_points_allocator) {
-    case gc::kAllocatorTypeDlMalloc: {
-      SetQuickAllocEntryPoints_dlmalloc(qpoints, entry_points_instrumented);
-      break;
-    }
-    case gc::kAllocatorTypeRosAlloc: {
-      SetQuickAllocEntryPoints_rosalloc(qpoints, entry_points_instrumented);
-      break;
-    }
-    case gc::kAllocatorTypeBumpPointer: {
-      CHECK(kMovingCollector);
-      SetQuickAllocEntryPoints_bump_pointer(qpoints, entry_points_instrumented);
-      break;
-    }
-    case gc::kAllocatorTypeTLAB: {
-      CHECK(kMovingCollector);
-      SetQuickAllocEntryPoints_tlab(qpoints, entry_points_instrumented);
-      break;
-    }
-    default: {
-      LOG(FATAL) << "Unimplemented";
-    }
-  }
-}
-
-}  // namespace art
diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc
index 763cbde..c4a7b1b 100644
--- a/runtime/arch/x86/entrypoints_init_x86.cc
+++ b/runtime/arch/x86/entrypoints_init_x86.cc
@@ -15,6 +15,7 @@
  */
 
 #include "entrypoints/portable/portable_entrypoints.h"
+#include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "entrypoints/entrypoint_utils.h"
 
diff --git a/runtime/arch/x86_64/entrypoints_init_x86_64.cc b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
index fe298c8..30067cf 100644
--- a/runtime/arch/x86_64/entrypoints_init_x86_64.cc
+++ b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
@@ -15,6 +15,7 @@
  */
 
 #include "entrypoints/portable/portable_entrypoints.h"
+#include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "entrypoints/entrypoint_utils.h"
 
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
index 2e1b69d..ccc0f3d 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "entrypoints/quick/quick_alloc_entrypoints.h"
+
 #include "callee_save_frame.h"
 #include "entrypoints/entrypoint_utils.h"
 #include "mirror/art_method-inl.h"
@@ -104,4 +106,90 @@
 GENERATE_ENTRYPOINTS_FOR_ALLOCATOR(BumpPointer, gc::kAllocatorTypeBumpPointer)
 GENERATE_ENTRYPOINTS_FOR_ALLOCATOR(TLAB, gc::kAllocatorTypeTLAB)
 
+#define GENERATE_ENTRYPOINTS(suffix) \
+extern "C" void* art_quick_alloc_array##suffix(uint32_t, void*, int32_t); \
+extern "C" void* art_quick_alloc_array_resolved##suffix(void* klass, void*, int32_t); \
+extern "C" void* art_quick_alloc_array_with_access_check##suffix(uint32_t, void*, int32_t); \
+extern "C" void* art_quick_alloc_object##suffix(uint32_t type_idx, void* method); \
+extern "C" void* art_quick_alloc_object_resolved##suffix(void* klass, void* method); \
+extern "C" void* art_quick_alloc_object_initialized##suffix(void* klass, void* method); \
+extern "C" void* art_quick_alloc_object_with_access_check##suffix(uint32_t type_idx, void* method); \
+extern "C" void* art_quick_check_and_alloc_array##suffix(uint32_t, void*, int32_t); \
+extern "C" void* art_quick_check_and_alloc_array_with_access_check##suffix(uint32_t, void*, int32_t); \
+extern "C" void* art_quick_alloc_array##suffix##_instrumented(uint32_t, void*, int32_t); \
+extern "C" void* art_quick_alloc_array_resolved##suffix##_instrumented(void* klass, void*, int32_t); \
+extern "C" void* art_quick_alloc_array_with_access_check##suffix##_instrumented(uint32_t, void*, int32_t); \
+extern "C" void* art_quick_alloc_object##suffix##_instrumented(uint32_t type_idx, void* method); \
+extern "C" void* art_quick_alloc_object_resolved##suffix##_instrumented(void* klass, void* method); \
+extern "C" void* art_quick_alloc_object_initialized##suffix##_instrumented(void* klass, void* method); \
+extern "C" void* art_quick_alloc_object_with_access_check##suffix##_instrumented(uint32_t type_idx, void* method); \
+extern "C" void* art_quick_check_and_alloc_array##suffix##_instrumented(uint32_t, void*, int32_t); \
+extern "C" void* art_quick_check_and_alloc_array_with_access_check##suffix##_instrumented(uint32_t, void*, int32_t); \
+void SetQuickAllocEntryPoints##suffix(QuickEntryPoints* qpoints, bool instrumented) { \
+  if (instrumented) { \
+    qpoints->pAllocArray = art_quick_alloc_array##suffix##_instrumented; \
+    qpoints->pAllocArrayResolved = art_quick_alloc_array_resolved##suffix##_instrumented; \
+    qpoints->pAllocArrayWithAccessCheck = art_quick_alloc_array_with_access_check##suffix##_instrumented; \
+    qpoints->pAllocObject = art_quick_alloc_object##suffix##_instrumented; \
+    qpoints->pAllocObjectResolved = art_quick_alloc_object_resolved##suffix##_instrumented; \
+    qpoints->pAllocObjectInitialized = art_quick_alloc_object_initialized##suffix##_instrumented; \
+    qpoints->pAllocObjectWithAccessCheck = art_quick_alloc_object_with_access_check##suffix##_instrumented; \
+    qpoints->pCheckAndAllocArray = art_quick_check_and_alloc_array##suffix##_instrumented; \
+    qpoints->pCheckAndAllocArrayWithAccessCheck = art_quick_check_and_alloc_array_with_access_check##suffix##_instrumented; \
+  } else { \
+    qpoints->pAllocArray = art_quick_alloc_array##suffix; \
+    qpoints->pAllocArrayResolved = art_quick_alloc_array_resolved##suffix; \
+    qpoints->pAllocArrayWithAccessCheck = art_quick_alloc_array_with_access_check##suffix; \
+    qpoints->pAllocObject = art_quick_alloc_object##suffix; \
+    qpoints->pAllocObjectResolved = art_quick_alloc_object_resolved##suffix; \
+    qpoints->pAllocObjectInitialized = art_quick_alloc_object_initialized##suffix; \
+    qpoints->pAllocObjectWithAccessCheck = art_quick_alloc_object_with_access_check##suffix; \
+    qpoints->pCheckAndAllocArray = art_quick_check_and_alloc_array##suffix; \
+    qpoints->pCheckAndAllocArrayWithAccessCheck = art_quick_check_and_alloc_array_with_access_check##suffix; \
+  } \
+}
+
+// Generate the entrypoint functions.
+GENERATE_ENTRYPOINTS(_dlmalloc);
+GENERATE_ENTRYPOINTS(_rosalloc);
+GENERATE_ENTRYPOINTS(_bump_pointer);
+GENERATE_ENTRYPOINTS(_tlab);
+
+static bool entry_points_instrumented = false;
+static gc::AllocatorType entry_points_allocator = gc::kAllocatorTypeDlMalloc;
+
+void SetQuickAllocEntryPointsAllocator(gc::AllocatorType allocator) {
+  entry_points_allocator = allocator;
+}
+
+void SetQuickAllocEntryPointsInstrumented(bool instrumented) {
+  entry_points_instrumented = instrumented;
+}
+
+void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints) {
+  switch (entry_points_allocator) {
+    case gc::kAllocatorTypeDlMalloc: {
+      SetQuickAllocEntryPoints_dlmalloc(qpoints, entry_points_instrumented);
+      break;
+    }
+    case gc::kAllocatorTypeRosAlloc: {
+      SetQuickAllocEntryPoints_rosalloc(qpoints, entry_points_instrumented);
+      break;
+    }
+    case gc::kAllocatorTypeBumpPointer: {
+      CHECK(kMovingCollector);
+      SetQuickAllocEntryPoints_bump_pointer(qpoints, entry_points_instrumented);
+      break;
+    }
+    case gc::kAllocatorTypeTLAB: {
+      CHECK(kMovingCollector);
+      SetQuickAllocEntryPoints_tlab(qpoints, entry_points_instrumented);
+      break;
+    }
+    default: {
+      LOG(FATAL) << "Unimplemented";
+    }
+  }
+}
+
 }  // namespace art
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.h b/runtime/entrypoints/quick/quick_alloc_entrypoints.h
new file mode 100644
index 0000000..7fd3fe9
--- /dev/null
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_ALLOC_ENTRYPOINTS_H_
+#define ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_ALLOC_ENTRYPOINTS_H_
+
+#include "gc/heap.h"
+#include "quick_entrypoints.h"
+
+namespace art {
+
+namespace gc {
+enum AllocatorType;
+}  // namespace gc
+
+void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints);
+
+// Runtime shutdown lock is necessary to prevent races in thread initialization. When the thread is
+// starting it doesn't hold the mutator lock until after it has been added to the thread list.
+// However, Thread::Init is guarded by the runtime shutdown lock, so we can prevent these races by
+// holding the runtime shutdown lock and the mutator lock when we update the entrypoints.
+
+void SetQuickAllocEntryPointsAllocator(gc::AllocatorType allocator)
+    EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::runtime_shutdown_lock_);
+
+void SetQuickAllocEntryPointsInstrumented(bool instrumented)
+    EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::runtime_shutdown_lock_);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_ALLOC_ENTRYPOINTS_H_
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,
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 01ad46d..e10d881 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -23,6 +23,7 @@
 #include "class_linker.h"
 #include "debugger.h"
 #include "dex_file-inl.h"
+#include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "interpreter/interpreter.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
@@ -41,8 +42,6 @@
 
 namespace art {
 
-extern void SetQuickAllocEntryPointsInstrumented(bool instrumented);
-
 namespace instrumentation {
 
 const bool kVerboseInstrumentation = false;
@@ -466,10 +465,13 @@
       quick_alloc_entry_points_instrumentation_counter_.FetchAndAdd(1) == 0;
   if (enable_instrumentation) {
     // Instrumentation wasn't enabled so enable it.
-    SetQuickAllocEntryPointsInstrumented(true);
     ThreadList* tl = Runtime::Current()->GetThreadList();
     tl->SuspendAll();
-    ResetQuickAllocEntryPoints();
+    {
+      MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_);
+      SetQuickAllocEntryPointsInstrumented(true);
+      ResetQuickAllocEntryPoints();
+    }
     tl->ResumeAll();
   }
 }
@@ -481,10 +483,13 @@
   const bool disable_instrumentation =
       quick_alloc_entry_points_instrumentation_counter_.FetchAndSub(1) == 1;
   if (disable_instrumentation) {
-    SetQuickAllocEntryPointsInstrumented(false);
     ThreadList* tl = Runtime::Current()->GetThreadList();
     tl->SuspendAll();
-    ResetQuickAllocEntryPoints();
+    {
+      MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_);
+      SetQuickAllocEntryPointsInstrumented(false);
+      ResetQuickAllocEntryPoints();
+    }
     tl->ResumeAll();
   }
 }
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index 017573a..d7a0b4d 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -167,9 +167,11 @@
     return interpreter_handler_table_;
   }
 
-  void InstrumentQuickAllocEntryPoints() LOCKS_EXCLUDED(Locks::thread_list_lock_);
-  void UninstrumentQuickAllocEntryPoints() LOCKS_EXCLUDED(Locks::thread_list_lock_);
-  void ResetQuickAllocEntryPoints();
+  void InstrumentQuickAllocEntryPoints() LOCKS_EXCLUDED(Locks::thread_list_lock_,
+                                                        Locks::runtime_shutdown_lock_);
+  void UninstrumentQuickAllocEntryPoints() LOCKS_EXCLUDED(Locks::thread_list_lock_,
+                                                          Locks::runtime_shutdown_lock_);
+  void ResetQuickAllocEntryPoints() EXCLUSIVE_LOCKS_REQUIRED(Locks::runtime_shutdown_lock_);
 
   // Update the code of a method respecting any installed stubs.
   void UpdateMethodsCode(mirror::ArtMethod* method, const void* quick_code,
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 3862ae2..f843ae5 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -40,6 +40,7 @@
 #include "debugger.h"
 #include "dex_file-inl.h"
 #include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "gc_map.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/heap.h"
@@ -109,8 +110,6 @@
                   &quick_entrypoints_);
 }
 
-void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints);
-
 void Thread::ResetQuickAllocEntryPointsForThread() {
   ResetQuickAllocEntryPoints(&quick_entrypoints_);
 }