[vm] Remove Thread::{Enter,Exit}IsolateAsHelper

For every isolate there should be only one mutator with
a unique [Thread] object.

We change existing tests that use this functionality to instead use
`Thread::{Enter,Exit}IsolateGroupAsHelper`. It also results in a net
removal of code.

TEST=ci

Change-Id: Ic326e868a98ddedbab5b8c429252d38ea71bbf04
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/295940
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index e9911d0..9861648 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -2653,14 +2653,16 @@
 
 class BackgroundGCTask : public ThreadPool::Task {
  public:
-  BackgroundGCTask(Isolate* isolate, Monitor* monitor, bool* done)
-      : isolate_(isolate), monitor_(monitor), done_(done) {}
+  BackgroundGCTask(IsolateGroup* isolate_group, Monitor* monitor, bool* done)
+      : isolate_group_(isolate_group), monitor_(monitor), done_(done) {}
   virtual void Run() {
-    Thread::EnterIsolateAsHelper(isolate_, Thread::kUnknownTask);
+    const bool kBypassSafepoint = false;
+    Thread::EnterIsolateGroupAsHelper(isolate_group_, Thread::kUnknownTask,
+                                      kBypassSafepoint);
     for (intptr_t i = 0; i < 10; i++) {
       GCTestHelper::CollectAllGarbage();
     }
-    Thread::ExitIsolateAsHelper();
+    Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
     {
       MonitorLocker ml(monitor_);
       *done_ = true;
@@ -2669,7 +2671,7 @@
   }
 
  private:
-  Isolate* isolate_;
+  IsolateGroup* isolate_group_;
   Monitor* monitor_;
   bool* done_;
 };
@@ -2704,7 +2706,7 @@
 
   Monitor monitor;
   bool done = false;
-  Dart::thread_pool()->Run<BackgroundGCTask>(Isolate::Current(), &monitor,
+  Dart::thread_pool()->Run<BackgroundGCTask>(IsolateGroup::Current(), &monitor,
                                              &done);
 
   for (intptr_t i = 0; i < 10; i++) {
diff --git a/runtime/vm/heap/heap_test.cc b/runtime/vm/heap/heap_test.cc
index 1385420..a751da8 100644
--- a/runtime/vm/heap/heap_test.cc
+++ b/runtime/vm/heap/heap_test.cc
@@ -793,13 +793,17 @@
 
 class ConcurrentForceGrowthScopeTask : public ThreadPool::Task {
  public:
-  ConcurrentForceGrowthScopeTask(Isolate* isolate,
+  ConcurrentForceGrowthScopeTask(IsolateGroup* isolate_group,
                                  Monitor* monitor,
                                  intptr_t* done_count)
-      : isolate_(isolate), monitor_(monitor), done_count_(done_count) {}
+      : isolate_group_(isolate_group),
+        monitor_(monitor),
+        done_count_(done_count) {}
 
   virtual void Run() {
-    Thread::EnterIsolateAsHelper(isolate_, Thread::kUnknownTask);
+    const bool kBypassSafepoint = false;
+    Thread::EnterIsolateGroupAsHelper(isolate_group_, Thread::kUnknownTask,
+                                      kBypassSafepoint);
     {
       Thread* thread = Thread::Current();
       StackZone stack_zone(thread);
@@ -819,7 +823,7 @@
         accumulate.Add(element);
       }
     }
-    Thread::ExitIsolateAsHelper();
+    Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
     // Notify the main thread that this thread has exited.
     {
       MonitorLocker ml(monitor_);
@@ -829,7 +833,7 @@
   }
 
  private:
-  Isolate* isolate_;
+  IsolateGroup* isolate_group_;
   Monitor* monitor_;
   intptr_t* done_count_;
 };
@@ -841,7 +845,7 @@
 
   for (intptr_t i = 0; i < task_count; i++) {
     Dart::thread_pool()->Run<ConcurrentForceGrowthScopeTask>(
-        thread->isolate(), &monitor, &done_count);
+        thread->isolate_group(), &monitor, &done_count);
   }
 
   {
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 6575e6b..99657fa 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -3654,12 +3654,8 @@
   return thread_registry_->threads_lock();
 }
 
-Thread* Isolate::ScheduleThread(bool is_mutator,
-                                bool is_nested_reenter,
-                                bool bypass_safepoint) {
-  if (is_mutator) {
-    group()->IncreaseMutatorCount(this, is_nested_reenter);
-  }
+Thread* Isolate::ScheduleThread(bool is_nested_reenter) {
+  group()->IncreaseMutatorCount(this, is_nested_reenter);
 
   // We are about to associate the thread with an isolate group and it would
   // not be possible to correctly track no_safepoint_scope_depth for the
@@ -3669,7 +3665,7 @@
   MonitorLocker ml(group()->threads_lock(), false);
 
   // Check to make sure we don't already have a mutator thread.
-  if (is_mutator && scheduled_mutator_thread_ != nullptr) {
+  if (scheduled_mutator_thread_ != nullptr) {
     return nullptr;
   }
 
@@ -3680,7 +3676,7 @@
 
   // We lazily create a [Thread] structure for the mutator thread, but we'll
   // reuse it until the death of the isolate.
-  Thread* existing_mutator_thread = is_mutator ? mutator_thread_ : nullptr;
+  Thread* existing_mutator_thread = mutator_thread_;
   if (existing_mutator_thread != nullptr) {
     ASSERT(existing_mutator_thread->is_mutator_thread_);
   }
@@ -3689,23 +3685,19 @@
   // with it (this is done while we are holding the thread registry lock).
   Thread* thread =
       group()->ScheduleThreadLocked(&ml, existing_mutator_thread, is_vm_isolate,
-                                    is_mutator, bypass_safepoint);
-  if (is_mutator) {
-    ASSERT(mutator_thread_ == nullptr || mutator_thread_ == thread);
-    mutator_thread_ = thread;
-    scheduled_mutator_thread_ = thread;
-    thread->is_mutator_thread_ = true;
-    thread->field_table_values_ = field_table_->table();
-  }
+                                    /*is_mutator=*/true,
+                                    /*bypass_safepoint=*/false);
+  ASSERT(mutator_thread_ == nullptr || mutator_thread_ == thread);
+  mutator_thread_ = thread;
+  scheduled_mutator_thread_ = thread;
+  thread->is_mutator_thread_ = true;
+  thread->field_table_values_ = field_table_->table();
   thread->isolate_ = this;
 
   return thread;
 }
 
-void Isolate::UnscheduleThread(Thread* thread,
-                               bool is_mutator,
-                               bool is_nested_exit,
-                               bool bypass_safepoint) {
+void Isolate::UnscheduleThread(Thread* thread, bool is_nested_exit) {
   {
     // Disassociate the 'Thread' structure and unschedule the thread
     // from this isolate.
@@ -3716,26 +3708,18 @@
     // no_safepoint_scope_depth increments/decrements.
     MonitorLocker ml(group()->threads_lock(), false);
 
-    if (is_mutator) {
-      if (thread->sticky_error() != Error::null()) {
-        ASSERT(sticky_error_ == Error::null());
-        sticky_error_ = thread->StealStickyError();
-      }
-      ASSERT(mutator_thread_ == thread);
-      ASSERT(mutator_thread_ == scheduled_mutator_thread_);
-      scheduled_mutator_thread_ = nullptr;
-    } else {
-      // We only reset the isolate pointer for non-mutator threads, since
-      // mutator threads can still be visited during GC even if unscheduled.
-      // See also IsolateGroup::UnscheduleThreadLocked`
-      thread->isolate_ = nullptr;
+    if (thread->sticky_error() != Error::null()) {
+      ASSERT(sticky_error_ == Error::null());
+      sticky_error_ = thread->StealStickyError();
     }
+    ASSERT(mutator_thread_ == thread);
+    ASSERT(mutator_thread_ == scheduled_mutator_thread_);
+    scheduled_mutator_thread_ = nullptr;
     thread->field_table_values_ = nullptr;
-    group()->UnscheduleThreadLocked(&ml, thread, is_mutator, bypass_safepoint);
+    group()->UnscheduleThreadLocked(&ml, thread, /*is_mutator=*/true,
+                                    /*bypass_safepoint=*/false);
   }
-  if (is_mutator) {
-    group()->DecreaseMutatorCount(this, is_nested_exit);
-  }
+  group()->DecreaseMutatorCount(this, is_nested_exit);
 }
 
 #if !defined(PRODUCT)
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index f0e8ba5..5ed759f 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -1537,13 +1537,8 @@
       const GrowableObjectArray& value);
 #endif  // !defined(PRODUCT)
 
-  Thread* ScheduleThread(bool is_mutator,
-                         bool is_nested_reenter,
-                         bool bypass_safepoint);
-  void UnscheduleThread(Thread* thread,
-                        bool is_mutator,
-                        bool is_nested_exit,
-                        bool bypass_safepoint);
+  Thread* ScheduleThread(bool is_nested_reenter);
+  void UnscheduleThread(Thread* thread, bool is_nested_exit);
 
   // DEPRECATED: Use Thread's methods instead. During migration, these default
   // to using the mutator thread (which must also be the current thread).
diff --git a/runtime/vm/isolate_test.cc b/runtime/vm/isolate_test.cc
index 8e8b85d..d15f049 100644
--- a/runtime/vm/isolate_test.cc
+++ b/runtime/vm/isolate_test.cc
@@ -113,7 +113,9 @@
       : thread_(thread), barrier_(barrier) {}
 
   virtual void Run() {
-    Thread::EnterIsolateAsHelper(thread_->isolate(), Thread::kUnknownTask);
+    const bool kBypassSafepoint = false;
+    Thread::EnterIsolateGroupAsHelper(thread_->isolate_group(),
+                                      Thread::kUnknownTask, kBypassSafepoint);
     // Tell main thread that we are ready.
     barrier_->Sync();
     for (intptr_t i = 0; i < kIterations; ++i) {
@@ -129,7 +131,7 @@
       // Tell main thread that we observed the interrupt.
       barrier_->Sync();
     }
-    Thread::ExitIsolateAsHelper();
+    Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
     barrier_->Sync();
     barrier_->Release();
   }
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index 0248c57..ca41563 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -300,15 +300,18 @@
         reinterpret_cast<RunInSafepointAndRWCodeArgs*>(arg);
     Isolate* const isolate = args->isolate;
     CHECK_ISOLATE(isolate);
-    Thread::EnterIsolateAsHelper(isolate, Thread::TaskKind::kUnknownTask);
+    auto isolate_group = isolate->group();
+    const bool kBypassSafepoint = false;
+    Thread::EnterIsolateGroupAsHelper(isolate_group, Thread::kUnknownTask,
+                                      kBypassSafepoint);
     Thread* const thread = Thread::Current();
     {
       GcSafepointOperationScope scope(thread);
-      args->isolate->group()->heap()->WriteProtectCode(/*read_only=*/false);
+      isolate_group->heap()->WriteProtectCode(/*read_only=*/false);
       (*args->callback)();
-      args->isolate->group()->heap()->WriteProtectCode(/*read_only=*/true);
+      isolate_group->heap()->WriteProtectCode(/*read_only=*/true);
     }
-    Thread::ExitIsolateAsHelper();
+    Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
     return nullptr;
 
   } else {
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 53074cb..e91499e 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -1790,9 +1790,9 @@
   }
 };
 
-void Profiler::ProcessCompletedBlocks(Thread* thread) {
+void Profiler::ProcessCompletedBlocks(Isolate* isolate) {
   if (!Service::profiler_stream.enabled()) return;
-  Isolate* isolate = thread->isolate();
+  auto thread = Thread::Current();
   if (Isolate::IsSystemIsolate(isolate)) return;
 
   TIMELINE_DURATION(thread, Isolate, "Profiler::ProcessCompletedBlocks")
@@ -1809,7 +1809,7 @@
 
 void Profiler::IsolateShutdown(Thread* thread) {
   FlushSampleBlocks(thread->isolate());
-  ProcessCompletedBlocks(thread);
+  ProcessCompletedBlocks(thread->isolate());
 }
 
 class SampleBlockProcessorVisitor : public IsolateVisitor {
@@ -1819,9 +1819,11 @@
 
   void VisitIsolate(Isolate* isolate) {
     if (isolate->TakeHasCompletedBlocks()) {
-      Thread::EnterIsolateAsHelper(isolate, Thread::kSampleBlockTask);
-      Profiler::ProcessCompletedBlocks(Thread::Current());
-      Thread::ExitIsolateAsHelper();
+      const bool kBypassSafepoint = false;
+      Thread::EnterIsolateGroupAsHelper(
+          isolate->group(), Thread::kSampleBlockTask, kBypassSafepoint);
+      Profiler::ProcessCompletedBlocks(isolate);
+      Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
     }
   }
 };
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index 3ea4905..6b05d0c 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -94,7 +94,7 @@
   }
   inline static intptr_t Size();
 
-  static void ProcessCompletedBlocks(Thread* thread);
+  static void ProcessCompletedBlocks(Isolate* isolate);
   static void IsolateShutdown(Thread* thread);
 
  private:
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 21a3a54..29cedd0 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -272,15 +272,11 @@
 }
 
 bool Thread::EnterIsolate(Isolate* isolate, bool is_nested_reenter) {
-  const bool kIsMutatorThread = true;
-  const bool kBypassSafepoint = false;
-
   is_nested_reenter = is_nested_reenter ||
                       (isolate->mutator_thread() != nullptr &&
                        isolate->mutator_thread()->top_exit_frame_info() != 0);
 
-  Thread* thread = isolate->ScheduleThread(kIsMutatorThread, is_nested_reenter,
-                                           kBypassSafepoint);
+  Thread* thread = isolate->ScheduleThread(is_nested_reenter);
   if (thread != nullptr) {
     ASSERT(thread->store_buffer_block_ == nullptr);
     ASSERT(thread->isolate() == isolate);
@@ -304,48 +300,10 @@
   Isolate* isolate = thread->isolate();
   thread->set_vm_tag(isolate->is_runnable() ? VMTag::kIdleTagId
                                             : VMTag::kLoadWaitTagId);
-  const bool kIsMutatorThread = true;
-  const bool kBypassSafepoint = false;
   is_nested_exit =
       is_nested_exit || (isolate->mutator_thread() != nullptr &&
                          isolate->mutator_thread()->top_exit_frame_info() != 0);
-  isolate->UnscheduleThread(thread, kIsMutatorThread, is_nested_exit,
-                            kBypassSafepoint);
-}
-
-bool Thread::EnterIsolateAsHelper(Isolate* isolate,
-                                  TaskKind kind,
-                                  bool bypass_safepoint) {
-  ASSERT(kind != kMutatorTask);
-  const bool kIsMutatorThread = false;
-  const bool kIsNestedReenter = false;
-  Thread* thread = isolate->ScheduleThread(kIsMutatorThread, kIsNestedReenter,
-                                           bypass_safepoint);
-  if (thread != nullptr) {
-    ASSERT(!thread->IsMutatorThread());
-    ASSERT(thread->isolate() == isolate);
-    ASSERT(thread->isolate_group() == isolate->group());
-    thread->FinishEntering(kind);
-    return true;
-  }
-  return false;
-}
-
-void Thread::ExitIsolateAsHelper(bool bypass_safepoint) {
-  Thread* thread = Thread::Current();
-  ASSERT(thread != nullptr);
-  ASSERT(!thread->IsMutatorThread());
-  ASSERT(thread->isolate() != nullptr);
-  ASSERT(thread->isolate_group() != nullptr);
-
-  thread->PrepareLeaving();
-
-  Isolate* isolate = thread->isolate();
-  ASSERT(isolate != nullptr);
-  const bool kIsMutatorThread = false;
-  const bool kIsNestedExit = false;
-  isolate->UnscheduleThread(thread, kIsMutatorThread, kIsNestedExit,
-                            bypass_safepoint);
+  isolate->UnscheduleThread(thread, is_nested_exit);
 }
 
 bool Thread::EnterIsolateGroupAsHelper(IsolateGroup* isolate_group,
@@ -452,7 +410,7 @@
 
 #if !defined(PRODUCT)
     if (isolate()->TakeHasCompletedBlocks()) {
-      Profiler::ProcessCompletedBlocks(this);
+      Profiler::ProcessCompletedBlocks(isolate());
     }
 #endif  // !defined(PRODUCT)
 
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 6086aeb..f47008e 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -362,15 +362,6 @@
   // Makes the current thread exit its isolate.
   static void ExitIsolate(bool is_nested_exit = false);
 
-  // A VM thread other than the main mutator thread can enter an isolate as a
-  // "helper" to gain limited concurrent access to the isolate. One example is
-  // SweeperTask (which uses the class table, which is copy-on-write).
-  // TODO(koda): Properly synchronize heap access to expand allowed operations.
-  static bool EnterIsolateAsHelper(Isolate* isolate,
-                                   TaskKind kind,
-                                   bool bypass_safepoint = false);
-  static void ExitIsolateAsHelper(bool bypass_safepoint = false);
-
   static bool EnterIsolateGroupAsHelper(IsolateGroup* isolate_group,
                                         TaskKind kind,
                                         bool bypass_safepoint);
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index 877a7f9..b227681 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -112,13 +112,18 @@
 
 class TaskWithZoneAllocation : public ThreadPool::Task {
  public:
-  TaskWithZoneAllocation(Isolate* isolate,
+  TaskWithZoneAllocation(IsolateGroup* isolate_group,
                          Monitor* monitor,
                          bool* done,
                          intptr_t id)
-      : isolate_(isolate), monitor_(monitor), done_(done), id_(id) {}
+      : isolate_group_(isolate_group),
+        monitor_(monitor),
+        done_(done),
+        id_(id) {}
   virtual void Run() {
-    Thread::EnterIsolateAsHelper(isolate_, Thread::kUnknownTask);
+    const bool kBypassSafepoint = false;
+    Thread::EnterIsolateGroupAsHelper(isolate_group_, Thread::kUnknownTask,
+                                      kBypassSafepoint);
     {
       Thread* thread = Thread::Current();
       // Create a zone (which is also a stack resource) and exercise it a bit.
@@ -140,7 +145,7 @@
       EXPECT(smi.Value() == unique_smi);
       {
         HeapIterationScope iteration(thread);
-        ObjectCounter counter(isolate_->group(), &smi);
+        ObjectCounter counter(isolate_group_, &smi);
         // Ensure that our particular zone is visited.
         iteration.IterateStackPointers(&counter,
                                        ValidationPolicy::kValidateFrames);
@@ -157,7 +162,7 @@
       EXPECT(unique_str.Equals(unique_chars));
       {
         HeapIterationScope iteration(thread);
-        ObjectCounter str_counter(isolate_->group(), &unique_str);
+        ObjectCounter str_counter(isolate_group_, &unique_str);
         // Ensure that our particular zone is visited.
         iteration.IterateStackPointers(&str_counter,
                                        ValidationPolicy::kValidateFrames);
@@ -165,7 +170,7 @@
         EXPECT_EQ(1, str_counter.count());
       }
     }
-    Thread::ExitIsolateAsHelper();
+    Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
     {
       MonitorLocker ml(monitor_);
       *done_ = true;
@@ -174,7 +179,7 @@
   }
 
  private:
-  Isolate* isolate_;
+  IsolateGroup* isolate_group_;
   Monitor* monitor_;
   bool* done_;
   intptr_t id_;
@@ -184,10 +189,11 @@
   const int kTaskCount = 100;
   Monitor sync[kTaskCount];
   bool done[kTaskCount];
-  Isolate* isolate = thread->isolate();
+  auto isolate = thread->isolate();
+  auto isolate_group = thread->isolate_group();
   for (int i = 0; i < kTaskCount; i++) {
     done[i] = false;
-    Dart::thread_pool()->Run<TaskWithZoneAllocation>(isolate, &sync[i],
+    Dart::thread_pool()->Run<TaskWithZoneAllocation>(isolate_group, &sync[i],
                                                      &done[i], i);
   }
   bool in_isolate = true;
@@ -220,14 +226,14 @@
 class SimpleTaskWithZoneAllocation : public ThreadPool::Task {
  public:
   SimpleTaskWithZoneAllocation(intptr_t id,
-                               Isolate* isolate,
+                               IsolateGroup* isolate_group,
                                Thread** thread_ptr,
                                Monitor* sync,
                                Monitor* monitor,
                                intptr_t* done_count,
                                bool* wait)
       : id_(id),
-        isolate_(isolate),
+        isolate_group_(isolate_group),
         thread_ptr_(thread_ptr),
         sync_(sync),
         monitor_(monitor),
@@ -235,13 +241,15 @@
         wait_(wait) {}
 
   virtual void Run() {
-    Thread::EnterIsolateAsHelper(isolate_, Thread::kUnknownTask);
+    const bool kBypassSafepoint = false;
+    Thread::EnterIsolateGroupAsHelper(isolate_group_, Thread::kUnknownTask,
+                                      kBypassSafepoint);
     {
       Thread* thread = Thread::Current();
       *thread_ptr_ = thread;
       CreateStackZones(id_);
     }
-    Thread::ExitIsolateAsHelper();
+    Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
     // Notify the main thread that this thread has exited.
     {
       MonitorLocker ml(monitor_);
@@ -288,7 +296,7 @@
   }
 
   intptr_t id_;
-  Isolate* isolate_;
+  IsolateGroup* isolate_group_;
   Thread** thread_ptr_;
   Monitor* sync_;
   Monitor* monitor_;
@@ -301,7 +309,7 @@
   Monitor monitor;
   Monitor sync;
   Thread* threads[kTaskCount];
-  Isolate* isolate = Thread::Current()->isolate();
+  auto isolate_group = thread->isolate_group();
   intptr_t done_count = 0;
   bool wait = true;
 
@@ -311,7 +319,8 @@
 
   for (intptr_t i = 0; i < kTaskCount; i++) {
     Dart::thread_pool()->Run<SimpleTaskWithZoneAllocation>(
-        (i + 1), isolate, &threads[i], &sync, &monitor, &done_count, &wait);
+        (i + 1), isolate_group, &threads[i], &sync, &monitor, &done_count,
+        &wait);
   }
   // Wait until all spawned tasks finish their memory operations.
   {
@@ -371,12 +380,12 @@
  public:
   static constexpr intptr_t kTaskCount = 1;
 
-  ICDataTestTask(Isolate* isolate,
+  ICDataTestTask(IsolateGroup* isolate_group,
                  const Array& ic_datas,
                  Monitor* monitor,
                  intptr_t* exited,
                  std::atomic<bool>* done)
-      : isolate_(isolate),
+      : isolate_group_(isolate_group),
         ic_datas_(ic_datas),
         len_(ic_datas.Length()),
         monitor_(monitor),
@@ -384,7 +393,9 @@
         done_(done) {}
 
   virtual void Run() {
-    Thread::EnterIsolateAsHelper(isolate_, Thread::kUnknownTask);
+    const bool kBypassSafepoint = false;
+    Thread::EnterIsolateGroupAsHelper(isolate_group_, Thread::kUnknownTask,
+                                      kBypassSafepoint);
 
     Thread* thread = Thread::Current();
 
@@ -414,7 +425,7 @@
       }
     }
 
-    Thread::ExitIsolateAsHelper();
+    Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
     {
       MonitorLocker ml(monitor_);
       ++*exited_;
@@ -423,7 +434,7 @@
   }
 
  private:
-  Isolate* isolate_;
+  IsolateGroup* isolate_group_;
   const Array& ic_datas_;
   const intptr_t len_;
   Monitor* monitor_;
@@ -450,8 +461,8 @@
 // Test that checks that other threads only see a fully initialized ICData
 // whenever ICData is updated.
 ISOLATE_UNIT_TEST_CASE(ICDataTest) {
-  Isolate* isolate = thread->isolate();
-  USE(isolate);
+  auto isolate_group = thread->isolate_group();
+  USE(isolate_group);
   Monitor monitor;
   intptr_t exited = 0;
   std::atomic<bool> done = {false};
@@ -472,7 +483,7 @@
   }
 
   for (int i = 0; i < ICDataTestTask::kTaskCount; i++) {
-    Dart::thread_pool()->Run<ICDataTestTask>(isolate, ic_datas, &monitor,
+    Dart::thread_pool()->Run<ICDataTestTask>(isolate_group, ic_datas, &monitor,
                                              &exited, &done);
   }
 
@@ -524,7 +535,9 @@
         local_done_(false) {}
 
   virtual void Run() {
-    Thread::EnterIsolateAsHelper(isolate_, Thread::kUnknownTask);
+    const bool kBypassSafepoint = false;
+    Thread::EnterIsolateGroupAsHelper(isolate_->group(), Thread::kUnknownTask,
+                                      kBypassSafepoint);
     {
       MonitorLocker ml(monitor_);
       ++*expected_count_;
@@ -573,7 +586,7 @@
         }
       }
     }
-    Thread::ExitIsolateAsHelper();
+    Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
     {
       MonitorLocker ml(monitor_);
       ++*exited_;
@@ -837,20 +850,24 @@
 
 class AllocAndGCTask : public ThreadPool::Task {
  public:
-  AllocAndGCTask(Isolate* isolate, Monitor* done_monitor, bool* done)
-      : isolate_(isolate), done_monitor_(done_monitor), done_(done) {}
+  AllocAndGCTask(IsolateGroup* isolate_group, Monitor* done_monitor, bool* done)
+      : isolate_group_(isolate_group),
+        done_monitor_(done_monitor),
+        done_(done) {}
 
   virtual void Run() {
-    Thread::EnterIsolateAsHelper(isolate_, Thread::kUnknownTask);
+    const bool kBypassSafepoint = false;
+    Thread::EnterIsolateGroupAsHelper(isolate_group_, Thread::kUnknownTask,
+                                      kBypassSafepoint);
     {
       Thread* thread = Thread::Current();
       StackZone stack_zone(thread);
       Zone* zone = stack_zone.GetZone();
       String& old_str = String::Handle(zone, String::New("old", Heap::kOld));
-      isolate_->group()->heap()->CollectAllGarbage();
+      isolate_group_->heap()->CollectAllGarbage();
       EXPECT(old_str.Equals("old"));
     }
-    Thread::ExitIsolateAsHelper();
+    Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
     // Tell main thread that we are ready.
     {
       MonitorLocker ml(done_monitor_);
@@ -861,7 +878,7 @@
   }
 
  private:
-  Isolate* isolate_;
+  IsolateGroup* isolate_group_;
   Monitor* done_monitor_;
   bool* done_;
 };
@@ -869,8 +886,8 @@
 ISOLATE_UNIT_TEST_CASE(HelperAllocAndGC) {
   Monitor done_monitor;
   bool done = false;
-  Isolate* isolate = thread->isolate();
-  Dart::thread_pool()->Run<AllocAndGCTask>(isolate, &done_monitor, &done);
+  auto isolate_group = thread->isolate_group();
+  Dart::thread_pool()->Run<AllocAndGCTask>(isolate_group, &done_monitor, &done);
   {
     while (true) {
       TransitionVMToBlocked transition(thread);
@@ -884,11 +901,17 @@
 
 class AllocateGlobsOfMemoryTask : public ThreadPool::Task {
  public:
-  AllocateGlobsOfMemoryTask(Isolate* isolate, Monitor* done_monitor, bool* done)
-      : isolate_(isolate), done_monitor_(done_monitor), done_(done) {}
+  AllocateGlobsOfMemoryTask(IsolateGroup* isolate_group,
+                            Monitor* done_monitor,
+                            bool* done)
+      : isolate_group_(isolate_group),
+        done_monitor_(done_monitor),
+        done_(done) {}
 
   virtual void Run() {
-    Thread::EnterIsolateAsHelper(isolate_, Thread::kUnknownTask);
+    const bool kBypassSafepoint = false;
+    Thread::EnterIsolateGroupAsHelper(isolate_group_, Thread::kUnknownTask,
+                                      kBypassSafepoint);
     {
       Thread* thread = Thread::Current();
       StackZone stack_zone(thread);
@@ -898,7 +921,7 @@
         String::Handle(zone, String::New("abc"));
       }
     }
-    Thread::ExitIsolateAsHelper();
+    Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
     // Tell main thread that we are ready.
     {
       MonitorLocker ml(done_monitor_);
@@ -909,7 +932,7 @@
   }
 
  private:
-  Isolate* isolate_;
+  IsolateGroup* isolate_group_;
   Monitor* done_monitor_;
   bool* done_;
 };
@@ -918,11 +941,11 @@
   const int NUMBER_TEST_THREADS = 10;
   Monitor done_monitor[NUMBER_TEST_THREADS];
   bool done[NUMBER_TEST_THREADS];
-  Isolate* isolate = thread->isolate();
+  auto isolate_group = thread->isolate_group();
   for (int i = 0; i < NUMBER_TEST_THREADS; i++) {
     done[i] = false;
     Dart::thread_pool()->Run<AllocateGlobsOfMemoryTask>(
-        isolate, &done_monitor[i], &done[i]);
+        isolate_group, &done_monitor[i], &done[i]);
   }
 
   for (int i = 0; i < NUMBER_TEST_THREADS; i++) {