[vm] Unify type testing stub testing framework.

In particular, make it so that the type testing stub testing
framework can use the same indirect stub call generation as
the flow graph compiler. This avoids having to change generation
in two places if we later update how indirect calls are generated.

Other changes:

* Generate a register mask of modified registers instead of a boolean
  for more precise reporting of what was modified.

* Add a STCInternalRegs struct, like TTSInternalRegs, which exposes
  the registers not preserved by the subtype test cache stubs.

* Be more precise in the TypeTestABI about which registers are preserved
  on successful checks (namely, the inputs provided by AssertAssignable
  and InstanceOf) and which may not be, and add the TTS and STC internal
  registers to the non-preserved list.

TEST=Ran modified test on trybots for each supported architecture.

Cq-Include-Trybots: luci.dart.try:vm-kernel-linux-release-simarm64-try,vm-kernel-linux-release-x64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-ia32-try
Change-Id: I58711213bc54572ea7f1e6525707fd193a000235
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/173721
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
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",