blob: 858a984c4d7a5cade9529f2aef730e42c68ce9ed [file] [log] [blame] [edit]
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Verify that List bound check is eliminated in a loop
// using iterator over growable list.
import 'package:vm/testing/il_matchers.dart';
@pragma('vm:never-inline')
void myprint(Object o) {
print(o);
}
@pragma('vm:never-inline')
@pragma('vm:testing:print-flow-graph')
useList2(List<int> a) {
for (final iter = MyIter(a); iter.moveNext();) {
final value = iter.current;
myprint(value);
}
}
class MyIter<E> implements Iterator<E> {
final List<E> _list;
int _index = 0;
E? _current;
MyIter(this._list);
E get current => _current as E;
bool moveNext() {
int length = _list.length;
if (_index >= length) {
_current = null;
return false;
}
_current = _list[_index];
_index++;
return true;
}
}
main() {
useList2([]);
useList2([30, 40]);
}
void matchIL$useList2(FlowGraph graph) {
graph.dump();
graph.match([
match.block('Graph', [
'c_null' << match.Constant(value: null),
'c_zero' << match.UnboxedConstant(value: 0),
'c_one' << match.UnboxedConstant(value: 1),
]),
match.block('Function', [
'a' << match.Parameter(index: 0),
match.CheckStackOverflow(),
match.Goto('B5'),
]),
'B5' <<
match.block('Join', [
'i' << match.Phi('c_zero', 'i+1'),
match.CheckStackOverflow(),
'a.length' <<
match.LoadField('a', slot: 'GrowableObjectArray.length'),
if (is32BitConfiguration)
'a.length_unboxed' << match.UnboxInt32('a.length')
else
'a.length_unboxed' << match.UnboxInt64('a.length'),
match.Branch(
match.RelationalOp('i', 'a.length_unboxed', kind: '>='),
ifTrue: 'B4',
ifFalse: 'B10',
),
]),
'B4' << match.block('Target', [match.DartReturn('c_null')]),
'B10' <<
match.block('Target', [
// No bounds check here.
'a.data' <<
match.LoadField(
'a',
slot: 'GrowableObjectArray.data',
skipUntilMatched: false,
),
if (is32BitConfiguration)
'i_boxed' << match.BoxInt32('i', skipUntilMatched: false),
'value' <<
match.LoadIndexed(
'a.data',
is32BitConfiguration ? 'i_boxed' : 'i',
skipUntilMatched: false,
),
if (is32BitConfiguration)
'i+1' << match.BinaryInt32Op('i', 'c_one', op_kind: '+')
else
'i+1' << match.BinaryInt64Op('i', 'c_one', op_kind: '+'),
'value_unboxed' << match.UnboxInt64('value'),
match.StaticCall('value_unboxed'),
match.Goto('B5'),
]),
]);
}