Skip to content

Commit 4eaacc3

Browse files
mkustermannCommit Bot
authored and
Commit Bot
committed
[vm] Improve async performance by taking advantage of static types of returned values
In general any async function can return X or Future<X>. Though the future implementation has to do different things depending on which case we're in. It does so by using a `<obj> is Future<T>` test. This test is very expensive if many different classes flow into `<obj>`. Though most functions do not return `Future` objects from async functions. We can determine that statically by looking if any returned expression could be a future. If not, we can bypass the `is Future<T>` test entirely. Issue #48226 Issue #48235 TEST=pkg/front_end/testcases/general/async_function_returns_future_or.dart Change-Id: If655bdbdddc214dd7b12be9905b3c788252547d0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/230662 Reviewed-by: Alexander Markov <[email protected]> Reviewed-by: Lasse Nielsen <[email protected]> Commit-Queue: Martin Kustermann <[email protected]>
1 parent 0962b17 commit 4eaacc3

File tree

115 files changed

+1107
-423
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+1107
-423
lines changed

pkg/front_end/lib/src/fasta/source/source_loader.dart

+2
Original file line numberDiff line numberDiff line change
@@ -2570,6 +2570,8 @@ _awaitHelper(object, thenCallback, errorCallback, awaiter) {}
25702570
25712571
_completeOnAsyncReturn(_future, value, async_jump_var) {}
25722572
2573+
_completeWithNoFutureOnAsyncReturn(_future, value, async_jump_var) {}
2574+
25732575
_completeOnAsyncError(_future, e, st, async_jump_var) {}
25742576
25752577
class _AsyncStarStreamController {

pkg/front_end/testcases/extensions/async_extensions.dart.weak.transformed.expect

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ static method Extension|get#syncStarMethod(lowered final core::int* #this) → (
2828
static method Extension|asyncMethod(lowered final core::int* #this) → dynamic /* originally async */ {
2929
final asy::_Future<dynamic>* :async_future = new asy::_Future::•<dynamic>();
3030
core::bool* :is_sync = false;
31-
FutureOr<dynamic>* :return_value;
31+
dynamic :return_value;
3232
(dynamic) →* dynamic :async_op_then;
3333
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
3434
core::int* :await_jump_var = 0;
@@ -37,7 +37,7 @@ static method Extension|asyncMethod(lowered final core::int* #this) → dynamic
3737
try {
3838
#L1:
3939
{}
40-
asy::_completeOnAsyncReturn(:async_future, :return_value, :is_sync);
40+
asy::_completeWithNoFutureOnAsyncReturn(:async_future, :return_value, :is_sync);
4141
return;
4242
}
4343
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {

pkg/front_end/testcases/extensions/deferred_explicit_access.dart.weak.transformed.expect

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import "org-dartlang-testcase:///deferred_explicit_access_lib.dart" deferred as
1717
static method main() → dynamic /* originally async */ {
1818
final asy::_Future<dynamic>* :async_future = new asy::_Future::•<dynamic>();
1919
core::bool* :is_sync = false;
20-
FutureOr<dynamic>* :return_value;
20+
dynamic :return_value;
2121
(dynamic) →* dynamic :async_op_then;
2222
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
2323
core::int* :await_jump_var = 0;
@@ -38,7 +38,7 @@ static method main() → dynamic /* originally async */ {
3838
self::expect(87, let final core::Object* #t11 = CheckLibraryIsLoaded(prefix) in def::Extension|staticProperty = 87);
3939
self::expect(87, let final core::Object* #t12 = CheckLibraryIsLoaded(prefix) in def::Extension|staticMethod());
4040
}
41-
asy::_completeOnAsyncReturn(:async_future, :return_value, :is_sync);
41+
asy::_completeWithNoFutureOnAsyncReturn(:async_future, :return_value, :is_sync);
4242
return;
4343
}
4444
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {

pkg/front_end/testcases/extensions/deferred_import_hidden.dart.weak.transformed.expect

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import "org-dartlang-testcase:///deferred_explicit_access_lib.dart" deferred as
99
static method main() → dynamic /* originally async */ {
1010
final asy::_Future<dynamic>* :async_future = new asy::_Future::•<dynamic>();
1111
core::bool* :is_sync = false;
12-
FutureOr<dynamic>* :return_value;
12+
dynamic :return_value;
1313
(dynamic) →* dynamic :async_op_then;
1414
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
1515
core::int* :await_jump_var = 0;
@@ -29,7 +29,7 @@ static method main() → dynamic /* originally async */ {
2929
self::expect(87, let final core::Object* #t7 = CheckLibraryIsLoaded(prefix) in def::topLevelProperty);
3030
self::expect(87, let final core::Object* #t8 = CheckLibraryIsLoaded(prefix) in def::topLevelMethod());
3131
}
32-
asy::_completeOnAsyncReturn(:async_future, :return_value, :is_sync);
32+
asy::_completeWithNoFutureOnAsyncReturn(:async_future, :return_value, :is_sync);
3333
return;
3434
}
3535
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {

pkg/front_end/testcases/general/async_function.dart.weak.transformed.expect

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ static field core::List<core::String*>* stringList = core::_GrowableList::_liter
1010
static method asyncString() → asy::Future<core::String*>* /* originally async */ {
1111
final asy::_Future<core::String*>* :async_future = new asy::_Future::•<core::String*>();
1212
core::bool* :is_sync = false;
13-
FutureOr<core::String*>* :return_value;
13+
core::String? :return_value;
1414
(dynamic) →* dynamic :async_op_then;
1515
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
1616
core::int* :await_jump_var = 0;
@@ -22,7 +22,7 @@ static method asyncString() → asy::Future<core::String*>* /* originally async
2222
:return_value = "foo";
2323
break #L1;
2424
}
25-
asy::_completeOnAsyncReturn(:async_future, :return_value, :is_sync);
25+
asy::_completeWithNoFutureOnAsyncReturn(:async_future, :return_value, :is_sync);
2626
return;
2727
}
2828
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
@@ -181,7 +181,7 @@ static method asyncStarString2() → asy::Stream<core::String*>* /* originally a
181181
static method main() → dynamic /* originally async */ {
182182
final asy::_Future<dynamic>* :async_future = new asy::_Future::•<dynamic>();
183183
core::bool* :is_sync = false;
184-
FutureOr<dynamic>* :return_value;
184+
dynamic :return_value;
185185
(dynamic) →* dynamic :async_op_then;
186186
(core::Object*, core::StackTrace*) →* dynamic :async_op_error;
187187
core::int* :await_jump_var = 0;
@@ -194,7 +194,7 @@ static method main() → dynamic /* originally async */ {
194194
[yield] let dynamic #t2 = asy::_awaitHelper(self::asyncString(), :async_op_then, :async_op_error, :async_op) in null;
195195
core::String* str = _in::unsafeCast<core::String*>(:result);
196196
}
197-
asy::_completeOnAsyncReturn(:async_future, :return_value, :is_sync);
197+
asy::_completeWithNoFutureOnAsyncReturn(:async_future, :return_value, :is_sync);
198198
return;
199199
}
200200
on dynamic catch(dynamic exception, core::StackTrace* stack_trace) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:async';
6+
7+
main() async {
8+
await returnsString();
9+
await returnsFutureOrString();
10+
await returnsAwaitFutureOrString();
11+
await returnsFutureString();
12+
await returnsAwaitFutureString();
13+
await returnsObject();
14+
await returnsFutureOrObject();
15+
await returnsAwaitFutureOrObject();
16+
await returnsFutureObject();
17+
await returnsAwaitFutureObject();
18+
}
19+
20+
Future<String> returnsString() async => 'a';
21+
Future<String> returnsFutureOrString() async => getFutureOr<String>('a');
22+
Future<String> returnsAwaitFutureOrString() async =>
23+
await getFutureOr<String>('a');
24+
Future<String> returnsFutureString() async => getFuture<String>('a');
25+
FutureOr<String> returnsAwaitFutureString() async =>
26+
await getFuture<String>('a');
27+
28+
Future<Object> returnsObject() async => Object();
29+
Future<Object> returnsFutureOrObject() async => getFutureOr<Object>(Object());
30+
Future<Object> returnsAwaitFutureOrObject() async =>
31+
await getFutureOr<Object>(Object());
32+
Future<Object> returnsFutureObject() async => getFuture<Object>(Object());
33+
FutureOr<Object> returnsAwaitFutureObject() async =>
34+
await getFuture<Object>(Object());
35+
36+
FutureOr<T> getFutureOr<T>(T v) async => v;
37+
Future<T> getFuture<T>(T v) async => v;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import 'dart:async';
2+
3+
main() async {}
4+
Future<String> returnsString() async => 'a';
5+
Future<String> returnsFutureOrString() async => getFutureOr<String>('a');
6+
Future<String> returnsAwaitFutureOrString() async =>
7+
await getFutureOr<String>('a');
8+
Future<String> returnsFutureString() async => getFuture<String>('a');
9+
FutureOr<String> returnsAwaitFutureString() async =>
10+
await getFuture<String>('a');
11+
Future<Object> returnsObject() async => Object();
12+
Future<Object> returnsFutureOrObject() async => getFutureOr<Object>(Object());
13+
Future<Object> returnsAwaitFutureOrObject() async =>
14+
await getFutureOr<Object>(Object());
15+
Future<Object> returnsFutureObject() async => getFuture<Object>(Object());
16+
FutureOr<Object> returnsAwaitFutureObject() async =>
17+
await getFuture<Object>(Object());
18+
FutureOr<T> getFutureOr<T>(T v) async => v;
19+
Future<T> getFuture<T>(T v) async => v;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import 'dart:async';
2+
3+
Future<Object> returnsAwaitFutureOrObject() async =>
4+
await getFutureOr<Object>(Object());
5+
Future<Object> returnsFutureObject() async => getFuture<Object>(Object());
6+
Future<Object> returnsFutureOrObject() async => getFutureOr<Object>(Object());
7+
Future<Object> returnsObject() async => Object();
8+
Future<String> returnsAwaitFutureOrString() async =>
9+
await getFutureOr<String>('a');
10+
Future<String> returnsFutureOrString() async => getFutureOr<String>('a');
11+
Future<String> returnsFutureString() async => getFuture<String>('a');
12+
Future<String> returnsString() async => 'a';
13+
Future<T> getFuture<T>(T v) async => v;
14+
FutureOr<Object> returnsAwaitFutureObject() async =>
15+
await getFuture<Object>(Object());
16+
FutureOr<String> returnsAwaitFutureString() async =>
17+
await getFuture<String>('a');
18+
FutureOr<T> getFutureOr<T>(T v) async => v;
19+
main() async {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:async" as asy;
4+
import "dart:core" as core;
5+
6+
import "dart:async";
7+
8+
static method main() → dynamic async {
9+
await self::returnsString();
10+
await self::returnsFutureOrString();
11+
await self::returnsAwaitFutureOrString();
12+
await self::returnsFutureString();
13+
await self::returnsAwaitFutureString();
14+
await self::returnsObject();
15+
await self::returnsFutureOrObject();
16+
await self::returnsAwaitFutureOrObject();
17+
await self::returnsFutureObject();
18+
await self::returnsAwaitFutureObject();
19+
}
20+
static method returnsString() → asy::Future<core::String> async
21+
return "a";
22+
static method returnsFutureOrString() → asy::Future<core::String> async
23+
return self::getFutureOr<core::String>("a");
24+
static method returnsAwaitFutureOrString() → asy::Future<core::String> async
25+
return await self::getFutureOr<core::String>("a");
26+
static method returnsFutureString() → asy::Future<core::String> async
27+
return self::getFuture<core::String>("a");
28+
static method returnsAwaitFutureString() → FutureOr<core::String> async
29+
return await self::getFuture<core::String>("a");
30+
static method returnsObject() → asy::Future<core::Object> async
31+
return new core::Object::•();
32+
static method returnsFutureOrObject() → asy::Future<core::Object> async
33+
return self::getFutureOr<core::Object>(new core::Object::•());
34+
static method returnsAwaitFutureOrObject() → asy::Future<core::Object> async
35+
return await self::getFutureOr<core::Object>(new core::Object::•());
36+
static method returnsFutureObject() → asy::Future<core::Object> async
37+
return self::getFuture<core::Object>(new core::Object::•());
38+
static method returnsAwaitFutureObject() → FutureOr<core::Object> async
39+
return await self::getFuture<core::Object>(new core::Object::•());
40+
static method getFutureOr<T extends core::Object? = dynamic>(self::getFutureOr::T% v) → FutureOr<self::getFutureOr::T%> async
41+
return v;
42+
static method getFuture<T extends core::Object? = dynamic>(self::getFuture::T% v) → asy::Future<self::getFuture::T%> async
43+
return v;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:async" as asy;
4+
import "dart:core" as core;
5+
6+
import "dart:async";
7+
8+
static method main() → dynamic async {
9+
await self::returnsString();
10+
await self::returnsFutureOrString();
11+
await self::returnsAwaitFutureOrString();
12+
await self::returnsFutureString();
13+
await self::returnsAwaitFutureString();
14+
await self::returnsObject();
15+
await self::returnsFutureOrObject();
16+
await self::returnsAwaitFutureOrObject();
17+
await self::returnsFutureObject();
18+
await self::returnsAwaitFutureObject();
19+
}
20+
static method returnsString() → asy::Future<core::String> async
21+
return "a";
22+
static method returnsFutureOrString() → asy::Future<core::String> async
23+
return self::getFutureOr<core::String>("a");
24+
static method returnsAwaitFutureOrString() → asy::Future<core::String> async
25+
return await self::getFutureOr<core::String>("a");
26+
static method returnsFutureString() → asy::Future<core::String> async
27+
return self::getFuture<core::String>("a");
28+
static method returnsAwaitFutureString() → FutureOr<core::String> async
29+
return await self::getFuture<core::String>("a");
30+
static method returnsObject() → asy::Future<core::Object> async
31+
return new core::Object::•();
32+
static method returnsFutureOrObject() → asy::Future<core::Object> async
33+
return self::getFutureOr<core::Object>(new core::Object::•());
34+
static method returnsAwaitFutureOrObject() → asy::Future<core::Object> async
35+
return await self::getFutureOr<core::Object>(new core::Object::•());
36+
static method returnsFutureObject() → asy::Future<core::Object> async
37+
return self::getFuture<core::Object>(new core::Object::•());
38+
static method returnsAwaitFutureObject() → FutureOr<core::Object> async
39+
return await self::getFuture<core::Object>(new core::Object::•());
40+
static method getFutureOr<T extends core::Object? = dynamic>(self::getFutureOr::T% v) → FutureOr<self::getFutureOr::T%> async
41+
return v;
42+
static method getFuture<T extends core::Object? = dynamic>(self::getFuture::T% v) → asy::Future<self::getFuture::T%> async
43+
return v;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:async" as asy;
4+
import "dart:core" as core;
5+
6+
import "dart:async";
7+
8+
static method main() → dynamic async
9+
;
10+
static method returnsString() → asy::Future<core::String> async
11+
;
12+
static method returnsFutureOrString() → asy::Future<core::String> async
13+
;
14+
static method returnsAwaitFutureOrString() → asy::Future<core::String> async
15+
;
16+
static method returnsFutureString() → asy::Future<core::String> async
17+
;
18+
static method returnsAwaitFutureString() → FutureOr<core::String> async
19+
;
20+
static method returnsObject() → asy::Future<core::Object> async
21+
;
22+
static method returnsFutureOrObject() → asy::Future<core::Object> async
23+
;
24+
static method returnsAwaitFutureOrObject() → asy::Future<core::Object> async
25+
;
26+
static method returnsFutureObject() → asy::Future<core::Object> async
27+
;
28+
static method returnsAwaitFutureObject() → FutureOr<core::Object> async
29+
;
30+
static method getFutureOr<T extends core::Object? = dynamic>(self::getFutureOr::T% v) → FutureOr<self::getFutureOr::T%> async
31+
;
32+
static method getFuture<T extends core::Object? = dynamic>(self::getFuture::T% v) → asy::Future<self::getFuture::T%> async
33+
;

0 commit comments

Comments
 (0)