Add uninterruptible role

Example error:
cannot call function 'CopyOf' while mutex 'uninterruptible_' is held

TODO: Add annotation to more locations.

Bug: 20072211

Change-Id: I1bbf5a77e3deeafa5898df529cb7cb53a6d010d2
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 6f82f28..d0504d9 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -471,11 +471,11 @@
 // upon destruction.
 class SCOPED_CAPABILITY MutexLock {
  public:
-  explicit MutexLock(Thread* self, Mutex& mu) EXCLUSIVE_LOCK_FUNCTION(mu) : self_(self), mu_(mu) {
+  explicit MutexLock(Thread* self, Mutex& mu) ACQUIRE(mu) : self_(self), mu_(mu) {
     mu_.ExclusiveLock(self_);
   }
 
-  ~MutexLock() UNLOCK_FUNCTION() {
+  ~MutexLock() RELEASE() {
     mu_.ExclusiveUnlock(self_);
   }
 
@@ -491,12 +491,12 @@
 // construction and releases it upon destruction.
 class SCOPED_CAPABILITY ReaderMutexLock {
  public:
-  explicit ReaderMutexLock(Thread* self, ReaderWriterMutex& mu) EXCLUSIVE_LOCK_FUNCTION(mu) :
+  explicit ReaderMutexLock(Thread* self, ReaderWriterMutex& mu) ACQUIRE(mu) :
       self_(self), mu_(mu) {
     mu_.SharedLock(self_);
   }
 
-  ~ReaderMutexLock() UNLOCK_FUNCTION() {
+  ~ReaderMutexLock() RELEASE() {
     mu_.SharedUnlock(self_);
   }
 
@@ -531,6 +531,17 @@
 // "WriterMutexLock mu(lock)".
 #define WriterMutexLock(x) static_assert(0, "WriterMutexLock declaration missing variable name")
 
+// For StartNoThreadSuspension and EndNoThreadSuspension.
+class CAPABILITY("role") Role {
+ public:
+  void Acquire() ACQUIRE() {}
+  void Release() RELEASE() {}
+  const Role& operator!() const { return *this; }
+};
+
+class Uninterruptible : public Role {
+};
+
 // Global mutexes corresponding to the levels above.
 class Locks {
  public:
@@ -666,6 +677,11 @@
   static Mutex* lambda_table_lock_ ACQUIRED_AFTER(mutator_lock_);
 };
 
+class Roles {
+ public:
+  static Uninterruptible uninterruptible_;
+};
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_BASE_MUTEX_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index e0be5af..fc59d50 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3447,8 +3447,7 @@
   return DotToDescriptor(name->ToModifiedUtf8().c_str());
 }
 
-ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class,
-                                                   ArtMethod* proxy_method) {
+ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class, ArtMethod* proxy_method) {
   DCHECK(proxy_class->IsProxyClass());
   DCHECK(proxy_method->IsProxyMethod());
   {
@@ -4984,6 +4983,7 @@
         self, old_virtuals, old_method_count * method_size, new_method_count * method_size));
     if (UNLIKELY(virtuals == nullptr)) {
       self->AssertPendingOOMException();
+      self->EndAssertNoThreadSuspension(old_cause);
       return false;
     }
     ScopedArenaUnorderedMap<ArtMethod*, ArtMethod*> move_table(allocator.Adapter());
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 0239b64..05a809e 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -195,16 +195,16 @@
   // result in the DexCache. The referrer is used to identity the
   // target DexCache and ClassLoader to use for resolution.
   mirror::Class* ResolveType(const DexFile& dex_file, uint16_t type_idx, mirror::Class* referrer)
-      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
   // Resolve a Type with the given index from the DexFile, storing the
   // result in the DexCache. The referrer is used to identify the
   // target DexCache and ClassLoader to use for resolution.
   mirror::Class* ResolveType(uint16_t type_idx, ArtMethod* referrer)
-      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
   mirror::Class* ResolveType(uint16_t type_idx, ArtField* referrer)
-      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
   // Resolve a type with the given ID from the DexFile, storing the
   // result in DexCache. The ClassLoader is used to search for the
@@ -213,7 +213,7 @@
   mirror::Class* ResolveType(const DexFile& dex_file, uint16_t type_idx,
                              Handle<mirror::DexCache> dex_cache,
                              Handle<mirror::ClassLoader> class_loader)
-      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
   // Resolve a method with a given ID from the DexFile, storing the
   // result in DexCache. The ClassLinker and ClassLoader are used as
@@ -224,19 +224,19 @@
                            Handle<mirror::DexCache> dex_cache,
                            Handle<mirror::ClassLoader> class_loader, ArtMethod* referrer,
                            InvokeType type)
-      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
   ArtMethod* GetResolvedMethod(uint32_t method_idx, ArtMethod* referrer)
       SHARED_REQUIRES(Locks::mutator_lock_);
   ArtMethod* ResolveMethod(Thread* self, uint32_t method_idx, ArtMethod* referrer, InvokeType type)
-      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
   ArtField* GetResolvedField(uint32_t field_idx, mirror::Class* field_declaring_class)
       SHARED_REQUIRES(Locks::mutator_lock_);
   ArtField* GetResolvedField(uint32_t field_idx, mirror::DexCache* dex_cache)
       SHARED_REQUIRES(Locks::mutator_lock_);
   ArtField* ResolveField(uint32_t field_idx, ArtMethod* referrer, bool is_static)
-      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
   // Resolve a field with a given ID from the DexFile, storing the
   // result in DexCache. The ClassLinker and ClassLoader are used as
@@ -246,7 +246,7 @@
   ArtField* ResolveField(const DexFile& dex_file, uint32_t field_idx,
                          Handle<mirror::DexCache> dex_cache,
                          Handle<mirror::ClassLoader> class_loader, bool is_static)
-      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
   // Resolve a field with a given ID from the DexFile, storing the
   // result in DexCache. The ClassLinker and ClassLoader are used as
@@ -255,7 +255,7 @@
   ArtField* ResolveFieldJLS(const DexFile& dex_file, uint32_t field_idx,
                             Handle<mirror::DexCache> dex_cache,
                             Handle<mirror::ClassLoader> class_loader)
-      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
   // Get shorty from method index without resolution. Used to do handlerization.
   const char* MethodShorty(uint32_t method_idx, ArtMethod* referrer, uint32_t* length)
@@ -266,11 +266,12 @@
   // given the restriction that no <clinit> execution is possible.
   bool EnsureInitialized(Thread* self, Handle<mirror::Class> c, bool can_init_fields,
                          bool can_init_parents)
-      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
   // Initializes classes that have instances in the image but that have
   // <clinit> methods so they could not be initialized by the compiler.
-  void RunRootClinits() SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+  void RunRootClinits() SHARED_REQUIRES(Locks::mutator_lock_)
+      REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
   void RegisterDexFile(const DexFile& dex_file)
       REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
@@ -330,33 +331,33 @@
       REQUIRES(!dex_lock_, !Locks::mutator_lock_);
 
   // Allocate an instance of a java.lang.Object.
-  mirror::Object* AllocObject(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::Object* AllocObject(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_)
+      REQUIRES(!Roles::uninterruptible_);
 
   // TODO: replace this with multiple methods that allocate the correct managed type.
   template <class T>
   mirror::ObjectArray<T>* AllocObjectArray(Thread* self, size_t length)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
   mirror::ObjectArray<mirror::Class>* AllocClassArray(Thread* self, size_t length)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
   mirror::ObjectArray<mirror::String>* AllocStringArray(Thread* self, size_t length)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
+
+  ArtField* AllocArtFieldArray(Thread* self, size_t length);
 
   ArtMethod* AllocArtMethodArray(Thread* self, size_t length);
 
   mirror::PointerArray* AllocPointerArray(Thread* self, size_t length)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
   mirror::IfTable* AllocIfTable(Thread* self, size_t ifcount)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
-  ArtField* AllocArtFieldArray(Thread* self, size_t length)
-      SHARED_REQUIRES(Locks::mutator_lock_);
-
-  mirror::ObjectArray<mirror::StackTraceElement>* AllocStackTraceElementArray(Thread* self,
-                                                                              size_t length)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+  mirror::ObjectArray<mirror::StackTraceElement>* AllocStackTraceElementArray(
+      Thread* self, size_t length) SHARED_REQUIRES(Locks::mutator_lock_)
+          REQUIRES(!Roles::uninterruptible_);
 
   void VerifyClass(Thread* self, Handle<mirror::Class> klass)
       SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
@@ -479,28 +480,29 @@
       REQUIRES(!dex_lock_)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
-  void FinishInit(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+  void FinishInit(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_)
+      REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
   // For early bootstrapping by Init
   mirror::Class* AllocClass(Thread* self, mirror::Class* java_lang_Class, uint32_t class_size)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
   // Alloc* convenience functions to avoid needing to pass in mirror::Class*
   // values that are known to the ClassLinker such as
   // kObjectArrayClass and kJavaLangString etc.
   mirror::Class* AllocClass(Thread* self, uint32_t class_size)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
   mirror::DexCache* AllocDexCache(Thread* self, const DexFile& dex_file)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
   mirror::Class* CreatePrimitiveClass(Thread* self, Primitive::Type type)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
   mirror::Class* InitializePrimitiveClass(mirror::Class* primitive_class, Primitive::Type type)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
   mirror::Class* CreateArrayClass(Thread* self, const char* descriptor, size_t hash,
                                   Handle<mirror::ClassLoader> class_loader)
-      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
   void AppendToBootClassPath(Thread* self, const DexFile& dex_file)
       SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 790a98c..09c18b8 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -189,7 +189,8 @@
   mirror::Object* AllocObject(Thread* self, mirror::Class* klass, size_t num_bytes,
                               const PreFenceVisitor& pre_fence_visitor)
       SHARED_REQUIRES(Locks::mutator_lock_)
-      REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !*backtrace_lock_) {
+      REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !*backtrace_lock_,
+               !Roles::uninterruptible_) {
     return AllocObjectWithAllocator<kInstrumented, true>(
         self, klass, num_bytes, GetCurrentAllocator(), pre_fence_visitor);
   }
@@ -198,7 +199,8 @@
   mirror::Object* AllocNonMovableObject(Thread* self, mirror::Class* klass, size_t num_bytes,
                                         const PreFenceVisitor& pre_fence_visitor)
       SHARED_REQUIRES(Locks::mutator_lock_)
-      REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !*backtrace_lock_) {
+      REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !*backtrace_lock_,
+               !Roles::uninterruptible_) {
     return AllocObjectWithAllocator<kInstrumented, true>(
         self, klass, num_bytes, GetCurrentNonMovingAllocator(), pre_fence_visitor);
   }
@@ -208,7 +210,8 @@
       Thread* self, mirror::Class* klass, size_t byte_count, AllocatorType allocator,
       const PreFenceVisitor& pre_fence_visitor)
       SHARED_REQUIRES(Locks::mutator_lock_)
-      REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !*backtrace_lock_);
+      REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !*backtrace_lock_,
+               !Roles::uninterruptible_);
 
   AllocatorType GetCurrentAllocator() const {
     return current_allocator_;
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 08c12e9..d21cfae 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -39,11 +39,11 @@
   template <bool kIsInstrumented, bool kFillUsable = false>
   ALWAYS_INLINE static Array* Alloc(Thread* self, Class* array_class, int32_t component_count,
                                     size_t component_size_shift, gc::AllocatorType allocator_type)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
   static Array* CreateMultiArray(Thread* self, Handle<Class> element_class,
                                  Handle<IntArray> dimensions)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
            ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
@@ -84,7 +84,8 @@
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ALWAYS_INLINE bool CheckIsValidIndex(int32_t index) SHARED_REQUIRES(Locks::mutator_lock_);
 
-  Array* CopyOf(Thread* self, int32_t new_length) SHARED_REQUIRES(Locks::mutator_lock_);
+  Array* CopyOf(Thread* self, int32_t new_length) SHARED_REQUIRES(Locks::mutator_lock_)
+      REQUIRES(!Roles::uninterruptible_);
 
  protected:
   void ThrowArrayStoreException(Object* object) SHARED_REQUIRES(Locks::mutator_lock_);
@@ -107,7 +108,7 @@
   typedef T ElementType;
 
   static PrimitiveArray<T>* Alloc(Thread* self, size_t length)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
   const T* GetData() const ALWAYS_INLINE  SHARED_REQUIRES(Locks::mutator_lock_) {
     return reinterpret_cast<const T*>(GetRawData(sizeof(T), 0));
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index be87dee..f1eb9be 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -479,12 +479,12 @@
   // Creates a raw object instance but does not invoke the default constructor.
   template<bool kIsInstrumented, bool kCheckAddFinalizer = true>
   ALWAYS_INLINE Object* Alloc(Thread* self, gc::AllocatorType allocator_type)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
   Object* AllocObject(Thread* self)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
   Object* AllocNonMovableObject(Thread* self)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
            ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 8b541fd..eea9f37 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -112,7 +112,8 @@
            ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   size_t SizeOf() SHARED_REQUIRES(Locks::mutator_lock_);
 
-  Object* Clone(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_);
+  Object* Clone(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_)
+      REQUIRES(!Roles::uninterruptible_);
 
   int32_t IdentityHashCode() const
       SHARED_REQUIRES(Locks::mutator_lock_)
diff --git a/runtime/mirror/object_array.h b/runtime/mirror/object_array.h
index cee17e9..607b000 100644
--- a/runtime/mirror/object_array.h
+++ b/runtime/mirror/object_array.h
@@ -32,10 +32,10 @@
 
   static ObjectArray<T>* Alloc(Thread* self, Class* object_array_class, int32_t length,
                                gc::AllocatorType allocator_type)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
   static ObjectArray<T>* Alloc(Thread* self, Class* object_array_class, int32_t length)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
   T* Get(int32_t i) ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_);
 
@@ -81,7 +81,7 @@
       SHARED_REQUIRES(Locks::mutator_lock_);
 
   ObjectArray<T>* CopyOf(Thread* self, int32_t new_length)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
   // TODO fix thread safety analysis broken by the use of template. This should be
   // SHARED_REQUIRES(Locks::mutator_lock_).
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 2af31cc..6949b0b 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1808,26 +1808,23 @@
         trace_(nullptr),
         pointer_size_(Runtime::Current()->GetClassLinker()->GetImagePointerSize()) {}
 
-  bool Init(int depth)
-      SHARED_REQUIRES(Locks::mutator_lock_) {
+  bool Init(int depth) SHARED_REQUIRES(Locks::mutator_lock_) ACQUIRE(Roles::uninterruptible_) {
     // Allocate method trace with format [method pointers][pcs].
     auto* cl = Runtime::Current()->GetClassLinker();
     trace_ = cl->AllocPointerArray(self_, depth * 2);
+    const char* last_no_suspend_cause =
+        self_->StartAssertNoThreadSuspension("Building internal stack trace");
     if (trace_ == nullptr) {
       self_->AssertPendingOOMException();
       return false;
     }
     // If We are called from native, use non-transactional mode.
-    const char* last_no_suspend_cause =
-        self_->StartAssertNoThreadSuspension("Building internal stack trace");
     CHECK(last_no_suspend_cause == nullptr) << last_no_suspend_cause;
     return true;
   }
 
-  virtual ~BuildInternalStackTraceVisitor() {
-    if (trace_ != nullptr) {
-      self_->EndAssertNoThreadSuspension(nullptr);
-    }
+  virtual ~BuildInternalStackTraceVisitor() RELEASE(Roles::uninterruptible_) {
+    self_->EndAssertNoThreadSuspension(nullptr);
   }
 
   bool VisitFrame() SHARED_REQUIRES(Locks::mutator_lock_) {
diff --git a/runtime/thread.h b/runtime/thread.h
index 06934ea..0aa4b5b 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -253,12 +253,13 @@
   // Transition from runnable into a state where mutator privileges are denied. Releases share of
   // mutator lock.
   void TransitionFromRunnableToSuspended(ThreadState new_state)
-      REQUIRES(!Locks::thread_suspend_count_lock_)
+      REQUIRES(!Locks::thread_suspend_count_lock_, !Roles::uninterruptible_)
       UNLOCK_FUNCTION(Locks::mutator_lock_)
       ALWAYS_INLINE;
 
   // Once called thread suspension will cause an assertion failure.
-  const char* StartAssertNoThreadSuspension(const char* cause) {
+  const char* StartAssertNoThreadSuspension(const char* cause) ACQUIRE(Roles::uninterruptible_) {
+    Roles::uninterruptible_.Acquire();  // No-op.
     if (kIsDebugBuild) {
       CHECK(cause != nullptr);
       const char* previous_cause = tlsPtr_.last_no_thread_suspension_cause;
@@ -271,13 +272,14 @@
   }
 
   // End region where no thread suspension is expected.
-  void EndAssertNoThreadSuspension(const char* old_cause) {
+  void EndAssertNoThreadSuspension(const char* old_cause) RELEASE(Roles::uninterruptible_) {
     if (kIsDebugBuild) {
       CHECK(old_cause != nullptr || tls32_.no_thread_suspension == 1);
       CHECK_GT(tls32_.no_thread_suspension, 0U);
       tls32_.no_thread_suspension--;
       tlsPtr_.last_no_thread_suspension_cause = old_cause;
     }
+    Roles::uninterruptible_.Release();  // No-op.
   }
 
   void AssertThreadSuspensionIsAllowable(bool check_locks = true) const;
@@ -1342,12 +1344,12 @@
   DISALLOW_COPY_AND_ASSIGN(Thread);
 };
 
-class ScopedAssertNoThreadSuspension {
+class SCOPED_CAPABILITY ScopedAssertNoThreadSuspension {
  public:
-  ScopedAssertNoThreadSuspension(Thread* self, const char* cause)
+  ScopedAssertNoThreadSuspension(Thread* self, const char* cause) ACQUIRE(Roles::uninterruptible_)
       : self_(self), old_cause_(self->StartAssertNoThreadSuspension(cause)) {
   }
-  ~ScopedAssertNoThreadSuspension() {
+  ~ScopedAssertNoThreadSuspension() RELEASE(Roles::uninterruptible_) {
     self_->EndAssertNoThreadSuspension(old_cause_);
   }
   Thread* Self() {