mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 14:49:43 +00:00
[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:
parent
d1c9b09042
commit
c5ea3e85a0
|
@ -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> {
|
||||
|
|
|
@ -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) {
|
||||
return StaticInvocation(
|
||||
_growableListFactory, Arguments([length], types: args.types))
|
||||
..fileOffset = node.fileOffset;
|
||||
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 {
|
||||
return StaticInvocation(
|
||||
_fixedListFactory, Arguments([length], types: args.types))
|
||||
..fileOffset = node.fileOffset;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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") \
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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";
|
||||
|
|
Loading…
Reference in a new issue