[vm] Allow STCs that only store instantiator, not function, type args.
If we are generating a SubtypeTestCache for a known type that only
needs instantiator type arguments to be fully instantiated, then
don't store and check against the unneeded function type arguments.
TEST=vm/cc/STC, vm/cc/TTS, ci
Change-Id: I370adf820168079322b8a87811057670a47ee6b3
Cq-Include-Trybots: luci.dart.try:vm-tsan-linux-release-x64-try,vm-reload-rollback-linux-release-x64-try,vm-reload-linux-release-x64-try,vm-linux-release-x64-try,vm-aot-tsan-linux-release-x64-try,vm-aot-linux-release-x64-try,vm-aot-linux-product-x64-try,vm-aot-linux-debug-x64-try,vm-linux-debug-x64-try,vm-mac-debug-arm64-try,vm-aot-mac-release-arm64-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-linux-debug-ia32-try,vm-linux-release-ia32-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/311382
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 080f034..3d629e5 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -2669,10 +2669,13 @@
if (!type.IsFutureOrType()) {
__ BranchIfSmi(TypeTestABI::kInstanceReg, is_not_instance_lbl);
}
+ const TypeTestStubKind test_kind =
+ type.IsInstantiated(kFunctions) ? TypeTestStubKind::kTestTypeThreeArgs
+ : TypeTestStubKind::kTestTypeFourArgs;
// Uninstantiated type class is known at compile time, but the type
// arguments are determined at runtime by the instantiator(s).
- return GenerateCallSubtypeTestStub(TypeTestStubKind::kTestTypeFourArgs,
- is_instance_lbl, is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(test_kind, is_instance_lbl,
+ is_not_instance_lbl);
}
return SubtypeTestCache::null();
}
@@ -2744,9 +2747,9 @@
// Expected inputs (from TypeTestABI):
// - kInstanceReg: instance (preserved).
// - kInstantiatorTypeArgumentsReg: instantiator type arguments
-// (for test_kind == kTestTypeFourArg or test_kind == kTestTypeSixArg).
+// (for test_kind >= kTestTypeThreeArg).
// - kFunctionTypeArgumentsReg: function type arguments
-// (for test_kind == kTestTypeFourArg or test_kind == kTestTypeSixArg).
+// (for test_kind >= kTestTypeFourArg).
//
// See the arch-specific GenerateSubtypeNTestCacheStub method to see which
// registers may need saving across this call.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index c04c8a2..d898353 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -1023,10 +1023,17 @@
compiler::Label* is_not_instance_lbl);
enum class TypeTestStubKind {
+ // Just check the instance cid (no closures).
kTestTypeOneArg = 1,
+ // Also check the instance type arguments.
kTestTypeTwoArgs = 2,
+ // Also check the instantiator type arguments for the destination type.
+ kTestTypeThreeArgs = 3,
+ // Also check the function type arguments for the destination type.
kTestTypeFourArgs = 4,
+ // Also check the parent function and delayed type arguments for a closure.
kTestTypeSixArgs = 6,
+ // Also check the destination type, as it is not known at compile time.
kTestTypeSevenArgs = 7,
};
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
index 2d2d22c..c1e00b9 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
@@ -190,9 +190,9 @@
// - kInstanceReg: instance.
// - kDstTypeReg: destination type (for test_kind == kTestTypeSevenArg).
// - kInstantiatorTypeArgumentsReg: instantiator type arguments
-// (for test_kind == kTestTypeFourArg, kTestTypeSixArg, or kTestTypeSevenArg).
+// (for test_kind >= kTestTypeThreeArg).
// - kFunctionTypeArgumentsReg: function type arguments
-// (for test_kind == kTestTypeFourArg, kTestTypeSixArg, or kTestTypeSevenArg).
+// (for test_kind >= kTestTypeFourArg).
//
// Only preserves kInstanceReg from TypeTestABI, all other TypeTestABI
// registers may be used and thus must be saved by the caller.
diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc
index 966035a..5a33326 100644
--- a/runtime/vm/compiler/runtime_api.cc
+++ b/runtime/vm/compiler/runtime_api.cc
@@ -297,6 +297,10 @@
return dart::StubCode::Subtype2TestCache();
}
+const Code& StubCodeSubtype3TestCache() {
+ return dart::StubCode::Subtype3TestCache();
+}
+
const Code& StubCodeSubtype4TestCache() {
return dart::StubCode::Subtype4TestCache();
}
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index d3aa4ed..52b0b39 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -216,6 +216,7 @@
const Code& StubCodeAllocateArray();
const Code& StubCodeSubtype2TestCache();
+const Code& StubCodeSubtype3TestCache();
const Code& StubCodeSubtype4TestCache();
const Code& StubCodeSubtype6TestCache();
const Code& StubCodeSubtype7TestCache();
diff --git a/runtime/vm/compiler/stub_code_compiler.cc b/runtime/vm/compiler/stub_code_compiler.cc
index 63fa5fd..c337f18 100644
--- a/runtime/vm/compiler/stub_code_compiler.cc
+++ b/runtime/vm/compiler/stub_code_compiler.cc
@@ -1091,15 +1091,17 @@
// If the subtype-cache is null, it needs to be lazily-created by the runtime.
__ CompareObject(TypeTestABI::kSubtypeTestCacheReg, NullObject());
- __ BranchIf(EQUAL, &call_runtime, Assembler::kNearJump);
+ __ BranchIf(EQUAL, &call_runtime);
// Use the number of inputs used by the STC to determine which stub to call.
- Label call_2, call_4, call_6;
+ Label call_2, call_3, call_4, call_6;
__ Comment("Check number of STC inputs");
__ LoadFromSlot(TypeTestABI::kScratchReg, TypeTestABI::kSubtypeTestCacheReg,
Slot::SubtypeTestCache_num_inputs());
__ CompareImmediate(TypeTestABI::kScratchReg, 2);
__ BranchIf(EQUAL, &call_2, Assembler::kNearJump);
+ __ CompareImmediate(TypeTestABI::kScratchReg, 3);
+ __ BranchIf(EQUAL, &call_3, Assembler::kNearJump);
__ CompareImmediate(TypeTestABI::kScratchReg, 4);
__ BranchIf(EQUAL, &call_4, Assembler::kNearJump);
__ CompareImmediate(TypeTestABI::kScratchReg, 6);
@@ -1135,6 +1137,16 @@
__ Jump(&call_runtime, Assembler::kNearJump);
}
+ __ Bind(&call_3);
+ {
+ __ Comment("Call 3 input STC check");
+ __ Call(StubCodeSubtype3TestCache());
+ __ CompareObject(TypeTestABI::kSubtypeTestCacheResultReg,
+ CastHandle<Object>(TrueObject()));
+ __ BranchIf(EQUAL, &done); // Cache said: yes.
+ __ Jump(&call_runtime, Assembler::kNearJump);
+ }
+
__ Bind(&call_2);
{
__ Comment("Call 2 input STC check");
@@ -3101,7 +3113,7 @@
// Fill in all the STC input registers.
Label initialized, not_closure;
- if (n >= 4) {
+ if (n >= 3) {
__ LoadClassIdMayBeSmi(instance_cid_or_sig_reg, TypeTestABI::kInstanceReg);
} else {
// If the type is fully instantiated, then it can be determined at compile
@@ -3212,6 +3224,11 @@
}
// See comment on [GenerateSubtypeNTestCacheStub].
+void StubCodeCompiler::GenerateSubtype3TestCacheStub() {
+ GenerateSubtypeNTestCacheStub(assembler, 3);
+}
+
+// See comment on [GenerateSubtypeNTestCacheStub].
void StubCodeCompiler::GenerateSubtype4TestCacheStub() {
GenerateSubtypeNTestCacheStub(assembler, 4);
}
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index e32d1d2..6109d78 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -2738,7 +2738,11 @@
// - kSubtypeTestCacheResultReg: the cached result, or null if not found.
void StubCodeCompiler::GenerateSubtypeNTestCacheStub(Assembler* assembler,
int n) {
- ASSERT(n == 1 || n == 2 || n == 4 || n == 6 || n == 7);
+ ASSERT(n >= 1);
+ ASSERT(n <= SubtypeTestCache::kMaxInputs);
+ // If we need the parent function type arguments for a closure, we also need
+ // the delayed type arguments, so this case will never happen.
+ ASSERT(n != 5);
RegisterSet saved_registers;
// Safe as the original value of TypeTestABI::kSubtypeTestCacheReg is only
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index 63070e7..48161d2 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -3072,7 +3072,11 @@
// - kSubtypeTestCacheResultReg: the cached result, or null if not found.
void StubCodeCompiler::GenerateSubtypeNTestCacheStub(Assembler* assembler,
int n) {
- ASSERT(n == 1 || n == 2 || n == 4 || n == 6 || n == 7);
+ ASSERT(n >= 1);
+ ASSERT(n <= SubtypeTestCache::kMaxInputs);
+ // If we need the parent function type arguments for a closure, we also need
+ // the delayed type arguments, so this case will never happen.
+ ASSERT(n != 5);
// We could initialize kSubtypeTestCacheResultReg with null and use that as
// the null register up until exit, which means we'd just need to return
diff --git a/runtime/vm/compiler/stub_code_compiler_ia32.cc b/runtime/vm/compiler/stub_code_compiler_ia32.cc
index a83a863..486425f 100644
--- a/runtime/vm/compiler/stub_code_compiler_ia32.cc
+++ b/runtime/vm/compiler/stub_code_compiler_ia32.cc
@@ -2501,7 +2501,11 @@
// result (true or false).
void StubCodeCompiler::GenerateSubtypeNTestCacheStub(Assembler* assembler,
int n) {
- ASSERT(n == 1 || n == 2 || n == 4 || n == 6 || n == 7);
+ ASSERT(n >= 1);
+ ASSERT(n <= SubtypeTestCache::kMaxInputs);
+ // If we need the parent function type arguments for a closure, we also need
+ // the delayed type arguments, so this case will never happen.
+ ASSERT(n != 5);
const auto& raw_null = Immediate(target::ToRawPointer(NullObject()));
@@ -2545,7 +2549,7 @@
target::Array::data_offset() - kHeapObjectTag);
Label loop, not_closure;
- if (n >= 4) {
+ if (n >= 3) {
__ LoadClassIdMayBeSmi(STCInternal::kInstanceCidOrSignatureReg,
TypeTestABI::kInstanceReg);
} else {
diff --git a/runtime/vm/compiler/stub_code_compiler_riscv.cc b/runtime/vm/compiler/stub_code_compiler_riscv.cc
index b5e5217..3ce14c7 100644
--- a/runtime/vm/compiler/stub_code_compiler_riscv.cc
+++ b/runtime/vm/compiler/stub_code_compiler_riscv.cc
@@ -2838,7 +2838,11 @@
// - kSubtypeTestCacheResultReg: the cached result, or null if not found.
void StubCodeCompiler::GenerateSubtypeNTestCacheStub(Assembler* assembler,
int n) {
- ASSERT(n == 1 || n == 2 || n == 4 || n == 6 || n == 7);
+ ASSERT(n >= 1);
+ ASSERT(n <= SubtypeTestCache::kMaxInputs);
+ // If we need the parent function type arguments for a closure, we also need
+ // the delayed type arguments, so this case will never happen.
+ ASSERT(n != 5);
// We could initialize kSubtypeTestCacheResultReg with null and use that as
// the null register up until exit, which means we'd just need to return
diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc
index 8020821..a5098bc 100644
--- a/runtime/vm/compiler/stub_code_compiler_x64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_x64.cc
@@ -3036,7 +3036,11 @@
// - kSubtypeTestCacheResultReg: the cached result, or null if not found.
void StubCodeCompiler::GenerateSubtypeNTestCacheStub(Assembler* assembler,
int n) {
- ASSERT(n == 1 || n == 2 || n == 4 || n == 6 || n == 7);
+ ASSERT(n >= 1);
+ ASSERT(n <= SubtypeTestCache::kMaxInputs);
+ // If we need the parent function type arguments for a closure, we also need
+ // the delayed type arguments, so this case will never happen.
+ ASSERT(n != 5);
RegisterSet saved_registers;
// Until we have the result, we use the result register to store the null
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index ee3f3e9..a29f44a 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -19939,7 +19939,9 @@
intptr_t SubtypeTestCache::UsedInputsForType(const AbstractType& type) {
if (type.IsType()) {
- return type.IsInstantiated() ? 2 : 4;
+ if (type.IsInstantiated()) return 2;
+ if (type.IsInstantiated(kFunctions)) return 3;
+ return 4;
}
// Default to all inputs except for the destination type, which must be
// statically known, otherwise this method wouldn't be called.
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index 95c01d7..ee70ec4 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -69,6 +69,8 @@
return StubCode::Subtype1TestCache();
case 2:
return StubCode::Subtype2TestCache();
+ case 3:
+ return StubCode::Subtype3TestCache();
case 4:
return StubCode::Subtype4TestCache();
case 6:
diff --git a/runtime/vm/stub_code_list.h b/runtime/vm/stub_code_list.h
index 12d2403..d8ab228 100644
--- a/runtime/vm/stub_code_list.h
+++ b/runtime/vm/stub_code_list.h
@@ -109,6 +109,7 @@
V(NullIsAssignableToTypeNullSafe) \
V(Subtype1TestCache) \
V(Subtype2TestCache) \
+ V(Subtype3TestCache) \
V(Subtype4TestCache) \
V(Subtype6TestCache) \
V(Subtype7TestCache) \