| // Copyright (c) 2022, 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. |
| |
| // Check that inliner can also specialize calls between rounds of inlining. |
| // |
| // In the [test] function below we would only be able to fully eliminate |
| // abstractions and inline [TestIterable.elementAt] if inliner devirtualizes |
| // it during inlining. |
| |
| import 'dart:collection'; |
| |
| import 'package:vm/testing/il_matchers.dart'; |
| |
| @pragma('vm:never-inline') |
| void myprint(Object? obj) { |
| print(obj); |
| } |
| |
| class TestIterable extends IterableBase<int> { |
| @pragma('vm:prefer-inline') |
| TestIterator get iterator => TestIterator(this); |
| |
| @override |
| int get length => 10; |
| |
| @pragma('vm:prefer-inline') |
| int elementAt(int index) { |
| return index; |
| } |
| } |
| |
| class TestIterator implements Iterator<int> { |
| final Iterable<int> iterable; |
| int current = 0; |
| int index = 0; |
| |
| TestIterator(this.iterable); |
| |
| @pragma('vm:prefer-inline') |
| bool moveNext() { |
| if (index >= iterable.length) { |
| return false; |
| } |
| current = iterable.elementAt(index++); |
| return true; |
| } |
| |
| List<int> toList() => [for (; moveNext();) current]; |
| } |
| |
| @pragma('vm:never-inline') |
| @pragma('vm:testing:print-flow-graph') |
| void test(TestIterable obj) { |
| for (var el in obj) { |
| myprint(el); |
| } |
| } |
| |
| void matchIL$test(FlowGraph graph) { |
| graph.match([ |
| match.block('Graph'), |
| match.block('Function', [ |
| 'obj' << match.Parameter(index: 0), |
| match.CheckStackOverflow(), |
| match.Goto('LoopHeader'), |
| ]), |
| 'LoopHeader' << |
| match.block('Join', [ |
| 'index' << match.Phi(match.any, 'inc'), |
| match.CheckStackOverflow(), |
| match.Branch( |
| match.RelationalOp('index', match.any, kind: '>='), |
| ifTrue: 'LoopExit', |
| ifFalse: 'LoopBody', |
| ), |
| ]), |
| 'LoopExit' << match.block('Target', [match.DartReturn()]), |
| 'LoopBody' << |
| match.block('Target', [ |
| 'inc' << match.BinaryInt64Op('index', match.any), |
| 'boxed_index' << match.BoxInt64('index'), |
| match.StaticCall('boxed_index'), |
| match.Goto('LoopHeader'), |
| ]), |
| ]); |
| } |
| |
| void main() { |
| myprint(TestIterator([0, 1, 2, 3, 4]).toList()); |
| myprint(TestIterator(const [0, 1, 2, 3, 4]).toList()); |
| test(TestIterable()); |
| } |