Move thread-local mark-stack revocation outside SOA

Revoking mark-stack inside a ScopedObjectAccess scope could potentially
call checkpoints in its destructor, which may trigger read-barrier,
after the mark-stack is revoked.

Test: art/test/testrunner/testrunner.py --target
Bug: 140119552
Change-Id: I90d62cbf5edbaf953de73aeb2b3b59612b6897d3
diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h
index dd295d1..0240460 100644
--- a/runtime/gc/collector/concurrent_copying.h
+++ b/runtime/gc/collector/concurrent_copying.h
@@ -150,8 +150,7 @@
   bool IsWeakRefAccessEnabled() REQUIRES(Locks::thread_list_lock_) {
     return weak_ref_access_enabled_;
   }
-  void RevokeThreadLocalMarkStack(Thread* thread) REQUIRES_SHARED(Locks::mutator_lock_)
-      REQUIRES(!mark_stack_lock_);
+  void RevokeThreadLocalMarkStack(Thread* thread) REQUIRES(!mark_stack_lock_);
 
   mirror::Object* IsMarked(mirror::Object* from_ref) override
       REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 290b87f..59a1705 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -2439,9 +2439,11 @@
   {
     ScopedObjectAccess soa(self);
     Runtime::Current()->GetHeap()->RevokeThreadLocalBuffers(this);
-    if (kUseReadBarrier) {
-      Runtime::Current()->GetHeap()->ConcurrentCopyingCollector()->RevokeThreadLocalMarkStack(this);
-    }
+  }
+  // Mark-stack revocation must be performed at the very end. No
+  // checkpoint/flip-function or read-barrier should be called after this.
+  if (kUseReadBarrier) {
+    Runtime::Current()->GetHeap()->ConcurrentCopyingCollector()->RevokeThreadLocalMarkStack(this);
   }
 }