[vm, profiler] Don't assume the isolate has a mutator during a profile sample.

A sample can be taken when Thread::Current() and Thread::Current()->isolate() are non-NULL. When a thread is entering or exiting an isolate, the is a brief window between the TLS being set/cleared and Isolate::mutator_thread_ being set/cleared.

TEST=vm/cc/Profiler_EnterExitIsolate
Bug: https://github.com/flutter/flutter/issues/134548
Change-Id: I7a6b25dabf930e8480d1a85d7f24c4765fc36b15
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/328380
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Ben Konyi <bkonyi@google.com>
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 42d3ea6..08c0367 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -820,9 +820,13 @@
   }
   if (block != nullptr) {
     block->MarkCompleted();
-    if (!Isolate::IsSystemIsolate(isolate) &&
-        isolate->TrySetHasCompletedBlocks()) {
-      isolate->mutator_thread()->ScheduleInterrupts(Thread::kVMInterrupt);
+    if (!Isolate::IsSystemIsolate(isolate)) {
+      Thread* mutator = isolate->mutator_thread();
+      // The mutator thread might be NULL if we sample in the middle of
+      // Thread::Enter/ExitIsolate.
+      if ((mutator != nullptr) && isolate->TrySetHasCompletedBlocks()) {
+        mutator->ScheduleInterrupts(Thread::kVMInterrupt);
+      }
     }
   }
   return next->ReserveSample();
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 77d9b62..74fbfee 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -2430,6 +2430,23 @@
   EXPECT_EQ(table->FindCodeForPC(50), code1);
 }
 
+// Try to hit any races in related to setting TLS and Isolate::mutator_thread_.
+// https://github.com/flutter/flutter/issues/134548
+ISOLATE_UNIT_TEST_CASE(Profiler_EnterExitIsolate) {
+  EnableProfiler();
+  Profiler::SetSamplePeriod(50);  // Microseconds.
+
+  const char* kScript = "main() => null;\n";
+  const Library& root_library = Library::Handle(LoadTestScript(kScript));
+
+  Isolate* isolate = Isolate::Current();
+  for (intptr_t i = 0; i < 100000; i++) {
+    Thread::ExitIsolate();
+    Thread::EnterIsolate(isolate);
+    Invoke(root_library, "main");
+  }
+}
+
 #endif  // !PRODUCT
 
 }  // namespace dart