Skip to content

Commit 20ec71d

Browse files
mkustermanncommit-bot@chromium.org
authored andcommitted
[vm/compiler] Fix TypeTestingStub -> SubtypeTestCache fallback code if dst_type = TypeParameter
If the dst_type of an AssertAssignable is a type parameter, the AssertAssignable implementation will load the value of the type parameter using the (instantiator or function) type arguments. It will then call the type testing stub (TTS) of that type. If the TTS is not exhaustive (e.g. because `T = X<..>` wher `X` is implemented), it can fall back to the slower SubTypeTestCache implementation. Right now the STC fallback will get the loaded value of the type parameter for `dst_type` instead of the type parameter. Doing so is incorrect. => This CL ensures we preserve dst_type = TypeParameter for the STC fallback. Issue #39716 Change-Id: Idea2405efbdc01c031ee68dbb345820e721533eb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/127640 Commit-Queue: Martin Kustermann <[email protected]> Reviewed-by: Régis Crelier <[email protected]>
1 parent 1aeff32 commit 20ec71d

13 files changed

+79
-61
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:expect/expect.dart';
6+
7+
main() {
8+
// Ensure all classes are used.
9+
final l = <dynamic>[Base(), A<int>(), B<int>(), I<int>()];
10+
print(l);
11+
12+
// Call `add(T)` with `T = A<int/String>` (the VM will not generate an
13+
// optimized TTS for `A<int>` because there's two classes implementing
14+
// `A`, both have type argument vector at a different offset, so it wouldn't
15+
// know where to load it from)
16+
17+
// Populate the SubtypeTestCache with successfull `add(I<String>())`.
18+
final x = <dynamic>[<A<String>>[]];
19+
x.single.add(I<String>());
20+
21+
// Ensure type check fails if list type is now `A<int>`.
22+
final y = <dynamic>[<A<int>>[]];
23+
String exception = '';
24+
try {
25+
y.single.add(I<String>());
26+
} catch (e) {
27+
exception = e.toString();
28+
}
29+
print(exception);
30+
Expect.isTrue(exception.contains('is not a subtype of'));
31+
}
32+
33+
// Ensure depth-first preorder cid numbering will have the cid for [A] in the
34+
// middle and ensure type argument vector will be second field.
35+
class Base {
36+
final int baseField = int.parse('1');
37+
}
38+
39+
class A<T> extends Base {
40+
T foo(T arg) => arg;
41+
}
42+
43+
class B<T> extends A<T> {}
44+
45+
// Make another implementation of A<T> where type argument vector is first
46+
// field.
47+
class I<T> implements A<T> {
48+
int get baseField => int.parse('2');
49+
T foo(T arg) => arg;
50+
}

runtime/vm/compiler/backend/flow_graph_compiler.cc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2237,6 +2237,7 @@ void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
22372237
const Register function_type_args_reg,
22382238
const Register subtype_cache_reg,
22392239
const Register dst_type_reg,
2240+
const Register dst_type_reg_to_call,
22402241
const Register scratch_reg,
22412242
compiler::Label* done) {
22422243
TypeUsageInfo* type_usage_info = thread()->type_usage_info();
@@ -2250,6 +2251,11 @@ void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
22502251
is_non_smi = true;
22512252
}
22522253

2254+
// We use two type registers iff the dst type is a type parameter.
2255+
// We "dereference" the type parameter for the TTS call but leave the type
2256+
// parameter in the dst_type_reg for fallback into SubtypeTestCache.
2257+
ASSERT(dst_type.IsTypeParameter() == (dst_type_reg != dst_type_reg_to_call));
2258+
22532259
// We can handle certain types very efficiently on the call site (with a
22542260
// bailout to the normal stub, which will do a runtime call).
22552261
if (dst_type.IsTypeParameter()) {
@@ -2262,10 +2268,11 @@ void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
22622268
__ CompareObject(kTypeArgumentsReg, Object::null_object());
22632269
__ BranchIf(EQUAL, done);
22642270
__ LoadField(
2265-
dst_type_reg,
2271+
dst_type_reg_to_call,
22662272
compiler::FieldAddress(kTypeArgumentsReg,
22672273
compiler::target::TypeArguments::type_at_offset(
22682274
type_param.index())));
2275+
__ LoadObject(dst_type_reg, type_param);
22692276
if (type_usage_info != NULL) {
22702277
type_usage_info->UseTypeInAssertAssignable(dst_type);
22712278
}

runtime/vm/compiler/backend/flow_graph_compiler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,7 @@ class FlowGraphCompiler : public ValueObject {
501501
const Register function_type_args_reg,
502502
const Register subtype_cache_reg,
503503
const Register dst_type_reg,
504+
const Register dst_type_reg_to_call,
504505
const Register scratch_reg,
505506
compiler::Label* done);
506507

runtime/vm/compiler/backend/flow_graph_compiler_arm.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -762,14 +762,15 @@ void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
762762

763763
const Register kSubtypeTestCacheReg = R3;
764764
const Register kDstTypeReg = R8;
765+
const Register kRegToCall = dst_type.IsTypeParameter() ? R9 : kDstTypeReg;
765766
const Register kScratchReg = R4;
766767

767768
compiler::Label done;
768769

769770
GenerateAssertAssignableViaTypeTestingStub(
770771
dst_type, dst_name, kInstanceReg, kInstantiatorTypeArgumentsReg,
771-
kFunctionTypeArgumentsReg, kSubtypeTestCacheReg, kDstTypeReg, kScratchReg,
772-
&done);
772+
kFunctionTypeArgumentsReg, kSubtypeTestCacheReg, kDstTypeReg, kRegToCall,
773+
kScratchReg, &done);
773774
// We use 2 consecutive entries in the pool for the subtype cache and the
774775
// destination name. The second entry, namely [dst_name] seems to be unused,
775776
// but it will be used by the code throwing a TypeError if the type test fails
@@ -789,7 +790,7 @@ void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
789790
__ LoadField(
790791
R9,
791792
compiler::FieldAddress(
792-
kDstTypeReg,
793+
kRegToCall,
793794
compiler::target::AbstractType::type_test_stub_entry_point_offset()));
794795
__ LoadWordFromPoolOffset(kSubtypeTestCacheReg, sub_type_cache_offset, PP,
795796
AL);

runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -737,14 +737,15 @@ void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
737737

738738
const Register kSubtypeTestCacheReg = R3;
739739
const Register kDstTypeReg = R8;
740+
const Register kRegToCall = dst_type.IsTypeParameter() ? R9 : kDstTypeReg;
740741
const Register kScratchReg = R4;
741742

742743
compiler::Label done;
743744

744745
GenerateAssertAssignableViaTypeTestingStub(
745746
dst_type, dst_name, kInstanceReg, kInstantiatorTypeArgumentsReg,
746-
kFunctionTypeArgumentsReg, kSubtypeTestCacheReg, kDstTypeReg, kScratchReg,
747-
&done);
747+
kFunctionTypeArgumentsReg, kSubtypeTestCacheReg, kDstTypeReg, kRegToCall,
748+
kScratchReg, &done);
748749

749750
// We use 2 consecutive entries in the pool for the subtype cache and the
750751
// destination name. The second entry, namely [dst_name] seems to be unused,
@@ -763,7 +764,7 @@ void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
763764

764765
__ LoadField(
765766
R9, compiler::FieldAddress(
766-
kDstTypeReg, AbstractType::type_test_stub_entry_point_offset()));
767+
kRegToCall, AbstractType::type_test_stub_entry_point_offset()));
767768
__ LoadWordFromPoolOffset(kSubtypeTestCacheReg, sub_type_cache_offset);
768769
__ blr(R9);
769770
EmitCallsiteMetadata(token_pos, deopt_id, RawPcDescriptors::kOther, locs);

runtime/vm/compiler/backend/flow_graph_compiler_x64.cc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -750,12 +750,14 @@ void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
750750
compiler::Label done;
751751

752752
const Register subtype_cache_reg = R9;
753-
const Register kScratchReg = RBX;
753+
const Register kDstTypeReg = RBX;
754+
const Register kRegToCall = dst_type.IsTypeParameter() ? RSI : kDstTypeReg;
755+
const Register kScratchReg = kRegToCall;
754756

755757
GenerateAssertAssignableViaTypeTestingStub(
756758
dst_type, dst_name, kInstanceReg, kInstantiatorTypeArgumentsReg,
757-
kFunctionTypeArgumentsReg, subtype_cache_reg, kScratchReg, kScratchReg,
758-
&done);
759+
kFunctionTypeArgumentsReg, subtype_cache_reg, kDstTypeReg, kRegToCall,
760+
kScratchReg, &done);
759761

760762
// We use 2 consecutive entries in the pool for the subtype cache and the
761763
// destination name. The second entry, namely [dst_name] seems to be unused,
@@ -774,7 +776,7 @@ void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
774776

775777
__ movq(subtype_cache_reg, compiler::Address(PP, sub_type_cache_offset));
776778
__ call(compiler::FieldAddress(
777-
RBX, AbstractType::type_test_stub_entry_point_offset()));
779+
kRegToCall, AbstractType::type_test_stub_entry_point_offset()));
778780
EmitCallsiteMetadata(token_pos, deopt_id, RawPcDescriptors::kOther, locs);
779781
__ Bind(&done);
780782
}

runtime/vm/compiler/stub_code_compiler_arm.cc

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2798,18 +2798,6 @@ void StubCodeCompiler::GenerateTopTypeTypeTestStub(Assembler* assembler) {
27982798
__ Ret();
27992799
}
28002800

2801-
void StubCodeCompiler::GenerateTypeRefTypeTestStub(Assembler* assembler) {
2802-
const Register kTypeRefReg = R8;
2803-
2804-
// We dereference the TypeRef and tail-call to it's type testing stub.
2805-
__ ldr(kTypeRefReg,
2806-
FieldAddress(kTypeRefReg, target::TypeRef::type_offset()));
2807-
__ ldr(R9, FieldAddress(
2808-
kTypeRefReg,
2809-
target::AbstractType::type_test_stub_entry_point_offset()));
2810-
__ bx(R9);
2811-
}
2812-
28132801
void StubCodeCompiler::GenerateUnreachableTypeTestStub(Assembler* assembler) {
28142802
__ Breakpoint();
28152803
}

runtime/vm/compiler/stub_code_compiler_arm64.cc

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2890,18 +2890,6 @@ void StubCodeCompiler::GenerateTopTypeTypeTestStub(Assembler* assembler) {
28902890
__ Ret();
28912891
}
28922892

2893-
void StubCodeCompiler::GenerateTypeRefTypeTestStub(Assembler* assembler) {
2894-
const Register kTypeRefReg = R8;
2895-
2896-
// We dereference the TypeRef and tail-call to it's type testing stub.
2897-
__ ldr(kTypeRefReg,
2898-
FieldAddress(kTypeRefReg, target::TypeRef::type_offset()));
2899-
__ ldr(R9, FieldAddress(
2900-
kTypeRefReg,
2901-
target::AbstractType::type_test_stub_entry_point_offset()));
2902-
__ br(R9);
2903-
}
2904-
29052893
void StubCodeCompiler::GenerateUnreachableTypeTestStub(Assembler* assembler) {
29062894
__ Breakpoint();
29072895
}

runtime/vm/compiler/stub_code_compiler_ia32.cc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2432,11 +2432,6 @@ void StubCodeCompiler::GenerateTopTypeTypeTestStub(Assembler* assembler) {
24322432
__ Breakpoint();
24332433
}
24342434

2435-
void StubCodeCompiler::GenerateTypeRefTypeTestStub(Assembler* assembler) {
2436-
// Not implemented on ia32.
2437-
__ Breakpoint();
2438-
}
2439-
24402435
void StubCodeCompiler::GenerateUnreachableTypeTestStub(Assembler* assembler) {
24412436
// Not implemented on ia32.
24422437
__ Breakpoint();

runtime/vm/compiler/stub_code_compiler_x64.cc

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2927,16 +2927,6 @@ void StubCodeCompiler::GenerateTopTypeTypeTestStub(Assembler* assembler) {
29272927
__ Ret();
29282928
}
29292929

2930-
void StubCodeCompiler::GenerateTypeRefTypeTestStub(Assembler* assembler) {
2931-
const Register kTypeRefReg = RBX;
2932-
2933-
// We dereference the TypeRef and tail-call to it's type testing stub.
2934-
__ movq(kTypeRefReg,
2935-
FieldAddress(kTypeRefReg, target::TypeRef::type_offset()));
2936-
__ jmp(FieldAddress(
2937-
kTypeRefReg, target::AbstractType::type_test_stub_entry_point_offset()));
2938-
}
2939-
29402930
void StubCodeCompiler::GenerateUnreachableTypeTestStub(Assembler* assembler) {
29412931
__ Breakpoint();
29422932
}

0 commit comments

Comments
 (0)