Skip to content

Commit 3f717df

Browse files
alexmarkovCommit Queue
authored andcommitted
[vm/compiler] Infer array element type from static type Iterable<E>
Inferring array element type E from static type Iterable<E> allows compiler to remove extra checks left from iterator code. This is valid as List<E> implements Iterable<E>. This change makes for-in loops over built-in lists with static types Iterable<E> as efficient as loops over List<E>. TEST=runtime/tests/vm/dart/regress_56840_il_test.dart Fixes #56840 Change-Id: Ie52208b9c3e92dcc52079e66c910b023f09a2173 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/392401 Reviewed-by: Slava Egorov <[email protected]> Commit-Queue: Alexander Markov <[email protected]>
1 parent 37af167 commit 3f717df

File tree

2 files changed

+83
-1
lines changed

2 files changed

+83
-1
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (c) 2024, 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+
// Verify that all checks are optimized out in a for-in loop over built-in
6+
// list with Iterable<String> static type.
7+
8+
import 'package:vm/testing/il_matchers.dart';
9+
10+
@pragma('vm:never-inline')
11+
@pragma('vm:testing:print-flow-graph')
12+
bool foobar(String token, Iterable<String> values) {
13+
for (String tokenValue in values) {
14+
if (identical(tokenValue, token)) {
15+
return true;
16+
}
17+
}
18+
return false;
19+
}
20+
21+
void matchIL$foobar(FlowGraph graph) {
22+
graph.match([
23+
match.block('Graph', [
24+
'int 0' << match.UnboxedConstant(value: 0),
25+
'int 1' << match.UnboxedConstant(value: 1),
26+
]),
27+
match.block('Function', [
28+
'token' << match.Parameter(index: 0),
29+
'values' << match.Parameter(index: 1),
30+
'values.length' <<
31+
match.LoadField('values', slot: 'GrowableObjectArray.length'),
32+
'values.length_unboxed' << match.UnboxInt64('values.length'),
33+
'values.data' <<
34+
match.LoadField('values', slot: 'GrowableObjectArray.data'),
35+
match.Goto('B16'),
36+
]),
37+
'B16' <<
38+
match.block('Join', [
39+
'i' << match.Phi('int 0', 'i+1'),
40+
if (is32BitConfiguration)
41+
'i_64' << match.IntConverter('i', from: 'int32', to: 'int64'),
42+
match.Branch(
43+
match.RelationalOp(
44+
is32BitConfiguration ? 'i_64' : 'i', 'values.length_unboxed',
45+
kind: '>='),
46+
ifTrue: 'B4',
47+
ifFalse: 'B12'),
48+
]),
49+
'B4' <<
50+
match.block('Target', [
51+
match.DartReturn(match.any),
52+
]),
53+
'B12' <<
54+
match.block('Target', [
55+
if (is32BitConfiguration) 'i_boxed' << match.BoxInt32('i'),
56+
'tokenValue' <<
57+
match.LoadIndexed(
58+
'values.data', is32BitConfiguration ? 'i_boxed' : 'i'),
59+
if (is32BitConfiguration)
60+
'i+1' << match.BinaryInt32Op('i', 'int 1')
61+
else
62+
'i+1' << match.BinaryInt64Op('i', 'int 1'),
63+
match.Branch(match.StrictCompare('tokenValue', 'token', kind: '==='),
64+
ifTrue: 'B5', ifFalse: 'B6'),
65+
]),
66+
'B5' <<
67+
match.block('Target', [
68+
match.DartReturn(match.any),
69+
]),
70+
'B6' <<
71+
match.block('Target', [
72+
match.Goto('B16'),
73+
]),
74+
]);
75+
}
76+
77+
main() {
78+
print(foobar('a', ['a', 'b', 'c']));
79+
print(foobar('b', ['b', 'c']));
80+
}

runtime/vm/compiler/backend/type_propagator.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1822,7 +1822,9 @@ static AbstractTypePtr ExtractElementTypeFromArrayType(
18221822
if (cid == kGrowableObjectArrayCid || cid == kArrayCid ||
18231823
cid == kImmutableArrayCid ||
18241824
array_type.type_class() ==
1825-
IsolateGroup::Current()->object_store()->list_class()) {
1825+
IsolateGroup::Current()->object_store()->list_class() ||
1826+
array_type.type_class() ==
1827+
IsolateGroup::Current()->object_store()->iterable_class()) {
18261828
const auto& type_args =
18271829
TypeArguments::Handle(Type::Cast(array_type).arguments());
18281830
return type_args.TypeAtNullSafe(Array::kElementTypeTypeArgPos);

0 commit comments

Comments
 (0)