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(¬_closure, NE);
// Closure handling.
{
- __ ldr(kInstanceCidOrFunction,
+ __ ldr(STCInternalRegs::kInstanceCidOrFunctionReg,
FieldAddress(TypeTestABI::kInstanceReg,
target::Closure::function_offset()));
if (n >= 3) {
@@ -2709,7 +2711,7 @@
__ Bind(¬_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(¬_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(¬_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(¬_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, ¬_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(¬_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, ¬_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(¬_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