Skip to content

Commit 9dcd726

Browse files
lrhncommit-bot@chromium.org
authored andcommitted
Remove unnecessary completers from async_patch code.
Use _Future directly. Add ability to get trace of awaited continuations. Change-Id: I6c3aba0bdc2e54afe1d84fdd802fb5210d7598ac Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/112721 Reviewed-by: Martin Kustermann <[email protected]> Commit-Queue: Lasse R.H. Nielsen <[email protected]>
1 parent b9217ef commit 9dcd726

File tree

4 files changed

+83
-57
lines changed

4 files changed

+83
-57
lines changed

runtime/lib/async_patch.dart

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,24 @@ import "dart:_internal" show VMLibraryHooks, patch;
1818
_fatal(msg) native "DartAsync_fatal";
1919

2020
class _AsyncAwaitCompleter<T> implements Completer<T> {
21-
final _completer = new Completer<T>.sync();
21+
final _future = new _Future<T>();
2222
bool isSync;
2323

2424
_AsyncAwaitCompleter() : isSync = false;
2525

2626
void complete([FutureOr<T> value]) {
27-
if (isSync) {
28-
_completer.complete(value);
29-
} else if (value is Future<T>) {
30-
value.then(_completer.complete, onError: _completer.completeError);
27+
if (!isSync || value is Future<T>) {
28+
_future._asyncComplete(value);
3129
} else {
32-
scheduleMicrotask(() {
33-
_completer.complete(value);
34-
});
30+
_future._completeWithValue(value);
3531
}
3632
}
3733

3834
void completeError(e, [st]) {
3935
if (isSync) {
40-
_completer.completeError(e, st);
36+
_future._completeError(e, st);
4137
} else {
42-
scheduleMicrotask(() {
43-
_completer.completeError(e, st);
44-
});
38+
_future._asyncCompleteError(e, st);
4539
}
4640
}
4741

@@ -50,8 +44,8 @@ class _AsyncAwaitCompleter<T> implements Completer<T> {
5044
isSync = true;
5145
}
5246

53-
Future<T> get future => _completer.future;
54-
bool get isCompleted => _completer.isCompleted;
47+
Future<T> get future => _future;
48+
bool get isCompleted => !_future._mayComplete;
5549
}
5650

5751
// We need to pass the value as first argument and leave the second and third
@@ -107,7 +101,7 @@ Future _awaitHelper(
107101
// We can only do this for our internal futures (the default implementation of
108102
// all futures that are constructed by the `dart:async` library).
109103
object._awaiter = awaiter;
110-
return object._thenNoZoneRegistration(thenCallback, errorCallback);
104+
return object._thenAwait(thenCallback, errorCallback);
111105
}
112106

113107
// Called as part of the 'await for (...)' construct. Registers the
@@ -143,7 +137,7 @@ class _AsyncStarStreamController<T> {
143137
bool onListenReceived = false;
144138
bool isScheduled = false;
145139
bool isSuspendedAtYield = false;
146-
Completer cancellationCompleter = null;
140+
_Future cancellationFuture = null;
147141

148142
Stream<T> get stream {
149143
final Stream<T> local = controller.stream;
@@ -210,10 +204,10 @@ class _AsyncStarStreamController<T> {
210204
}
211205

212206
void addError(Object error, StackTrace stackTrace) {
213-
if ((cancellationCompleter != null) && !cancellationCompleter.isCompleted) {
207+
if ((cancellationFuture != null) && cancellationFuture._mayComplete) {
214208
// If the stream has been cancelled, complete the cancellation future
215209
// with the error.
216-
cancellationCompleter.completeError(error, stackTrace);
210+
cancellationFuture._completeError(error, stackTrace);
217211
return;
218212
}
219213
// If stream is cancelled, tell caller to exit the async generator.
@@ -226,10 +220,10 @@ class _AsyncStarStreamController<T> {
226220
}
227221

228222
close() {
229-
if ((cancellationCompleter != null) && !cancellationCompleter.isCompleted) {
223+
if ((cancellationFuture != null) && cancellationFuture._mayComplete) {
230224
// If the stream has been cancelled, complete the cancellation future
231225
// with the error.
232-
cancellationCompleter.complete();
226+
cancellationFuture._completeWithValue(null);
233227
}
234228
controller.close();
235229
}
@@ -257,16 +251,16 @@ class _AsyncStarStreamController<T> {
257251
if (controller.isClosed) {
258252
return null;
259253
}
260-
if (cancellationCompleter == null) {
261-
cancellationCompleter = new Completer();
254+
if (cancellationFuture == null) {
255+
cancellationFuture = new _Future();
262256
// Only resume the generator if it is suspended at a yield.
263257
// Cancellation does not affect an async generator that is
264258
// suspended at an await.
265259
if (isSuspendedAtYield) {
266260
scheduleGenerator();
267261
}
268262
}
269-
return cancellationCompleter.future;
263+
return cancellationFuture;
270264
}
271265
}
272266

sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ _async<T>(Function() initGenerator) {
3737
} else {
3838
f = _Future.value(value);
3939
}
40-
f = JS('', '#', f._thenNoZoneRegistration(onValue, onError));
40+
f = JS('', '#', f._thenAwait(onValue, onError));
4141
return f;
4242
}
4343

@@ -363,7 +363,7 @@ class _AsyncStarImpl<T> {
363363
} else {
364364
f = _Future.value(value);
365365
}
366-
f._thenNoZoneRegistration(_runBodyCallback, handleError);
366+
f._thenAwait(_runBodyCallback, handleError);
367367
}
368368

369369
/// Adds element to [stream] and returns true if the caller should terminate

sdk/lib/_internal/js_runtime/lib/async_patch.dart

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -190,35 +190,29 @@ bool _hasTimer() {
190190
}
191191

192192
class _AsyncAwaitCompleter<T> implements Completer<T> {
193-
final _completer = new Completer<T>.sync();
193+
final _future = new _Future<T>();
194194
bool isSync;
195195

196196
_AsyncAwaitCompleter() : isSync = false;
197197

198198
void complete([FutureOr<T> value]) {
199-
if (isSync) {
200-
_completer.complete(value);
201-
} else if (value is Future<T>) {
202-
value.then(_completer.complete, onError: _completer.completeError);
199+
if (!isSync || value is Future<T>) {
200+
_future._asyncComplete(value);
203201
} else {
204-
scheduleMicrotask(() {
205-
_completer.complete(value);
206-
});
202+
_future._completeWithValue(value);
207203
}
208204
}
209205

210206
void completeError(e, [st]) {
211207
if (isSync) {
212-
_completer.completeError(e, st);
208+
_future._completeError(e, st);
213209
} else {
214-
scheduleMicrotask(() {
215-
_completer.completeError(e, st);
216-
});
210+
_future._asyncCompleteError(e, st);
217211
}
218212
}
219213

220-
Future<T> get future => _completer.future;
221-
bool get isCompleted => _completer.isCompleted;
214+
Future<T> get future => _future;
215+
bool get isCompleted => !_future._mayComplete;
222216
}
223217

224218
/// Creates a Completer for an `async` function.
@@ -295,15 +289,14 @@ void _awaitOnObject(object, _WrappedAsyncBody bodyFunction) {
295289
if (object is _Future) {
296290
// We can skip the zone registration, since the bodyFunction is already
297291
// registered (see [_wrapJsFunctionForAsync]).
298-
object._thenNoZoneRegistration(thenCallback, errorCallback);
292+
object._thenAwait(thenCallback, errorCallback);
299293
} else if (object is Future) {
300294
object.then(thenCallback, onError: errorCallback);
301295
} else {
302-
_Future future = new _Future();
303-
future._setValue(object);
296+
_Future future = new _Future().._setValue(object);
304297
// We can skip the zone registration, since the bodyFunction is already
305298
// registered (see [_wrapJsFunctionForAsync]).
306-
future._thenNoZoneRegistration(thenCallback, null);
299+
future._thenAwait(thenCallback, null);
307300
}
308301
}
309302

@@ -381,15 +374,15 @@ void _asyncStarHelper(
381374
if (identical(bodyFunctionOrErrorCode, async_error_codes.SUCCESS)) {
382375
// This happens on return from the async* function.
383376
if (controller.isCanceled) {
384-
controller.cancelationCompleter.complete();
377+
controller.cancelationFuture._completeWithValue(null);
385378
} else {
386379
controller.close();
387380
}
388381
return;
389382
} else if (identical(bodyFunctionOrErrorCode, async_error_codes.ERROR)) {
390383
// The error is a js-error.
391384
if (controller.isCanceled) {
392-
controller.cancelationCompleter.completeError(
385+
controller.cancelationFuture._completeError(
393386
unwrapException(object), getTraceFromException(object));
394387
} else {
395388
controller.addError(
@@ -465,13 +458,13 @@ class _AsyncStarStreamController<T> {
465458

466459
bool get isPaused => controller.isPaused;
467460

468-
Completer cancelationCompleter = null;
461+
_Future cancelationFuture = null;
469462

470463
/// True after the StreamSubscription has been cancelled.
471464
/// When this is true, errors thrown from the async* body should go to the
472-
/// [cancelationCompleter] instead of adding them to [controller], and
473-
/// returning from the async function should complete [cancelationCompleter].
474-
bool get isCanceled => cancelationCompleter != null;
465+
/// [cancelationFuture] instead of adding them to [controller], and
466+
/// returning from the async function should complete [cancelationFuture].
467+
bool get isCanceled => cancelationFuture != null;
475468

476469
add(event) => controller.add(event);
477470

@@ -503,15 +496,15 @@ class _AsyncStarStreamController<T> {
503496
}, onCancel: () {
504497
// If the async* is finished we ignore cancel events.
505498
if (!controller.isClosed) {
506-
cancelationCompleter = new Completer();
499+
cancelationFuture = new _Future();
507500
if (isSuspended) {
508501
// Resume the suspended async* function to run finalizers.
509502
isSuspended = false;
510503
scheduleMicrotask(() {
511504
body(async_error_codes.STREAM_WAS_CANCELED, null);
512505
});
513506
}
514-
return cancelationCompleter.future;
507+
return cancelationFuture;
515508
}
516509
});
517510
}

sdk/lib/async/future_impl.dart

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ class _FutureListener<S, T> {
6767
static const int stateCatcherror = maskError;
6868
static const int stateCatcherrorTest = maskError | maskTestError;
6969
static const int stateWhencomplete = maskWhencomplete;
70+
static const int maskType =
71+
maskValue | maskError | maskTestError | maskWhencomplete;
72+
static const int stateIsAwait = 16;
7073
// Listeners on the same future are linked through this link.
7174
_FutureListener _nextListener;
7275
// The future to complete when this listener is activated.
@@ -84,6 +87,13 @@ class _FutureListener<S, T> {
8487
errorCallback = errorCallback,
8588
state = (errorCallback == null) ? stateThen : stateThenOnerror;
8689

90+
_FutureListener.thenAwait(
91+
this.result, _FutureOnValue<S, T> onValue, Function errorCallback)
92+
: callback = onValue,
93+
errorCallback = errorCallback,
94+
state = ((errorCallback == null) ? stateThen : stateThenOnerror)
95+
| stateIsAwait ;
96+
8797
_FutureListener.catchError(this.result, this.errorCallback, this.callback)
8898
: state = (callback == null) ? stateCatcherror : stateCatcherrorTest;
8999

@@ -95,8 +105,9 @@ class _FutureListener<S, T> {
95105

96106
bool get handlesValue => (state & maskValue != 0);
97107
bool get handlesError => (state & maskError != 0);
98-
bool get hasErrorTest => (state == stateCatcherrorTest);
99-
bool get handlesComplete => (state == stateWhencomplete);
108+
bool get hasErrorTest => (state & maskType == stateCatcherrorTest);
109+
bool get handlesComplete => (state & maskType == stateWhencomplete);
110+
bool get isAwait => (state & stateIsAwait != 0);
100111

101112
_FutureOnValue<S, T> get _onValue {
102113
assert(handlesValue);
@@ -229,6 +240,27 @@ class _Future<T> implements Future<T> {
229240
bool get _isComplete => _state >= _stateValue;
230241
bool get _hasError => _state == _stateError;
231242

243+
static List<Function> _continuationFunctions(_Future<Object> future) {
244+
List<Function> result = null;
245+
while (true) {
246+
if (future._mayAddListener) return result;
247+
assert(!future._isComplete);
248+
assert(!future._isChained);
249+
// So _resultOrListeners contains listeners.
250+
_FutureListener<Object, Object> listener = future._resultOrListeners;
251+
if (listener != null &&
252+
listener._nextListener == null &&
253+
listener.isAwait) {
254+
(result ??= <Function>[]).add(listener.handleValue);
255+
future = listener.result;
256+
assert(!future._isComplete);
257+
} else {
258+
break;
259+
}
260+
}
261+
return result;
262+
}
263+
232264
void _setChained(_Future source) {
233265
assert(_mayAddListener);
234266
_state = _stateChained;
@@ -246,14 +278,21 @@ class _Future<T> implements Future<T> {
246278
onError = _registerErrorHandler(onError, currentZone);
247279
}
248280
}
249-
return _thenNoZoneRegistration<R>(f, onError);
281+
_Future<R> result = new _Future<R>();
282+
_addListener(new _FutureListener<T, R>.then(result, f, onError));
283+
return result;
250284
}
251285

252-
// This method is used by async/await.
253-
Future<E> _thenNoZoneRegistration<E>(
286+
/// Registers a system created result and error continuation.
287+
///
288+
/// Used by the implementation of `await` to listen to a future.
289+
/// The system created liseners are not registered in the zone,
290+
/// and the listener is marked as being from an `await`.
291+
/// This marker is used in [_continuationFunctions].
292+
Future<E> _thenAwait<E>(
254293
FutureOr<E> f(T value), Function onError) {
255294
_Future<E> result = new _Future<E>();
256-
_addListener(new _FutureListener<T, E>.then(result, f, onError));
295+
_addListener(new _FutureListener<T, E>.thenAwait(result, f, onError));
257296
return result;
258297
}
259298

0 commit comments

Comments
 (0)