Skip to content

Commit 9439795

Browse files
osa1Commit Queue
authored andcommitted
[dart2wasm] Complete async fun futures directly, instead of via completer
In `async` functions, instead of completing the function's `Future` via `Completer`, do it directly. This should be slightly more efficient as we eliminate a layer of indirection when completing. Move reading the `_future` field of `_AsyncSuspendState` to the completion functions, to avoid adding a `struct.get`s at each call site. In ACX demo, makes the final binary 0.1% smaller (13,689 bytes). Fixes #60719. Issue: #60719 CoreLibraryReviewExempt: Wasm-specific change. Change-Id: I27b376eb2fb9c3705ee930fb33b06d9accfd14b8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/429000 Reviewed-by: Martin Kustermann <[email protected]> Commit-Queue: Ömer Ağacan <[email protected]>
1 parent 9cf2137 commit 9439795

File tree

6 files changed

+45
-57
lines changed

6 files changed

+45
-57
lines changed

pkg/dart2wasm/lib/async.dart

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ mixin AsyncCodeGeneratorMixin on StateMachineEntryAstCodeGenerator {
4141
b.ref_null(w.HeapType.struct);
4242
}
4343

44-
// _AsyncCompleter _completer
44+
// _Future _future
4545
types.makeType(this, functionNode.emittedValueType!);
46-
call(translator.makeAsyncCompleter.reference);
46+
call(translator.makeFuture.reference);
4747

4848
// Allocate `_AsyncSuspendState`
4949
call(translator.newAsyncSuspendState.reference);
@@ -61,18 +61,11 @@ mixin AsyncCodeGeneratorMixin on StateMachineEntryAstCodeGenerator {
6161
translator.callFunction(resumeFun, b);
6262
b.drop(); // drop null
6363

64-
// (3) Return the completer's future.
64+
// (3) Return the future.
6565

6666
b.local_get(asyncStateLocal);
67-
final completerFutureGetterType = translator
68-
.signatureForDirectCall(translator.completerFuture.getterReference);
6967
b.struct_get(
70-
asyncSuspendStateInfo.struct, FieldIndex.asyncSuspendStateCompleter);
71-
translator.convertType(
72-
b,
73-
asyncSuspendStateInfo.struct.fields[5].type.unpacked,
74-
completerFutureGetterType.inputs[0]);
75-
call(translator.completerFuture.getterReference);
68+
asyncSuspendStateInfo.struct, FieldIndex.asyncSuspendStateFuture);
7669
b.return_();
7770
b.end();
7871

@@ -179,10 +172,9 @@ class AsyncStateMachineCodeGenerator extends StateMachineCodeGenerator {
179172
@override
180173
void emitReturn(void Function() emitValue) {
181174
b.local_get(_suspendStateLocal);
182-
b.struct_get(
183-
asyncSuspendStateInfo.struct, FieldIndex.asyncSuspendStateCompleter);
184175
emitValue();
185-
call(translator.getFunctionEntry(translator.completerComplete.reference,
176+
call(translator.getFunctionEntry(
177+
translator.asyncSuspendStateComplete.reference,
186178
uncheckedEntry: true));
187179
b.return_();
188180
}
@@ -262,10 +254,9 @@ class AsyncStateMachineCodeGenerator extends StateMachineCodeGenerator {
262254
// Final state: return.
263255
emitTargetLabel(targets.last);
264256
b.local_get(_suspendStateLocal);
265-
b.struct_get(
266-
asyncSuspendStateInfo.struct, FieldIndex.asyncSuspendStateCompleter);
267257
b.ref_null(translator.topInfo.struct);
268-
call(translator.getFunctionEntry(translator.completerComplete.reference,
258+
call(translator.getFunctionEntry(
259+
translator.asyncSuspendStateComplete.reference,
269260
uncheckedEntry: true));
270261
b.return_();
271262
b.end(); // masterLoop
@@ -277,20 +268,16 @@ class AsyncStateMachineCodeGenerator extends StateMachineCodeGenerator {
277268

278269
void callCompleteError() {
279270
b.local_get(_suspendStateLocal);
280-
b.struct_get(
281-
asyncSuspendStateInfo.struct, FieldIndex.asyncSuspendStateCompleter);
282271
b.local_get(exceptionLocal);
283272
b.local_get(stackTraceLocal);
284-
call(translator.completerCompleteError.reference);
273+
call(translator.asyncSuspendStateCompleteError.reference);
285274
b.return_();
286275
}
287276

288277
void callCompleteErrorWithCurrentStack() {
289278
b.local_get(_suspendStateLocal);
290-
b.struct_get(
291-
asyncSuspendStateInfo.struct, FieldIndex.asyncSuspendStateCompleter);
292279
b.local_get(exceptionLocal);
293-
call(translator.completerCompleteErrorWithCurrentStack.reference);
280+
call(translator.asyncSuspendStateCompleteErrorWithCurrentStack.reference);
294281
b.return_();
295282
}
296283

pkg/dart2wasm/lib/class_info.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class FieldIndex {
2121
static const asyncSuspendStateResume = 2;
2222
static const asyncSuspendStateContext = 3;
2323
static const asyncSuspendStateTargetIndex = 4;
24-
static const asyncSuspendStateCompleter = 5;
24+
static const asyncSuspendStateFuture = 5;
2525
static const asyncSuspendStateCurrentException = 6;
2626
static const asyncSuspendStateCurrentExceptionStackTrace = 7;
2727
static const asyncSuspendStateCurrentReturnValue = 8;
@@ -95,8 +95,8 @@ class FieldIndex {
9595
FieldIndex.asyncSuspendStateContext);
9696
check(translator.asyncSuspendStateClass, "_targetIndex",
9797
FieldIndex.asyncSuspendStateTargetIndex);
98-
check(translator.asyncSuspendStateClass, "_completer",
99-
FieldIndex.asyncSuspendStateCompleter);
98+
check(translator.asyncSuspendStateClass, "_future",
99+
FieldIndex.asyncSuspendStateFuture);
100100
check(translator.asyncSuspendStateClass, "_currentException",
101101
FieldIndex.asyncSuspendStateCurrentException);
102102
check(translator.asyncSuspendStateClass, "_currentExceptionStackTrace",

pkg/dart2wasm/lib/kernel_nodes.dart

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,24 +141,23 @@ mixin KernelNodes {
141141
// async support classes
142142
late final Class asyncSuspendStateClass =
143143
index.getClass("dart:async", "_AsyncSuspendState");
144-
late final Procedure makeAsyncCompleter =
145-
index.getTopLevelProcedure("dart:async", "_makeAsyncCompleter");
146-
late final Field completerFuture =
147-
index.getField("dart:async", "_Completer", "future");
148-
late final Procedure completerComplete =
149-
index.getProcedure("dart:async", "_AsyncCompleter", "complete");
150-
late final Procedure completerCompleteErrorWithCurrentStack =
151-
index.getProcedure(
152-
"dart:async", "_AsyncCompleter", "_completeErrorWithCurrentStack");
153-
late final Procedure completerCompleteError =
154-
index.getProcedure("dart:async", "_Completer", "completeError");
155144
late final Procedure awaitHelper =
156145
index.getTopLevelProcedure("dart:async", "_awaitHelper");
157146
late final Procedure awaitHelperWithTypeCheck =
158147
index.getTopLevelProcedure("dart:async", "_awaitHelperWithTypeCheck");
159148
late final Procedure newAsyncSuspendState =
160149
index.getTopLevelProcedure("dart:async", "_newAsyncSuspendState");
161150

151+
late final Procedure asyncSuspendStateComplete =
152+
index.getProcedure("dart:async", "_AsyncSuspendState", "_complete");
153+
late final Procedure asyncSuspendStateCompleteError =
154+
index.getProcedure("dart:async", "_AsyncSuspendState", "_completeError");
155+
late final Procedure asyncSuspendStateCompleteErrorWithCurrentStack =
156+
index.getProcedure(
157+
"dart:async", "_AsyncSuspendState", "_completeErrorWithCurrentStack");
158+
late final Procedure makeFuture =
159+
index.getTopLevelProcedure("dart:async", "_makeFuture");
160+
162161
// dart:ffi classes
163162
late final Class ffiPointerClass = index.getClass("dart:ffi", "Pointer");
164163

sdk/lib/_internal/wasm/lib/async_patch.dart

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,9 @@ class _AsyncSuspendState {
4141
@pragma("wasm:entry-point")
4242
WasmI32 _targetIndex;
4343

44-
// The completer. The inner function calls `_completer.complete` or
45-
// `_completer.onError` on completion.
44+
// The future that will be completed.
4645
@pragma("wasm:entry-point")
47-
final _AsyncCompleter _completer;
46+
final _Future _future;
4847

4948
// When a called function throws this stores the thrown exception. Used when
5049
// performing type tests in catch blocks.
@@ -63,11 +62,26 @@ class _AsyncSuspendState {
6362
Object? _currentReturnValue;
6463

6564
@pragma("wasm:entry-point")
66-
_AsyncSuspendState(this._resume, this._context, this._completer)
65+
_AsyncSuspendState(this._resume, this._context, this._future)
6766
: _targetIndex = WasmI32.fromInt(0),
6867
_currentException = null,
6968
_currentExceptionStackTrace = null,
7069
_currentReturnValue = null;
70+
71+
@pragma("wasm:entry-point")
72+
void _complete(FutureOr value) {
73+
_future._asyncComplete(value == null ? value as dynamic : value);
74+
}
75+
76+
@pragma("wasm:entry-point")
77+
void _completeError(Object error, StackTrace stackTrace) {
78+
_future._asyncCompleteError(error, stackTrace);
79+
}
80+
81+
@pragma("wasm:entry-point")
82+
void _completeErrorWithCurrentStack(Object error) {
83+
_future._asyncCompleteError(error, StackTrace.current);
84+
}
7185
}
7286

7387
// Note: [_AsyncCompleter] is taken as an argument to be able to pass the type
@@ -78,20 +92,11 @@ class _AsyncSuspendState {
7892
_AsyncSuspendState _newAsyncSuspendState(
7993
_AsyncResumeFun resume,
8094
WasmStructRef? context,
81-
_AsyncCompleter completer,
82-
) => _AsyncSuspendState(resume, context, completer);
83-
84-
@pragma("wasm:entry-point")
85-
_AsyncCompleter<T> _makeAsyncCompleter<T>() => _AsyncCompleter<T>();
95+
_Future future,
96+
) => _AsyncSuspendState(resume, context, future);
8697

87-
@patch
8898
@pragma("wasm:entry-point")
89-
class _AsyncCompleter<T> extends _Completer<T> {
90-
@pragma("wasm:entry-point")
91-
void _completeErrorWithCurrentStack(Object error) {
92-
completeError(error, StackTrace.current);
93-
}
94-
}
99+
_Future<T> _makeFuture<T>() => _Future<T>();
95100

96101
@pragma("wasm:entry-point")
97102
void _awaitHelper(_AsyncSuspendState suspendState, Future operand) {

sdk/lib/_internal/wasm/lib/errors_patch.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class Error {
2424
@pragma("wasm:entry-point")
2525
StackTrace? _stackTrace;
2626

27+
@pragma("wasm:entry-point")
2728
static void _trySetStackTrace(Object object, StackTrace stackTrace) {
2829
// Guard against implementors of [Error] that do not have the stack trace
2930
// field by ensuring the error object is a direct/indirect subclass.

sdk/lib/async/future_impl.dart

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,12 @@ AsyncError _interceptUserError(Object error, StackTrace? stackTrace) {
7171
}
7272

7373
abstract class _Completer<T> implements Completer<T> {
74-
@pragma("wasm:entry-point")
7574
@pragma("vm:entry-point")
7675
final _Future<T> future = _Future<T>();
7776

7877
// Overridden by either a synchronous or asynchronous implementation.
7978
void complete([FutureOr<T>? value]);
8079

81-
@pragma("wasm:entry-point")
8280
void completeError(Object error, [StackTrace? stackTrace]) {
8381
if (!future._mayComplete) throw StateError("Future already completed");
8482
_completeErrorObject(_interceptUserError(error, stackTrace));
@@ -95,7 +93,6 @@ abstract class _Completer<T> implements Completer<T> {
9593
/// Completer which completes future asynchronously.
9694
@pragma("vm:entry-point")
9795
class _AsyncCompleter<T> extends _Completer<T> {
98-
@pragma("wasm:entry-point")
9996
void complete([FutureOr<T>? value]) {
10097
if (!future._mayComplete) throw StateError("Future already completed");
10198
future._asyncComplete(value == null ? value as dynamic : value);
@@ -280,7 +277,6 @@ class _FutureListener<S, T> {
280277
bool shouldChain(Future<dynamic> value) => value is Future<T> || value is! T;
281278
}
282279

283-
@pragma("wasm:entry-point")
284280
class _Future<T> implements Future<T> {
285281
/// Initial state, waiting for a result. In this state, the
286282
/// [_resultOrListeners] field holds a single-linked list of

0 commit comments

Comments
 (0)