[vm] Avoid expensive runtime function type checks in Future implementation
The `_FutureListener.callback` field is used for multiple purposes (possibly to save memory by avoiding additional fields) so it cannot have a specific function type. This causes the `Function?` typed `_FutureListener.callback` field to be casted to proper function types such as `T Function(S)`. => Those runtime type checks are very expensive. To avoid introducing more fields we use an `unsafeCast<T>()` for those casts, since the implementation guarantees they are going to suceed. Issue https://github.com/dart-lang/sdk/issues/48225 TEST=ci Change-Id: I6f0cc87600462c8ca5baceeb511ce8a06c61237e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/230240 Reviewed-by: Nicholas Shahan <nshahan@google.com> Reviewed-by: Lasse Nielsen <lrn@google.com> Commit-Queue: Martin Kustermann <kustermann@google.com>
This commit is contained in:
committed by
Commit Bot
parent
860f7c532d
commit
ddcd028cde
@@ -37,5 +37,5 @@ constants {
|
||||
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-testcase:///external_import.dart:
|
||||
- ExternalName. (from org-dartlang-sdk:///sdk/lib/internal/internal.dart:92:9)
|
||||
- ExternalName. (from org-dartlang-sdk:///sdk/lib/internal/internal.dart:109:9)
|
||||
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
|
||||
|
||||
@@ -37,5 +37,5 @@ constants {
|
||||
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-testcase:///external_import.dart:
|
||||
- ExternalName. (from org-dartlang-sdk:///sdk/lib/internal/internal.dart:92:9)
|
||||
- ExternalName. (from org-dartlang-sdk:///sdk/lib/internal/internal.dart:109:9)
|
||||
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
|
||||
|
||||
@@ -37,5 +37,5 @@ constants {
|
||||
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-testcase:///external_import.dart:
|
||||
- ExternalName. (from org-dartlang-sdk:///sdk/lib/internal/internal.dart:92:9)
|
||||
- ExternalName. (from org-dartlang-sdk:///sdk/lib/internal/internal.dart:109:9)
|
||||
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
|
||||
|
||||
@@ -42,5 +42,5 @@ constants {
|
||||
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-testcase:///native_is_illegal.dart:
|
||||
- ExternalName. (from org-dartlang-sdk:///sdk/lib/internal/internal.dart:92:9)
|
||||
- ExternalName. (from org-dartlang-sdk:///sdk/lib/internal/internal.dart:109:9)
|
||||
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
|
||||
|
||||
@@ -42,5 +42,5 @@ constants {
|
||||
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-testcase:///native_is_illegal.dart:
|
||||
- ExternalName. (from org-dartlang-sdk:///sdk/lib/internal/internal.dart:92:9)
|
||||
- ExternalName. (from org-dartlang-sdk:///sdk/lib/internal/internal.dart:109:9)
|
||||
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
|
||||
|
||||
@@ -42,5 +42,5 @@ constants {
|
||||
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-testcase:///native_is_illegal.dart:
|
||||
- ExternalName. (from org-dartlang-sdk:///sdk/lib/internal/internal.dart:92:9)
|
||||
- ExternalName. (from org-dartlang-sdk:///sdk/lib/internal/internal.dart:109:9)
|
||||
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
|
||||
|
||||
@@ -62,3 +62,6 @@ T createSentinel<T>() => throw UnsupportedError('createSentinel');
|
||||
|
||||
@patch
|
||||
bool isSentinel(dynamic value) => throw UnsupportedError('isSentinel');
|
||||
|
||||
@patch
|
||||
T unsafeCast<T>(dynamic v) => v;
|
||||
|
||||
@@ -73,3 +73,7 @@ T createSentinel<T>() => createJsSentinel<T>();
|
||||
@patch
|
||||
@pragma('dart2js:tryInline')
|
||||
bool isSentinel(dynamic value) => isJsSentinel(value);
|
||||
|
||||
@patch
|
||||
@pragma('dart2js:tryInline')
|
||||
T unsafeCast<T>(dynamic v) => v;
|
||||
|
||||
@@ -156,13 +156,9 @@ Int32List _growRegExpStack(Int32List stack) {
|
||||
return newStack;
|
||||
}
|
||||
|
||||
// This function can be used to skip implicit or explicit checked down casts in
|
||||
// the parts of the core library implementation where we know by construction the
|
||||
// type of a value.
|
||||
//
|
||||
// Important: this is unsafe and must be used with care.
|
||||
@patch
|
||||
@pragma("vm:external-name", "Internal_unsafeCast")
|
||||
external T unsafeCast<T>(Object? v);
|
||||
external T unsafeCast<T>(dynamic v);
|
||||
|
||||
// This function can be used to keep an object alive till that point.
|
||||
@pragma("vm:recognized", "other")
|
||||
|
||||
@@ -114,7 +114,8 @@ import "dart:_internal"
|
||||
printToZone,
|
||||
printToConsole,
|
||||
Since,
|
||||
typeAcceptsNull;
|
||||
typeAcceptsNull,
|
||||
unsafeCast;
|
||||
|
||||
part 'async_error.dart';
|
||||
part 'broadcast_stream_controller.dart';
|
||||
|
||||
@@ -4,15 +4,6 @@
|
||||
|
||||
part of dart.async;
|
||||
|
||||
/// The onValue and onError handlers return either a value or a future
|
||||
typedef FutureOr<T> _FutureOnValue<S, T>(S value);
|
||||
|
||||
/// Test used by [Future.catchError] to handle skip some errors.
|
||||
typedef bool _FutureErrorTest(Object error);
|
||||
|
||||
/// Used by [WhenFuture].
|
||||
typedef dynamic _FutureAction();
|
||||
|
||||
abstract class _Completer<T> implements Completer<T> {
|
||||
final _Future<T> future = new _Future<T>();
|
||||
|
||||
@@ -106,7 +97,7 @@ class _FutureListener<S, T> {
|
||||
state = (errorCallback == null) ? stateThen : stateThenOnerror;
|
||||
|
||||
_FutureListener.thenAwait(
|
||||
this.result, _FutureOnValue<S, T> onValue, Function errorCallback)
|
||||
this.result, FutureOr<T> Function(S) onValue, Function errorCallback)
|
||||
: callback = onValue,
|
||||
errorCallback = errorCallback,
|
||||
state = stateThenOnerror;
|
||||
@@ -127,19 +118,19 @@ class _FutureListener<S, T> {
|
||||
|
||||
FutureOr<T> Function(S) get _onValue {
|
||||
assert(handlesValue);
|
||||
return callback as dynamic;
|
||||
return unsafeCast<FutureOr<T> Function(S)>(callback);
|
||||
}
|
||||
|
||||
Function? get _onError => errorCallback;
|
||||
|
||||
_FutureErrorTest get _errorTest {
|
||||
bool Function(Object) get _errorTest {
|
||||
assert(hasErrorTest);
|
||||
return callback as dynamic;
|
||||
return unsafeCast<bool Function(Object)>(callback);
|
||||
}
|
||||
|
||||
_FutureAction get _whenCompleteAction {
|
||||
dynamic Function() get _whenCompleteAction {
|
||||
assert(handlesComplete);
|
||||
return callback as dynamic;
|
||||
return unsafeCast<dynamic Function()>(callback);
|
||||
}
|
||||
|
||||
/// Whether this listener has an error callback.
|
||||
|
||||
@@ -35,6 +35,23 @@ part 'symbol.dart';
|
||||
// execution mode.
|
||||
external bool typeAcceptsNull<T>();
|
||||
|
||||
/// Unsafely treats [value] as type [T].
|
||||
///
|
||||
/// An unsafe cast allows casting any value to any type,
|
||||
/// without any runtime type checks.
|
||||
///
|
||||
/// Can be used internally in platform library implementations of
|
||||
/// data structures, where a value is known to have a type different
|
||||
/// from its static type (like knowing that a string is definitely
|
||||
/// a "_OneByteString" or that the value stored into a heterogenous
|
||||
/// list is really a value of the surrounding map).
|
||||
///
|
||||
/// Must only be used for casts which would definitely *succeed*
|
||||
/// as a normal cast.
|
||||
///
|
||||
/// Should only be used for performance in performance critical code.
|
||||
external T unsafeCast<T>(dynamic value);
|
||||
|
||||
// Powers of 10 up to 10^22 are representable as doubles.
|
||||
// Powers of 10 above that are only approximate due to lack of precission.
|
||||
// Used by double-parsing.
|
||||
|
||||
Reference in New Issue
Block a user