[vm/nnbd] Further specialize invocations of List.filled factory

If 'growable' argument of List.filled factory invocation is known at
compile time we can replace it with more specialized constructors
creating growable or fixed-size lists. This results in a more accurate
inferred type and more efficient code which uses the created list.

Fixes https://github.com/dart-lang/sdk/issues/42551

Change-Id: I427e1bdb8a0f2a83410a9533050d19cbca2d27d6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/153064
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov 2020-07-03 23:19:02 +00:00 committed by commit-bot@chromium.org
parent d1c9b09042
commit c5ea3e85a0
6 changed files with 62 additions and 12 deletions

View file

@ -1300,10 +1300,12 @@ class List<E> extends Iterable {
class _GrowableList<E> {
factory _GrowableList() => null;
factory _GrowableList.filled() => null;
}
class _List<E> {
factory _List() => null;
factory _List.filled() => null;
}
class MapEntry<K, V> {

View file

@ -13,13 +13,17 @@ import 'package:kernel/core_types.dart' show CoreTypes;
/// new List() => new _GrowableList(0)
/// new List(n) => new _List(n)
/// new List.filled(n, null, growable: true) => new _GrowableList(n)
/// new List.filled(n, x, growable: true) => new _GrowableList.filled(n, x)
/// new List.filled(n, null) => new _List(n)
/// new List.filled(n, x) => new _List.filled(n, x)
///
class ListFactorySpecializer {
final Procedure _defaultListFactory;
final Procedure _listFilledFactory;
final Procedure _growableListFactory;
final Procedure _growableListFilledFactory;
final Procedure _fixedListFactory;
final Procedure _fixedListFilledFactory;
ListFactorySpecializer(CoreTypes coreTypes)
: _defaultListFactory =
@ -28,12 +32,17 @@ class ListFactorySpecializer {
coreTypes.index.getMember('dart:core', 'List', 'filled'),
_growableListFactory =
coreTypes.index.getMember('dart:core', '_GrowableList', ''),
_fixedListFactory =
coreTypes.index.getMember('dart:core', '_List', '') {
_growableListFilledFactory =
coreTypes.index.getMember('dart:core', '_GrowableList', 'filled'),
_fixedListFactory = coreTypes.index.getMember('dart:core', '_List', ''),
_fixedListFilledFactory =
coreTypes.index.getMember('dart:core', '_List', 'filled') {
assert(_defaultListFactory.isFactory);
assert(_listFilledFactory.isFactory);
assert(_growableListFactory.isFactory);
assert(_growableListFilledFactory.isFactory);
assert(_fixedListFactory.isFactory);
assert(_fixedListFilledFactory.isFactory);
}
TreeNode transformStaticInvocation(StaticInvocation node) {
@ -53,10 +62,8 @@ class ListFactorySpecializer {
assert(args.positional.length == 2);
final length = args.positional[0];
final fill = args.positional[1];
if (fill is! NullLiteral &&
!(fill is ConstantExpression && fill.constant is NullConstant)) {
return node;
}
final fillingWithNull = fill is NullLiteral ||
(fill is ConstantExpression && fill.constant is NullConstant);
bool growable;
if (args.named.isEmpty) {
growable = false;
@ -78,13 +85,25 @@ class ListFactorySpecializer {
}
}
if (growable) {
if (fillingWithNull) {
return StaticInvocation(
_growableListFactory, Arguments([length], types: args.types))
..fileOffset = node.fileOffset;
} else {
return StaticInvocation(_growableListFilledFactory,
Arguments([length, fill], types: args.types))
..fileOffset = node.fileOffset;
}
} else {
if (fillingWithNull) {
return StaticInvocation(
_fixedListFactory, Arguments([length], types: args.types))
..fileOffset = node.fileOffset;
} else {
return StaticInvocation(_fixedListFilledFactory,
Arguments([length, fill], types: args.types))
..fileOffset = node.fileOffset;
}
}
}

View file

@ -444,8 +444,11 @@ namespace dart {
// result-cid, fingerprint).
#define RECOGNIZED_LIST_FACTORY_LIST(V) \
V(_ListFactory, _List, ., kArrayCid, 0x03ddbd3a) \
V(_ListFilledFactory, _List, .filled, kArrayCid, 0x0) \
V(_GrowableListWithData, _GrowableList, ._withData, kGrowableObjectArrayCid, \
0x5cfd6a7f) \
V(_GrowableListFilledFactory, _GrowableList, .filled, \
kGrowableObjectArrayCid, 0x0) \
V(_GrowableListFactory, _GrowableList, ., kGrowableObjectArrayCid, \
0x3eed680b) \
V(_Int8ArrayFactory, Int8List, ., kTypedDataInt8ArrayCid, 0x6ce2f102) \

View file

@ -361,6 +361,7 @@ class ObjectPointerVisitor;
V(_FutureListener, "_FutureListener") \
V(_GrowableList, "_GrowableList") \
V(_GrowableListFactory, "_GrowableList.") \
V(_GrowableListFilledFactory, "_GrowableList.filled") \
V(_GrowableListWithData, "_GrowableList._withData") \
V(_ImmutableList, "_ImmutableList") \
V(_Int16ArrayFactory, "Int16List.") \
@ -388,6 +389,7 @@ class ObjectPointerVisitor;
V(_LinkedHashSet, "_CompactLinkedHashSet") \
V(_List, "_List") \
V(_ListFactory, "_List.") \
V(_ListFilledFactory, "_List.filled") \
V(_MethodMirror, "_MethodMirror") \
V(_Mint, "_Mint") \
V(_MirrorReference, "_MirrorReference") \

View file

@ -11,6 +11,18 @@ class _List<E> extends FixedLengthListBase<E> {
@pragma("vm:prefer-inline")
factory _List(length) native "List_allocate";
// Specialization of List.filled constructor for growable == false.
// Used by pkg/vm/lib/transformations/list_factory_specializer.dart.
factory _List.filled(int length, E fill) {
final result = _List<E>(length);
if (fill != null) {
for (int i = 0; i < result.length; i++) {
result[i] = fill;
}
}
return result;
}
E operator [](int index) native "List_getIndexed";
void operator []=(int index, E value) {

View file

@ -107,6 +107,18 @@ class _GrowableList<T> extends ListBase<T> {
return new _GrowableList<T>._withData(data);
}
// Specialization of List.filled constructor for growable == true.
// Used by pkg/vm/lib/transformations/list_factory_specializer.dart.
factory _GrowableList.filled(int length, T fill) {
final result = _GrowableList<T>(length);
if (fill != null) {
for (int i = 0; i < result.length; i++) {
result[i] = fill;
}
}
return result;
}
@pragma("vm:exact-result-type",
<dynamic>[_GrowableList, "result-type-uses-passed-type-arguments"])
factory _GrowableList._withData(_List data) native "GrowableList_allocate";