Skip to content

Commit cfb057d

Browse files
alexmarkovcommit-bot@chromium.org
authored and
commit-bot@chromium.org
committed
Reland "[vm] Hide internal implementation List types and expose them as List"
This is a reland of 824bec5 Original change's description: > [vm] Hide internal implementation List types and expose them as List > > When taking a type of an instance with x.runtimeType we can map > internal classes _List, _ImmutableList and _GrowableList to a > user-visible List class. This is similar to what we do for > implementation classes of int, String and Type. > After that, result of x.runtimeType for built-in lists would be > compatible with List<T> type literals. > > Also, both intrinsic and native implementations of _haveSameRuntimeType > are updated to agree with new semantic of runtimeType. > > TEST=co19/LanguageFeatures/Constructor-tear-offs/type_literal_A01_t01 > TEST=runtime/tests/vm/dart/have_same_runtime_type_test > > Fixes #46893 > Issue #46231 > > Change-Id: Ie24a9f527f66a06118427b7a09e49c03dff93d8e > Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/210066 > Commit-Queue: Alexander Markov <alexmarkov@google.com> > Reviewed-by: Tess Strickland <sstrickl@google.com> TEST=co19/LanguageFeatures/Constructor-tear-offs/type_literal_A01_t01 TEST=runtime/tests/vm/dart/have_same_runtime_type_test TEST=lib/mirrors/regress_b196606044_test Fixes #46893 Issue #46231 Change-Id: I79b587540338808bd73a6554f00a5eed042f4c26 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/210201 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Tess Strickland <sstrickl@google.com>
1 parent 6fdf8f1 commit cfb057d

14 files changed

+261
-39
lines changed

runtime/lib/object.cc

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,18 @@ DEFINE_NATIVE_ENTRY(Object_runtimeType, 0, 1) {
8888
return Type::Double();
8989
} else if (instance.IsType() || instance.IsFunctionType()) {
9090
return Type::DartTypeType();
91+
} else if (IsArrayClassId(instance.GetClassId())) {
92+
const auto& cls = Class::Handle(
93+
zone, thread->isolate_group()->object_store()->list_class());
94+
const auto& type_arguments =
95+
TypeArguments::Handle(zone, instance.GetTypeArguments());
96+
const auto& type = Type::Handle(
97+
zone,
98+
Type::New(cls, type_arguments, Nullability::kNonNullable, Heap::kNew));
99+
type.SetIsFinalized();
100+
return type.Canonicalize(thread, nullptr);
91101
}
102+
92103
return instance.GetType(Heap::kNew);
93104
}
94105

@@ -101,14 +112,18 @@ static bool HaveSameRuntimeTypeHelper(Zone* zone,
101112
if (left_cid != right_cid) {
102113
if (IsIntegerClassId(left_cid)) {
103114
return IsIntegerClassId(right_cid);
104-
}
105-
if (IsStringClassId(left_cid)) {
115+
} else if (IsStringClassId(left_cid)) {
106116
return IsStringClassId(right_cid);
107-
}
108-
if (IsTypeClassId(left_cid)) {
117+
} else if (IsTypeClassId(left_cid)) {
109118
return IsTypeClassId(right_cid);
119+
} else if (IsArrayClassId(left_cid)) {
120+
if (!IsArrayClassId(right_cid)) {
121+
return false;
122+
}
123+
// Still need to check type arguments.
124+
} else {
125+
return false;
110126
}
111-
return false;
112127
}
113128

114129
if (left_cid == kClosureCid) {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) 2021, 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+
// Test for corner cases of 'a.runtimeType == b.runtimeType' pattern
6+
// which is recognized and optimized in AOT mode.
7+
8+
import "package:expect/expect.dart";
9+
10+
@pragma('vm:never-inline')
11+
Object getType(Object obj) => obj.runtimeType;
12+
13+
@pragma('vm:never-inline')
14+
void test(bool expected, Object a, Object b) {
15+
bool result1 = getType(a) == getType(b);
16+
bool result2 = a.runtimeType == b.runtimeType;
17+
Expect.equals(expected, result1);
18+
Expect.equals(expected, result2);
19+
}
20+
21+
typedef Func = void Function();
22+
23+
void main() {
24+
test(true, 0x7fffffffffffffff, int.parse('42'));
25+
test(true, 'hi', String.fromCharCode(1114111));
26+
test(false, 'hi', 1);
27+
test(true, List, Func);
28+
test(true, <int>[1], const <int>[2]);
29+
test(true, const <String>[], List<String>.filled(1, ''));
30+
test(true, <String>[]..add('hi'), List<String>.filled(2, ''));
31+
test(false, <int>[], <String>[]);
32+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) 2021, 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+
// Test for corner cases of 'a.runtimeType == b.runtimeType' pattern
6+
// which is recognized and optimized in AOT mode.
7+
8+
// @dart = 2.9
9+
10+
import "package:expect/expect.dart";
11+
12+
@pragma('vm:never-inline')
13+
Object getType(Object obj) => obj.runtimeType;
14+
15+
@pragma('vm:never-inline')
16+
void test(bool expected, Object a, Object b) {
17+
bool result1 = getType(a) == getType(b);
18+
bool result2 = a.runtimeType == b.runtimeType;
19+
Expect.equals(expected, result1);
20+
Expect.equals(expected, result2);
21+
}
22+
23+
typedef Func = void Function();
24+
25+
void main() {
26+
test(true, 0x7fffffffffffffff, int.parse('42'));
27+
test(true, 'hi', String.fromCharCode(1114111));
28+
test(false, 'hi', 1);
29+
test(true, List, Func);
30+
test(true, <int>[1], const <int>[2]);
31+
test(true, const <String>[], List<String>.filled(1, ''));
32+
test(true, <String>[]..add('hi'), List<String>.filled(2, ''));
33+
test(false, <int>[], <String>[]);
34+
}

runtime/vm/class_id.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ typedef uint16_t ClassIdTagType;
7878
V(Mint) \
7979
V(Double) \
8080
V(Bool) \
81-
V(GrowableObjectArray) \
8281
V(Float32x4) \
8382
V(Int32x4) \
8483
V(Float64x2) \
@@ -108,10 +107,14 @@ typedef uint16_t ClassIdTagType;
108107
// TODO(http://dartbug.com/45908): Add ImmutableLinkedHashSet.
109108
#define CLASS_LIST_SETS(V) V(LinkedHashSet)
110109

111-
#define CLASS_LIST_ARRAYS(V) \
110+
#define CLASS_LIST_FIXED_LENGTH_ARRAYS(V) \
112111
V(Array) \
113112
V(ImmutableArray)
114113

114+
#define CLASS_LIST_ARRAYS(V) \
115+
CLASS_LIST_FIXED_LENGTH_ARRAYS(V) \
116+
V(GrowableObjectArray)
117+
115118
#define CLASS_LIST_STRINGS(V) \
116119
V(String) \
117120
V(OneByteString) \
@@ -182,6 +185,7 @@ typedef uint16_t ClassIdTagType;
182185
V(LinkedHashMap) \
183186
V(LinkedHashSet) \
184187
V(Array) \
188+
V(GrowableObjectArray) \
185189
V(String)
186190

187191
#define CLASS_LIST_NO_OBJECT(V) \
@@ -327,11 +331,15 @@ inline bool IsExternalStringClassId(intptr_t index) {
327331
index == kExternalTwoByteStringCid);
328332
}
329333

334+
inline bool IsArrayClassId(intptr_t index) {
335+
COMPILE_ASSERT(kImmutableArrayCid == kArrayCid + 1);
336+
COMPILE_ASSERT(kGrowableObjectArrayCid == kArrayCid + 2);
337+
return (index >= kArrayCid && index <= kGrowableObjectArrayCid);
338+
}
339+
330340
inline bool IsBuiltinListClassId(intptr_t index) {
331341
// Make sure this function is updated when new builtin List types are added.
332-
COMPILE_ASSERT(kImmutableArrayCid == kArrayCid + 1);
333-
return ((index >= kArrayCid && index <= kImmutableArrayCid) ||
334-
(index == kGrowableObjectArrayCid) || IsTypedDataBaseClassId(index) ||
342+
return (IsArrayClassId(index) || IsTypedDataBaseClassId(index) ||
335343
(index == kByteBufferCid));
336344
}
337345

runtime/vm/compiler/asm_intrinsifier_arm.cc

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,6 +1198,14 @@ static void JumpIfNotString(Assembler* assembler,
11981198
kIfNotInRange, target);
11991199
}
12001200

1201+
static void JumpIfNotList(Assembler* assembler,
1202+
Register cid,
1203+
Register tmp,
1204+
Label* target) {
1205+
RangeCheck(assembler, cid, tmp, kArrayCid, kGrowableObjectArrayCid,
1206+
kIfNotInRange, target);
1207+
}
1208+
12011209
static void JumpIfType(Assembler* assembler,
12021210
Register cid,
12031211
Register tmp,
@@ -1284,7 +1292,7 @@ static void EquivalentClassIds(Assembler* assembler,
12841292
Register scratch,
12851293
bool testing_instance_cids) {
12861294
Label different_cids, equal_cids_but_generic, not_integer,
1287-
not_integer_or_string;
1295+
not_integer_or_string, not_integer_or_string_or_list;
12881296

12891297
// Check if left hand side is a closure. Closures are handled in the runtime.
12901298
__ CompareImmediate(cid1, kClosureCid);
@@ -1310,7 +1318,8 @@ static void EquivalentClassIds(Assembler* assembler,
13101318
__ b(equal);
13111319

13121320
// Class ids are different. Check if we are comparing two string types (with
1313-
// different representations) or two integer types or two type types.
1321+
// different representations), two integer types, two list types or two type
1322+
// types.
13141323
__ Bind(&different_cids);
13151324
__ CompareImmediate(cid1, kNumPredefinedCids);
13161325
__ b(not_equal, HI);
@@ -1335,9 +1344,20 @@ static void EquivalentClassIds(Assembler* assembler,
13351344

13361345
if (testing_instance_cids) {
13371346
__ Bind(&not_integer_or_string);
1347+
// Check if both are List types.
1348+
JumpIfNotList(assembler, cid1, scratch, &not_integer_or_string_or_list);
1349+
1350+
// First type is a List. Check if the second is a List too.
1351+
JumpIfNotList(assembler, cid2, scratch, not_equal);
1352+
ASSERT(compiler::target::Array::type_arguments_offset() ==
1353+
compiler::target::GrowableObjectArray::type_arguments_offset());
1354+
__ LoadImmediate(scratch, compiler::target::Array::type_arguments_offset());
1355+
__ b(&equal_cids_but_generic);
1356+
1357+
__ Bind(&not_integer_or_string_or_list);
13381358
// Check if the first type is a Type. If it is not then types are not
13391359
// equivalent because they have different class ids and they are not String
1340-
// or integer or Type.
1360+
// or integer or List or Type.
13411361
JumpIfNotType(assembler, cid1, scratch, not_equal);
13421362

13431363
// First type is a Type. Check if the second is a Type too.

runtime/vm/compiler/asm_intrinsifier_arm64.cc

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,6 +1342,14 @@ static void JumpIfNotString(Assembler* assembler,
13421342
kIfNotInRange, target);
13431343
}
13441344

1345+
static void JumpIfNotList(Assembler* assembler,
1346+
Register cid,
1347+
Register tmp,
1348+
Label* target) {
1349+
RangeCheck(assembler, cid, tmp, kArrayCid, kGrowableObjectArrayCid,
1350+
kIfNotInRange, target);
1351+
}
1352+
13451353
static void JumpIfType(Assembler* assembler,
13461354
Register cid,
13471355
Register tmp,
@@ -1432,7 +1440,7 @@ static void EquivalentClassIds(Assembler* assembler,
14321440
Register scratch,
14331441
bool testing_instance_cids) {
14341442
Label different_cids, equal_cids_but_generic, not_integer,
1435-
not_integer_or_string;
1443+
not_integer_or_string, not_integer_or_string_or_list;
14361444

14371445
// Check if left hand side is a closure. Closures are handled in the runtime.
14381446
__ CompareImmediate(cid1, kClosureCid);
@@ -1458,7 +1466,8 @@ static void EquivalentClassIds(Assembler* assembler,
14581466
__ b(equal);
14591467

14601468
// Class ids are different. Check if we are comparing two string types (with
1461-
// different representations) or two integer types or two type types.
1469+
// different representations), two integer types, two list types or two type
1470+
// types.
14621471
__ Bind(&different_cids);
14631472
__ CompareImmediate(cid1, kNumPredefinedCids);
14641473
__ b(not_equal, HI);
@@ -1483,9 +1492,20 @@ static void EquivalentClassIds(Assembler* assembler,
14831492

14841493
if (testing_instance_cids) {
14851494
__ Bind(&not_integer_or_string);
1495+
// Check if both are List types.
1496+
JumpIfNotList(assembler, cid1, scratch, &not_integer_or_string_or_list);
1497+
1498+
// First type is a List. Check if the second is a List too.
1499+
JumpIfNotList(assembler, cid2, scratch, not_equal);
1500+
ASSERT(compiler::target::Array::type_arguments_offset() ==
1501+
compiler::target::GrowableObjectArray::type_arguments_offset());
1502+
__ LoadImmediate(scratch, compiler::target::Array::type_arguments_offset());
1503+
__ b(&equal_cids_but_generic);
1504+
1505+
__ Bind(&not_integer_or_string_or_list);
14861506
// Check if the first type is a Type. If it is not then types are not
14871507
// equivalent because they have different class ids and they are not String
1488-
// or integer or Type.
1508+
// or integer or List or Type.
14891509
JumpIfNotType(assembler, cid1, scratch, not_equal);
14901510

14911511
// First type is a Type. Check if the second is a Type too.

runtime/vm/compiler/asm_intrinsifier_ia32.cc

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,11 @@ static void JumpIfNotString(Assembler* assembler, Register cid, Label* target) {
12811281
kIfNotInRange, target);
12821282
}
12831283

1284+
static void JumpIfNotList(Assembler* assembler, Register cid, Label* target) {
1285+
RangeCheck(assembler, cid, kArrayCid, kGrowableObjectArrayCid, kIfNotInRange,
1286+
target);
1287+
}
1288+
12841289
static void JumpIfType(Assembler* assembler, Register cid, Label* target) {
12851290
RangeCheck(assembler, cid, kTypeCid, kFunctionTypeCid, kIfInRange, target);
12861291
}
@@ -1370,7 +1375,7 @@ static void EquivalentClassIds(Assembler* assembler,
13701375
Register scratch,
13711376
bool testing_instance_cids) {
13721377
Label different_cids, equal_cids_but_generic, not_integer,
1373-
not_integer_or_string;
1378+
not_integer_or_string, not_integer_or_string_or_list;
13741379

13751380
// Check if left hand side is a closure. Closures are handled in the runtime.
13761381
__ cmpl(cid1, Immediate(kClosureCid));
@@ -1392,11 +1397,12 @@ static void EquivalentClassIds(Assembler* assembler,
13921397
scratch,
13931398
target::Class::host_type_arguments_field_offset_in_words_offset()));
13941399
__ cmpl(scratch, Immediate(target::Class::kNoTypeArguments));
1395-
__ j(NOT_EQUAL, &equal_cids_but_generic, Assembler::kNearJump);
1400+
__ j(NOT_EQUAL, &equal_cids_but_generic);
13961401
__ jmp(equal);
13971402

13981403
// Class ids are different. Check if we are comparing two string types (with
1399-
// different representations) or two integer types or two type types.
1404+
// different representations), two integer types, two list types or two type
1405+
// types.
14001406
__ Bind(&different_cids);
14011407
__ cmpl(cid1, Immediate(kNumPredefinedCids));
14021408
__ j(ABOVE_EQUAL, not_equal);
@@ -1406,25 +1412,42 @@ static void EquivalentClassIds(Assembler* assembler,
14061412
JumpIfNotInteger(assembler, scratch, &not_integer);
14071413

14081414
// First type is an integer. Check if the second is an integer too.
1409-
JumpIfInteger(assembler, cid2, equal);
1415+
__ movl(scratch, cid2);
1416+
JumpIfInteger(assembler, scratch, equal);
14101417
// Integer types are only equivalent to other integer types.
14111418
__ jmp(not_equal);
14121419

14131420
__ Bind(&not_integer);
14141421
// Check if both are String types.
1415-
JumpIfNotString(assembler, cid1,
1422+
__ movl(scratch, cid1);
1423+
JumpIfNotString(assembler, scratch,
14161424
testing_instance_cids ? &not_integer_or_string : not_equal);
14171425

14181426
// First type is a String. Check if the second is a String too.
1419-
JumpIfString(assembler, cid2, equal);
1427+
__ movl(scratch, cid2);
1428+
JumpIfString(assembler, scratch, equal);
14201429
// String types are only equivalent to other String types.
14211430
__ jmp(not_equal);
14221431

14231432
if (testing_instance_cids) {
14241433
__ Bind(&not_integer_or_string);
1434+
// Check if both are List types.
1435+
__ movl(scratch, cid1);
1436+
JumpIfNotList(assembler, scratch, &not_integer_or_string_or_list);
1437+
1438+
// First type is a List. Check if the second is a List too.
1439+
__ movl(scratch, cid2);
1440+
JumpIfNotList(assembler, scratch, not_equal);
1441+
ASSERT(compiler::target::Array::type_arguments_offset() ==
1442+
compiler::target::GrowableObjectArray::type_arguments_offset());
1443+
__ movl(scratch,
1444+
Immediate(compiler::target::Array::type_arguments_offset()));
1445+
__ jmp(&equal_cids_but_generic, Assembler::kNearJump);
1446+
1447+
__ Bind(&not_integer_or_string_or_list);
14251448
// Check if the first type is a Type. If it is not then types are not
14261449
// equivalent because they have different class ids and they are not String
1427-
// or integer or Type.
1450+
// or integer or List or Type.
14281451
JumpIfNotType(assembler, cid1, not_equal);
14291452

14301453
// First type is a Type. Check if the second is a Type too.

0 commit comments

Comments
 (0)