[vm] Remove redundant type-checks from core libraries.
In conjunction with previous revisions, this improves several Flutter microbenchmarks by 2-4%.
Change-Id: Ic864fd586dc57d87b80cebd6ceace0a8165fa82b
Reviewed-on: https://dart-review.googlesource.com/c/88702
Commit-Queue: Samir Jindel <sjindel@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart b/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart
index ab94a36..781a0c9 100644
--- a/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart
+++ b/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart
@@ -572,3 +572,30 @@
iterator);
}
}
+
+@patch
+abstract class _SplayTree<K, Node extends _SplayTreeNode<K>> {
+ @patch
+ Node _splayMin(Node node) {
+ Node current = node;
+ while (current.left != null) {
+ Node left = current.left;
+ current.left = left.right;
+ left.right = current;
+ current = left;
+ }
+ return current;
+ }
+
+ @patch
+ Node _splayMax(Node node) {
+ Node current = node;
+ while (current.right != null) {
+ Node right = current.right;
+ current.right = right.left;
+ right.left = current;
+ current = right;
+ }
+ return current;
+ }
+}
diff --git a/runtime/lib/array_patch.dart b/runtime/lib/array_patch.dart
index 1ec264d..7bea7c9 100644
--- a/runtime/lib/array_patch.dart
+++ b/runtime/lib/array_patch.dart
@@ -24,7 +24,7 @@
@patch
factory List.from(Iterable elements, {bool growable: true}) {
- if (elements is EfficientLengthIterable) {
+ if (elements is EfficientLengthIterable<E>) {
int length = elements.length;
var list = growable ? new _GrowableList<E>(length) : new _List<E>(length);
if (length > 0) {
@@ -36,12 +36,25 @@
}
return list;
}
- List<E> list = new _GrowableList<E>(0);
- for (E e in elements) {
- list.add(e);
+ // If elements is an Iterable<E>, we won't need a type-test for each
+ // element. In the "common case" that elements is an Iterable<E>, this
+ // replaces a type-test on every element with a single type-test before
+ // starting the loop.
+ if (elements is Iterable<E>) {
+ List<E> list = new _GrowableList<E>(0);
+ for (E e in elements) {
+ list.add(e);
+ }
+ if (growable) return list;
+ return makeListFixedLength(list);
+ } else {
+ List<E> list = new _GrowableList<E>(0);
+ for (E e in elements) {
+ list.add(e);
+ }
+ if (growable) return list;
+ return makeListFixedLength(list);
}
- if (growable) return list;
- return makeListFixedLength(list);
}
@patch
diff --git a/runtime/lib/collection_patch.dart b/runtime/lib/collection_patch.dart
index 07d6afb5..83f12ca 100644
--- a/runtime/lib/collection_patch.dart
+++ b/runtime/lib/collection_patch.dart
@@ -908,3 +908,31 @@
@patch
factory LinkedHashSet.identity() => new _CompactLinkedIdentityHashSet<E>();
}
+
+@patch
+abstract class _SplayTree<K, Node extends _SplayTreeNode<K>> {
+ // We override _splayMin and _splayMax to optimize type-checks.
+ @patch
+ Node _splayMin(Node node) {
+ Node current = node;
+ while (current.left != null) {
+ Node left = internal.unsafeCast<Node>(current.left);
+ current.left = left.right;
+ left.right = current;
+ current = left;
+ }
+ return current;
+ }
+
+ @patch
+ Node _splayMax(Node node) {
+ Node current = node;
+ while (current.right != null) {
+ Node right = internal.unsafeCast<Node>(current.right);
+ current.right = right.left;
+ right.left = current;
+ current = right;
+ }
+ return current;
+ }
+}
diff --git a/runtime/lib/compact_hash.dart b/runtime/lib/compact_hash.dart
index 20ddf7a..8123b0f 100644
--- a/runtime/lib/compact_hash.dart
+++ b/runtime/lib/compact_hash.dart
@@ -433,7 +433,8 @@
final int _checkSum;
E current;
- _CompactIterator(table, this._data, this._len, this._offset, this._step)
+ _CompactIterator(
+ _HashBase table, this._data, this._len, this._offset, this._step)
: _table = table,
_checkSum = table._checkSum;
@@ -445,7 +446,7 @@
_offset += _step;
} while (_offset < _len && _HashBase._isDeleted(_data, _data[_offset]));
if (_offset < _len) {
- current = _data[_offset];
+ current = internal.unsafeCast<E>(_data[_offset]);
return true;
} else {
current = null;
diff --git a/runtime/lib/core_patch.dart b/runtime/lib/core_patch.dart
index 1b0f849..7b1876d6 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -24,7 +24,8 @@
is64Bit,
makeFixedListUnmodifiable,
makeListFixedLength,
- patch;
+ patch,
+ unsafeCast;
import "dart:async" show Completer, Future, Timer;
@@ -116,8 +117,8 @@
Iterator<T> get iterator {
// Note: _Closure._clone returns _Closure which is not related to
// _SyncGeneratorCallback, which means we need explicit cast.
- return new _SyncIterator<T>(
- (_moveNextFn as _Closure)._clone() as _SyncGeneratorCallback<T>);
+ return new _SyncIterator<T>(unsafeCast<_SyncGeneratorCallback<T>>(
+ unsafeCast<_Closure>(_moveNextFn)._clone()));
}
}
diff --git a/sdk/lib/_internal/js_runtime/lib/collection_patch.dart b/sdk/lib/_internal/js_runtime/lib/collection_patch.dart
index 95e7a7a..fc7a3bf 100644
--- a/sdk/lib/_internal/js_runtime/lib/collection_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/collection_patch.dart
@@ -1673,3 +1673,30 @@
}
}
}
+
+@patch
+abstract class _SplayTree<K, Node extends _SplayTreeNode<K>> {
+ @patch
+ Node _splayMin(Node node) {
+ Node current = node;
+ while (current.left != null) {
+ Node left = current.left;
+ current.left = left.right;
+ left.right = current;
+ current = left;
+ }
+ return current;
+ }
+
+ @patch
+ Node _splayMax(Node node) {
+ Node current = node;
+ while (current.right != null) {
+ Node right = current.right;
+ current.right = right.left;
+ right.left = current;
+ current = right;
+ }
+ return current;
+ }
+}
diff --git a/sdk/lib/collection/splay_tree.dart b/sdk/lib/collection/splay_tree.dart
index 5bc9a6c..9856d55 100644
--- a/sdk/lib/collection/splay_tree.dart
+++ b/sdk/lib/collection/splay_tree.dart
@@ -147,32 +147,14 @@
// anchored at [node].
// and that node is returned. It should replace the reference to [node]
// in any parent tree or root pointer.
- Node _splayMin(Node node) {
- Node current = node;
- while (current.left != null) {
- Node left = current.left;
- current.left = left.right;
- left.right = current;
- current = left;
- }
- return current;
- }
+ external Node _splayMin(Node node);
// Emulates splaying with a key that is greater than any in the subtree
// anchored at [node].
// After this, the largest element in the tree is the root of the subtree,
// and that node is returned. It should replace the reference to [node]
// in any parent tree or root pointer.
- Node _splayMax(Node node) {
- Node current = node;
- while (current.right != null) {
- Node right = current.right;
- current.right = right.left;
- right.left = current;
- current = right;
- }
- return current;
- }
+ external Node _splayMax(Node node);
Node _remove(K key) {
if (_root == null) return null;