Revert "[vm] Enable type stubs based type checks in JIT mode for some types."
This reverts commit 4be50d6fa1737dcb8402041ecb7334e5a34ba3a1.
Reason for revert: Failures on SIMDBC64 and Analyzer bots.
Original change's description:
> [vm] Enable type stubs based type checks in JIT mode for some types.
>
> For now we are limiting this to type checks against type parameter types.
>
> # Performance improvements
>
> In Dart 1 mode Dart2JS compiles itself in 28s when running from source
> and in 23s when running from ideal app-jit snapshot (trained on the
> same workload).
>
> Before this change in Dart 2 mode numbers were 51s and 57s respectively.
>
> After this change in Dart 2 mode numbers are 38s and 32s. Meaning
> that regression is reduced by 50%.
>
> Issue https://github.com/dart-lang/sdk/issues/31798
> Issue https://github.com/dart-lang/sdk/issues/33257
>
> Change-Id: I34bf5385a5cc3c7702dc281c6dfa89da85d3dde1
> Reviewed-on: https://dart-review.googlesource.com/57601
> Reviewed-by: RĂ©gis Crelier <regis@google.com>
> Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
TBR=vegorov@google.com,kustermann@google.com,regis@google.com
Change-Id: I85a30c962b0cd556310e19193f5993ab76ecf2e7
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/57840
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 4cce63f..989960e 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -33,10 +33,6 @@
return RawObject::FromAddr(address);
}
-static bool SnapshotContainsTypeTestingStubs(Snapshot::Kind kind) {
- return kind == Snapshot::kFullAOT || kind == Snapshot::kFullJIT;
-}
-
void Deserializer::InitializeHeader(RawObject* raw,
intptr_t class_id,
intptr_t size,
@@ -3062,8 +3058,6 @@
void WriteFill(Serializer* s) {
const bool is_vm_isolate = s->isolate() == Dart::vm_isolate();
- const bool should_write_type_testing_stub =
- SnapshotContainsTypeTestingStubs(s->kind());
intptr_t count = canonical_objects_.length();
for (intptr_t i = 0; i < count; i++) {
@@ -3075,7 +3069,7 @@
}
s->WriteTokenPosition(type->ptr()->token_pos_);
s->Write<int8_t>(type->ptr()->type_state_);
- if (should_write_type_testing_stub) {
+ if (s->kind() == Snapshot::kFullAOT) {
RawInstructions* instr = type_testing_stubs_.LookupByAddresss(
type->ptr()->type_test_stub_entry_point_);
s->WriteInstructions(instr, Code::null());
@@ -3091,7 +3085,7 @@
}
s->WriteTokenPosition(type->ptr()->token_pos_);
s->Write<int8_t>(type->ptr()->type_state_);
- if (should_write_type_testing_stub) {
+ if (s->kind() == Snapshot::kFullAOT) {
RawInstructions* instr = type_testing_stubs_.LookupByAddresss(
type->ptr()->type_test_stub_entry_point_);
s->WriteInstructions(instr, Code::null());
@@ -3100,7 +3094,7 @@
// The dynamic/void objects are not serialized, so we manually send
// the type testing stub for it.
- if (should_write_type_testing_stub && is_vm_isolate) {
+ if (s->kind() == Snapshot::kFullAOT && is_vm_isolate) {
RawInstructions* dynamic_instr = type_testing_stubs_.LookupByAddresss(
Type::dynamic_type().type_test_stub_entry_point());
s->WriteInstructions(dynamic_instr, Code::null());
@@ -3143,8 +3137,6 @@
void ReadFill(Deserializer* d) {
const bool is_vm_isolate = d->isolate() == Dart::vm_isolate();
- const bool should_read_type_testing_stub =
- SnapshotContainsTypeTestingStubs(d->kind());
for (intptr_t id = canonical_start_index_; id < canonical_stop_index_;
id++) {
@@ -3158,7 +3150,7 @@
}
type->ptr()->token_pos_ = d->ReadTokenPosition();
type->ptr()->type_state_ = d->Read<int8_t>();
- if (should_read_type_testing_stub) {
+ if (d->kind() == Snapshot::kFullAOT) {
instr_ = d->ReadInstructions();
type_ = type;
type_.SetTypeTestingStub(instr_);
@@ -3176,7 +3168,7 @@
}
type->ptr()->token_pos_ = d->ReadTokenPosition();
type->ptr()->type_state_ = d->Read<int8_t>();
- if (should_read_type_testing_stub) {
+ if (d->kind() == Snapshot::kFullAOT) {
instr_ = d->ReadInstructions();
type_ = type;
type_.SetTypeTestingStub(instr_);
@@ -3185,7 +3177,7 @@
// The dynamic/void objects are not serialized, so we manually send
// the type testing stub for it.
- if (should_read_type_testing_stub && is_vm_isolate) {
+ if (d->kind() == Snapshot::kFullAOT && is_vm_isolate) {
instr_ = d->ReadInstructions();
Type::dynamic_type().SetTypeTestingStub(instr_);
instr_ = d->ReadInstructions();
@@ -3194,7 +3186,7 @@
}
void PostLoad(const Array& refs, Snapshot::Kind kind, Zone* zone) {
- if (!SnapshotContainsTypeTestingStubs(kind)) {
+ if (kind != Snapshot::kFullAOT) {
for (intptr_t id = canonical_start_index_; id < canonical_stop_index_;
id++) {
type_ ^= refs.At(id);
@@ -3245,9 +3237,6 @@
}
void WriteFill(Serializer* s) {
- const bool should_write_type_testing_stub =
- SnapshotContainsTypeTestingStubs(s->kind());
-
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawTypeRef* type = objects_[i];
@@ -3256,7 +3245,7 @@
for (RawObject** p = from; p <= to; p++) {
s->WriteRef(*p);
}
- if (should_write_type_testing_stub) {
+ if (s->kind() == Snapshot::kFullAOT) {
RawInstructions* instr = type_testing_stubs_.LookupByAddresss(
type->ptr()->type_test_stub_entry_point_);
s->WriteInstructions(instr, Code::null());
@@ -3287,9 +3276,7 @@
}
void ReadFill(Deserializer* d) {
- const bool is_vm_object = d->isolate() == Dart::vm_isolate();
- const bool should_read_type_testing_stub =
- SnapshotContainsTypeTestingStubs(d->kind());
+ bool is_vm_object = d->isolate() == Dart::vm_isolate();
for (intptr_t id = start_index_; id < stop_index_; id++) {
RawTypeRef* type = reinterpret_cast<RawTypeRef*>(d->Ref(id));
@@ -3300,7 +3287,7 @@
for (RawObject** p = from; p <= to; p++) {
*p = d->ReadRef();
}
- if (should_read_type_testing_stub) {
+ if (d->kind() == Snapshot::kFullAOT) {
instr_ = d->ReadInstructions();
type_ = type;
type_.SetTypeTestingStub(instr_);
@@ -3308,16 +3295,6 @@
}
}
- void PostLoad(const Array& refs, Snapshot::Kind kind, Zone* zone) {
- if (!SnapshotContainsTypeTestingStubs(kind)) {
- for (intptr_t id = start_index_; id < stop_index_; id++) {
- type_ ^= refs.At(id);
- instr_ = TypeTestingStubGenerator::DefaultCodeForType(type_);
- type_.SetTypeTestingStub(instr_);
- }
- }
- }
-
private:
AbstractType& type_;
Instructions& instr_;
@@ -3354,9 +3331,6 @@
}
void WriteFill(Serializer* s) {
- const bool should_write_type_testing_stub =
- SnapshotContainsTypeTestingStubs(s->kind());
-
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawTypeParameter* type = objects_[i];
@@ -3369,7 +3343,7 @@
s->WriteTokenPosition(type->ptr()->token_pos_);
s->Write<int16_t>(type->ptr()->index_);
s->Write<int8_t>(type->ptr()->type_state_);
- if (should_write_type_testing_stub) {
+ if (s->kind() == Snapshot::kFullAOT) {
RawInstructions* instr = type_testing_stubs_.LookupByAddresss(
type->ptr()->type_test_stub_entry_point_);
s->WriteInstructions(instr, Code::null());
@@ -3402,8 +3376,6 @@
void ReadFill(Deserializer* d) {
bool is_vm_object = d->isolate() == Dart::vm_isolate();
- const bool should_read_type_testing_stub =
- SnapshotContainsTypeTestingStubs(d->kind());
for (intptr_t id = start_index_; id < stop_index_; id++) {
RawTypeParameter* type = reinterpret_cast<RawTypeParameter*>(d->Ref(id));
@@ -3418,7 +3390,7 @@
type->ptr()->token_pos_ = d->ReadTokenPosition();
type->ptr()->index_ = d->Read<int16_t>();
type->ptr()->type_state_ = d->Read<int8_t>();
- if (should_read_type_testing_stub) {
+ if (d->kind() == Snapshot::kFullAOT) {
instr_ = d->ReadInstructions();
type_ = type;
type_.SetTypeTestingStub(instr_);
@@ -3427,7 +3399,7 @@
}
void PostLoad(const Array& refs, Snapshot::Kind kind, Zone* zone) {
- if (!SnapshotContainsTypeTestingStubs(kind)) {
+ if (kind != Snapshot::kFullAOT) {
for (intptr_t id = start_index_; id < stop_index_; id++) {
type_ ^= refs.At(id);
instr_ = TypeTestingStubGenerator::DefaultCodeForType(type_);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 187e12f..199e17c 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -1934,12 +1934,7 @@
}
}
-bool FlowGraphCompiler::ShouldUseTypeTestingStubFor(bool optimizing,
- const AbstractType& type) {
- return FLAG_precompiled_mode || (optimizing && type.IsTypeParameter());
-}
-
-void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
+void FlowGraphCompiler::GenerateAssertAssignableAOT(
const AbstractType& dst_type,
const String& dst_name,
const Register instance_reg,
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index 8185f32..b4123f2 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -364,28 +364,21 @@
const AbstractType& dst_type,
const String& dst_name,
LocationSummary* locs);
+ void GenerateAssertAssignableAOT(TokenPosition token_pos,
+ intptr_t deopt_id,
+ const AbstractType& dst_type,
+ const String& dst_name,
+ LocationSummary* locs);
- // Returns true if we can use a type testing stub based assert
- // assignable code pattern for the given type.
- static bool ShouldUseTypeTestingStubFor(bool optimizing,
- const AbstractType& type);
-
- void GenerateAssertAssignableViaTypeTestingStub(TokenPosition token_pos,
- intptr_t deopt_id,
- const AbstractType& dst_type,
- const String& dst_name,
- LocationSummary* locs);
-
- void GenerateAssertAssignableViaTypeTestingStub(
- const AbstractType& dst_type,
- const String& dst_name,
- const Register instance_reg,
- const Register instantiator_type_args_reg,
- const Register function_type_args_reg,
- const Register subtype_cache_reg,
- const Register dst_type_reg,
- const Register scratch_reg,
- Label* done);
+ void GenerateAssertAssignableAOT(const AbstractType& dst_type,
+ const String& dst_name,
+ const Register instance_reg,
+ const Register instantiator_type_args_reg,
+ const Register function_type_args_reg,
+ const Register subtype_cache_reg,
+ const Register dst_type_reg,
+ const Register scratch_reg,
+ Label* done);
// DBC emits calls very differently from all other architectures due to its
// interpreted nature.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index e41694f..a27e76c 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -663,8 +663,7 @@
}
if (FLAG_precompiled_mode) {
- GenerateAssertAssignableViaTypeTestingStub(token_pos, deopt_id, dst_type,
- dst_name, locs);
+ GenerateAssertAssignableAOT(token_pos, deopt_id, dst_type, dst_name, locs);
} else {
Label is_assignable_fast, is_assignable, runtime_call;
@@ -692,11 +691,10 @@
__ PushObject(dst_name); // Push the name of the destination.
__ LoadUniqueObject(R0, test_cache);
__ Push(R0);
- __ PushObject(Smi::ZoneHandle(zone(), Smi::New(kTypeCheckFromInline)));
- GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 7, locs);
+ GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
// Pop the parameters supplied to the runtime entry. The result of the
// type check runtime call is the checked value.
- __ Drop(7);
+ __ Drop(6);
__ Pop(R0);
__ Bind(&is_assignable);
__ PopList((1 << kFunctionTypeArgumentsReg) |
@@ -705,7 +703,7 @@
}
}
-void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
+void FlowGraphCompiler::GenerateAssertAssignableAOT(
TokenPosition token_pos,
intptr_t deopt_id,
const AbstractType& dst_type,
@@ -721,10 +719,10 @@
Label done;
- GenerateAssertAssignableViaTypeTestingStub(
- dst_type, dst_name, kInstanceReg, kInstantiatorTypeArgumentsReg,
- kFunctionTypeArgumentsReg, kSubtypeTestCacheReg, kDstTypeReg, kScratchReg,
- &done);
+ GenerateAssertAssignableAOT(dst_type, dst_name, kInstanceReg,
+ kInstantiatorTypeArgumentsReg,
+ kFunctionTypeArgumentsReg, kSubtypeTestCacheReg,
+ kDstTypeReg, kScratchReg, &done);
// We use 2 consecutive entries in the pool for the subtype cache and the
// destination name. The second entry, namely [dst_name] seems to be unused,
// but it will be used by the code throwing a TypeError if the type test fails
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index a74cec8..c76e56d 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -643,9 +643,8 @@
return;
}
- if (ShouldUseTypeTestingStubFor(is_optimizing(), dst_type)) {
- GenerateAssertAssignableViaTypeTestingStub(token_pos, deopt_id, dst_type,
- dst_name, locs);
+ if (FLAG_precompiled_mode) {
+ GenerateAssertAssignableAOT(token_pos, deopt_id, dst_type, dst_name, locs);
} else {
Label is_assignable_fast, is_assignable, runtime_call;
@@ -670,11 +669,10 @@
__ PushObject(dst_name); // Push the name of the destination.
__ LoadUniqueObject(R0, test_cache);
__ Push(R0);
- __ PushObject(Smi::ZoneHandle(zone(), Smi::New(kTypeCheckFromInline)));
- GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 7, locs);
+ GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
// Pop the parameters supplied to the runtime entry. The result of the
// type check runtime call is the checked value.
- __ Drop(7);
+ __ Drop(6);
__ Pop(R0);
__ Bind(&is_assignable);
__ PopPair(kFunctionTypeArgumentsReg, kInstantiatorTypeArgumentsReg);
@@ -682,7 +680,7 @@
}
}
-void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
+void FlowGraphCompiler::GenerateAssertAssignableAOT(
TokenPosition token_pos,
intptr_t deopt_id,
const AbstractType& dst_type,
@@ -698,10 +696,10 @@
Label done;
- GenerateAssertAssignableViaTypeTestingStub(
- dst_type, dst_name, kInstanceReg, kInstantiatorTypeArgumentsReg,
- kFunctionTypeArgumentsReg, kSubtypeTestCacheReg, kDstTypeReg, kScratchReg,
- &done);
+ GenerateAssertAssignableAOT(dst_type, dst_name, kInstanceReg,
+ kInstantiatorTypeArgumentsReg,
+ kFunctionTypeArgumentsReg, kSubtypeTestCacheReg,
+ kDstTypeReg, kScratchReg, &done);
// We use 2 consecutive entries in the pool for the subtype cache and the
// destination name. The second entry, namely [dst_name] seems to be unused,
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
index f19eea3..0580e5c 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
@@ -686,11 +686,10 @@
__ PushObject(dst_name); // Push the name of the destination.
__ LoadObject(EAX, test_cache);
__ pushl(EAX);
- __ PushObject(Smi::ZoneHandle(zone(), Smi::New(kTypeCheckFromInline)));
- GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 7, locs);
+ GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
// Pop the parameters supplied to the runtime entry. The result of the
// type check runtime call is the checked value.
- __ Drop(7);
+ __ Drop(6);
__ popl(EAX);
__ Bind(&is_assignable);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index 0ef54a5..4a2c58b 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -654,9 +654,8 @@
return;
}
- if (ShouldUseTypeTestingStubFor(is_optimizing(), dst_type)) {
- GenerateAssertAssignableViaTypeTestingStub(token_pos, deopt_id, dst_type,
- dst_name, locs);
+ if (FLAG_precompiled_mode) {
+ GenerateAssertAssignableAOT(token_pos, deopt_id, dst_type, dst_name, locs);
} else {
Label is_assignable, runtime_call;
@@ -679,17 +678,16 @@
__ PushObject(dst_name); // Push the name of the destination.
__ LoadUniqueObject(RAX, test_cache);
__ pushq(RAX);
- __ PushObject(Smi::ZoneHandle(zone(), Smi::New(kTypeCheckFromInline)));
- GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 7, locs);
+ GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
// Pop the parameters supplied to the runtime entry. The result of the
// type check runtime call is the checked value.
- __ Drop(7);
+ __ Drop(6);
__ popq(RAX);
__ Bind(&is_assignable);
}
}
-void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
+void FlowGraphCompiler::GenerateAssertAssignableAOT(
TokenPosition token_pos,
intptr_t deopt_id,
const AbstractType& dst_type,
@@ -704,10 +702,10 @@
const Register subtype_cache_reg = R9;
const Register kScratchReg = RBX;
- GenerateAssertAssignableViaTypeTestingStub(
- dst_type, dst_name, kInstanceReg, kInstantiatorTypeArgumentsReg,
- kFunctionTypeArgumentsReg, subtype_cache_reg, kScratchReg, kScratchReg,
- &done);
+ GenerateAssertAssignableAOT(dst_type, dst_name, kInstanceReg,
+ kInstantiatorTypeArgumentsReg,
+ kFunctionTypeArgumentsReg, subtype_cache_reg,
+ kScratchReg, kScratchReg, &done);
// We use 2 consecutive entries in the pool for the subtype cache and the
// destination name. The second entry, namely [dst_name] seems to be unused,
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 84ff39f..3d7b61d 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -396,19 +396,16 @@
LocationSummary* AssertAssignableInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
- // When using a type testing stub, we want to prevent spilling of the
- // function/instantiator type argument vectors, since stub preserves them. So
- // we make this a `kNoCall` summary, even though most other registers can be
- // modified by the stub. To tell the register allocator about it, we reserve
+ // In AOT mode, we want to prevent spilling of the function/instantiator type
+ // argument vectors, since we preserve them. So we make this a `kNoCall`
+ // summary. Though most other registers can be modified by the type testing
+ // stubs we are calling. To tell the register allocator about it, we reserve
// all the other registers as temporary registers.
// TODO(http://dartbug.com/32788): Simplify this.
const Register kInstanceReg = R0;
const Register kInstantiatorTypeArgumentsReg = R2;
const Register kFunctionTypeArgumentsReg = R1;
- const bool using_stub =
- FlowGraphCompiler::ShouldUseTypeTestingStubFor(opt, dst_type());
-
const intptr_t kNonChangeableInputRegs =
(1 << kInstanceReg) | (1 << kInstantiatorTypeArgumentsReg) |
(1 << kFunctionTypeArgumentsReg);
@@ -416,13 +413,14 @@
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps =
- using_stub ? (Utils::CountOneBits64(kDartAvailableCpuRegs) -
- Utils::CountOneBits64(kNonChangeableInputRegs))
- : 0;
+ FLAG_precompiled_mode ? (Utils::CountOneBits64(kDartAvailableCpuRegs) -
+ Utils::CountOneBits64(kNonChangeableInputRegs))
+ : 0;
- LocationSummary* summary = new (zone) LocationSummary(
- zone, kNumInputs, kNumTemps,
- using_stub ? LocationSummary::kCallCalleeSafe : LocationSummary::kCall);
+ LocationSummary* summary = new (zone)
+ LocationSummary(zone, kNumInputs, kNumTemps,
+ FLAG_precompiled_mode ? LocationSummary::kCallCalleeSafe
+ : LocationSummary::kCall);
summary->set_in(0, Location::RegisterLocation(kInstanceReg)); // Value.
summary->set_in(1,
Location::RegisterLocation(
@@ -434,7 +432,7 @@
// once register allocator no longer hits assertion.
summary->set_out(0, Location::RegisterLocation(kInstanceReg));
- if (using_stub) {
+ if (FLAG_precompiled_mode) {
// Let's reserve all registers except for the input ones.
intptr_t next_temp = 0;
for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 8c857b4..9a9bc82 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -394,19 +394,16 @@
LocationSummary* AssertAssignableInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
- // When using a type testing stub, we want to prevent spilling of the
- // function/instantiator type argument vectors, since stub preserves them. So
- // we make this a `kNoCall` summary, even though most other registers can be
- // modified by the stub. To tell the register allocator about it, we reserve
+ // In AOT mode, we want to prevent spilling of the function/instantiator type
+ // argument vectors, since we preserve them. So we make this a `kNoCall`
+ // summary. Though most other registers can be modified by the type testing
+ // stubs we are calling. To tell the register allocator about it, we reserve
// all the other registers as temporary registers.
// TODO(http://dartbug.com/32788): Simplify this.
const Register kInstanceReg = R0;
const Register kInstantiatorTypeArgumentsReg = R1;
const Register kFunctionTypeArgumentsReg = R2;
- const bool using_stub =
- FlowGraphCompiler::ShouldUseTypeTestingStubFor(opt, dst_type());
-
const intptr_t kNonChangeableInputRegs =
(1 << kInstanceReg) | (1 << kInstantiatorTypeArgumentsReg) |
(1 << kFunctionTypeArgumentsReg);
@@ -414,13 +411,14 @@
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps =
- using_stub ? (Utils::CountOneBits64(kDartAvailableCpuRegs) -
- Utils::CountOneBits64(kNonChangeableInputRegs))
- : 0;
+ FLAG_precompiled_mode ? (Utils::CountOneBits64(kDartAvailableCpuRegs) -
+ Utils::CountOneBits64(kNonChangeableInputRegs))
+ : 0;
- LocationSummary* summary = new (zone) LocationSummary(
- zone, kNumInputs, kNumTemps,
- using_stub ? LocationSummary::kCallCalleeSafe : LocationSummary::kCall);
+ LocationSummary* summary = new (zone)
+ LocationSummary(zone, kNumInputs, kNumTemps,
+ FLAG_precompiled_mode ? LocationSummary::kCallCalleeSafe
+ : LocationSummary::kCall);
summary->set_in(0, Location::RegisterLocation(kInstanceReg)); // Value.
summary->set_in(1,
Location::RegisterLocation(
@@ -432,7 +430,7 @@
// once register allocator no longer hits assertion.
summary->set_out(0, Location::RegisterLocation(kInstanceReg));
- if (using_stub) {
+ if (FLAG_precompiled_mode) {
// Let's reserve all registers except for the input ones.
intptr_t next_temp = 0;
for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 869704f..cbbd640 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -362,19 +362,16 @@
LocationSummary* AssertAssignableInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
- // When using a type testing stub, we want to prevent spilling of the
- // function/instantiator type argument vectors, since stub preserves them. So
- // we make this a `kNoCall` summary, even though most other registers can be
- // modified by the stub. To tell the register allocator about it, we reserve
+ // In AOT mode, we want to prevent spilling of the function/instantiator type
+ // argument vectors, since we preserve them. So we make this a `kNoCall`
+ // summary. Though most other registers can be modified by the type testing
+ // stubs we are calling. To tell the register allocator about it, we reserve
// all the other registers as temporary registers.
// TODO(http://dartbug.com/32788): Simplify this.
const Register kInstanceReg = RAX;
const Register kInstantiatorTypeArgumentsReg = RDX;
const Register kFunctionTypeArgumentsReg = RCX;
- const bool using_stub =
- FlowGraphCompiler::ShouldUseTypeTestingStubFor(opt, dst_type());
-
const intptr_t kNonChangeableInputRegs =
(1 << kInstanceReg) | (1 << kInstantiatorTypeArgumentsReg) |
(1 << kFunctionTypeArgumentsReg);
@@ -382,13 +379,14 @@
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps =
- using_stub ? (Utils::CountOneBits64(kDartAvailableCpuRegs) -
- Utils::CountOneBits64(kNonChangeableInputRegs))
- : 0;
+ FLAG_precompiled_mode ? (Utils::CountOneBits64(kDartAvailableCpuRegs) -
+ Utils::CountOneBits64(kNonChangeableInputRegs))
+ : 0;
- LocationSummary* summary = new (zone) LocationSummary(
- zone, kNumInputs, kNumTemps,
- using_stub ? LocationSummary::kCallCalleeSafe : LocationSummary::kCall);
+ LocationSummary* summary = new (zone)
+ LocationSummary(zone, kNumInputs, kNumTemps,
+ FLAG_precompiled_mode ? LocationSummary::kCallCalleeSafe
+ : LocationSummary::kCall);
summary->set_in(0, Location::RegisterLocation(kInstanceReg)); // Value.
summary->set_in(1,
Location::RegisterLocation(
@@ -400,7 +398,7 @@
// once register allocator no longer hits assertion.
summary->set_out(0, Location::RegisterLocation(kInstanceReg));
- if (using_stub) {
+ if (FLAG_precompiled_mode) {
// Let's reserve all registers except for the input ones.
intptr_t next_temp = 0;
for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
diff --git a/runtime/vm/instructions.h b/runtime/vm/instructions.h
index eb39a5d..e0ec51f 100644
--- a/runtime/vm/instructions.h
+++ b/runtime/vm/instructions.h
@@ -28,7 +28,7 @@
bool DecodeLoadObjectFromPoolOrThread(uword pc, const Code& code, Object* obj);
-#if !defined(TARGET_ARCH_IA32) && !defined(TARGET_ARCH_DBC)
+#if defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME)
class TypeTestingStubCallPattern : public ValueObject {
public:
@@ -40,7 +40,7 @@
const uword pc_;
};
-#endif // !defined(TARGET_ARCH_IA32) && !defined(TARGET_ARCH_DBC)
+#endif // defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME)
} // namespace dart
diff --git a/runtime/vm/instructions_arm.cc b/runtime/vm/instructions_arm.cc
index 38dbee5..f62215f 100644
--- a/runtime/vm/instructions_arm.cc
+++ b/runtime/vm/instructions_arm.cc
@@ -285,6 +285,8 @@
return false;
}
+#if defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME)
+
intptr_t TypeTestingStubCallPattern::GetSubtypeTestCachePoolIndex() {
// Calls to the type testing stubs look like:
// ldr R3, [PP+idx]
@@ -302,6 +304,8 @@
return pool_index;
}
+#endif // defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME)
+
} // namespace dart
#endif // defined TARGET_ARCH_ARM
diff --git a/runtime/vm/instructions_arm64.cc b/runtime/vm/instructions_arm64.cc
index a08eda0..f728ffd 100644
--- a/runtime/vm/instructions_arm64.cc
+++ b/runtime/vm/instructions_arm64.cc
@@ -351,6 +351,8 @@
return bx_lr->InstructionBits() == instruction;
}
+#if defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME)
+
intptr_t TypeTestingStubCallPattern::GetSubtypeTestCachePoolIndex() {
// Calls to the type testing stubs look like:
// ldr R3, [PP+idx]
@@ -368,6 +370,8 @@
return pool_index;
}
+#endif // defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME)
+
} // namespace dart
#endif // defined TARGET_ARCH_ARM64
diff --git a/runtime/vm/instructions_x64.cc b/runtime/vm/instructions_x64.cc
index 4765a52..3c63a75 100644
--- a/runtime/vm/instructions_x64.cc
+++ b/runtime/vm/instructions_x64.cc
@@ -64,6 +64,8 @@
return false;
}
+#if defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME)
+
intptr_t TypeTestingStubCallPattern::GetSubtypeTestCachePoolIndex() {
const intptr_t kCallPatternSize = 10;
static int16_t pattern[kCallPatternSize] = {
@@ -76,6 +78,8 @@
return IndexFromPPLoad(start + 3);
}
+#endif // defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME)
+
} // namespace dart
#endif // defined TARGET_ARCH_X64
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index dba91ad..d8b68f7 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -3368,9 +3368,8 @@
SP[4] = args[2]; // function type args
SP[5] = args[4]; // name
SP[6] = cache;
- SP[7] = Smi::New(kTypeCheckFromInline);
- Exit(thread, FP, SP + 8, pc);
- NativeArguments native_args(thread, 7, SP + 1, SP - 4);
+ Exit(thread, FP, SP + 7, pc);
+ NativeArguments native_args(thread, 6, SP + 1, SP - 4);
INVOKE_RUNTIME(DRT_TypeCheck, native_args);
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index ed6ecb1..8be76ae 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -18247,8 +18247,6 @@
cloned_ref_type = ref_type.CloneUninstantiated(new_owner, trail);
ASSERT(!cloned_ref_type.IsTypeRef());
cloned_type_ref.set_type(cloned_ref_type);
- cloned_type_ref.SetTypeTestingStub(Instructions::Handle(
- TypeTestingStubGenerator::DefaultCodeForType(cloned_type_ref)));
return cloned_type_ref.raw();
}
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index f1c80c5..e62baec 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1811,13 +1811,6 @@
kFinalizedInstantiated, // Instantiated type ready for use.
kFinalizedUninstantiated, // Uninstantiated type ready for use.
};
-
- // Note: we don't handle this field in GC in any special way.
- // Instead we rely on two things:
- // (1) GC not moving code objects and
- // (2) lifetime of optimized stubs exceeding that of types;
- // Practically (2) means that optimized stubs never die because
- // canonical types to which they are attached never die.
uword type_test_stub_entry_point_; // Accessed from generated code.
private:
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index e5571e4..e8af8b8 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -9,7 +9,6 @@
#include "vm/snapshot.h"
#include "vm/stub_code.h"
#include "vm/symbols.h"
-#include "vm/type_testing_stubs.h"
#include "vm/visitor.h"
namespace dart {
@@ -237,11 +236,6 @@
type.SetCanonical();
}
- // Fill in the type testing stub.
- Instructions& instr = *reader->InstructionsHandle();
- instr = TypeTestingStubGenerator::DefaultCodeForType(type);
- type.SetTypeTestingStub(instr);
-
return type.raw();
}
@@ -312,11 +306,6 @@
READ_OBJECT_FIELDS(type_ref, type_ref.raw()->from(), type_ref.raw()->to(),
kAsReference);
- // Fill in the type testing stub.
- Instructions& instr = *reader->InstructionsHandle();
- instr = TypeTestingStubGenerator::DefaultCodeForType(type_ref);
- type_ref.SetTypeTestingStub(instr);
-
return type_ref.raw();
}
@@ -368,11 +357,6 @@
Class::RawCast(reader->ReadObjectImpl(kAsReference));
type_parameter.set_parameterized_class(*reader->ClassHandle());
- // Fill in the type testing stub.
- Instructions& instr = *reader->InstructionsHandle();
- instr = TypeTestingStubGenerator::DefaultCodeForType(type_parameter);
- type_parameter.SetTypeTestingStub(instr);
-
return type_parameter.raw();
}
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index da751b3..645f1ea 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -26,7 +26,6 @@
#include "vm/stack_frame.h"
#include "vm/symbols.h"
#include "vm/thread_registry.h"
-#include "vm/type_testing_stubs.h"
#include "vm/verifier.h"
namespace dart {
@@ -681,9 +680,8 @@
// Arg3: type arguments of the function of the type being assigned to.
// Arg4: name of variable being assigned to.
// Arg5: SubtypeTestCache.
-// Arg6: invocation mode (see TypeCheckMode)
// Return value: instance if a subtype, otherwise throw a TypeError.
-DEFINE_RUNTIME_ENTRY(TypeCheck, 7) {
+DEFINE_RUNTIME_ENTRY(TypeCheck, 6) {
const Instance& src_instance =
Instance::CheckedHandle(zone, arguments.ArgAt(0));
AbstractType& dst_type =
@@ -700,13 +698,6 @@
cache ^= arguments.ArgAt(5);
ASSERT(cache.IsNull() || cache.IsSubtypeTestCache());
- const TypeCheckMode mode = static_cast<TypeCheckMode>(
- Smi::CheckedHandle(zone, arguments.ArgAt(6)).Value());
-
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_DBC)
- ASSERT(mode == kTypeCheckFromInline);
-#endif
-
ASSERT(!dst_type.IsMalformed()); // Already checked in code generator.
ASSERT(!dst_type.IsMalbounded()); // Already checked in code generator.
ASSERT(!dst_type.IsDynamicType()); // No need to check assignment.
@@ -740,10 +731,8 @@
bound_error_message = String::New(bound_error.ToErrorCString());
}
if (dst_name.IsNull()) {
-#if !defined(TARGET_ARCH_DBC) && !defined(TARGET_ARCH_IA32)
- // Can only come here from type testing stub.
- ASSERT(mode != kTypeCheckFromInline);
-
+#if !defined(TARGET_ARCH_DBC) && !defined(TARGET_ARCH_IA32) && \
+ (defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME))
// Grab the [dst_name] from the pool. It's stored at one pool slot after
// the subtype-test-cache.
DartFrameIterator iterator(thread,
@@ -767,20 +756,14 @@
UNREACHABLE();
}
- bool should_update_cache = true;
+ if (cache.IsNull()) {
#if !defined(TARGET_ARCH_DBC) && !defined(TARGET_ARCH_IA32) && \
- !defined(DART_PRECOMPILED_RUNTIME)
- if (mode == kTypeCheckFromLazySpecializeStub) {
- TypeTestingStubGenerator::SpecializeStubFor(thread, dst_type);
- // Only create the cache when we come from a normal stub.
- should_update_cache = false;
- }
-#endif
+ (defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME))
- if (should_update_cache) {
- if (cache.IsNull()) {
-#if !defined(TARGET_ARCH_DBC) && !defined(TARGET_ARCH_IA32)
- ASSERT(mode == kTypeCheckFromSlowStub);
+#if defined(DART_PRECOMPILER)
+ if (FLAG_precompiled_mode) {
+#endif // defined(DART_PRECOMPILER)
+
// We lazily create [SubtypeTestCache] for those call sites which actually
// need one and will patch the pool entry.
DartFrameIterator iterator(thread,
@@ -797,15 +780,37 @@
ASSERT(pool.ObjectAt(stc_pool_idx) == Object::null());
cache = SubtypeTestCache::New();
pool.SetObjectAt(stc_pool_idx, cache);
-#else
- UNREACHABLE();
-#endif
- }
- UpdateTypeTestCache(src_instance, dst_type, instantiator_type_arguments,
- function_type_arguments, Bool::True(), cache);
+#if defined(DART_PRECOMPILER)
+ }
+#endif // defined(DART_PRECOMPILER)
+
+#else
+ // WARNING: If we ever come here, it's a really bad sign, because it means
+ // that there was a type test, which generated code could not handle but we
+ // have no subtype cache. Which means that this successfully-passing type
+ // check will always go to runtime.
+ //
+ // Currently there is one known case when this happens:
+ //
+ // The [FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest] is
+ // handling type checks against int/num specially: It generates a number of
+ // class-id checks. Unfortunately it handles only normal implementations of
+ // 'int', such as kSmiCid, kMintCid, kBigintCid. It will signal that there
+ // is no subtype-cache necessary on that call site, because all integer
+ // types have been handled.
+ //
+ // -> Though this is not true, due to (from runtime/lib/array_patch.dart):
+ //
+ // class _GrowableArrayMarker implements int { }
+ //
+ // Because of this, we cannot have an `UNREACHABLE()` here, but rather just
+ // have a NOP and return `true`, to signal the type check passed.
+#endif // defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME)
}
+ UpdateTypeTestCache(src_instance, dst_type, instantiator_type_arguments,
+ function_type_arguments, Bool::True(), cache);
arguments.SetReturn(src_instance);
}
diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc
index 5730b52..487143f 100644
--- a/runtime/vm/simulator_dbc.cc
+++ b/runtime/vm/simulator_dbc.cc
@@ -3060,9 +3060,8 @@
SP[4] = args[2]; // function type args
SP[5] = args[4]; // name
SP[6] = cache;
- SP[7] = Smi::New(kTypeCheckFromInline);
- Exit(thread, FP, SP + 8, pc);
- NativeArguments native_args(thread, 8, SP + 1, SP - 4);
+ Exit(thread, FP, SP + 7, pc);
+ NativeArguments native_args(thread, 6, SP + 1, SP - 4);
INVOKE_RUNTIME(DRT_TypeCheck, native_args);
}
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index d1fb4ba..d3667ce 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -192,7 +192,6 @@
old_space_(thread_->isolate()->heap()->old_space()),
cls_(Class::Handle(zone_)),
code_(Code::Handle(zone_)),
- instructions_(Instructions::Handle(zone_)),
obj_(Object::Handle(zone_)),
pobj_(PassiveObject::Handle(zone_)),
array_(Array::Handle(zone_)),
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index b630cc3..60a944f 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -335,7 +335,6 @@
Array* ArrayHandle() { return &array_; }
Class* ClassHandle() { return &cls_; }
Code* CodeHandle() { return &code_; }
- Instructions* InstructionsHandle() { return &instructions_; }
String* StringHandle() { return &str_; }
AbstractType* TypeHandle() { return &type_; }
TypeArguments* TypeArgumentsHandle() { return &type_arguments_; }
@@ -441,21 +440,20 @@
bool is_vm_isolate() const;
- Snapshot::Kind kind_; // Indicates type of the snapshot.
- Thread* thread_; // Current thread.
- Zone* zone_; // Zone for allocations while reading.
- Heap* heap_; // Heap of the current isolate.
- PageSpace* old_space_; // Old space of the current isolate.
- Class& cls_; // Temporary Class handle.
- Code& code_; // Temporary Code handle.
- Instructions& instructions_; // Temporary Instructions handle
- Object& obj_; // Temporary Object handle.
- PassiveObject& pobj_; // Temporary PassiveObject handle.
- Array& array_; // Temporary Array handle.
- Field& field_; // Temporary Field handle.
- String& str_; // Temporary String handle.
- Library& library_; // Temporary library handle.
- AbstractType& type_; // Temporary type handle.
+ Snapshot::Kind kind_; // Indicates type of snapshot(full, script, message).
+ Thread* thread_; // Current thread.
+ Zone* zone_; // Zone for allocations while reading snapshot.
+ Heap* heap_; // Heap of the current isolate.
+ PageSpace* old_space_; // Old space of the current isolate.
+ Class& cls_; // Temporary Class handle.
+ Code& code_; // Temporary Code handle.
+ Object& obj_; // Temporary Object handle.
+ PassiveObject& pobj_; // Temporary PassiveObject handle.
+ Array& array_; // Temporary Array handle.
+ Field& field_; // Temporary Field handle.
+ String& str_; // Temporary String handle.
+ Library& library_; // Temporary library handle.
+ AbstractType& type_; // Temporary type handle.
TypeArguments& type_arguments_; // Temporary type argument handle.
GrowableObjectArray& tokens_; // Temporary tokens handle.
TokenStream& stream_; // Temporary token stream handle.
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index b6c1c3c..01ffc6f 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -74,7 +74,6 @@
V(TypeRefTypeTest) \
V(UnreachableTypeTest) \
V(SlowTypeTest) \
- V(LazySpecializeTypeTest) \
V(CallClosureNoSuchMethod) \
V(FrameAwaitingMaterialization) \
V(AsynchronousGapMarker)
@@ -95,7 +94,6 @@
V(TypeRefTypeTest) \
V(UnreachableTypeTest) \
V(SlowTypeTest) \
- V(LazySpecializeTypeTest) \
V(FrameAwaitingMaterialization) \
V(AsynchronousGapMarker)
@@ -217,23 +215,6 @@
enum DeoptStubKind { kLazyDeoptFromReturn, kLazyDeoptFromThrow, kEagerDeopt };
-// Invocation mode for TypeCheck runtime entry that describes
-// where we are calling it from.
-enum TypeCheckMode {
- // TypeCheck is invoked from LazySpecializeTypeTest stub.
- // It should replace stub on the type with a specialized version.
- kTypeCheckFromLazySpecializeStub,
-
- // TypeCheck is invoked from the SlowTypeTest stub.
- // This means that cache can be lazily created (if needed)
- // and dst_name can be fetched from the pool.
- kTypeCheckFromSlowStub,
-
- // TypeCheck is invoked from normal inline AssertAssignable.
- // Both cache and dst_name must be already populated.
- kTypeCheckFromInline
-};
-
// Zap value used to indicate unused CODE_REG in deopt.
static const uword kZapCodeReg = 0xf1f1f1f1;
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 6aa0494..a97ccc5 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -1952,54 +1952,11 @@
__ Breakpoint();
}
-static void InvokeTypeCheckFromTypeTestStub(Assembler* assembler,
- TypeCheckMode mode) {
- const Register kInstanceReg = R0;
- const Register kInstantiatorTypeArgumentsReg = R2;
- const Register kFunctionTypeArgumentsReg = R1;
- const Register kDstTypeReg = R8;
- const Register kSubtypeTestCacheReg = R3;
-
- __ PushObject(Object::null_object()); // Make room for result.
- __ Push(kInstanceReg);
- __ Push(kDstTypeReg);
- __ Push(kInstantiatorTypeArgumentsReg);
- __ Push(kFunctionTypeArgumentsReg);
- __ PushObject(Object::null_object());
- __ Push(kSubtypeTestCacheReg);
- __ PushObject(Smi::ZoneHandle(Smi::New(mode)));
- __ CallRuntime(kTypeCheckRuntimeEntry, 7);
- __ Drop(1); // mode
- __ Pop(kSubtypeTestCacheReg);
- __ Drop(1); // dst_name
- __ Pop(kFunctionTypeArgumentsReg);
- __ Pop(kInstantiatorTypeArgumentsReg);
- __ Pop(kDstTypeReg);
- __ Pop(kInstanceReg);
- __ Drop(1); // Discard return value.
-}
-
-void StubCode::GenerateLazySpecializeTypeTestStub(Assembler* assembler) {
- const Register kInstanceReg = R0;
- Label done;
-
- __ CompareObject(kInstanceReg, Object::null_object());
- __ BranchIf(EQUAL, &done);
-
- __ ldr(CODE_REG,
- Address(THR, Thread::lazy_specialize_type_test_stub_offset()));
- __ EnterStubFrame();
- InvokeTypeCheckFromTypeTestStub(assembler, kTypeCheckFromLazySpecializeStub);
- __ LeaveStubFrame();
-
- __ Bind(&done);
- __ Ret();
-}
-
void StubCode::GenerateSlowTypeTestStub(Assembler* assembler) {
Label done, call_runtime;
const Register kInstanceReg = R0;
+ const Register kInstantiatorTypeArgumentsReg = R2;
const Register kFunctionTypeArgumentsReg = R1;
const Register kDstTypeReg = R8;
const Register kSubtypeTestCacheReg = R3;
@@ -2074,8 +2031,21 @@
__ CompareObject(kDstTypeReg, Type::Handle(Type::ObjectType()));
__ BranchIf(EQUAL, &done);
- InvokeTypeCheckFromTypeTestStub(assembler, kTypeCheckFromSlowStub);
-
+ __ PushObject(Object::null_object()); // Make room for result.
+ __ Push(kInstanceReg);
+ __ Push(kDstTypeReg);
+ __ Push(kInstantiatorTypeArgumentsReg);
+ __ Push(kFunctionTypeArgumentsReg);
+ __ PushObject(Object::null_object());
+ __ Push(kSubtypeTestCacheReg);
+ __ CallRuntime(kTypeCheckRuntimeEntry, 6);
+ __ Pop(kSubtypeTestCacheReg);
+ __ Drop(1); // dst_name
+ __ Pop(kFunctionTypeArgumentsReg);
+ __ Pop(kInstantiatorTypeArgumentsReg);
+ __ Pop(kDstTypeReg);
+ __ Pop(kInstanceReg);
+ __ Drop(1); // Discard return value.
__ Bind(&done);
__ LeaveStubFrame();
__ Ret();
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 5d07eb1..df85dd5 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -2007,56 +2007,12 @@
kFunctionTypeArgumentsReg, kOwnTypeArgumentValue, check_failed);
}
-static void InvokeTypeCheckFromTypeTestStub(Assembler* assembler,
- TypeCheckMode mode) {
- const Register kInstanceReg = R0;
- const Register kInstantiatorTypeArgumentsReg = R1;
- const Register kFunctionTypeArgumentsReg = R2;
-
- const Register kSubtypeTestCacheReg = R3;
- const Register kDstTypeReg = R8;
-
- __ PushObject(Object::null_object()); // Make room for result.
- __ Push(kInstanceReg);
- __ Push(kDstTypeReg);
- __ Push(kInstantiatorTypeArgumentsReg);
- __ Push(kFunctionTypeArgumentsReg);
- __ PushObject(Object::null_object());
- __ Push(kSubtypeTestCacheReg);
- __ PushObject(Smi::ZoneHandle(Smi::New(mode)));
- __ CallRuntime(kTypeCheckRuntimeEntry, 7);
- __ Drop(1); // mode
- __ Pop(kSubtypeTestCacheReg);
- __ Drop(1); // dst_name
- __ Pop(kFunctionTypeArgumentsReg);
- __ Pop(kInstantiatorTypeArgumentsReg);
- __ Pop(kDstTypeReg);
- __ Pop(kInstanceReg);
- __ Drop(1); // Discard return value.
-}
-
-void StubCode::GenerateLazySpecializeTypeTestStub(Assembler* assembler) {
- const Register kInstanceReg = R0;
- Label done;
-
- __ CompareObject(kInstanceReg, Object::null_object());
- __ BranchIf(EQUAL, &done);
-
- __ ldr(CODE_REG,
- Address(THR, Thread::lazy_specialize_type_test_stub_offset()));
- __ EnterStubFrame();
- InvokeTypeCheckFromTypeTestStub(assembler, kTypeCheckFromLazySpecializeStub);
- __ LeaveStubFrame();
-
- __ Bind(&done);
- __ Ret();
-}
-
void StubCode::GenerateSlowTypeTestStub(Assembler* assembler) {
Label done, call_runtime;
const Register kInstanceReg = R0;
const Register kInstantiatorTypeArgumentsReg = R1;
+ const Register kFunctionTypeArgumentsReg = R2;
const Register kSubtypeTestCacheReg = R3;
const Register kDstTypeReg = R8;
@@ -2127,8 +2083,21 @@
__ CompareObject(kDstTypeReg, Type::Handle(Type::ObjectType()));
__ BranchIf(EQUAL, &done);
- InvokeTypeCheckFromTypeTestStub(assembler, kTypeCheckFromSlowStub);
-
+ __ PushObject(Object::null_object()); // Make room for result.
+ __ Push(kInstanceReg);
+ __ Push(kDstTypeReg);
+ __ Push(kInstantiatorTypeArgumentsReg);
+ __ Push(kFunctionTypeArgumentsReg);
+ __ PushObject(Object::null_object());
+ __ Push(kSubtypeTestCacheReg);
+ __ CallRuntime(kTypeCheckRuntimeEntry, 6);
+ __ Pop(kSubtypeTestCacheReg);
+ __ Drop(1); // dst_name
+ __ Pop(kFunctionTypeArgumentsReg);
+ __ Pop(kInstantiatorTypeArgumentsReg);
+ __ Pop(kDstTypeReg);
+ __ Pop(kInstanceReg);
+ __ Drop(1); // Discard return value.
__ Bind(&done);
__ LeaveStubFrame();
__ Ret();
diff --git a/runtime/vm/stub_code_dbc.cc b/runtime/vm/stub_code_dbc.cc
index 130e4f8..f78a5d1 100644
--- a/runtime/vm/stub_code_dbc.cc
+++ b/runtime/vm/stub_code_dbc.cc
@@ -104,11 +104,6 @@
}
// TODO(kustermann): Don't generate this stub.
-void StubCode::GenerateLazySpecializeTypeTestStub(Assembler* assembler) {
- __ Trap();
-}
-
-// TODO(kustermann): Don't generate this stub.
void StubCode::GenerateSlowTypeTestStub(Assembler* assembler) {
__ Trap();
}
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index ae5b070..feb5068 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -1788,32 +1788,27 @@
}
void StubCode::GenerateDefaultTypeTestStub(Assembler* assembler) {
- // Not implemented on ia32.
+ // Only used in AOT and therefore not on ia32.
__ Breakpoint();
}
void StubCode::GenerateTopTypeTypeTestStub(Assembler* assembler) {
- // Not implemented on ia32.
+ // Only used in AOT and therefore not on ia32.
__ Breakpoint();
}
void StubCode::GenerateTypeRefTypeTestStub(Assembler* assembler) {
- // Not implemented on ia32.
+ // Only used in AOT and therefore not on ia32.
__ Breakpoint();
}
void StubCode::GenerateUnreachableTypeTestStub(Assembler* assembler) {
- // Not implemented on ia32.
- __ Breakpoint();
-}
-
-void StubCode::GenerateLazySpecializeTypeTestStub(Assembler* assembler) {
- // Not implemented on ia32.
+ // Only used in AOT and therefore not on ia32.
__ Breakpoint();
}
void StubCode::GenerateSlowTypeTestStub(Assembler* assembler) {
- // Not implemented on ia32.
+ // Only used in AOT and therefore not on ia32.
__ Breakpoint();
}
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index c5d5151..d87f045 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -2121,56 +2121,12 @@
kFunctionTypeArgumentsReg, kOwnTypeArgumentValue, check_failed);
}
-static void InvokeTypeCheckFromTypeTestStub(Assembler* assembler,
- TypeCheckMode mode) {
- const Register kInstanceReg = RAX;
- const Register kInstantiatorTypeArgumentsReg = RDX;
- const Register kFunctionTypeArgumentsReg = RCX;
- const Register kDstTypeReg = RBX;
- const Register kSubtypeTestCacheReg = R9;
-
- __ PushObject(Object::null_object()); // Make room for result.
- __ pushq(kInstanceReg);
- __ pushq(kDstTypeReg);
- __ pushq(kInstantiatorTypeArgumentsReg);
- __ pushq(kFunctionTypeArgumentsReg);
- __ PushObject(Object::null_object());
- __ pushq(kSubtypeTestCacheReg);
- __ PushObject(Smi::ZoneHandle(Smi::New(mode)));
- __ CallRuntime(kTypeCheckRuntimeEntry, 7);
- __ Drop(1);
- __ popq(kSubtypeTestCacheReg);
- __ Drop(1);
- __ popq(kFunctionTypeArgumentsReg);
- __ popq(kInstantiatorTypeArgumentsReg);
- __ popq(kDstTypeReg);
- __ popq(kInstanceReg);
- __ Drop(1); // Discard return value.
-}
-
-void StubCode::GenerateLazySpecializeTypeTestStub(Assembler* assembler) {
- const Register kInstanceReg = RAX;
-
- Label done;
-
- // Fast case for 'null'.
- __ CompareObject(kInstanceReg, Object::null_object());
- __ BranchIf(EQUAL, &done);
-
- __ movq(CODE_REG,
- Address(THR, Thread::lazy_specialize_type_test_stub_offset()));
- __ EnterStubFrame();
- InvokeTypeCheckFromTypeTestStub(assembler, kTypeCheckFromLazySpecializeStub);
- __ LeaveStubFrame();
-
- __ Bind(&done);
- __ Ret();
-}
-
void StubCode::GenerateSlowTypeTestStub(Assembler* assembler) {
Label done, call_runtime;
const Register kInstanceReg = RAX;
+ const Register kInstantiatorTypeArgumentsReg = RDX;
+ const Register kFunctionTypeArgumentsReg = RCX;
const Register kDstTypeReg = RBX;
const Register kSubtypeTestCacheReg = R9;
@@ -2235,8 +2191,21 @@
__ CompareObject(kDstTypeReg, Type::Handle(Type::ObjectType()));
__ BranchIf(EQUAL, &done);
- InvokeTypeCheckFromTypeTestStub(assembler, kTypeCheckFromSlowStub);
-
+ __ PushObject(Object::null_object()); // Make room for result.
+ __ pushq(kInstanceReg);
+ __ pushq(kDstTypeReg);
+ __ pushq(kInstantiatorTypeArgumentsReg);
+ __ pushq(kFunctionTypeArgumentsReg);
+ __ PushObject(Object::null_object());
+ __ pushq(kSubtypeTestCacheReg);
+ __ CallRuntime(kTypeCheckRuntimeEntry, 6);
+ __ popq(kSubtypeTestCacheReg);
+ __ Drop(1);
+ __ popq(kFunctionTypeArgumentsReg);
+ __ popq(kInstantiatorTypeArgumentsReg);
+ __ popq(kDstTypeReg);
+ __ popq(kInstanceReg);
+ __ Drop(1); // Discard return value.
__ Bind(&done);
__ LeaveStubFrame();
__ Ret();
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 4f176a1..802233a 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -102,9 +102,7 @@
V(RawCode*, lazy_deopt_from_throw_stub_, \
StubCode::DeoptimizeLazyFromThrow_entry()->code(), NULL) \
V(RawCode*, slow_type_test_stub_, StubCode::SlowTypeTest_entry()->code(), \
- NULL) \
- V(RawCode*, lazy_specialize_type_test_stub_, \
- StubCode::LazySpecializeTypeTest_entry()->code(), NULL)
+ NULL)
#endif
diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc
index 3ec5386..2a3b85c 100644
--- a/runtime/vm/type_testing_stubs.cc
+++ b/runtime/vm/type_testing_stubs.cc
@@ -92,8 +92,7 @@
}
RawInstructions* TypeTestingStubGenerator::DefaultCodeForType(
- const AbstractType& type,
- bool lazy_specialize /* = true */) {
+ const AbstractType& type) {
// During bootstrapping we have no access to stubs yet, so we'll just return
// `null` and patch these later in `Object::FinishInitOnce()`.
if (!StubCode::HasBeenInitialized()) {
@@ -113,27 +112,13 @@
}
if (type.IsType() || type.IsTypeParameter()) {
- const bool should_specialize = !FLAG_precompiled_mode && lazy_specialize;
- return Code::InstructionsOf(
- should_specialize ? StubCode::LazySpecializeTypeTest_entry()->code()
- : StubCode::DefaultTypeTest_entry()->code());
+ return Code::InstructionsOf(StubCode::DefaultTypeTest_entry()->code());
} else {
ASSERT(type.IsBoundedType() || type.IsMixinAppType());
return Code::InstructionsOf(StubCode::UnreachableTypeTest_entry()->code());
}
}
-#if !defined(DART_PRECOMPILED_RUNTIME)
-void TypeTestingStubGenerator::SpecializeStubFor(Thread* thread,
- const AbstractType& type) {
- HierarchyInfo hi(thread);
- TypeTestingStubGenerator generator;
- const Instructions& instr = Instructions::Handle(
- thread->zone(), generator.OptimizedCodeForType(type));
- type.SetTypeTestingStub(instr);
-}
-#endif
-
TypeTestingStubGenerator::TypeTestingStubGenerator()
: object_store_(Isolate::Current()->object_store()),
array_(GrowableObjectArray::Handle()),
@@ -182,7 +167,7 @@
}
}
#endif // !defined(TARGET_ARCH_DBC) && !defined(TARGET_ARCH_IA32)
- return TypeTestingStubGenerator::DefaultCodeForType(type, false);
+ return TypeTestingStubGenerator::DefaultCodeForType(type);
}
TypeTestingStubFinder::TypeTestingStubFinder()
@@ -204,10 +189,6 @@
if (entry_point == code_.UncheckedEntryPoint()) {
return code_.instructions();
}
- code_ = StubCode::LazySpecializeTypeTest_entry()->code();
- if (entry_point == code_.UncheckedEntryPoint()) {
- return code_.instructions();
- }
code_ = StubCode::TopTypeTypeTest_entry()->code();
if (entry_point == code_.UncheckedEntryPoint()) {
return code_.instructions();
@@ -232,10 +213,6 @@
if (entry_point == code_.UncheckedEntryPoint()) {
return "TypeTestingStub_Default";
}
- code_ = StubCode::LazySpecializeTypeTest_entry()->code();
- if (entry_point == code_.UncheckedEntryPoint()) {
- return "TypeTestingStub_LazySpecialize";
- }
code_ = StubCode::TopTypeTypeTest_entry()->code();
if (entry_point == code_.UncheckedEntryPoint()) {
return "TypeTestingStub_Top";
@@ -354,7 +331,7 @@
#ifndef PRODUCT
if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
LogBlock lb;
- THR_Print("Code for stub '%s' (type = %s): {\n", name, type.ToCString());
+ THR_Print("Code for stub '%s': {\n", name);
DisassembleToStdout formatter;
code.Disassemble(&formatter);
THR_Print("}\n");
diff --git a/runtime/vm/type_testing_stubs.h b/runtime/vm/type_testing_stubs.h
index ce589c8..d03b48a 100644
--- a/runtime/vm/type_testing_stubs.h
+++ b/runtime/vm/type_testing_stubs.h
@@ -36,12 +36,7 @@
// During bootstrapping it will return `null` for a whitelisted set of types,
// otherwise it will return a default stub which tail-calls
// subtypingtest/runtime code.
- static RawInstructions* DefaultCodeForType(const AbstractType& type,
- bool lazy_specialize = true);
-
-#if !defined(DART_PRECOMPILED_RUNTIME)
- static void SpecializeStubFor(Thread* thread, const AbstractType& type);
-#endif
+ static RawInstructions* DefaultCodeForType(const AbstractType& type);
TypeTestingStubGenerator();