Ensure flip-function is completed before running synchronous checkpoint

Currently, there is a possibility that the target (for synchronous
checkpoint) thread is not flipped but the caller is. This could result
in accessing from-space objects or having a mix of 'from' and 'to' space
references on the target's stack. This is particularly an issue with
userfaultfd GC.

Bug: 279006963
Bug: 160737021
Test: art/test/testrunner/testrunner.py --target -t 1913-get-set-local-objects
Change-Id: I3df64ded15d126b84638b13fdbb80d9009423698
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 16f5f87..6b1934c 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1803,6 +1803,17 @@
           sched_yield();
         }
       }
+      // Ensure that the flip function for this thread, if pending, is finished *before*
+      // the checkpoint function is run. Otherwise, we may end up with both `to' and 'from'
+      // space references on the stack, confusing the GC's thread-flip logic. The caller is
+      // runnable so can't have a pending flip function.
+      DCHECK_EQ(self->GetState(), ThreadState::kRunnable);
+      DCHECK(
+          !self->GetStateAndFlags(std::memory_order_relaxed).IsAnyOfFlagsSet(FlipFunctionFlags()));
+      EnsureFlipFunctionStarted(self);
+      while (GetStateAndFlags(std::memory_order_acquire).IsAnyOfFlagsSet(FlipFunctionFlags())) {
+        sched_yield();
+      }
 
       function->Run(this);
     }