Version 2.13.0-29.0.dev

Merge commit '02f65fa501e15b1c145870063058b30a1369d521' into 'dev'
diff --git a/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart b/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart
index 269b771..80f8741 100644
--- a/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart
@@ -111,7 +111,7 @@
     Map arguments = event['args'];
     expect(arguments, isA<Map>());
     expect(arguments['isolateGroupId'], isA<String>());
-    if (event['cat'] != 'GC') {
+    if (!const ['GC', 'Compiler', 'CompilerVerbose'].contains(event['cat'])) {
       expect(arguments['isolateId'], isA<String>());
     }
   }
diff --git a/runtime/observatory_2/tests/service_2/get_vm_timeline_rpc_test.dart b/runtime/observatory_2/tests/service_2/get_vm_timeline_rpc_test.dart
index 8dc5899..1be667e 100644
--- a/runtime/observatory_2/tests/service_2/get_vm_timeline_rpc_test.dart
+++ b/runtime/observatory_2/tests/service_2/get_vm_timeline_rpc_test.dart
@@ -111,7 +111,7 @@
     Map arguments = event['args'];
     expect(arguments, isA<Map>());
     expect(arguments['isolateGroupId'], isA<String>());
-    if (event['cat'] != 'GC') {
+    if (!const ['GC', 'Compiler', 'CompilerVerbose'].contains(event['cat'])) {
       expect(arguments['isolateId'], isA<String>());
     }
   }
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 0dfec5c..95ae6e3 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1309,7 +1309,6 @@
 void ClassFinalizer::SortClasses() {
   auto T = Thread::Current();
   auto Z = T->zone();
-  auto I = T->isolate();
   auto IG = T->isolate_group();
 
   // Prevent background compiler from adding deferred classes or canonicalizing
@@ -1384,11 +1383,11 @@
   ASSERT(next_new_cid == num_cids);
   RemapClassIds(old_to_new_cid.get());
   RehashTypes();         // Types use cid's as part of their hashes.
-  I->RehashConstants();  // Const objects use cid's as part of their hashes.
+  IG->RehashConstants();  // Const objects use cid's as part of their hashes.
 
   // Ensure any newly spawned isolate will apply this permutation map right
   // after kernel loading.
-  I->group()->source()->cid_permutation_map = std::move(old_to_new_cid);
+  IG->source()->cid_permutation_map = std::move(old_to_new_cid);
 }
 
 class CidRewriteVisitor : public ObjectVisitor {
@@ -1551,7 +1550,6 @@
 void ClassFinalizer::RehashTypes() {
   auto T = Thread::Current();
   auto Z = T->zone();
-  auto I = T->isolate();
   auto IG = T->isolate_group();
 
   // Clear all cached hash values.
@@ -1635,7 +1633,7 @@
 
   // The canonical constant tables use canonical hashcodes which can change
   // due to cid-renumbering.
-  I->RehashConstants();
+  IG->RehashConstants();
 
   dict_size = Utils::RoundUpToPowerOfTwo(typeargs.Length() * 4 / 3);
   CanonicalTypeArgumentsSet typeargs_table(
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 45bced2..1849a38 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -59,9 +59,10 @@
     GrowableArray<CodePtr>* code_objects,
     GrowableArray<ImageWriterCommand>* image_writer_commands) {
   auto thread = Thread::Current();
-  auto isolate = is_vm ? Dart::vm_isolate() : thread->isolate();
+  auto isolate_group =
+      is_vm ? Dart::vm_isolate()->group() : thread->isolate_group();
 
-  WritableCodePages writable_code_pages(thread, isolate);
+  WritableCodePages writable_code_pages(thread, isolate_group);
   CodeRelocator::Relocate(thread, code_objects, image_writer_commands, is_vm);
 }
 
@@ -146,8 +147,7 @@
     Serializer* s,
     intptr_t class_id) {
   const auto unboxed_fields_bitmap_host =
-      s->isolate()->group()->shared_class_table()->GetUnboxedFieldsMapAt(
-          class_id);
+      s->isolate_group()->shared_class_table()->GetUnboxedFieldsMapAt(class_id);
 
   UnboxedFieldBitmap unboxed_fields_bitmap;
   if (unboxed_fields_bitmap_host.IsEmpty() ||
@@ -358,7 +358,7 @@
       }
     }
 
-    auto shared_class_table = d->isolate()->group()->shared_class_table();
+    auto shared_class_table = d->isolate_group()->shared_class_table();
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       ClassPtr cls = static_cast<ClassPtr>(d->Ref(id));
       Deserializer::InitializeHeader(cls, kClassCid, Class::InstanceSize());
@@ -498,7 +498,7 @@
   }
 
   void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
-    if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
+    if (is_canonical && (d->isolate_group() != Dart::vm_isolate()->group())) {
       CanonicalTypeArgumentsSet table(
           d->zone(),
           d->isolate_group()->object_store()->canonical_type_arguments());
@@ -2367,7 +2367,7 @@
 
   void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
     if (is_canonical && IsStringClassId(cid_) &&
-        (d->isolate() != Dart::vm_isolate())) {
+        (d->isolate_group() != Dart::vm_isolate()->group())) {
       CanonicalStringSet table(
           d->zone(), d->isolate_group()->object_store()->symbol_table());
       String& str = String::Handle(d->zone());
@@ -3165,8 +3165,7 @@
     const intptr_t next_field_offset = host_next_field_offset_in_words_
                                        << kWordSizeLog2;
     const auto unboxed_fields_bitmap =
-        s->isolate()->group()->shared_class_table()->GetUnboxedFieldsMapAt(
-            cid_);
+        s->isolate_group()->shared_class_table()->GetUnboxedFieldsMapAt(cid_);
     intptr_t offset = Instance::NextFieldOffset();
     while (offset < next_field_offset) {
       // Skips unboxed fields
@@ -3203,8 +3202,7 @@
     const intptr_t count = objects_.length();
     s->WriteUnsigned64(CalculateTargetUnboxedFieldsBitmap(s, cid_).Value());
     const auto unboxed_fields_bitmap =
-        s->isolate()->group()->shared_class_table()->GetUnboxedFieldsMapAt(
-            cid_);
+        s->isolate_group()->shared_class_table()->GetUnboxedFieldsMapAt(cid_);
 
     for (intptr_t i = 0; i < count; i++) {
       InstancePtr instance = objects_[i];
@@ -3458,7 +3456,7 @@
   }
 
   void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
-    if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
+    if (is_canonical && (d->isolate_group() != Dart::vm_isolate()->group())) {
       CanonicalTypeSet table(
           d->zone(), d->isolate_group()->object_store()->canonical_types());
       Type& type = Type::Handle(d->zone());
@@ -3578,7 +3576,7 @@
   }
 
   void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
-    if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
+    if (is_canonical && (d->isolate_group() != Dart::vm_isolate()->group())) {
       CanonicalFunctionTypeSet table(
           d->zone(),
           d->isolate_group()->object_store()->canonical_function_types());
@@ -3785,7 +3783,7 @@
   }
 
   void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
-    if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
+    if (is_canonical && (d->isolate_group() != Dart::vm_isolate()->group())) {
       CanonicalTypeParameterSet table(
           d->zone(),
           d->isolate_group()->object_store()->canonical_type_parameters());
@@ -3955,7 +3953,7 @@
   void ReadFill(Deserializer* d, bool is_canonical) {}
 
   void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
-    if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
+    if (is_canonical && (d->isolate_group() != Dart::vm_isolate()->group())) {
       const Class& mint_cls = Class::Handle(
           d->zone(), IsolateGroup::Current()->object_store()->mint_class());
       mint_cls.set_constants(Object::null_array());
@@ -4843,7 +4841,7 @@
   }
 
   void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
-    if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
+    if (is_canonical && (d->isolate_group() != Dart::vm_isolate()->group())) {
       CanonicalStringSet table(
           d->zone(), d->isolate_group()->object_store()->symbol_table());
       String& str = String::Handle(d->zone());
@@ -4940,7 +4938,7 @@
   }
 
   void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
-    if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
+    if (is_canonical && (d->isolate_group() != Dart::vm_isolate()->group())) {
       CanonicalStringSet table(
           d->zone(), d->isolate_group()->object_store()->symbol_table());
       String& str = String::Handle(d->zone());
@@ -5274,7 +5272,6 @@
   }
 
   void PostLoad(Deserializer* d, const Array& refs) {
-    auto isolate = d->thread()->isolate();
     auto isolate_group = d->thread()->isolate_group();
     isolate_group->class_table()->CopySizesFromClassObjects();
     d->heap()->old_space()->EvaluateAfterLoading();
@@ -5286,7 +5283,6 @@
       unit ^= units.At(LoadingUnit::kRootId);
       unit.set_base_objects(refs);
     }
-    isolate->isolate_object_store()->PreallocateObjects();
 
     // Setup native resolver for bootstrap impl.
     Bootstrap::SetupNativeResolver();
@@ -5392,7 +5388,7 @@
 
     // Reinitialize the dispatch table by rereading the table's serialization
     // in the root snapshot.
-    IsolateGroup* group = d->thread()->isolate()->group();
+    IsolateGroup* group = d->thread()->isolate_group();
     if (group->dispatch_table_snapshot() != nullptr) {
       ReadStream stream(group->dispatch_table_snapshot(),
                         group->dispatch_table_snapshot_size());
@@ -6005,7 +6001,7 @@
   WriteBytes(reinterpret_cast<const uint8_t*>(expected_version), version_len);
 
   const char* expected_features =
-      Dart::FeaturesString(Isolate::Current(), is_vm_snapshot, kind_);
+      Dart::FeaturesString(IsolateGroup::Current(), is_vm_snapshot, kind_);
   ASSERT(expected_features != NULL);
   const intptr_t features_len = strlen(expected_features);
   WriteBytes(reinterpret_cast<const uint8_t*>(expected_features),
@@ -6522,7 +6518,6 @@
   // object, from which we can get the reference ID for any code object.
   const intptr_t first_code_id = stream->ReadUnsigned();
 
-  auto const I = isolate();
   auto const IG = isolate_group();
   auto code = IG->object_store()->dispatch_table_null_error_stub();
   ASSERT(code != Code::null());
@@ -6560,11 +6555,11 @@
   }
   ASSERT(repeat_count == 0);
 
-  I->group()->set_dispatch_table(table);
+  IG->set_dispatch_table(table);
   intptr_t table_snapshot_size =
       stream->AddressOfCurrentPosition() - table_snapshot_start;
-  I->group()->set_dispatch_table_snapshot(table_snapshot_start);
-  I->group()->set_dispatch_table_snapshot_size(table_snapshot_size);
+  IG->set_dispatch_table_snapshot(table_snapshot_start);
+  IG->set_dispatch_table_snapshot_size(table_snapshot_size);
 #endif
 }
 
@@ -6575,11 +6570,12 @@
   return ApiError::null();
 }
 
-char* SnapshotHeaderReader::VerifyVersionAndFeatures(Isolate* isolate,
-                                                     intptr_t* offset) {
+char* SnapshotHeaderReader::VerifyVersionAndFeatures(
+    IsolateGroup* isolate_group,
+    intptr_t* offset) {
   char* error = VerifyVersion();
   if (error == nullptr) {
-    error = VerifyFeatures(isolate);
+    error = VerifyFeatures(isolate_group);
   }
   if (error == nullptr) {
     *offset = stream_.Position();
@@ -6622,9 +6618,9 @@
   return nullptr;
 }
 
-char* SnapshotHeaderReader::VerifyFeatures(Isolate* isolate) {
+char* SnapshotHeaderReader::VerifyFeatures(IsolateGroup* isolate_group) {
   const char* expected_features =
-      Dart::FeaturesString(isolate, (isolate == NULL), kind_);
+      Dart::FeaturesString(isolate_group, (isolate_group == NULL), kind_);
   ASSERT(expected_features != NULL);
   const intptr_t expected_len = strlen(expected_features);
 
@@ -6912,10 +6908,10 @@
   roots->PostLoad(this, refs);
 
 #if defined(DEBUG)
-  Isolate* isolate = thread()->isolate();
-  isolate->ValidateClassTable();
-  if (isolate != Dart::vm_isolate()) {
-    isolate->group()->heap()->Verify();
+  auto isolate_group = thread()->isolate_group();
+  isolate_group->ValidateClassTable();
+  if (isolate_group != Dart::vm_isolate()->group()) {
+    isolate_group->heap()->Verify();
   }
 #endif
 
@@ -6956,14 +6952,14 @@
       clustered_isolate_size_(0),
       mapped_data_size_(0),
       mapped_text_size_(0) {
-  ASSERT(isolate() != NULL);
+  ASSERT(isolate_group() != NULL);
   ASSERT(heap() != NULL);
   ObjectStore* object_store = isolate_group()->object_store();
   ASSERT(object_store != NULL);
 
 #if defined(DEBUG)
-  isolate()->ValidateClassTable();
-  isolate()->ValidateConstants();
+  isolate_group()->ValidateClassTable();
+  isolate_group()->ValidateConstants();
 #endif  // DEBUG
 
 #if defined(DART_PRECOMPILER)
@@ -7289,8 +7285,8 @@
   SnapshotHeaderReader header_reader(kind_, buffer_, size_);
 
   intptr_t offset = 0;
-  char* error =
-      header_reader.VerifyVersionAndFeatures(/*isolate=*/NULL, &offset);
+  char* error = header_reader.VerifyVersionAndFeatures(
+      /*isolate_group=*/nullptr, &offset);
   if (error != nullptr) {
     return ConvertToApiError(error);
   }
@@ -7305,11 +7301,11 @@
 
   if (Snapshot::IncludesCode(kind_)) {
     ASSERT(data_image_ != NULL);
-    thread_->isolate()->SetupImagePage(data_image_,
-                                       /* is_executable */ false);
+    thread_->isolate_group()->SetupImagePage(data_image_,
+                                             /* is_executable */ false);
     ASSERT(instructions_image_ != NULL);
-    thread_->isolate()->SetupImagePage(instructions_image_,
-                                       /* is_executable */ true);
+    thread_->isolate_group()->SetupImagePage(instructions_image_,
+                                             /* is_executable */ true);
   }
 
   VMDeserializationRoots roots;
@@ -7331,7 +7327,7 @@
   SnapshotHeaderReader header_reader(kind_, buffer_, size_);
   intptr_t offset = 0;
   char* error =
-      header_reader.VerifyVersionAndFeatures(thread_->isolate(), &offset);
+      header_reader.VerifyVersionAndFeatures(thread_->isolate_group(), &offset);
   if (error != nullptr) {
     return ConvertToApiError(error);
   }
@@ -7346,11 +7342,11 @@
 
   if (Snapshot::IncludesCode(kind_)) {
     ASSERT(data_image_ != NULL);
-    thread_->isolate()->SetupImagePage(data_image_,
-                                       /* is_executable */ false);
+    thread_->isolate_group()->SetupImagePage(data_image_,
+                                             /* is_executable */ false);
     ASSERT(instructions_image_ != NULL);
-    thread_->isolate()->SetupImagePage(instructions_image_,
-                                       /* is_executable */ true);
+    thread_->isolate_group()->SetupImagePage(instructions_image_,
+                                             /* is_executable */ true);
   }
 
   ProgramDeserializationRoots roots(thread_->isolate_group()->object_store());
@@ -7366,7 +7362,7 @@
   SnapshotHeaderReader header_reader(kind_, buffer_, size_);
   intptr_t offset = 0;
   char* error =
-      header_reader.VerifyVersionAndFeatures(thread_->isolate(), &offset);
+      header_reader.VerifyVersionAndFeatures(thread_->isolate_group(), &offset);
   if (error != nullptr) {
     return ConvertToApiError(error);
   }
@@ -7392,11 +7388,11 @@
 
   if (Snapshot::IncludesCode(kind_)) {
     ASSERT(data_image_ != NULL);
-    thread_->isolate()->SetupImagePage(data_image_,
-                                       /* is_executable */ false);
+    thread_->isolate_group()->SetupImagePage(data_image_,
+                                             /* is_executable */ false);
     ASSERT(instructions_image_ != NULL);
-    thread_->isolate()->SetupImagePage(instructions_image_,
-                                       /* is_executable */ true);
+    thread_->isolate_group()->SetupImagePage(instructions_image_,
+                                             /* is_executable */ true);
   }
 
   UnitDeserializationRoots roots(unit);
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index fcd5d90..c4bd073 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -537,12 +537,12 @@
   // Returns null on success and a malloc()ed error on failure.
   // The [offset] will be the next position in the snapshot stream after the
   // features.
-  char* VerifyVersionAndFeatures(Isolate* isolate, intptr_t* offset);
+  char* VerifyVersionAndFeatures(IsolateGroup* isolate_group, intptr_t* offset);
 
  private:
   char* VerifyVersion();
   char* ReadFeatures(const char** features, intptr_t* features_length);
-  char* VerifyFeatures(Isolate* isolate);
+  char* VerifyFeatures(IsolateGroup* isolate_group);
   char* BuildError(const char* message);
 
   Snapshot::Kind kind_;
@@ -685,7 +685,6 @@
 
   Thread* thread() const { return thread_; }
   Zone* zone() const { return thread_->zone(); }
-  Isolate* isolate() const { return thread_->isolate(); }
   IsolateGroup* isolate_group() const { return thread_->isolate_group(); }
   Heap* heap() const { return isolate_group()->heap(); }
 
diff --git a/runtime/vm/compiler/backend/constant_propagator.h b/runtime/vm/compiler/backend/constant_propagator.h
index 36368d0..f2a6929 100644
--- a/runtime/vm/compiler/backend/constant_propagator.h
+++ b/runtime/vm/compiler/backend/constant_propagator.h
@@ -88,8 +88,6 @@
   // thus should not be stored anywhere.
   PhiInfo* GetPhiInfo(PhiInstr* phi);
 
-  Isolate* isolate() const { return graph_->isolate(); }
-
   FlowGraph* graph_;
 
   // Sentinels for unknown constant and non-constant values.
diff --git a/runtime/vm/compiler/backend/flow_graph.h b/runtime/vm/compiler/backend/flow_graph.h
index 8a8bb32..09e3caf 100644
--- a/runtime/vm/compiler/backend/flow_graph.h
+++ b/runtime/vm/compiler/backend/flow_graph.h
@@ -238,7 +238,6 @@
 
   Thread* thread() const { return thread_; }
   Zone* zone() const { return thread()->zone(); }
-  Isolate* isolate() const { return thread()->isolate(); }
   IsolateGroup* isolate_group() const { return thread()->isolate_group(); }
 
   intptr_t max_block_id() const { return max_block_id_; }
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 7005c7b..6fac0ad 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -300,9 +300,9 @@
 
 bool FlowGraphCompiler::ForceSlowPathForStackOverflow() const {
 #if !defined(PRODUCT)
-  if ((FLAG_stacktrace_every > 0) || (FLAG_deoptimize_every > 0) ||
-      (FLAG_gc_every > 0) ||
-      (isolate()->reload_every_n_stack_overflow_checks() > 0)) {
+  if (FLAG_stacktrace_every > 0 || FLAG_deoptimize_every > 0 ||
+      FLAG_gc_every > 0 ||
+      (isolate_group()->reload_every_n_stack_overflow_checks() > 0)) {
     if (!IsolateGroup::IsSystemIsolateGroup(isolate_group())) {
       return true;
     }
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index 7a145d1..f3f422e 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -945,7 +945,6 @@
   }
 
   Thread* thread() const { return thread_; }
-  Isolate* isolate() const { return thread_->isolate(); }
   IsolateGroup* isolate_group() const { return thread_->isolate_group(); }
   Zone* zone() const { return zone_; }
 
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index acb987e..459aec0 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -83,7 +83,6 @@
 
 // Quick access to the current zone.
 #define Z (zone())
-#define I (isolate())
 
 #define TRACE_INLINING(statement)                                              \
   do {                                                                         \
@@ -608,7 +607,7 @@
 
   TargetEntryInstr* BuildDecisionGraph();
 
-  Isolate* isolate() const;
+  IsolateGroup* isolate_group() const;
   Zone* zone() const;
   intptr_t AllocateBlockId() const;
   inline bool trace_inlining() const;
@@ -762,7 +761,6 @@
   FlowGraph* caller_graph() const { return caller_graph_; }
 
   Thread* thread() const { return caller_graph_->thread(); }
-  Isolate* isolate() const { return caller_graph_->isolate(); }
   Zone* zone() const { return caller_graph_->zone(); }
 
   bool trace_inlining() const { return inliner_->trace_inlining(); }
@@ -1663,8 +1661,8 @@
       exit_collector_(new (Z) InlineExitCollector(owner->caller_graph(), call)),
       caller_function_(caller_function) {}
 
-Isolate* PolymorphicInliner::isolate() const {
-  return owner_->caller_graph()->isolate();
+IsolateGroup* PolymorphicInliner::isolate_group() const {
+  return owner_->caller_graph()->isolate_group();
 }
 
 Zone* PolymorphicInliner::zone() const {
diff --git a/runtime/vm/compiler/backend/redundancy_elimination.h b/runtime/vm/compiler/backend/redundancy_elimination.h
index ab09270..877223b 100644
--- a/runtime/vm/compiler/backend/redundancy_elimination.h
+++ b/runtime/vm/compiler/backend/redundancy_elimination.h
@@ -72,7 +72,6 @@
 
   void EliminateAllocation(Definition* alloc);
 
-  Isolate* isolate() const { return flow_graph_->isolate(); }
   Zone* zone() const { return flow_graph_->zone(); }
 
   FlowGraph* flow_graph_;
diff --git a/runtime/vm/compiler/call_specializer.h b/runtime/vm/compiler/call_specializer.h
index ccad4cb..c0ad62d 100644
--- a/runtime/vm/compiler/call_specializer.h
+++ b/runtime/vm/compiler/call_specializer.h
@@ -74,7 +74,6 @@
 
  protected:
   Thread* thread() const { return flow_graph_->thread(); }
-  Isolate* isolate() const { return flow_graph_->isolate(); }
   IsolateGroup* isolate_group() const { return flow_graph_->isolate_group(); }
   Zone* zone() const { return flow_graph_->zone(); }
   const Function& function() const { return flow_graph_->function(); }
diff --git a/runtime/vm/compiler/frontend/flow_graph_builder.h b/runtime/vm/compiler/frontend/flow_graph_builder.h
index f2d5364..25d74d6 100644
--- a/runtime/vm/compiler/frontend/flow_graph_builder.h
+++ b/runtime/vm/compiler/frontend/flow_graph_builder.h
@@ -73,7 +73,6 @@
                           Instruction** last_instruction,
                           intptr_t try_index);
 
-  Isolate* isolate() const { return caller_graph_->isolate(); }
   Zone* zone() const { return caller_graph_->zone(); }
 
   FlowGraph* caller_graph_;
diff --git a/runtime/vm/compiler/jit/compiler.cc b/runtime/vm/compiler/jit/compiler.cc
index eeb7cd7..92c90ce 100644
--- a/runtime/vm/compiler/jit/compiler.cc
+++ b/runtime/vm/compiler/jit/compiler.cc
@@ -323,6 +323,7 @@
   intptr_t osr_id() const { return osr_id_; }
   Thread* thread() const { return thread_; }
   Isolate* isolate() const { return thread_->isolate(); }
+  IsolateGroup* isolate_group() const { return thread_->isolate_group(); }
   CodePtr FinalizeCompilation(compiler::Assembler* assembler,
                               FlowGraphCompiler* graph_compiler,
                               FlowGraph* flow_graph);
@@ -1110,8 +1111,8 @@
   DISALLOW_COPY_AND_ASSIGN(BackgroundCompilerTask);
 };
 
-BackgroundCompiler::BackgroundCompiler(Isolate* isolate)
-    : isolate_(isolate),
+BackgroundCompiler::BackgroundCompiler(IsolateGroup* isolate_group)
+    : isolate_group_(isolate_group),
       queue_monitor_(),
       function_queue_(new BackgroundCompilationQueue()),
       done_monitor_(),
@@ -1125,10 +1126,11 @@
 }
 
 void BackgroundCompiler::Run() {
-  while (running_) {
+  while (true) {
     // Maybe something is already in the queue, check first before waiting
     // to be notified.
-    bool result = Thread::EnterIsolateAsHelper(isolate_, Thread::kCompilerTask);
+    bool result = Thread::EnterIsolateGroupAsHelper(
+        isolate_group_, Thread::kCompilerTask, /*bypass_safepoint=*/false);
     ASSERT(result);
     {
       Thread* thread = Thread::Current();
@@ -1173,13 +1175,16 @@
         }
       }
     }
-    Thread::ExitIsolateAsHelper();
+    Thread::ExitIsolateGroupAsHelper(/*bypass_safepoint=*/false);
     {
       // Wait to be notified when the work queue is not empty.
       MonitorLocker ml(&queue_monitor_);
       while (function_queue()->IsEmpty() && running_) {
         ml.Wait();
       }
+      if (!running_) {
+        break;
+      }
     }
   }  // while running
 
@@ -1187,7 +1192,7 @@
     // Notify that the thread is done.
     MonitorLocker ml_done(&done_monitor_);
     done_ = true;
-    ml_done.Notify();
+    ml_done.NotifyAll();
   }
 }
 
@@ -1229,7 +1234,7 @@
 
 void BackgroundCompiler::Stop() {
   Thread* thread = Thread::Current();
-  ASSERT(thread->IsMutatorThread());
+  ASSERT(thread->isolate() == nullptr || thread->IsMutatorThread());
   ASSERT(!thread->IsAtSafepoint());
 
   SafepointMonitorLocker ml_done(&done_monitor_);
diff --git a/runtime/vm/compiler/jit/compiler.h b/runtime/vm/compiler/jit/compiler.h
index 5ed55be..456c70b 100644
--- a/runtime/vm/compiler/jit/compiler.h
+++ b/runtime/vm/compiler/jit/compiler.h
@@ -119,12 +119,11 @@
 // No OSR compilation in the background compiler.
 class BackgroundCompiler {
  public:
-  explicit BackgroundCompiler(Isolate* isolate);
+  explicit BackgroundCompiler(IsolateGroup* isolate_group);
   virtual ~BackgroundCompiler();
 
-  static void Stop(Isolate* isolate) {
-    ASSERT(Thread::Current()->IsMutatorThread());
-    isolate->background_compiler()->Stop();
+  static void Stop(IsolateGroup* isolate_group) {
+    isolate_group->background_compiler()->Stop();
   }
 
   // Enqueues a function to be compiled in the background.
@@ -148,7 +147,7 @@
   void Disable();
   bool IsRunning() { return !done_; }
 
-  Isolate* isolate_;
+  IsolateGroup* isolate_group_;
 
   Monitor queue_monitor_;  // Controls access to the queue.
   BackgroundCompilationQueue* function_queue_;
@@ -165,13 +164,15 @@
 class NoBackgroundCompilerScope : public StackResource {
  public:
   explicit NoBackgroundCompilerScope(Thread* thread)
-      : StackResource(thread), isolate_(thread->isolate()) {
-    isolate_->background_compiler()->Disable();
+      : StackResource(thread), isolate_group_(thread->isolate_group()) {
+    isolate_group_->background_compiler()->Disable();
   }
-  ~NoBackgroundCompilerScope() { isolate_->background_compiler()->Enable(); }
+  ~NoBackgroundCompilerScope() {
+    isolate_group_->background_compiler()->Enable();
+  }
 
  private:
-  Isolate* isolate_;
+  IsolateGroup* isolate_group_;
 };
 
 }  // namespace dart
diff --git a/runtime/vm/compiler_test.cc b/runtime/vm/compiler_test.cc
index d5d9a5e..49df77f 100644
--- a/runtime/vm/compiler_test.cc
+++ b/runtime/vm/compiler_test.cc
@@ -88,8 +88,8 @@
   // Constant in product mode.
   FLAG_background_compilation = true;
 #endif
-  Isolate* isolate = thread->isolate();
-  isolate->background_compiler()->EnqueueCompilation(func);
+  auto isolate_group = thread->isolate_group();
+  isolate_group->background_compiler()->EnqueueCompilation(func);
   Monitor* m = new Monitor();
   {
     SafepointMonitorLocker ml(m);
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index c1259f2..51a197c 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -879,9 +879,6 @@
   HandleScope handle_scope(T);
   bool was_child_cloned_into_existing_isolate = false;
   if (source_isolate_group != nullptr) {
-    I->isolate_object_store()->Init();
-    I->isolate_object_store()->PreallocateObjects();
-
     // If a static field gets registered in [IsolateGroup::RegisterStaticField]:
     //
     //   * before this block it will ignore this isolate. The [Clone] of the
@@ -938,16 +935,16 @@
 
   I->set_ic_miss_code(StubCode::SwitchableCallMiss());
 
-  if ((snapshot_data == NULL) || (kernel_buffer != NULL)) {
-    Error& error = Error::Handle();
+  Error& error = Error::Handle();
+  if (snapshot_data == nullptr || kernel_buffer != nullptr) {
     error ^= IG->object_store()->PreallocateObjects();
     if (!error.IsNull()) {
       return error.ptr();
     }
-    error ^= I->isolate_object_store()->PreallocateObjects();
-    if (!error.IsNull()) {
-      return error.ptr();
-    }
+  }
+  error ^= I->isolate_object_store()->PreallocateObjects();
+  if (!error.IsNull()) {
+    return error.ptr();
   }
 
   if (!was_child_cloned_into_existing_isolate) {
@@ -983,11 +980,9 @@
   return Error::null();
 }
 
-const char* Dart::FeaturesString(Isolate* isolate,
+const char* Dart::FeaturesString(IsolateGroup* isolate_group,
                                  bool is_vm_isolate,
                                  Snapshot::Kind kind) {
-  auto isolate_group = isolate != nullptr ? isolate->group() : nullptr;
-
   TextBuffer buffer(64);
 
 // Different fields are included for DEBUG/RELEASE/PRODUCT.
diff --git a/runtime/vm/dart.h b/runtime/vm/dart.h
index b7406c1..fa95787 100644
--- a/runtime/vm/dart.h
+++ b/runtime/vm/dart.h
@@ -101,7 +101,7 @@
   static uword AllocateReadOnlyHandle();
   static bool IsReadOnlyHandle(uword address);
 
-  static const char* FeaturesString(Isolate* isolate,
+  static const char* FeaturesString(IsolateGroup* isolate_group,
                                     bool is_vm_snapshot,
                                     Snapshot::Kind kind);
   static Snapshot::Kind vm_snapshot_kind() { return vm_snapshot_kind_; }
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 96d9b1b..21d315c 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1435,7 +1435,7 @@
 
 DART_EXPORT void Dart_ShutdownIsolate() {
   Thread* T = Thread::Current();
-  Isolate* I = T->isolate();
+  auto I = T->isolate();
   CHECK_ISOLATE(I);
 
   // The Thread structure is disassociated from the isolate, we do the
@@ -1461,7 +1461,7 @@
     StackZone zone(T);
     HandleScope handle_scope(T);
 #if defined(DEBUG)
-    I->ValidateConstants();
+    T->isolate_group()->ValidateConstants();
 #endif
     Dart::RunShutdownCallback();
   }
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 61be4a2..acf1abd 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -3506,9 +3506,23 @@
 }
 
 bool Debugger::IsDebugging(Thread* thread, const Function& func) {
-  Debugger* debugger = thread->isolate()->debugger();
-  return debugger->IsStepping() ||
-         debugger->HasBreakpoint(func, thread->zone());
+  // TODO(dartbug.com/36097): We might need to adjust this once we start adding
+  // debugging support to --enable-isolate-groups.
+  auto isolate_group = thread->isolate_group();
+
+  bool has_breakpoint = false;
+  bool is_single_stepping = false;
+  isolate_group->ForEachIsolate(
+      [&](Isolate* isolate) {
+        if (isolate->debugger()->IsStepping()) {
+          is_single_stepping = true;
+        }
+        if (isolate->debugger()->HasBreakpoint(func, thread->zone())) {
+          has_breakpoint = true;
+        }
+      },
+      thread->IsAtSafepoint());
+  return has_breakpoint || is_single_stepping;
 }
 
 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, Breakpoint* bpt) {
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index 9757a28..2422e51 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -1210,13 +1210,14 @@
   }
 }
 
-WritableCodePages::WritableCodePages(Thread* thread, Isolate* isolate)
-    : StackResource(thread), isolate_(isolate) {
-  isolate_->group()->heap()->WriteProtectCode(false);
+WritableCodePages::WritableCodePages(Thread* thread,
+                                     IsolateGroup* isolate_group)
+    : StackResource(thread), isolate_group_(isolate_group) {
+  isolate_group_->heap()->WriteProtectCode(false);
 }
 
 WritableCodePages::~WritableCodePages() {
-  isolate_->group()->heap()->WriteProtectCode(true);
+  isolate_group_->heap()->WriteProtectCode(true);
 }
 
 }  // namespace dart
diff --git a/runtime/vm/heap/heap.h b/runtime/vm/heap/heap.h
index ac1f0ff..6ec7705 100644
--- a/runtime/vm/heap/heap.h
+++ b/runtime/vm/heap/heap.h
@@ -484,11 +484,11 @@
 
 class WritableCodePages : StackResource {
  public:
-  explicit WritableCodePages(Thread* thread, Isolate* isolate);
+  WritableCodePages(Thread* thread, IsolateGroup* isolate_group);
   ~WritableCodePages();
 
  private:
-  Isolate* isolate_;
+  IsolateGroup* isolate_group_;
 };
 
 #if defined(TESTING)
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 5fff56a..5b8ffb7 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -342,6 +342,7 @@
       random_(),
 #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
       last_reload_timestamp_(OS::GetCurrentTimeMillis()),
+      reload_every_n_stack_overflow_checks_(FLAG_reload_every),
 #endif
       source_(std::move(source)),
       api_state_(new ApiState()),
@@ -353,6 +354,9 @@
       heap_(nullptr),
       saved_unlinked_calls_(Array::null()),
       initial_field_table_(new FieldTable(/*isolate=*/nullptr)),
+#if !defined(DART_PRECOMPILED_RUNTIME)
+      background_compiler_(new BackgroundCompiler(this)),
+#endif
       symbols_lock_(new SafepointRwLock()),
       type_canonicalization_mutex_(
           NOT_IN_PRODUCT("IsolateGroup::type_canonicalization_mutex_")),
@@ -850,11 +854,15 @@
 
 NoOOBMessageScope::NoOOBMessageScope(Thread* thread)
     : ThreadStackResource(thread) {
-  thread->DeferOOBMessageInterrupts();
+  if (thread->isolate() != nullptr) {
+    thread->DeferOOBMessageInterrupts();
+  }
 }
 
 NoOOBMessageScope::~NoOOBMessageScope() {
-  thread()->RestoreOOBMessageInterrupts();
+  if (thread()->isolate() != nullptr) {
+    thread()->RestoreOOBMessageInterrupts();
+  }
 }
 
 NoReloadScope::NoReloadScope(IsolateGroup* isolate_group, Thread* thread)
@@ -897,8 +905,8 @@
 }
 
 #if defined(DEBUG)
-void Isolate::ValidateClassTable() {
-  group()->class_table()->Validate();
+void IsolateGroup::ValidateClassTable() {
+  class_table()->Validate();
 }
 #endif  // DEBUG
 
@@ -934,7 +942,7 @@
   }
 }
 
-void Isolate::RehashConstants() {
+void IsolateGroup::RehashConstants() {
   Thread* thread = Thread::Current();
   StackZone stack_zone(thread);
   Zone* zone = stack_zone.GetZone();
@@ -942,10 +950,10 @@
   thread->heap()->ResetCanonicalHashTable();
 
   Class& cls = Class::Handle(zone);
-  intptr_t top = group()->class_table()->NumCids();
+  intptr_t top = class_table()->NumCids();
   for (intptr_t cid = kInstanceCid; cid < top; cid++) {
-    if (!group()->class_table()->IsValidIndex(cid) ||
-        !group()->class_table()->HasValidClassAt(cid)) {
+    if (!class_table()->IsValidIndex(cid) ||
+        !class_table()->HasValidClassAt(cid)) {
       continue;
     }
     if ((cid == kTypeArgumentsCid) || IsStringClassId(cid)) {
@@ -953,27 +961,27 @@
       // that aren't based on address.
       continue;
     }
-    cls = group()->class_table()->At(cid);
+    cls = class_table()->At(cid);
     cls.RehashConstants(zone);
   }
 }
 
 #if defined(DEBUG)
-void Isolate::ValidateConstants() {
+void IsolateGroup::ValidateConstants() {
   if (FLAG_precompiled_mode) {
     // TODO(27003)
     return;
   }
   // Issue(https://dartbug.com/44862): Figure out why hot-reload causes
   // existence of non-canonical constants.
-  if (group()->HasAttemptedReload()) {
+  if (HasAttemptedReload()) {
     return;
   }
 
   // Verify that all canonical instances are correctly setup in the
   // corresponding canonical tables.
   NoBackgroundCompilerScope no_bg_compiler(Thread::Current());
-  group()->heap()->CollectAllGarbage();
+  heap()->CollectAllGarbage();
   Thread* thread = Thread::Current();
   HeapIterationScope iteration(thread);
   VerifyCanonicalVisitor check_canonical(thread);
@@ -1705,7 +1713,6 @@
   metric_##variable##_(),
       ISOLATE_METRIC_LIST(ISOLATE_METRIC_CONSTRUCTORS)
 #undef ISOLATE_METRIC_CONSTRUCTORS
-          reload_every_n_stack_overflow_checks_(FLAG_reload_every),
 #endif  // !defined(PRODUCT)
       start_time_micros_(OS::GetCurrentMonotonicMicros()),
       on_shutdown_callback_(Isolate::ShutdownCallback()),
@@ -1734,8 +1741,6 @@
         "which violates the Dart standard.\n"
         "         See dartbug.com/30524 for more information.\n");
   }
-
-  NOT_IN_PRECOMPILED(background_compiler_ = new BackgroundCompiler(this));
 }
 
 #undef REUSABLE_HANDLE_SCOPE_INIT
@@ -1747,9 +1752,6 @@
   // RELEASE_ASSERT(program_reload_context_ == NULL);
 #endif  // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
 
-  delete background_compiler_;
-  background_compiler_ = nullptr;
-
 #if !defined(PRODUCT)
   delete debugger_;
   debugger_ = nullptr;
@@ -1845,6 +1847,10 @@
   result->set_pause_capability(result->random()->NextUInt64());
   result->set_terminate_capability(result->random()->NextUInt64());
 
+#if !defined(PRODUCT)
+  result->debugger_ = new Debugger(result);
+#endif
+
   // Now we register the isolate in the group. From this point on any GC would
   // traverse the isolate roots (before this point, the roots are only pointing
   // to vm-isolate objects, e.g. null)
@@ -1860,9 +1866,6 @@
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
   }
 
-#if !defined(PRODUCT)
-  result->debugger_ = new Debugger(result);
-#endif
   if (FLAG_trace_isolates) {
     if (name_prefix == nullptr || strcmp(name_prefix, "vm-isolate") != 0) {
       OS::PrintErr(
@@ -1915,10 +1918,11 @@
   return Api::UnwrapHandle(api_result);
 }
 
-void Isolate::SetupImagePage(const uint8_t* image_buffer, bool is_executable) {
+void IsolateGroup::SetupImagePage(const uint8_t* image_buffer,
+                                  bool is_executable) {
   Image image(image_buffer);
-  group()->heap()->SetupImagePage(image.object_start(), image.object_size(),
-                                  is_executable);
+  heap()->SetupImagePage(image.object_start(), image.object_size(),
+                         is_executable);
 }
 
 void Isolate::ScheduleInterrupts(uword interrupt_bits) {
@@ -2424,12 +2428,13 @@
 }
 
 #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
-void Isolate::MaybeIncreaseReloadEveryNStackOverflowChecks() {
+void IsolateGroup::MaybeIncreaseReloadEveryNStackOverflowChecks() {
   if (FLAG_reload_every_back_off) {
     if (reload_every_n_stack_overflow_checks_ < 5000) {
       reload_every_n_stack_overflow_checks_ += 99;
     } else {
-      reload_every_n_stack_overflow_checks_ *= 2;
+      const auto old_value = reload_every_n_stack_overflow_checks_;
+      reload_every_n_stack_overflow_checks_ = old_value * old_value;
     }
     // Cap the value.
     if (reload_every_n_stack_overflow_checks_ > 1000000) {
@@ -2449,12 +2454,8 @@
 }
 
 void Isolate::Shutdown() {
-  ASSERT(this == Isolate::Current());
-  NOT_IN_PRECOMPILED(BackgroundCompiler::Stop(this));
-  NOT_IN_PRECOMPILED(delete background_compiler_);
-  background_compiler_ = nullptr;
-
   Thread* thread = Thread::Current();
+  ASSERT(this == thread->isolate());
 
   // Don't allow anymore dart code to execution on this isolate.
   thread->ClearStackLimit();
@@ -2535,6 +2536,15 @@
   const bool shutdown_group =
       isolate_group->UnregisterIsolateDecrementCount(isolate);
   if (shutdown_group) {
+#if !defined(DART_PRECOMPILED_RUNTIME)
+    if (!is_vm_isolate) {
+      Thread::EnterIsolateGroupAsHelper(isolate_group, Thread::kUnknownTask,
+                                        /*bypass_safepoint=*/false);
+      BackgroundCompiler::Stop(isolate_group);
+      Thread::ExitIsolateGroupAsHelper(/*bypass_safepoint=*/false);
+    }
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
+
     // The "vm-isolate" does not have a thread pool.
     ASSERT(is_vm_isolate == (isolate_group->thread_pool() == nullptr));
     if (is_vm_isolate ||
@@ -2612,10 +2622,6 @@
       reinterpret_cast<ObjectPtr*>(&registered_service_extension_handlers_));
 #endif  // !defined(PRODUCT)
 
-  if (background_compiler() != nullptr) {
-    background_compiler()->VisitPointers(visitor);
-  }
-
 #if !defined(PRODUCT)
   // Visit objects in the debugger.
   if (debugger() != nullptr) {
@@ -2789,6 +2795,8 @@
   // is guarded with a monitor. This means that we can visit it only
   // when at safepoint or the field_list_mutex_ lock has been taken.
   visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&boxed_field_list_));
+
+  NOT_IN_PRECOMPILED(background_compiler()->VisitPointers(visitor));
 }
 
 void IsolateGroup::VisitStackPointers(ObjectPointerVisitor* visitor,
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index fefa565..b73263d 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -341,6 +341,12 @@
                Dart_IsolateFlags api_flags);
   ~IsolateGroup();
 
+  void RehashConstants();
+#if defined(DEBUG)
+  void ValidateConstants();
+  void ValidateClassTable();
+#endif
+
   IsolateGroupSource* source() const { return source_.get(); }
   std::shared_ptr<IsolateGroupSource> shareable_source() const {
     return source_;
@@ -352,6 +358,14 @@
 
   Heap* heap() const { return heap_.get(); }
 
+  BackgroundCompiler* background_compiler() const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+    return nullptr;
+#else
+    return background_compiler_.get();
+#endif
+  }
+
   IdleTimeHandler* idle_time_handler() { return &idle_time_handler_; }
 
   // Returns true if this is the first isolate registered.
@@ -371,6 +385,7 @@
   SafepointHandler* safepoint_handler() { return safepoint_handler_.get(); }
 
   void CreateHeap(bool is_vm_isolate, bool is_service_or_kernel_isolate);
+  void SetupImagePage(const uint8_t* snapshot_buffer, bool is_executable);
   void Shutdown();
 
 #define ISOLATE_METRIC_ACCESSOR(type, variable, name, unit)                    \
@@ -488,6 +503,10 @@
     isolate_group_flags_ =
         HasAttemptedReloadBit::update(value, isolate_group_flags_);
   }
+  void MaybeIncreaseReloadEveryNStackOverflowChecks();
+  intptr_t reload_every_n_stack_overflow_checks() const {
+    return reload_every_n_stack_overflow_checks_;
+  }
 #else
   bool HasAttemptedReload() const { return false; }
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
@@ -827,6 +846,8 @@
   std::shared_ptr<IsolateGroupReloadContext> group_reload_context_;
   RelaxedAtomic<intptr_t> no_reload_scope_depth_ =
       0;  // we can only reload when this is 0.
+  // Per-isolate-group copy of FLAG_reload_every.
+  RelaxedAtomic<intptr_t> reload_every_n_stack_overflow_checks_;
 #endif
 
 #define ISOLATE_METRIC_VARIABLE(type, variable, name, unit)                    \
@@ -865,6 +886,8 @@
   std::shared_ptr<FieldTable> initial_field_table_;
   uint32_t isolate_group_flags_ = 0;
 
+  NOT_IN_PRECOMPILED(std::unique_ptr<BackgroundCompiler> background_compiler_);
+
   std::unique_ptr<SafepointRwLock> symbols_lock_;
   Mutex type_canonicalization_mutex_;
   Mutex type_arguments_canonicalization_mutex_;
@@ -958,14 +981,6 @@
 
   // Register a newly introduced class.
   void RegisterClass(const Class& cls);
-#if defined(DEBUG)
-  void ValidateClassTable();
-#endif
-
-  void RehashConstants();
-#if defined(DEBUG)
-  void ValidateConstants();
-#endif
 
   ThreadRegistry* thread_registry() const { return group()->thread_registry(); }
 
@@ -1084,8 +1099,6 @@
   }
   ObjectPtr CallDeferredLoadHandler(intptr_t id);
 
-  void SetupImagePage(const uint8_t* snapshot_buffer, bool is_executable);
-
   void ScheduleInterrupts(uword interrupt_bits);
 
   const char* MakeRunnable();
@@ -1225,10 +1238,6 @@
     deopt_context_ = value;
   }
 
-  BackgroundCompiler* background_compiler() const {
-    return background_compiler_;
-  }
-
   intptr_t BlockClassFinalization() {
     ASSERT(defer_finalization_count_ >= 0);
     return defer_finalization_count_++;
@@ -1425,20 +1434,12 @@
     return IsolateGroup::IsSystemIsolateGroup(isolate->group());
   }
 
-#if !defined(PRODUCT)
-  intptr_t reload_every_n_stack_overflow_checks() const {
-    return reload_every_n_stack_overflow_checks_;
-  }
-#endif  // !defined(PRODUCT)
-
   HandlerInfoCache* handler_info_cache() { return &handler_info_cache_; }
 
   CatchEntryMovesCache* catch_entry_moves_cache() {
     return &catch_entry_moves_cache_;
   }
 
-  void MaybeIncreaseReloadEveryNStackOverflowChecks();
-
   // The weak table used in the snapshot writer for the purpose of fast message
   // sending.
   WeakTable* forward_table_new() { return forward_table_new_.get(); }
@@ -1589,8 +1590,6 @@
 
   uint32_t isolate_flags_ = 0;
 
-  BackgroundCompiler* background_compiler_ = nullptr;
-
 // Fields that aren't needed in a product build go here with boolean flags at
 // the top.
 #if !defined(PRODUCT)
@@ -1618,8 +1617,6 @@
   ISOLATE_METRIC_LIST(ISOLATE_METRIC_VARIABLE);
 #undef ISOLATE_METRIC_VARIABLE
 
-  // Per-isolate copy of FLAG_reload_every.
-  intptr_t reload_every_n_stack_overflow_checks_;
   ProgramReloadContext* program_reload_context_ = nullptr;
   // Ring buffer of objects assigned an id.
   ObjectIdRing* object_id_ring_ = nullptr;
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index f5b4498..2a13446 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -664,11 +664,7 @@
       [&](Isolate* isolate) { number_of_isolates++; });
 
   // Disable the background compiler while we are performing the reload.
-  ForEachIsolate([&](Isolate* isolate) {
-    // TODO(dartbug.com/36097): Once the BG compiler moves from Isolate to
-    // IsolateGroup this scope should cover most of this function.
-    NoBackgroundCompilerScope stop_bg_compiler(isolate->mutator_thread());
-  });
+  NoBackgroundCompilerScope stop_bg_compiler(thread);
 
   // Wait for any concurrent marking tasks to finish and turn off the
   // concurrent marker during reload as we might be allocating new instances
@@ -1705,11 +1701,11 @@
   // content may have changed from fields being added or removed.
   {
     TIMELINE_SCOPE(RehashConstants);
-    I->RehashConstants();
+    IG->RehashConstants();
   }
 
 #ifdef DEBUG
-  I->ValidateConstants();
+  IG->ValidateConstants();
 #endif
 
   if (FLAG_identity_reload) {
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 4b38596..740793b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -2614,7 +2614,7 @@
 class WriteBarrierUpdateVisitor : public ObjectPointerVisitor {
  public:
   explicit WriteBarrierUpdateVisitor(Thread* thread, ObjectPtr obj)
-      : ObjectPointerVisitor(thread->isolate()->group()),
+      : ObjectPointerVisitor(thread->isolate_group()),
         thread_(thread),
         old_obj_(obj) {
     ASSERT(old_obj_->IsOldObject());
@@ -6695,8 +6695,19 @@
 #if defined(PRODUCT)
   return false;
 #else
-  Thread* thread = Thread::Current();
-  return thread->isolate()->debugger()->HasBreakpoint(*this, thread->zone());
+  // TODO(dartbug.com/36097): We might need to adjust this once we start adding
+  // debugging support to --enable-isolate-groups.
+  auto thread = Thread::Current();
+  auto zone = thread->zone();
+  auto isolate_group = thread->isolate_group();
+
+  bool has_breakpoint = false;
+  isolate_group->ForEachIsolate([&](Isolate* isolate) {
+    if (isolate->debugger()->HasBreakpoint(*this, zone)) {
+      has_breakpoint = true;
+    }
+  });
+  return has_breakpoint;
 #endif
 }
 
@@ -7742,12 +7753,9 @@
     return CompilerState::Current().is_aot();
   }
 
-#if !defined(PRODUCT)
-  Thread* thread = Thread::Current();
-  if (thread->isolate()->debugger()->HasBreakpoint(*this, thread->zone())) {
+  if (HasBreakpoint()) {
     return false;
   }
-#endif  // !defined(PRODUCT)
 
   return is_inlinable() && !is_external() && !is_generated_body();
 }
@@ -10312,8 +10320,7 @@
   result.set_has_pragma(false);
   result.set_static_type_exactness_state(
       StaticTypeExactnessState::NotTracking());
-  auto isolate = Isolate::Current();
-  auto isolate_group = isolate->group();
+  auto isolate_group = IsolateGroup::Current();
 
 // Use field guards if they are enabled and the isolate has never reloaded.
 // TODO(johnmccutchan): The reload case assumes the worst case (everything is
@@ -16255,7 +16262,17 @@
 #if defined(PRODUCT)
   return false;
 #else
-  return Isolate::Current()->debugger()->HasBreakpoint(*this);
+  // TODO(dartbug.com/36097): We might need to adjust this once we start adding
+  // debugging support to --enable-isolate-groups.
+  auto isolate_group = Thread::Current()->isolate_group();
+
+  bool has_breakpoint = false;
+  isolate_group->ForEachIsolate([&](Isolate* isolate) {
+    if (isolate->debugger()->HasBreakpoint(*this)) {
+      has_breakpoint = true;
+    }
+  });
+  return has_breakpoint;
 #endif
 }
 
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index 2c78a12..e70b4fe 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -2481,7 +2481,7 @@
   bool do_reload = false;
   bool do_gc = false;
   const intptr_t isolate_reload_every =
-      isolate->reload_every_n_stack_overflow_checks();
+      isolate->group()->reload_every_n_stack_overflow_checks();
   if ((FLAG_deoptimize_every > 0) || (FLAG_stacktrace_every > 0) ||
       (FLAG_gc_every > 0) || (isolate_reload_every > 0)) {
     if (!Isolate::IsSystemIsolate(isolate)) {
@@ -2548,7 +2548,7 @@
   if (do_reload) {
     JSONStream js;
     // Maybe adjust the rate of future reloads.
-    isolate->MaybeIncreaseReloadEveryNStackOverflowChecks();
+    isolate->group()->MaybeIncreaseReloadEveryNStackOverflowChecks();
 
     const char* script_uri;
     {
@@ -2773,15 +2773,15 @@
   ASSERT(function.HasCode());
 
   if (Compiler::CanOptimizeFunction(thread, function)) {
+    auto isolate_group = thread->isolate_group();
     if (FLAG_background_compilation) {
       if (function.is_background_optimizable() &&
-          isolate->background_compiler()->EnqueueCompilation(function)) {
+          isolate_group->background_compiler()->EnqueueCompilation(function)) {
         // Reduce the chance of triggering a compilation while the function is
         // being compiled in the background. INT32_MIN should ensure that it
         // takes long time to trigger a compilation.
         // Note that the background compilation queue rejects duplicate entries.
         function.SetUsageCounter(INT32_MIN);
-
         // Continue in the same code.
         arguments.SetReturn(function);
         return;
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 5202079..f90b098 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -710,7 +710,8 @@
   return NULL;
 }
 
-ApiErrorPtr SnapshotReader::VerifyVersionAndFeatures(Isolate* isolate) {
+ApiErrorPtr SnapshotReader::VerifyVersionAndFeatures(
+    IsolateGroup* isolate_group) {
   // If the version string doesn't match, return an error.
   // Note: New things are allocated only if we're going to return an error.
 
@@ -747,7 +748,8 @@
   }
   Advance(version_len);
 
-  const char* expected_features = Dart::FeaturesString(isolate, false, kind_);
+  const char* expected_features =
+      Dart::FeaturesString(isolate_group, false, kind_);
   ASSERT(expected_features != NULL);
   const intptr_t expected_len = strlen(expected_features);
 
@@ -1566,7 +1568,7 @@
   WriteBytes(reinterpret_cast<const uint8_t*>(expected_version), version_len);
 
   const char* expected_features =
-      Dart::FeaturesString(Isolate::Current(), false, kind_);
+      Dart::FeaturesString(IsolateGroup::Current(), false, kind_);
   ASSERT(expected_features != NULL);
   const intptr_t features_len = strlen(expected_features);
   WriteBytes(reinterpret_cast<const uint8_t*>(expected_features),
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index d526847..8ad3cb1 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -289,7 +289,7 @@
   Object* GetBackRef(intptr_t id);
 
   // Read version number of snapshot and verify.
-  ApiErrorPtr VerifyVersionAndFeatures(Isolate* isolate);
+  ApiErrorPtr VerifyVersionAndFeatures(IsolateGroup* isolate_group);
 
   ObjectPtr NewInteger(int64_t value);
 
diff --git a/tools/VERSION b/tools/VERSION
index 4e84a35..05f7464 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 28
+PRERELEASE 29
 PRERELEASE_PATCH 0
\ No newline at end of file