Version 2.12.0-148.0.dev

Merge commit '57b54b00e107fd4fca95bfca86fb9cc47799c681' into 'dev'
diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc
index 0bc1761..b4185a9 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64.cc
@@ -114,15 +114,6 @@
   }
 }
 
-void Assembler::PushImmediate(const Immediate& imm) {
-  if (imm.is_int32()) {
-    pushq(imm);
-  } else {
-    LoadImmediate(TMP, imm);
-    pushq(TMP);
-  }
-}
-
 void Assembler::popq(Register reg) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitRegisterREX(reg, REX_NONE);
diff --git a/runtime/vm/compiler/assembler/assembler_x64.h b/runtime/vm/compiler/assembler/assembler_x64.h
index 3b5fa5c..eb7d69a 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.h
+++ b/runtime/vm/compiler/assembler/assembler_x64.h
@@ -304,7 +304,7 @@
   void pushq(Register reg);
   void pushq(const Address& address) { EmitUnaryL(address, 0xFF, 6); }
   void pushq(const Immediate& imm);
-  void PushImmediate(const Immediate& imm);
+  void PushImmediate(const Immediate& imm) { pushq(imm); }
   void PushImmediate(int64_t value) { PushImmediate(Immediate(value)); }
 
   void popq(Register reg);
@@ -915,6 +915,15 @@
                           OperandSize sz = kEightBytes) {
     LoadFromOffset(dst, FieldAddress(base, index, scale, payload_offset), sz);
   }
+  void StoreFieldToOffset(Register src,
+                          Register base,
+                          int32_t offset,
+                          OperandSize sz = kEightBytes) {
+    if (sz != kEightBytes) {
+      UNIMPLEMENTED();
+    }
+    StoreMemoryValue(src, base, offset - kHeapObjectTag);
+  }
   void LoadFromStack(Register dst, intptr_t depth);
   void StoreToStack(Register src, intptr_t depth);
   void CompareToStack(Register src, intptr_t depth);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 1f084c1..72ce4b3 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -2903,7 +2903,7 @@
     __ GenerateUnRelocatedPcRelativeCall();
     AddPcRelativeTTSCallTypeTarget(dst_type);
   } else {
-    GenerateIndirectTTSCall(reg_with_type, sub_type_cache_index);
+    GenerateIndirectTTSCall(assembler(), reg_with_type, sub_type_cache_index);
   }
   EmitCallsiteMetadata(token_pos, deopt_id, PcDescriptorsLayout::kOther, locs);
 }
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index cebc344..0e0815b 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -606,8 +606,9 @@
                        const String& dst_name,
                        LocationSummary* locs);
 
-  void GenerateIndirectTTSCall(Register reg_with_type,
-                               intptr_t sub_type_cache_index);
+  static void GenerateIndirectTTSCall(compiler::Assembler* assembler,
+                                      Register reg_with_type,
+                                      intptr_t sub_type_cache_index);
 #endif
 
   void GenerateRuntimeCall(TokenPosition token_pos,
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index 31ceee7..f6f4ece 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -204,7 +204,25 @@
 #undef __
 }
 
+#define __ assembler->
+// Static methods of FlowGraphCompiler that take an assembler.
+
+void FlowGraphCompiler::GenerateIndirectTTSCall(compiler::Assembler* assembler,
+                                                Register reg_to_call,
+                                                intptr_t sub_type_cache_index) {
+  __ LoadField(
+      TTSInternalRegs::kScratchReg,
+      compiler::FieldAddress(
+          reg_to_call,
+          compiler::target::AbstractType::type_test_stub_entry_point_offset()));
+  __ LoadWordFromPoolIndex(TypeTestABI::kSubtypeTestCacheReg,
+                           sub_type_cache_index);
+  __ blx(TTSInternalRegs::kScratchReg);
+}
+
+#undef __
 #define __ assembler()->
+// Instance methods of FlowGraphCompiler.
 
 // Fall through if bool_register contains null.
 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
@@ -222,18 +240,6 @@
   __ Bind(&fall_through);
 }
 
-void FlowGraphCompiler::GenerateIndirectTTSCall(Register reg_to_call,
-                                                intptr_t sub_type_cache_index) {
-  __ LoadField(
-      R9,
-      compiler::FieldAddress(
-          reg_to_call,
-          compiler::target::AbstractType::type_test_stub_entry_point_offset()));
-  __ LoadWordFromPoolIndex(TypeTestABI::kSubtypeTestCacheReg,
-                           sub_type_cache_index);
-  __ blx(R9);
-}
-
 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) {
   if (is_optimizing()) {
     return;
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index 668e0e2..92dd916 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -197,7 +197,25 @@
 #undef __
 }
 
+#define __ assembler->
+// Static methods of FlowGraphCompiler that take an assembler.
+
+void FlowGraphCompiler::GenerateIndirectTTSCall(compiler::Assembler* assembler,
+                                                Register reg_to_call,
+                                                intptr_t sub_type_cache_index) {
+  __ LoadField(
+      TTSInternalRegs::kScratchReg,
+      compiler::FieldAddress(
+          reg_to_call,
+          compiler::target::AbstractType::type_test_stub_entry_point_offset()));
+  __ LoadWordFromPoolIndex(TypeTestABI::kSubtypeTestCacheReg,
+                           sub_type_cache_index);
+  __ blr(TTSInternalRegs::kScratchReg);
+}
+
+#undef __
 #define __ assembler()->
+// Instance methods of FlowGraphCompiler.
 
 // Fall through if bool_register contains null.
 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
@@ -213,18 +231,6 @@
   __ Bind(&fall_through);
 }
 
-void FlowGraphCompiler::GenerateIndirectTTSCall(Register reg_to_call,
-                                                intptr_t sub_type_cache_index) {
-  __ LoadField(
-      R9,
-      compiler::FieldAddress(
-          reg_to_call,
-          compiler::target::AbstractType::type_test_stub_entry_point_offset()));
-  __ LoadWordFromPoolIndex(TypeTestABI::kSubtypeTestCacheReg,
-                           sub_type_cache_index);
-  __ blr(R9);
-}
-
 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) {
   if (is_optimizing()) {
     return;
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index 7905dec..29adb56 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -199,7 +199,22 @@
 #undef __
 }
 
+#define __ assembler->
+// Static methods of FlowGraphCompiler that take an assembler.
+
+void FlowGraphCompiler::GenerateIndirectTTSCall(compiler::Assembler* assembler,
+                                                Register reg_to_call,
+                                                intptr_t sub_type_cache_index) {
+  __ LoadWordFromPoolIndex(TypeTestABI::kSubtypeTestCacheReg,
+                           sub_type_cache_index);
+  __ Call(compiler::FieldAddress(
+      reg_to_call,
+      compiler::target::AbstractType::type_test_stub_entry_point_offset()));
+}
+
+#undef __
 #define __ assembler()->
+// Instance methods of FlowGraphCompiler.
 
 // Fall through if bool_register contains null.
 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
@@ -217,15 +232,6 @@
   __ Bind(&fall_through);
 }
 
-void FlowGraphCompiler::GenerateIndirectTTSCall(Register reg_to_call,
-                                                intptr_t sub_type_cache_index) {
-  __ LoadWordFromPoolIndex(TypeTestABI::kSubtypeTestCacheReg,
-                           sub_type_cache_index);
-  __ Call(compiler::FieldAddress(
-      reg_to_call,
-      compiler::target::AbstractType::type_test_stub_entry_point_offset()));
-}
-
 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) {
   if (is_optimizing()) {
     return;
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index fd13ab7..01e5a1f 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -2629,7 +2629,7 @@
   // used to initialize this register.
   const Register kCacheArrayReg = TypeTestABI::kSubtypeTestCacheReg;
   const Register kScratchReg = TypeTestABI::kScratchReg;
-  const Register kInstanceCidOrFunction = R9;
+
   // Registers that are only used for n >= 3 and must be preserved if used.
   Register kInstanceInstantiatorTypeArgumentsReg = kNoRegister;
   // Registers that are only used for n >= 7 and must be preserved if used.
@@ -2674,16 +2674,18 @@
 
   Label loop, not_closure;
   if (n >= 5) {
-    __ LoadClassIdMayBeSmi(kInstanceCidOrFunction, TypeTestABI::kInstanceReg);
+    __ LoadClassIdMayBeSmi(STCInternalRegs::kInstanceCidOrFunctionReg,
+                           TypeTestABI::kInstanceReg);
   } else {
-    __ LoadClassId(kInstanceCidOrFunction, TypeTestABI::kInstanceReg);
+    __ LoadClassId(STCInternalRegs::kInstanceCidOrFunctionReg,
+                   TypeTestABI::kInstanceReg);
   }
-  __ CompareImmediate(kInstanceCidOrFunction, kClosureCid);
+  __ CompareImmediate(STCInternalRegs::kInstanceCidOrFunctionReg, kClosureCid);
   __ b(&not_closure, NE);
 
   // Closure handling.
   {
-    __ ldr(kInstanceCidOrFunction,
+    __ ldr(STCInternalRegs::kInstanceCidOrFunctionReg,
            FieldAddress(TypeTestABI::kInstanceReg,
                         target::Closure::function_offset()));
     if (n >= 3) {
@@ -2709,7 +2711,7 @@
     __ Bind(&not_closure);
     if (n >= 3) {
       Label has_no_type_arguments;
-      __ LoadClassById(kScratchReg, kInstanceCidOrFunction);
+      __ LoadClassById(kScratchReg, STCInternalRegs::kInstanceCidOrFunctionReg);
       __ mov(kInstanceInstantiatorTypeArgumentsReg, Operand(kNullReg));
       __ ldr(
           kScratchReg,
@@ -2729,7 +2731,7 @@
         __ PushRegister(kNullReg);
       }
     }
-    __ SmiTag(kInstanceCidOrFunction);
+    __ SmiTag(STCInternalRegs::kInstanceCidOrFunctionReg);
   }
 
   const intptr_t kNoDepth = -1;
@@ -2746,7 +2748,7 @@
                      target::SubtypeTestCache::kInstanceClassIdOrFunction));
   __ cmp(kScratchReg, Operand(kNullReg));
   __ b(&not_found, EQ);
-  __ cmp(kScratchReg, Operand(kInstanceCidOrFunction));
+  __ cmp(kScratchReg, Operand(STCInternalRegs::kInstanceCidOrFunctionReg));
   if (n == 1) {
     __ b(&found, EQ);
   } else {
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index 15da38d..22a550e 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -2798,10 +2798,6 @@
 
   const Register kCacheArrayReg = TypeTestABI::kSubtypeTestCacheReg;
   const Register kScratchReg = TypeTestABI::kScratchReg;
-  const Register kInstanceCidOrFunction = R6;
-  const Register kInstanceInstantiatorTypeArgumentsReg = R5;
-  const Register kInstanceParentFunctionTypeArgumentsReg = R9;
-  const Register kInstanceDelayedFunctionTypeArgumentsReg = R10;
 
   // All of these must be distinct from TypeTestABI::kSubtypeTestCacheResultReg
   // since it is used for kNullReg as well.
@@ -2819,29 +2815,30 @@
 
   Label loop, not_closure;
   if (n >= 5) {
-    __ LoadClassIdMayBeSmi(kInstanceCidOrFunction,
+    __ LoadClassIdMayBeSmi(STCInternalRegs::kInstanceCidOrFunctionReg,
                            TypeTestABI::TypeTestABI::kInstanceReg);
   } else {
-    __ LoadClassId(kInstanceCidOrFunction, TypeTestABI::kInstanceReg);
+    __ LoadClassId(STCInternalRegs::kInstanceCidOrFunctionReg,
+                   TypeTestABI::kInstanceReg);
   }
-  __ CompareImmediate(kInstanceCidOrFunction, kClosureCid);
+  __ CompareImmediate(STCInternalRegs::kInstanceCidOrFunctionReg, kClosureCid);
   __ b(&not_closure, NE);
 
   // Closure handling.
   {
-    __ ldr(kInstanceCidOrFunction,
+    __ ldr(STCInternalRegs::kInstanceCidOrFunctionReg,
            FieldAddress(TypeTestABI::kInstanceReg,
                         target::Closure::function_offset()));
     if (n >= 3) {
       __ ldr(
-          kInstanceInstantiatorTypeArgumentsReg,
+          STCInternalRegs::kInstanceInstantiatorTypeArgumentsReg,
           FieldAddress(TypeTestABI::kInstanceReg,
                        target::Closure::instantiator_type_arguments_offset()));
       if (n >= 7) {
-        __ ldr(kInstanceParentFunctionTypeArgumentsReg,
+        __ ldr(STCInternalRegs::kInstanceParentFunctionTypeArgumentsReg,
                FieldAddress(TypeTestABI::kInstanceReg,
                             target::Closure::function_type_arguments_offset()));
-        __ ldr(kInstanceDelayedFunctionTypeArgumentsReg,
+        __ ldr(STCInternalRegs::kInstanceDelayedFunctionTypeArgumentsReg,
                FieldAddress(TypeTestABI::kInstanceReg,
                             target::Closure::delayed_type_arguments_offset()));
       }
@@ -2854,8 +2851,8 @@
     __ Bind(&not_closure);
     if (n >= 3) {
       Label has_no_type_arguments;
-      __ LoadClassById(kScratchReg, kInstanceCidOrFunction);
-      __ mov(kInstanceInstantiatorTypeArgumentsReg, kNullReg);
+      __ LoadClassById(kScratchReg, STCInternalRegs::kInstanceCidOrFunctionReg);
+      __ mov(STCInternalRegs::kInstanceInstantiatorTypeArgumentsReg, kNullReg);
       __ LoadFieldFromOffset(
           kScratchReg, kScratchReg,
           target::Class::host_type_arguments_field_offset_in_words_offset(),
@@ -2864,16 +2861,18 @@
       __ b(&has_no_type_arguments, EQ);
       __ add(kScratchReg, TypeTestABI::kInstanceReg,
              Operand(kScratchReg, LSL, 3));
-      __ ldr(kInstanceInstantiatorTypeArgumentsReg,
+      __ ldr(STCInternalRegs::kInstanceInstantiatorTypeArgumentsReg,
              FieldAddress(kScratchReg, 0));
       __ Bind(&has_no_type_arguments);
 
       if (n >= 7) {
-        __ mov(kInstanceParentFunctionTypeArgumentsReg, kNullReg);
-        __ mov(kInstanceDelayedFunctionTypeArgumentsReg, kNullReg);
+        __ mov(STCInternalRegs::kInstanceParentFunctionTypeArgumentsReg,
+               kNullReg);
+        __ mov(STCInternalRegs::kInstanceDelayedFunctionTypeArgumentsReg,
+               kNullReg);
       }
     }
-    __ SmiTag(kInstanceCidOrFunction);
+    __ SmiTag(STCInternalRegs::kInstanceCidOrFunctionReg);
   }
 
   Label found, done, next_iteration;
@@ -2886,7 +2885,7 @@
                      target::SubtypeTestCache::kInstanceClassIdOrFunction));
   __ cmp(kScratchReg, Operand(kNullReg));
   __ b(&done, EQ);
-  __ cmp(kScratchReg, Operand(kInstanceCidOrFunction));
+  __ cmp(kScratchReg, Operand(STCInternalRegs::kInstanceCidOrFunctionReg));
   if (n == 1) {
     __ b(&found, EQ);
   } else {
@@ -2901,7 +2900,8 @@
            Address(kCacheArrayReg,
                    target::kWordSize *
                        target::SubtypeTestCache::kInstanceTypeArguments));
-    __ cmp(kScratchReg, Operand(kInstanceInstantiatorTypeArgumentsReg));
+    __ cmp(kScratchReg,
+           Operand(STCInternalRegs::kInstanceInstantiatorTypeArgumentsReg));
     if (n == 3) {
       __ b(&found, EQ);
     } else {
@@ -2928,7 +2928,9 @@
                        target::kWordSize *
                            target::SubtypeTestCache::
                                kInstanceParentFunctionTypeArguments));
-        __ cmp(kScratchReg, Operand(kInstanceParentFunctionTypeArgumentsReg));
+        __ cmp(
+            kScratchReg,
+            Operand(STCInternalRegs::kInstanceParentFunctionTypeArgumentsReg));
         __ b(&next_iteration, NE);
 
         __ ldr(kScratchReg,
@@ -2936,7 +2938,9 @@
                        target::kWordSize *
                            target::SubtypeTestCache::
                                kInstanceDelayedFunctionTypeArguments));
-        __ cmp(kScratchReg, Operand(kInstanceDelayedFunctionTypeArgumentsReg));
+        __ cmp(
+            kScratchReg,
+            Operand(STCInternalRegs::kInstanceDelayedFunctionTypeArgumentsReg));
         __ b(&found, EQ);
       }
     }
diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc
index 08b540d..fc4f6ac 100644
--- a/runtime/vm/compiler/stub_code_compiler_x64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_x64.cc
@@ -2752,12 +2752,8 @@
   const Register kNullReg = TypeTestABI::kSubtypeTestCacheResultReg;
   __ LoadObject(kNullReg, NullObject());
 
-  // All of these must be distinct from TypeTestABI::kSubtypeTestCacheResultReg
-  // since it is used for kNullReg as well.
-  const Register kCacheArrayReg = RDI;
   const Register kScratchReg = TypeTestABI::kScratchReg;
-  const Register kInstanceCidOrFunction = R10;
-  const Register kInstanceInstantiatorTypeArgumentsReg = R13;
+
   // Only used for n >= 7, so set conditionally in that case to catch misuse.
   Register kInstanceParentFunctionTypeArgumentsReg = kNoRegister;
   Register kInstanceDelayedFunctionTypeArgumentsReg = kNoRegister;
@@ -2775,29 +2771,31 @@
 
   // We avoid a load-acquire barrier here by relying on the fact that all other
   // loads from the array are data-dependent loads.
-  __ movq(kCacheArrayReg,
+  __ movq(STCInternalRegs::kCacheEntryReg,
           FieldAddress(TypeTestABI::kSubtypeTestCacheReg,
                        target::SubtypeTestCache::cache_offset()));
-  __ addq(kCacheArrayReg,
+  __ addq(STCInternalRegs::kCacheEntryReg,
           Immediate(target::Array::data_offset() - kHeapObjectTag));
 
   Label loop, not_closure;
   if (n >= 5) {
-    __ LoadClassIdMayBeSmi(kInstanceCidOrFunction, TypeTestABI::kInstanceReg);
+    __ LoadClassIdMayBeSmi(STCInternalRegs::kInstanceCidOrFunctionReg,
+                           TypeTestABI::kInstanceReg);
   } else {
-    __ LoadClassId(kInstanceCidOrFunction, TypeTestABI::kInstanceReg);
+    __ LoadClassId(STCInternalRegs::kInstanceCidOrFunctionReg,
+                   TypeTestABI::kInstanceReg);
   }
-  __ cmpq(kInstanceCidOrFunction, Immediate(kClosureCid));
+  __ cmpq(STCInternalRegs::kInstanceCidOrFunctionReg, Immediate(kClosureCid));
   __ j(NOT_EQUAL, &not_closure, Assembler::kNearJump);
 
   // Closure handling.
   {
-    __ movq(kInstanceCidOrFunction,
+    __ movq(STCInternalRegs::kInstanceCidOrFunctionReg,
             FieldAddress(TypeTestABI::kInstanceReg,
                          target::Closure::function_offset()));
     if (n >= 3) {
       __ movq(
-          kInstanceInstantiatorTypeArgumentsReg,
+          STCInternalRegs::kInstanceInstantiatorTypeArgumentsReg,
           FieldAddress(TypeTestABI::kInstanceReg,
                        target::Closure::instantiator_type_arguments_offset()));
       if (n >= 7) {
@@ -2818,8 +2816,8 @@
     __ Bind(&not_closure);
     if (n >= 3) {
       Label has_no_type_arguments;
-      __ LoadClassById(kScratchReg, kInstanceCidOrFunction);
-      __ movq(kInstanceInstantiatorTypeArgumentsReg, kNullReg);
+      __ LoadClassById(kScratchReg, STCInternalRegs::kInstanceCidOrFunctionReg);
+      __ movq(STCInternalRegs::kInstanceInstantiatorTypeArgumentsReg, kNullReg);
       __ movl(
           kScratchReg,
           FieldAddress(kScratchReg,
@@ -2827,7 +2825,7 @@
                            host_type_arguments_field_offset_in_words_offset()));
       __ cmpl(kScratchReg, Immediate(target::Class::kNoTypeArguments));
       __ j(EQUAL, &has_no_type_arguments, Assembler::kNearJump);
-      __ movq(kInstanceInstantiatorTypeArgumentsReg,
+      __ movq(STCInternalRegs::kInstanceInstantiatorTypeArgumentsReg,
               FieldAddress(TypeTestABI::kInstanceReg, kScratchReg, TIMES_8, 0));
       __ Bind(&has_no_type_arguments);
 
@@ -2836,7 +2834,7 @@
         __ movq(kInstanceDelayedFunctionTypeArgumentsReg, kNullReg);
       }
     }
-    __ SmiTag(kInstanceCidOrFunction);
+    __ SmiTag(STCInternalRegs::kInstanceCidOrFunctionReg);
   }
 
   Label found, not_found, next_iteration;
@@ -2844,23 +2842,23 @@
   // Loop header.
   __ Bind(&loop);
   __ movq(kScratchReg,
-          Address(kCacheArrayReg,
+          Address(STCInternalRegs::kCacheEntryReg,
                   target::kWordSize *
                       target::SubtypeTestCache::kInstanceClassIdOrFunction));
   __ cmpq(kScratchReg, kNullReg);
   __ j(EQUAL, &not_found, Assembler::kNearJump);
-  __ cmpq(kScratchReg, kInstanceCidOrFunction);
+  __ cmpq(kScratchReg, STCInternalRegs::kInstanceCidOrFunctionReg);
   if (n == 1) {
     __ j(EQUAL, &found, Assembler::kNearJump);
   } else {
     __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
     __ cmpq(TypeTestABI::kDstTypeReg,
-            Address(kCacheArrayReg,
+            Address(STCInternalRegs::kCacheEntryReg,
                     target::kWordSize *
                         target::SubtypeTestCache::kDestinationType));
     __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
-    __ cmpq(kInstanceInstantiatorTypeArgumentsReg,
-            Address(kCacheArrayReg,
+    __ cmpq(STCInternalRegs::kInstanceInstantiatorTypeArgumentsReg,
+            Address(STCInternalRegs::kCacheEntryReg,
                     target::kWordSize *
                         target::SubtypeTestCache::kInstanceTypeArguments));
     if (n == 3) {
@@ -2869,12 +2867,12 @@
       __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
       __ cmpq(
           TypeTestABI::kInstantiatorTypeArgumentsReg,
-          Address(kCacheArrayReg,
+          Address(STCInternalRegs::kCacheEntryReg,
                   target::kWordSize *
                       target::SubtypeTestCache::kInstantiatorTypeArguments));
       __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
       __ cmpq(TypeTestABI::kFunctionTypeArgumentsReg,
-              Address(kCacheArrayReg,
+              Address(STCInternalRegs::kCacheEntryReg,
                       target::kWordSize *
                           target::SubtypeTestCache::kFunctionTypeArguments));
 
@@ -2885,13 +2883,13 @@
         __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
 
         __ cmpq(kInstanceParentFunctionTypeArgumentsReg,
-                Address(kCacheArrayReg,
+                Address(STCInternalRegs::kCacheEntryReg,
                         target::kWordSize *
                             target::SubtypeTestCache::
                                 kInstanceParentFunctionTypeArguments));
         __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
         __ cmpq(kInstanceDelayedFunctionTypeArgumentsReg,
-                Address(kCacheArrayReg,
+                Address(STCInternalRegs::kCacheEntryReg,
                         target::kWordSize *
                             target::SubtypeTestCache::
                                 kInstanceDelayedFunctionTypeArguments));
@@ -2901,14 +2899,14 @@
   }
 
   __ Bind(&next_iteration);
-  __ addq(kCacheArrayReg,
+  __ addq(STCInternalRegs::kCacheEntryReg,
           Immediate(target::kWordSize *
                     target::SubtypeTestCache::kTestEntryLength));
   __ jmp(&loop, Assembler::kNearJump);
 
   __ Bind(&found);
   __ movq(TypeTestABI::kSubtypeTestCacheResultReg,
-          Address(kCacheArrayReg,
+          Address(STCInternalRegs::kCacheEntryReg,
                   target::kWordSize * target::SubtypeTestCache::kTestResult));
 
   __ Bind(&not_found);
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index cf7b8a1..82ccda5 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -337,6 +337,24 @@
   static const Register kResultTypeReg = R0;
 };
 
+// Registers in addition to those listed in TypeTestABI used inside the
+// implementation of type testing stubs that are _not_ preserved.
+struct TTSInternalRegs {
+  static const Register kInstanceTypeArgumentsReg = R4;
+  static const Register kScratchReg = R9;
+
+  static const intptr_t kInternalRegisters =
+      (1 << kInstanceTypeArgumentsReg) | (1 << kScratchReg);
+};
+
+// Registers in addition to those listed in TypeTestABI used inside the
+// implementation of subtype test cache stubs that are _not_ preserved.
+struct STCInternalRegs {
+  static const Register kInstanceCidOrFunctionReg = R9;
+
+  static const intptr_t kInternalRegisters = (1 << kInstanceCidOrFunctionReg);
+};
+
 // Calling convention when calling TypeTestingStub and SubtypeTestCacheStub.
 struct TypeTestABI {
   static const Register kInstanceReg = R0;
@@ -356,10 +374,17 @@
   static const intptr_t kSubtypeTestCacheStubCallerSavedRegisters =
       1 << kSubtypeTestCacheReg;
 
-  static const intptr_t kAbiRegisters =
+  static const intptr_t kPreservedAbiRegisters =
       (1 << kInstanceReg) | (1 << kDstTypeReg) |
-      (1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg) |
-      (1 << kSubtypeTestCacheReg) | (1 << kScratchReg);
+      (1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg);
+
+  static const intptr_t kNonPreservedAbiRegisters =
+      TTSInternalRegs::kInternalRegisters |
+      STCInternalRegs::kInternalRegisters | (1 << kSubtypeTestCacheReg) |
+      (1 << kScratchReg) | (1 << kSubtypeTestCacheResultReg) | (1 << CODE_REG);
+
+  static const intptr_t kAbiRegisters =
+      kPreservedAbiRegisters | kNonPreservedAbiRegisters;
 };
 
 // Calling convention when calling AssertSubtypeStub.
@@ -379,15 +404,6 @@
   // (throws if the subtype check fails).
 };
 
-// Registers used inside the implementation of type testing stubs.
-struct TTSInternalRegs {
-  static const Register kInstanceTypeArgumentsReg = R4;
-  static const Register kScratchReg = R9;
-
-  static const intptr_t kInternalRegisters =
-      (1 << kInstanceTypeArgumentsReg) | (1 << kScratchReg);
-};
-
 // ABI for InitStaticFieldStub.
 struct InitStaticFieldABI {
   static const Register kFieldReg = R0;
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index 17288cf..e44ab62 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -170,6 +170,31 @@
   static const Register kResultTypeReg = R0;
 };
 
+// Registers in addition to those listed in TypeTestABI used inside the
+// implementation of type testing stubs that are _not_ preserved.
+struct TTSInternalRegs {
+  static const Register kInstanceTypeArgumentsReg = R7;
+  static const Register kScratchReg = R9;
+
+  static const intptr_t kInternalRegisters =
+      (1 << kInstanceTypeArgumentsReg) | (1 << kScratchReg);
+};
+
+// Registers in addition to those listed in TypeTestABI used inside the
+// implementation of subtype test cache stubs that are _not_ preserved.
+struct STCInternalRegs {
+  static const Register kInstanceCidOrFunctionReg = R6;
+  static const Register kInstanceInstantiatorTypeArgumentsReg = R5;
+  static const Register kInstanceParentFunctionTypeArgumentsReg = R9;
+  static const Register kInstanceDelayedFunctionTypeArgumentsReg = R10;
+
+  static const intptr_t kInternalRegisters =
+      (1 << kInstanceCidOrFunctionReg) |
+      (1 << kInstanceInstantiatorTypeArgumentsReg) |
+      (1 << kInstanceParentFunctionTypeArgumentsReg) |
+      (1 << kInstanceDelayedFunctionTypeArgumentsReg);
+};
+
 // Calling convention when calling TypeTestingStub and SubtypeTestCacheStub.
 struct TypeTestABI {
   static const Register kInstanceReg = R0;
@@ -189,11 +214,17 @@
   static const intptr_t kSubtypeTestCacheStubCallerSavedRegisters =
       1 << kSubtypeTestCacheReg;
 
-  static const intptr_t kAbiRegisters =
+  static const intptr_t kPreservedAbiRegisters =
       (1 << kInstanceReg) | (1 << kDstTypeReg) |
-      (1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg) |
-      (1 << kSubtypeTestCacheReg) | (1 << kScratchReg) |
-      (1 << kSubtypeTestCacheResultReg);
+      (1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg);
+
+  static const intptr_t kNonPreservedAbiRegisters =
+      TTSInternalRegs::kInternalRegisters |
+      STCInternalRegs::kInternalRegisters | (1 << kSubtypeTestCacheReg) |
+      (1 << kScratchReg) | (1 << kSubtypeTestCacheResultReg) | (1 << CODE_REG);
+
+  static const intptr_t kAbiRegisters =
+      kPreservedAbiRegisters | kNonPreservedAbiRegisters;
 };
 
 // Calling convention when calling AssertSubtypeStub.
@@ -213,15 +244,6 @@
   // (throws if the subtype check fails).
 };
 
-// Registers used inside the implementation of type testing stubs.
-struct TTSInternalRegs {
-  static const Register kInstanceTypeArgumentsReg = R7;
-  static const Register kScratchReg = R9;
-
-  static const intptr_t kInternalRegisters =
-      (1 << kInstanceTypeArgumentsReg) | (1 << kScratchReg);
-};
-
 // ABI for InitStaticFieldStub.
 struct InitStaticFieldABI {
   static const Register kFieldReg = R0;
diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h
index a403340..ea681ce 100644
--- a/runtime/vm/constants_x64.h
+++ b/runtime/vm/constants_x64.h
@@ -146,6 +146,28 @@
   static const Register kResultTypeReg = RAX;
 };
 
+// Registers in addition to those listed in TypeTestABI used inside the
+// implementation of type testing stubs that are _not_ preserved.
+struct TTSInternalRegs {
+  static const Register kInstanceTypeArgumentsReg = RSI;
+  static const Register kScratchReg = R8;
+
+  static const intptr_t kInternalRegisters =
+      (1 << kInstanceTypeArgumentsReg) | (1 << kScratchReg);
+};
+
+// Registers in addition to those listed in TypeTestABI used inside the
+// implementation of subtype test cache stubs that are _not_ preserved.
+struct STCInternalRegs {
+  static const Register kCacheEntryReg = RDI;
+  static const Register kInstanceCidOrFunctionReg = R10;
+  static const Register kInstanceInstantiatorTypeArgumentsReg = R13;
+
+  static const intptr_t kInternalRegisters =
+      (1 << kCacheEntryReg) | (1 << kInstanceCidOrFunctionReg) |
+      (1 << kInstanceInstantiatorTypeArgumentsReg);
+};
+
 // Calling convention when calling TypeTestingStub and SubtypeTestCacheStub.
 struct TypeTestABI {
   static const Register kInstanceReg = RAX;
@@ -164,11 +186,17 @@
   // No registers need saving across SubtypeTestCacheStub calls.
   static const intptr_t kSubtypeTestCacheStubCallerSavedRegisters = 0;
 
-  static const intptr_t kAbiRegisters =
+  static const intptr_t kPreservedAbiRegisters =
       (1 << kInstanceReg) | (1 << kDstTypeReg) |
-      (1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg) |
-      (1 << kSubtypeTestCacheReg) | (1 << kScratchReg) |
-      (1 << kSubtypeTestCacheResultReg);
+      (1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg);
+
+  static const intptr_t kNonPreservedAbiRegisters =
+      TTSInternalRegs::kInternalRegisters |
+      STCInternalRegs::kInternalRegisters | (1 << kSubtypeTestCacheReg) |
+      (1 << kScratchReg) | (1 << kSubtypeTestCacheResultReg) | (1 << CODE_REG);
+
+  static const intptr_t kAbiRegisters =
+      kPreservedAbiRegisters | kNonPreservedAbiRegisters;
 };
 
 // Calling convention when calling AssertSubtypeStub.
@@ -247,18 +275,6 @@
   static const Register kResultReg = RAX;
 };
 
-// Registers used inside the implementation of type testing stubs.
-struct TTSInternalRegs {
-  static const Register kInstanceTypeArgumentsReg = RSI;
-  static const Register kScratchReg = R8;
-
-  static const intptr_t kInternalRegisters =
-      (1 << kInstanceTypeArgumentsReg) | (1 << kScratchReg);
-};
-
-// TODO(regis): Add ABIs for type testing stubs and is-type test stubs instead
-// of reusing the constants of the instantiation stubs ABI.
-
 typedef uint32_t RegList;
 const RegList kAllCpuRegistersList = 0xFFFF;
 const RegList kAllFpuRegistersList = 0xFFFF;
diff --git a/runtime/vm/type_testing_stubs_test.cc b/runtime/vm/type_testing_stubs_test.cc
index 9cc1045..17bd0c4 100644
--- a/runtime/vm/type_testing_stubs_test.cc
+++ b/runtime/vm/type_testing_stubs_test.cc
@@ -7,10 +7,10 @@
 #include "platform/assert.h"
 
 #include "vm/class_finalizer.h"
+#include "vm/compiler/backend/flow_graph_compiler.h"
 #include "vm/compiler/backend/il_test_helper.h"
 #include "vm/symbols.h"
 #include "vm/type_testing_stubs.h"
-#include "vm/type_testing_stubs_test.h"
 #include "vm/unit_test.h"
 
 #if defined(TARGET_ARCH_ARM64) || defined(TARGET_ARCH_ARM) ||                  \
@@ -18,6 +18,129 @@
 
 namespace dart {
 
+#define __ assembler->
+
+static void GenerateInvokeTTSStub(compiler::Assembler* assembler) {
+  auto calculate_breadcrumb = [](const Register& reg) {
+    return 0x10 + 2 * (static_cast<intptr_t>(reg));
+  };
+
+  __ EnterDartFrame(0);
+
+  for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
+    if (((1 << i) & kDartAvailableCpuRegs) == 0) continue;
+    if (((1 << i) & TypeTestABI::kAbiRegisters) != 0) continue;
+    if (((1 << i) & TTSInternalRegs::kInternalRegisters) != 0) continue;
+    const Register reg = static_cast<Register>(i);
+    __ LoadImmediate(reg, calculate_breadcrumb(reg));
+  }
+
+  // Load the arguments into the right TTS calling convention registers.
+  const intptr_t instance_offset =
+      (kCallerSpSlotFromFp + 3) * compiler::target::kWordSize;
+  const intptr_t inst_type_args_offset =
+      (kCallerSpSlotFromFp + 2) * compiler::target::kWordSize;
+  const intptr_t fun_type_args_offset =
+      (kCallerSpSlotFromFp + 1) * compiler::target::kWordSize;
+  const intptr_t dst_type_offset =
+      (kCallerSpSlotFromFp + 0) * compiler::target::kWordSize;
+
+  __ LoadMemoryValue(TypeTestABI::kInstanceReg, FPREG, instance_offset);
+  __ LoadMemoryValue(TypeTestABI::kInstantiatorTypeArgumentsReg, FPREG,
+                     inst_type_args_offset);
+  __ LoadMemoryValue(TypeTestABI::kFunctionTypeArgumentsReg, FPREG,
+                     fun_type_args_offset);
+  __ LoadMemoryValue(TypeTestABI::kDstTypeReg, FPREG, dst_type_offset);
+
+  const intptr_t subtype_test_cache_index = __ object_pool_builder().AddObject(
+      Object::null_object(), compiler::ObjectPoolBuilderEntry::kPatchable);
+  const intptr_t dst_name_index = __ object_pool_builder().AddObject(
+      Symbols::OptimizedOut(), compiler::ObjectPoolBuilderEntry::kPatchable);
+  ASSERT_EQUAL(subtype_test_cache_index + 1, dst_name_index);
+  ASSERT(__ constant_pool_allowed());
+
+  FlowGraphCompiler::GenerateIndirectTTSCall(
+      assembler, TypeTestABI::kDstTypeReg, subtype_test_cache_index);
+
+  // We have the guarantee that TTS preserves all input registers, if the TTS
+  // handles the type test successfully.
+  //
+  // Let the test know which TTS abi registers were not preserved.
+  ASSERT(((1 << static_cast<intptr_t>(TypeTestABI::kInstanceReg)) &
+          TypeTestABI::kPreservedAbiRegisters) != 0);
+  // First we check the instance register, freeing it up in case there are no
+  // other safe registers to use since we need two registers: one to accumulate
+  // the register mask, another to load the array address when saving the mask.
+  __ LoadFromOffset(TypeTestABI::kScratchReg, FPREG, instance_offset);
+  compiler::Label instance_matches, done_with_instance;
+  __ CompareRegisters(TypeTestABI::kScratchReg, TypeTestABI::kInstanceReg);
+  __ BranchIf(EQUAL, &instance_matches, compiler::Assembler::kNearJump);
+  __ LoadImmediate(TypeTestABI::kScratchReg,
+                   1 << static_cast<intptr_t>(TypeTestABI::kInstanceReg));
+  __ Jump(&done_with_instance, compiler::Assembler::kNearJump);
+  __ Bind(&instance_matches);
+  __ LoadImmediate(TypeTestABI::kScratchReg, 0);
+  __ Bind(&done_with_instance);
+  for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
+    if (((1 << i) & TypeTestABI::kPreservedAbiRegisters) == 0) continue;
+    const Register reg = static_cast<Register>(i);
+    compiler::Label done;
+    switch (reg) {
+      case TypeTestABI::kInstanceReg:
+        // Skip the already handled instance register.
+        continue;
+      case TypeTestABI::kDstTypeReg:
+        __ LoadFromOffset(TypeTestABI::kInstanceReg, FPREG, dst_type_offset);
+        break;
+      case TypeTestABI::kFunctionTypeArgumentsReg:
+        __ LoadFromOffset(TypeTestABI::kInstanceReg, FPREG,
+                          fun_type_args_offset);
+        break;
+      case TypeTestABI::kInstantiatorTypeArgumentsReg:
+        __ LoadFromOffset(TypeTestABI::kInstanceReg, FPREG,
+                          inst_type_args_offset);
+        break;
+      default:
+        FATAL("Unexpected register %s", RegisterNames::RegisterName(reg));
+        break;
+    }
+    __ CompareRegisters(reg, TypeTestABI::kInstanceReg);
+    __ BranchIf(EQUAL, &done, compiler::Assembler::kNearJump);
+    __ AddImmediate(TypeTestABI::kScratchReg, 1 << i);
+    __ Bind(&done);
+  }
+  __ SmiTag(TypeTestABI::kScratchReg);
+  __ LoadFromOffset(TypeTestABI::kInstanceReg, FPREG,
+                    (kCallerSpSlotFromFp + 5) * compiler::target::kWordSize);
+  __ StoreFieldToOffset(TypeTestABI::kScratchReg, TypeTestABI::kInstanceReg,
+                        compiler::target::Array::element_offset(0));
+
+  // Let the test know which non-TTS abi registers were not preserved.
+  __ LoadImmediate(TypeTestABI::kScratchReg, 0);
+  for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
+    if (((1 << i) & kDartAvailableCpuRegs) == 0) continue;
+    if (((1 << i) & TypeTestABI::kAbiRegisters) != 0) continue;
+    const Register reg = static_cast<Register>(i);
+    compiler::Label done;
+    __ CompareImmediate(reg, calculate_breadcrumb(reg));
+    __ BranchIf(EQUAL, &done, compiler::Assembler::kNearJump);
+    __ AddImmediate(TypeTestABI::kScratchReg, 1 << i);
+    __ Bind(&done);
+  }
+  __ SmiTag(TypeTestABI::kScratchReg);
+  __ LoadFromOffset(TypeTestABI::kInstanceReg, FPREG,
+                    (kCallerSpSlotFromFp + 4) * compiler::target::kWordSize);
+  __ StoreFieldToOffset(TypeTestABI::kScratchReg, TypeTestABI::kInstanceReg,
+                        compiler::target::Array::element_offset(0));
+
+  // Set the return from the stub to be null.
+  __ LoadObject(CallingConventions::kReturnReg, Object::null_object());
+  __ LeaveDartFrame();
+  __ Ret();
+}
+
+#undef __
+
 static void FinalizeAndCanonicalize(AbstractType* type) {
   *type = ClassFinalizer::FinalizeType(*type);
   ASSERT(type->IsCanonical());
@@ -35,8 +158,8 @@
     std::function<void(const Object& result, const SubtypeTestCache& stc)> lazy,
     std::function<void(const Object& result,
                        const SubtypeTestCache& stc,
-                       const Bool& abi_regs_modified,
-                       const Bool& rest_regs_modified)> nonlazy) {
+                       const Smi& abi_regs_modified,
+                       const Smi& rest_regs_modified)> nonlazy) {
   ASSERT(instantiator_tav.IsNull() || instantiator_tav.IsCanonical());
   ASSERT(function_tav.IsNull() || function_tav.IsCanonical());
   auto thread = Thread::Current();
@@ -59,7 +182,7 @@
   invoke_tts.set_exception_handlers(
       ExceptionHandlers::Handle(ExceptionHandlers::New(0)));
 
-  EXPECT(pool.Length() == 2);
+  EXPECT_EQ(2, pool.Length());
   const intptr_t kSubtypeTestCacheIndex = 0;
 
   const auto& arguments_descriptor =
@@ -87,8 +210,8 @@
 
   auto& result = Object::Handle();
   auto& result2 = Object::Handle();
-  auto& abi_regs_modified = Bool::Handle();
-  auto& rest_regs_modified = Bool::Handle();
+  auto& abi_regs_modified = Smi::Handle();
+  auto& rest_regs_modified = Smi::Handle();
   auto& tts = Code::Handle();
   auto& tts2 = Code::Handle();
   auto& stc = SubtypeTestCache::Handle();
@@ -135,68 +258,103 @@
   nonlazy(result2, stc2, abi_regs_modified, rest_regs_modified);
 }
 
-static void ExpectLazilyHandledViaTTS(const Object& result,
-                                      const SubtypeTestCache& stc) {
+static void ReportModifiedRegisters(const Smi& modified_registers) {
+  const intptr_t reg_mask = Smi::Cast(modified_registers).Value();
+  for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
+    if (((1 << i) & reg_mask) != 0) {
+      const Register reg = static_cast<Register>(i);
+      dart::Expect(__FILE__, __LINE__)
+          .Fail("%s was modified", RegisterNames::RegisterName(reg));
+    }
+  }
+}
+
+static void CommonTTSHandledChecks(const Object& result,
+                                   const SubtypeTestCache& stc) {
   // Ensure the type test succeeded.
   EXPECT(result.IsNull());
   // Ensure we didn't fall back to the subtype test cache.
   EXPECT(stc.IsNull());
 }
 
-static void ExpectHandledViaTTS(const Object& result,
-                                const SubtypeTestCache& stc,
-                                const Bool& abi_regs_modified,
-                                const Bool& rest_regs_modified) {
-  ExpectLazilyHandledViaTTS(result, stc);
-  // Ensure the TTS abi registers were preserved.
-  EXPECT(!abi_regs_modified.value());
-  // Ensure the non-TTS abi registers were preserved.
-  EXPECT(!rest_regs_modified.value());
+static void ExpectLazilyHandledViaTTS(const Object& result,
+                                      const SubtypeTestCache& stc) {
+  THR_Print("Testing lazy handled via TTS\n");
+  CommonTTSHandledChecks(result, stc);
 }
 
-static void ExpectLazilyHandledViaSTC(const Object& result,
-                                      const SubtypeTestCache& stc) {
+static void ExpectHandledViaTTS(const Object& result,
+                                const SubtypeTestCache& stc,
+                                const Smi& abi_regs_modified,
+                                const Smi& rest_regs_modified) {
+  THR_Print("Testing non-lazy handled via TTS\n");
+  CommonTTSHandledChecks(result, stc);
+  // Ensure the TTS abi registers were preserved.
+  ReportModifiedRegisters(abi_regs_modified);
+  // Ensure the non-TTS abi registers were preserved.
+  ReportModifiedRegisters(rest_regs_modified);
+}
+
+static void CommonSTCHandledChecks(const Object& result,
+                                   const SubtypeTestCache& stc) {
   // Ensure the type test succeeded.
   EXPECT(result.IsNull());
   // Ensure we did fall back to the subtype test cache.
   EXPECT(!stc.IsNull());
   // Ensure the test is marked as succeeding in the STC.
-  EXPECT(stc.NumberOfChecks() == 1);
+  EXPECT_EQ(1, stc.NumberOfChecks());
   SubtypeTestCacheTable entries(Array::Handle(stc.cache()));
   EXPECT(entries[0].Get<SubtypeTestCache::kTestResult>() ==
          Object::bool_true().raw());
 }
 
+static void ExpectLazilyHandledViaSTC(const Object& result,
+                                      const SubtypeTestCache& stc) {
+  THR_Print("Testing lazy handled via STC\n");
+  CommonSTCHandledChecks(result, stc);
+}
+
 static void ExpectHandledViaSTC(const Object& result,
                                 const SubtypeTestCache& stc,
-                                const Bool& abi_regs_modified,
-                                const Bool& rest_regs_modified) {
-  ExpectLazilyHandledViaSTC(result, stc);
+                                const Smi& abi_regs_modified,
+                                const Smi& rest_regs_modified) {
+  THR_Print("Testing non-lazy handled via STC\n");
+  CommonSTCHandledChecks(result, stc);
   // Ensure the TTS/STC abi registers were preserved.
-  EXPECT(!abi_regs_modified.value());
+  ReportModifiedRegisters(abi_regs_modified);
+  // Ensure the non-TTS abi registers were preserved.
+  ReportModifiedRegisters(rest_regs_modified);
+}
+
+static void CommonTTSFailureChecks(const Object& result,
+                                   const SubtypeTestCache& stc) {
+  // Ensure we have not updated STC (which we shouldn't do in case the type test
+  // fails, i.e. an exception is thrown).
+  EXPECT(stc.IsNull());
+  // Ensure we get a proper exception for the type test.
+  EXPECT(result.IsUnhandledException());
+  const auto& error =
+      Instance::Handle(UnhandledException::Cast(result).exception());
+  EXPECT(strstr(error.ToCString(), "_TypeError"));
 }
 
 static void ExpectLazilyFailedViaTTS(const Object& result,
                                      const SubtypeTestCache& stc) {
-  // Ensure we have not updated STC (which we shouldn't do in case the type test
-  // fails, i.e. an exception is thrown).
-  EXPECT(stc.IsNull());
-  // Ensure we get a proper exception for the type test.
-  EXPECT(result.IsUnhandledException());
-  const auto& error =
-      Instance::Handle(UnhandledException::Cast(result).exception());
-  EXPECT(strstr(error.ToCString(), "_TypeError"));
+  THR_Print("Testing lazy failure via TTS\n");
+  CommonTTSFailureChecks(result, stc);
 }
 
 static void ExpectFailedViaTTS(const Object& result,
                                const SubtypeTestCache& stc,
-                               const Bool& abi_regs_modified,
-                               const Bool& rest_regs_modified) {
-  ExpectLazilyFailedViaTTS(result, stc);
+                               const Smi& abi_regs_modified,
+                               const Smi& rest_regs_modified) {
+  THR_Print("Testing nonlazy failure via TTS\n");
+  CommonTTSFailureChecks(result, stc);
+  // Registers only need to be preserved on success.
 }
 
-static void ExpectLazilyFailedViaSTC(const Object& result,
-                                     const SubtypeTestCache& stc) {
+static void CommonSTCFailureChecks(const Object& result,
+                                   const SubtypeTestCache& stc) {
   // Ensure we have not updated STC (which we shouldn't do in case the type test
   // fails, i.e. an exception is thrown).
   EXPECT(stc.IsNull());
@@ -207,11 +365,19 @@
   EXPECT(strstr(error.ToCString(), "_TypeError"));
 }
 
+static void ExpectLazilyFailedViaSTC(const Object& result,
+                                     const SubtypeTestCache& stc) {
+  THR_Print("Testing lazy failure via STC\n");
+  CommonSTCFailureChecks(result, stc);
+}
+
 static void ExpectFailedViaSTC(const Object& result,
                                const SubtypeTestCache& stc,
-                               const Bool& abi_regs_modified,
-                               const Bool& rest_regs_modified) {
-  ExpectLazilyFailedViaSTC(result, stc);
+                               const Smi& abi_regs_modified,
+                               const Smi& rest_regs_modified) {
+  THR_Print("Testing non-lazy failure via STC\n");
+  CommonSTCFailureChecks(result, stc);
+  // Registers only need to be preserved on success.
 }
 
 const char* kSubtypeRangeCheckScript =
@@ -697,11 +863,15 @@
   const auto& int_instance = Integer::Handle(Integer::New(1));
   const auto& string_instance = String::Handle(String::New("foo"));
 
+  THR_Print("Testing int instance, class parameter instantiated to int\n");
   RunTTSTest(int_instance, dst_type_t, int_tav, string_tav,
              ExpectLazilyHandledViaTTS, ExpectHandledViaTTS);
+  THR_Print("\nTesting string instance, class parameter instantiated to int\n");
   RunTTSTest(string_instance, dst_type_t, int_tav, string_tav,
              ExpectLazilyFailedViaTTS, ExpectFailedViaTTS);
 
+  THR_Print(
+      "\nTesting string instance, function parameter instantiated to string\n");
   RunTTSTest(string_instance, dst_type_h, int_tav, string_tav,
              ExpectLazilyHandledViaTTS, ExpectHandledViaTTS);
   RunTTSTest(int_instance, dst_type_h, int_tav, string_tav,
diff --git a/runtime/vm/type_testing_stubs_test.h b/runtime/vm/type_testing_stubs_test.h
deleted file mode 100644
index c11f2d8..0000000
--- a/runtime/vm/type_testing_stubs_test.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef RUNTIME_VM_TYPE_TESTING_STUBS_TEST_H_
-#define RUNTIME_VM_TYPE_TESTING_STUBS_TEST_H_
-
-#if defined(TARGET_ARCH_ARM64) || defined(TARGET_ARCH_ARM) ||                  \
-    defined(TARGET_ARCH_X64)
-
-#include "include/dart_api.h"
-
-namespace dart {
-
-namespace compiler {
-class Assembler;
-}
-
-void GenerateInvokeTTSStub(compiler::Assembler* assembler);
-
-}  // namespace dart
-
-#endif  // defined(TARGET_ARCH_ARM64) ||  defined(TARGET_ARCH_ARM) ||          \
-        // defined(TARGET_ARCH_X64)
-
-#endif  // RUNTIME_VM_TYPE_TESTING_STUBS_TEST_H_
diff --git a/runtime/vm/type_testing_stubs_test_arm.cc b/runtime/vm/type_testing_stubs_test_arm.cc
deleted file mode 100644
index 0391fe9..0000000
--- a/runtime/vm/type_testing_stubs_test_arm.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/globals.h"
-
-#if defined(TARGET_ARCH_ARM)
-
-#include "vm/compiler/assembler/assembler.h"
-#include "vm/compiler/runtime_api.h"
-#include "vm/constants.h"
-#include "vm/object.h"
-#include "vm/stack_frame.h"
-#include "vm/symbols.h"
-
-#define __ assembler->
-
-namespace dart {
-
-void GenerateInvokeTTSStub(compiler::Assembler* assembler) {
-  __ EnterDartFrame(0);
-
-  intptr_t sum = 0;
-  for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
-    if (((1 << i) & kDartAvailableCpuRegs) == 0) continue;
-    if (((1 << i) & TypeTestABI::kAbiRegisters) != 0) continue;
-    if (((1 << i) & TTSInternalRegs::kInternalRegisters) != 0) continue;
-    __ LoadImmediate(static_cast<Register>(i), 0x10 + 2 * i);
-    sum += 0x10 + 2 * i;
-  }
-
-  // Load the arguments into the right TTS calling convention registers.
-  __ ldr(TypeTestABI::kInstanceReg,
-         compiler::Address(
-             FP, (kCallerSpSlotFromFp + 3) * compiler::target::kWordSize));
-  __ ldr(TypeTestABI::kInstantiatorTypeArgumentsReg,
-         compiler::Address(
-             FP, (kCallerSpSlotFromFp + 2) * compiler::target::kWordSize));
-  __ ldr(TypeTestABI::kFunctionTypeArgumentsReg,
-         compiler::Address(
-             FP, (kCallerSpSlotFromFp + 1) * compiler::target::kWordSize));
-  __ ldr(TypeTestABI::kDstTypeReg,
-         compiler::Address(
-             FP, (kCallerSpSlotFromFp + 0) * compiler::target::kWordSize));
-
-  const intptr_t sub_type_cache_index = __ object_pool_builder().AddObject(
-      Object::null_object(), compiler::ObjectPoolBuilderEntry::kPatchable);
-  const intptr_t dst_name_index = __ object_pool_builder().AddObject(
-      Symbols::OptimizedOut(), compiler::ObjectPoolBuilderEntry::kPatchable);
-  ASSERT((sub_type_cache_index + 1) == dst_name_index);
-  ASSERT(__ constant_pool_allowed());
-
-  // Call the TTS.
-  __ ldr(R9, compiler::FieldAddress(
-                 TypeTestABI::kDstTypeReg,
-                 AbstractType::type_test_stub_entry_point_offset()));
-  __ LoadWordFromPoolIndex(TypeTestABI::kSubtypeTestCacheReg,
-                           sub_type_cache_index);
-  __ blx(R9);
-
-  // We have the guarantee that TTS preserve all registers except for one
-  // scratch register atm (if the TTS handles the type test successfully).
-  //
-  // Let the test know whether TTS abi registers were preserved.
-  compiler::Label abi_regs_modified, store_abi_regs_modified_bool;
-  __ CompareWithMemoryValue(
-      TypeTestABI::kInstanceReg,
-      compiler::Address(
-          FP, (kCallerSpSlotFromFp + 3) * compiler::target::kWordSize));
-  __ BranchIf(NOT_EQUAL, &abi_regs_modified);
-  __ CompareWithMemoryValue(
-      TypeTestABI::kInstantiatorTypeArgumentsReg,
-      compiler::Address(
-          FP, (kCallerSpSlotFromFp + 2) * compiler::target::kWordSize));
-  __ BranchIf(NOT_EQUAL, &abi_regs_modified);
-  __ CompareWithMemoryValue(
-      TypeTestABI::kFunctionTypeArgumentsReg,
-      compiler::Address(
-          FP, (kCallerSpSlotFromFp + 1) * compiler::target::kWordSize));
-  __ BranchIf(NOT_EQUAL, &abi_regs_modified);
-  __ CompareWithMemoryValue(
-      TypeTestABI::kDstTypeReg,
-      compiler::Address(
-          FP, (kCallerSpSlotFromFp + 0) * compiler::target::kWordSize));
-  __ BranchIf(NOT_EQUAL, &abi_regs_modified);
-  __ ldr(R0, compiler::Address(THR, Thread::bool_false_offset()));
-  __ b(&store_abi_regs_modified_bool);
-  __ Bind(&abi_regs_modified);
-  __ ldr(R0, compiler::Address(THR, Thread::bool_true_offset()));
-  __ Bind(&store_abi_regs_modified_bool);
-  __ ldr(TMP, compiler::Address(
-                  FP, (kCallerSpSlotFromFp + 5) * compiler::target::kWordSize));
-  __ str(R0, compiler::FieldAddress(TMP, Array::element_offset(0)));
-
-  // Let the test know whether the non-TTS abi registers were preserved.
-  compiler::Label rest_regs_modified, store_rest_regs_modified_bool;
-  __ mov(TMP, compiler::Operand(0));
-  for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
-    if (((1 << i) & kDartAvailableCpuRegs) == 0) continue;
-    if (((1 << i) & TypeTestABI::kAbiRegisters) != 0) continue;
-    if (((1 << i) & TTSInternalRegs::kInternalRegisters) != 0) continue;
-    __ add(TMP, TMP, compiler::Operand(static_cast<Register>(i)));
-  }
-  __ cmp(TMP, compiler::Operand(sum));
-  __ BranchIf(NOT_EQUAL, &rest_regs_modified);
-  __ ldr(R0, compiler::Address(THR, Thread::bool_false_offset()));
-  __ b(&store_rest_regs_modified_bool);
-  __ Bind(&rest_regs_modified);
-  __ ldr(R0, compiler::Address(THR, Thread::bool_true_offset()));
-  __ Bind(&store_rest_regs_modified_bool);
-  __ ldr(TMP, compiler::Address(
-                  FP, (kCallerSpSlotFromFp + 4) * compiler::target::kWordSize));
-  __ str(R0, compiler::FieldAddress(TMP, Array::element_offset(0)));
-
-  __ LoadObject(R0, Object::null_object());
-  __ LeaveDartFrameAndReturn();
-}
-
-}  // namespace dart
-
-#endif  // defined(TARGET_ARCH_ARM)
diff --git a/runtime/vm/type_testing_stubs_test_arm64.cc b/runtime/vm/type_testing_stubs_test_arm64.cc
deleted file mode 100644
index 39f7d36..0000000
--- a/runtime/vm/type_testing_stubs_test_arm64.cc
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/globals.h"
-
-#if defined(TARGET_ARCH_ARM64)
-
-#include "vm/compiler/assembler/assembler.h"
-#include "vm/compiler/runtime_api.h"
-#include "vm/constants.h"
-#include "vm/object.h"
-#include "vm/stack_frame.h"
-#include "vm/symbols.h"
-
-#define __ assembler->
-
-namespace dart {
-
-void GenerateInvokeTTSStub(compiler::Assembler* assembler) {
-  __ EnterDartFrame(0);
-
-  intptr_t sum = 0;
-  for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
-    if (((1 << i) & kDartAvailableCpuRegs) == 0) continue;
-    if (((1 << i) & TypeTestABI::kAbiRegisters) != 0) continue;
-    if (((1 << i) & TTSInternalRegs::kInternalRegisters) != 0) continue;
-    __ LoadImmediate(static_cast<Register>(i), 0x10 + 2 * i);
-    sum += 0x10 + 2 * i;
-  }
-
-  // Load the arguments into the right TTS calling convention registers.
-  __ ldr(TypeTestABI::kInstanceReg,
-         compiler::Address(
-             FP, (kCallerSpSlotFromFp + 3) * compiler::target::kWordSize));
-  __ ldr(TypeTestABI::kInstantiatorTypeArgumentsReg,
-         compiler::Address(
-             FP, (kCallerSpSlotFromFp + 2) * compiler::target::kWordSize));
-  __ ldr(TypeTestABI::kFunctionTypeArgumentsReg,
-         compiler::Address(
-             FP, (kCallerSpSlotFromFp + 1) * compiler::target::kWordSize));
-  __ ldr(TypeTestABI::kDstTypeReg,
-         compiler::Address(
-             FP, (kCallerSpSlotFromFp + 0) * compiler::target::kWordSize));
-
-  const intptr_t sub_type_cache_index = __ object_pool_builder().AddObject(
-      Object::null_object(), compiler::ObjectPoolBuilderEntry::kPatchable);
-  const intptr_t dst_name_index = __ object_pool_builder().AddObject(
-      Symbols::OptimizedOut(), compiler::ObjectPoolBuilderEntry::kPatchable);
-  ASSERT((sub_type_cache_index + 1) == dst_name_index);
-  ASSERT(__ constant_pool_allowed());
-
-  // Call the TTS.
-  __ ldr(R9, compiler::FieldAddress(
-                 TypeTestABI::kDstTypeReg,
-                 AbstractType::type_test_stub_entry_point_offset()));
-  __ LoadWordFromPoolIndex(TypeTestABI::kSubtypeTestCacheReg,
-                           sub_type_cache_index);
-  __ blr(R9);
-
-  // We have the guarantee that TTS preserve all registers except for one
-  // scratch register atm (if the TTS handles the type test successfully).
-  //
-  // Let the test know whether TTS abi registers were preserved.
-  compiler::Label abi_regs_modified, store_abi_regs_modified_bool;
-  __ CompareWithMemoryValue(
-      TypeTestABI::kInstanceReg,
-      compiler::Address(
-          FP, (kCallerSpSlotFromFp + 3) * compiler::target::kWordSize));
-  __ BranchIf(NOT_EQUAL, &abi_regs_modified);
-  __ CompareWithMemoryValue(
-      TypeTestABI::kInstantiatorTypeArgumentsReg,
-      compiler::Address(
-          FP, (kCallerSpSlotFromFp + 2) * compiler::target::kWordSize));
-  __ BranchIf(NOT_EQUAL, &abi_regs_modified);
-  __ CompareWithMemoryValue(
-      TypeTestABI::kFunctionTypeArgumentsReg,
-      compiler::Address(
-          FP, (kCallerSpSlotFromFp + 1) * compiler::target::kWordSize));
-  __ BranchIf(NOT_EQUAL, &abi_regs_modified);
-  __ CompareWithMemoryValue(
-      TypeTestABI::kDstTypeReg,
-      compiler::Address(
-          FP, (kCallerSpSlotFromFp + 0) * compiler::target::kWordSize));
-  __ BranchIf(NOT_EQUAL, &abi_regs_modified);
-  __ ldr(R0, compiler::Address(THR, Thread::bool_false_offset()));
-  __ b(&store_abi_regs_modified_bool);
-  __ Bind(&abi_regs_modified);
-  __ ldr(R0, compiler::Address(THR, Thread::bool_true_offset()));
-  __ Bind(&store_abi_regs_modified_bool);
-  __ ldr(TMP, compiler::Address(
-                  FP, (kCallerSpSlotFromFp + 5) * compiler::target::kWordSize));
-  __ str(R0, compiler::FieldAddress(TMP, Array::element_offset(0)));
-
-  // Let the test know whether the non-TTS abi registers were preserved.
-  compiler::Label rest_regs_modified, store_rest_regs_modified_bool;
-  __ LoadImmediate(TMP, 0);
-  for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
-    if (((1 << i) & kDartAvailableCpuRegs) == 0) continue;
-    if (((1 << i) & TypeTestABI::kAbiRegisters) != 0) continue;
-    if (((1 << i) & TTSInternalRegs::kInternalRegisters) != 0) continue;
-    __ add(TMP, TMP, compiler::Operand(static_cast<Register>(i)));
-  }
-  __ cmp(TMP, compiler::Operand(sum));
-  __ BranchIf(NOT_EQUAL, &rest_regs_modified);
-  __ ldr(R0, compiler::Address(THR, Thread::bool_false_offset()));
-  __ b(&store_rest_regs_modified_bool);
-  __ Bind(&rest_regs_modified);
-  __ ldr(R0, compiler::Address(THR, Thread::bool_true_offset()));
-  __ Bind(&store_rest_regs_modified_bool);
-  __ ldr(TMP, compiler::Address(
-                  FP, (kCallerSpSlotFromFp + 4) * compiler::target::kWordSize));
-  __ str(R0, compiler::FieldAddress(TMP, Array::element_offset(0)));
-
-  __ LoadObject(R0, Object::null_object());
-  __ LeaveDartFrame();
-  __ Ret();
-}
-
-}  // namespace dart
-
-#endif  // defined(TARGET_ARCH_ARM64)
diff --git a/runtime/vm/type_testing_stubs_test_x64.cc b/runtime/vm/type_testing_stubs_test_x64.cc
deleted file mode 100644
index 57ae551..0000000
--- a/runtime/vm/type_testing_stubs_test_x64.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/globals.h"
-
-#if defined(TARGET_ARCH_X64)
-
-#include "vm/compiler/assembler/assembler.h"
-#include "vm/compiler/runtime_api.h"
-#include "vm/constants.h"
-#include "vm/object.h"
-#include "vm/stack_frame.h"
-#include "vm/symbols.h"
-
-#define __ assembler->
-
-namespace dart {
-
-void GenerateInvokeTTSStub(compiler::Assembler* assembler) {
-  __ EnterDartFrame(0);
-  intptr_t sum = 0;
-  for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
-    if (((1 << i) & kDartAvailableCpuRegs) == 0) continue;
-    if (((1 << i) & TypeTestABI::kAbiRegisters) != 0) continue;
-    if (((1 << i) & TTSInternalRegs::kInternalRegisters) != 0) continue;
-    __ movq(static_cast<Register>(i), compiler::Immediate(0x10 + 2 * i));
-    sum += 0x10 + 2 * i;
-  }
-
-  // Load the arguments into the right TTS calling convention registers.
-  __ movq(TypeTestABI::kInstanceReg,
-          compiler::Address(
-              RBP, (kCallerSpSlotFromFp + 3) * compiler::target::kWordSize));
-  __ movq(TypeTestABI::kInstantiatorTypeArgumentsReg,
-          compiler::Address(
-              RBP, (kCallerSpSlotFromFp + 2) * compiler::target::kWordSize));
-  __ movq(TypeTestABI::kFunctionTypeArgumentsReg,
-          compiler::Address(
-              RBP, (kCallerSpSlotFromFp + 1) * compiler::target::kWordSize));
-  __ movq(TypeTestABI::kDstTypeReg,
-          compiler::Address(
-              RBP, (kCallerSpSlotFromFp + 0) * compiler::target::kWordSize));
-
-  const intptr_t sub_type_cache_index = __ object_pool_builder().AddObject(
-      Object::null_object(), compiler::ObjectPoolBuilderEntry::kPatchable);
-  const intptr_t sub_type_cache_offset =
-      ObjectPool::element_offset(sub_type_cache_index) - kHeapObjectTag;
-  const intptr_t dst_name_index = __ object_pool_builder().AddObject(
-      Symbols::OptimizedOut(), compiler::ObjectPoolBuilderEntry::kPatchable);
-  ASSERT((sub_type_cache_index + 1) == dst_name_index);
-  ASSERT(__ constant_pool_allowed());
-
-  // Call the TTS.
-  __ movq(TypeTestABI::kSubtypeTestCacheReg,
-          compiler::Address(PP, sub_type_cache_offset));
-  __ call(compiler::FieldAddress(
-      TypeTestABI::kDstTypeReg,
-      AbstractType::type_test_stub_entry_point_offset()));
-
-  // We have the guarantee that TTS preserve all registers except for one
-  // scratch register atm (if the TTS handles the type test successfully).
-  //
-  // Let the test know whether TTS abi registers were preserved.
-  compiler::Label abi_regs_modified, store_abi_regs_modified_bool;
-  __ cmpq(TypeTestABI::kInstanceReg,
-          compiler::Address(
-              RBP, (kCallerSpSlotFromFp + 3) * compiler::target::kWordSize));
-  __ BranchIf(NOT_EQUAL, &abi_regs_modified);
-  __ cmpq(TypeTestABI::kInstantiatorTypeArgumentsReg,
-          compiler::Address(
-              RBP, (kCallerSpSlotFromFp + 2) * compiler::target::kWordSize));
-  __ BranchIf(NOT_EQUAL, &abi_regs_modified);
-  __ cmpq(TypeTestABI::kFunctionTypeArgumentsReg,
-          compiler::Address(
-              RBP, (kCallerSpSlotFromFp + 1) * compiler::target::kWordSize));
-  __ BranchIf(NOT_EQUAL, &abi_regs_modified);
-  __ cmpq(TypeTestABI::kDstTypeReg,
-          compiler::Address(
-              RBP, (kCallerSpSlotFromFp + 0) * compiler::target::kWordSize));
-  __ BranchIf(NOT_EQUAL, &abi_regs_modified);
-  __ movq(RAX, compiler::Address(THR, Thread::bool_false_offset()));
-  __ jmp(&store_abi_regs_modified_bool);
-  __ Bind(&abi_regs_modified);
-  __ movq(RAX, compiler::Address(THR, Thread::bool_true_offset()));
-  __ Bind(&store_abi_regs_modified_bool);
-  __ movq(TMP, compiler::Address(RBP, (kCallerSpSlotFromFp + 5) *
-                                          compiler::target::kWordSize));
-  __ movq(compiler::FieldAddress(TMP, Array::element_offset(0)), RAX);
-
-  // Let the test know whether the non-TTS abi registers were preserved.
-  compiler::Label rest_regs_modified, store_rest_regs_modified_bool;
-  __ movq(TMP, compiler::Immediate(0));
-  for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
-    if (((1 << i) & kDartAvailableCpuRegs) == 0) continue;
-    if (((1 << i) & TypeTestABI::kAbiRegisters) != 0) continue;
-    if (((1 << i) & TTSInternalRegs::kInternalRegisters) != 0) continue;
-    __ addq(TMP, static_cast<Register>(i));
-  }
-  __ cmpq(TMP, compiler::Immediate(sum));
-  __ BranchIf(NOT_EQUAL, &rest_regs_modified);
-  __ movq(RAX, compiler::Address(THR, Thread::bool_false_offset()));
-  __ jmp(&store_rest_regs_modified_bool);
-  __ Bind(&rest_regs_modified);
-  __ movq(RAX, compiler::Address(THR, Thread::bool_true_offset()));
-  __ Bind(&store_rest_regs_modified_bool);
-  __ movq(TMP, compiler::Address(RBP, (kCallerSpSlotFromFp + 4) *
-                                          compiler::target::kWordSize));
-  __ movq(compiler::FieldAddress(TMP, Array::element_offset(0)), RAX);
-
-  __ LoadObject(RAX, Object::null_object());
-  __ LeaveDartFrame();
-  __ Ret();
-}
-
-}  // namespace dart
-
-#endif  // defined(TARGET_ARCH_X64)
diff --git a/runtime/vm/vm_sources.gni b/runtime/vm/vm_sources.gni
index 0f71c57..1473064 100644
--- a/runtime/vm/vm_sources.gni
+++ b/runtime/vm/vm_sources.gni
@@ -439,11 +439,7 @@
   "thread_pool_test.cc",
   "thread_test.cc",
   "timeline_test.cc",
-  "type_testing_stubs_test.h",
   "type_testing_stubs_test.cc",
-  "type_testing_stubs_test_x64.cc",
-  "type_testing_stubs_test_arm.cc",
-  "type_testing_stubs_test_arm64.cc",
   "unicode_test.cc",
   "unit_test.cc",
   "unit_test.h",
diff --git a/tools/VERSION b/tools/VERSION
index a70c823..7cf65c7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 147
+PRERELEASE 148
 PRERELEASE_PATCH 0
\ No newline at end of file