mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 15:50:01 +00:00
[vm] More efficient 'await' of not Future and completed _Future
When awaiting a value which is not a Future or a completed built-in _Future, 'await' implementation can bypass heavyweight _Future/_FutureListener machinery and schedule micro-tasks directly. Benchmarks: JIT, x64: AsyncLiveVars.* +46-54% (bigger is better) Calls.AwaitAsyncCall -46% (less is better) Calls.AwaitAsyncCallInstanceTargetPolymorphic -46% Calls.AwaitAsyncCallClosureTargetPolymorphic -45% Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits -45% Calls.AwaitFutureOrCall -60% Calls.AwaitFutureOrCallInstanceTargetPolymorphic -60% Calls.AwaitFutureOrCallClosureTargetPolymorphic -59% JIT, ia32: AsyncLiveVars.* +43-52% (bigger is better) Calls.AwaitAsyncCall -42% (less is better) Calls.AwaitAsyncCallInstanceTargetPolymorphic -42% Calls.AwaitAsyncCallClosureTargetPolymorphic -41% Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits -39% Calls.AwaitFutureOrCall -55% Calls.AwaitFutureOrCallInstanceTargetPolymorphic -54% Calls.AwaitFutureOrCallClosureTargetPolymorphic -53% JIT, arm: AsyncLiveVars.* +64-71% (bigger is better) Calls.AwaitAsyncCallInstanceTargetPolymorphic -51% (less is better) Calls.AwaitAsyncCallClosureTargetPolymorphic -47% Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits -48% Calls.AwaitFutureOrCall -64% Calls.AwaitFutureOrCallInstanceTargetPolymorphic -64% Calls.AwaitFutureOrCallClosureTargetPolymorphic -59% JIT, arm64: AsyncLiveVars.* +65-78% (bigger is better) Calls.AwaitAsyncCall -51% (less is better) Calls.AwaitAsyncCallInstanceTargetPolymorphic -51% Calls.AwaitAsyncCallClosureTargetPolymorphic -50% Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits -49% Calls.AwaitFutureOrCall -69% Calls.AwaitFutureOrCallInstanceTargetPolymorphic -68% Calls.AwaitFutureOrCallClosureTargetPolymorphic -67% AOT, x64: AsyncLiveVars.* +55-61% (bigger is better) Calls.AwaitAsyncCall -47% (less is better) Calls.AwaitAsyncCallInstanceTargetPolymorphic -46% Calls.AwaitAsyncCallClosureTargetPolymorphic -47% Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits -46% Calls.AwaitFutureOrCall -59% Calls.AwaitFutureOrCallInstanceTargetPolymorphic -59% Calls.AwaitFutureOrCallClosureTargetPolymorphic -58% AOT, arm: AsyncLiveVars.* 54-66% (bigger is better) Calls.AwaitAsyncCall -46-51% (less is better) Calls.AwaitAsyncCallInstanceTargetPolymorphic -46-50% Calls.AwaitAsyncCallClosureTargetPolymorphic -46-52% Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits -45-50% Calls.AwaitFutureOrCall -63-68% Calls.AwaitFutureOrCallInstanceTargetPolymorphic -63-66% Calls.AwaitFutureOrCallClosureTargetPolymorphic -63-67% AOT, arm64: AsyncLiveVars.* +53-66% (bigger is better) Calls.AwaitAsyncCall -50-51% (less is better) Calls.AwaitAsyncCallInstanceTargetPolymorphic -50% Calls.AwaitAsyncCallClosureTargetPolymorphic -50-51% Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits -49-50% Calls.AwaitFutureOrCall -66-68% Calls.AwaitFutureOrCallInstanceTargetPolymorphic -66-68% Calls.AwaitFutureOrCallClosureTargetPolymorphic -63-67% TEST=ci Issue: https://github.com/dart-lang/sdk/issues/48378 Change-Id: I65e3702fcd816ee3fee876ff442b9887c035b1ec Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/243102 Reviewed-by: Lasse Nielsen <lrn@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
parent
213ae5429b
commit
6b3d1752fa
|
@ -95,7 +95,7 @@ final tests = <IsolateTest>[
|
|||
(VmService service, IsolateRef isolateRef) async {
|
||||
final result = await service.getStack(isolateRef.id!);
|
||||
|
||||
expect(result.frames, hasLength(10));
|
||||
expect(result.frames, hasLength(6));
|
||||
expect(result.asyncCausalFrames, hasLength(26));
|
||||
expect(result.awaiterFrames, hasLength(13));
|
||||
|
||||
|
@ -105,10 +105,6 @@ final tests = <IsolateTest>[
|
|||
[equals('Regular'), anything], // Internal mech. ..
|
||||
[equals('Regular'), anything],
|
||||
[equals('Regular'), anything],
|
||||
[equals('Regular'), anything],
|
||||
[equals('Regular'), anything],
|
||||
[equals('Regular'), anything],
|
||||
[equals('Regular'), anything],
|
||||
[equals('Regular'), endsWith(' _RawReceivePortImpl._handleMessage')],
|
||||
]);
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ var tests = <IsolateTest>[
|
|||
var frames = stack['frames'];
|
||||
var asyncFrames = stack['asyncCausalFrames'];
|
||||
var awaiterFrames = stack['awaiterFrames'];
|
||||
expect(frames.length, greaterThanOrEqualTo(20));
|
||||
expect(frames.length, greaterThanOrEqualTo(12));
|
||||
expect(asyncFrames.length, greaterThan(frames.length));
|
||||
expect(awaiterFrames.length, greaterThan(frames.length));
|
||||
expect(stack['truncated'], false);
|
||||
|
|
|
@ -51,7 +51,7 @@ var tests = <IsolateTest>[
|
|||
var frames = stack['frames'];
|
||||
var asyncFrames = stack['asyncCausalFrames'];
|
||||
var awaiterFrames = stack['awaiterFrames'];
|
||||
expect(frames.length, greaterThanOrEqualTo(20));
|
||||
expect(frames.length, greaterThanOrEqualTo(12));
|
||||
expect(asyncFrames.length, greaterThan(frames.length));
|
||||
expect(awaiterFrames.length, greaterThan(frames.length));
|
||||
expect(stack['truncated'], false);
|
||||
|
|
|
@ -372,15 +372,69 @@ class _SuspendState {
|
|||
}
|
||||
}
|
||||
|
||||
@pragma("vm:invisible")
|
||||
@pragma("vm:prefer-inline")
|
||||
void _awaitCompletedFuture(_Future future) {
|
||||
assert(future._isComplete);
|
||||
final zone = Zone._current;
|
||||
if (future._hasError) {
|
||||
@pragma("vm:invisible")
|
||||
void run() {
|
||||
final AsyncError asyncError =
|
||||
unsafeCast<AsyncError>(future._resultOrListeners);
|
||||
zone.runBinary(
|
||||
unsafeCast<dynamic Function(Object, StackTrace)>(_errorCallback),
|
||||
asyncError.error,
|
||||
asyncError.stackTrace);
|
||||
}
|
||||
|
||||
zone.scheduleMicrotask(run);
|
||||
} else {
|
||||
@pragma("vm:invisible")
|
||||
void run() {
|
||||
zone.runUnary(unsafeCast<dynamic Function(dynamic)>(_thenCallback),
|
||||
future._resultOrListeners);
|
||||
}
|
||||
|
||||
zone.scheduleMicrotask(run);
|
||||
}
|
||||
}
|
||||
|
||||
@pragma("vm:invisible")
|
||||
@pragma("vm:prefer-inline")
|
||||
void _awaitNotFuture(Object? object) {
|
||||
final zone = Zone._current;
|
||||
@pragma("vm:invisible")
|
||||
void run() {
|
||||
zone.runUnary(
|
||||
unsafeCast<dynamic Function(dynamic)>(_thenCallback), object);
|
||||
}
|
||||
|
||||
zone.scheduleMicrotask(run);
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point", "call")
|
||||
@pragma("vm:invisible")
|
||||
Object? _await(Object? object) {
|
||||
if (_trace) print('_awaitAsync (object=$object)');
|
||||
if (_trace) print('_await (object=$object)');
|
||||
if (_thenCallback == null) {
|
||||
_createAsyncCallbacks();
|
||||
}
|
||||
_awaitHelper(object, unsafeCast<dynamic Function(dynamic)>(_thenCallback),
|
||||
unsafeCast<dynamic Function(Object, StackTrace)>(_errorCallback));
|
||||
if (object is _Future) {
|
||||
if (object._isComplete) {
|
||||
_awaitCompletedFuture(object);
|
||||
} else {
|
||||
object._thenAwait<dynamic>(
|
||||
unsafeCast<dynamic Function(dynamic)>(_thenCallback),
|
||||
unsafeCast<dynamic Function(Object, StackTrace)>(_errorCallback));
|
||||
}
|
||||
} else if (object is! Future) {
|
||||
_awaitNotFuture(object);
|
||||
} else {
|
||||
object.then(unsafeCast<dynamic Function(dynamic)>(_thenCallback),
|
||||
onError:
|
||||
unsafeCast<dynamic Function(Object, StackTrace)>(_errorCallback));
|
||||
}
|
||||
return _functionData;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue