diff --git a/pkg/vm_service/test/get_stack_test.dart b/pkg/vm_service/test/get_stack_test.dart index f1ba6f16ea7..28c50010f44 100644 --- a/pkg/vm_service/test/get_stack_test.dart +++ b/pkg/vm_service/test/get_stack_test.dart @@ -52,11 +52,12 @@ final tests = [ // Before the first await. hasStoppedAtBreakpoint, stoppedAtLine(LINE_A), + // At LINE_A we're still running sync. so no asyncCausalFrames. (VmService service, IsolateRef isolateRef) async { final result = await service.getStack(isolateRef.id!); expect(result.frames, hasLength(16)); - expect(result.asyncCausalFrames, hasLength(16)); + expect(result.asyncCausalFrames, isNull); expect(result.awaiterFrames, hasLength(16)); expectFrames(result.frames, [ @@ -73,20 +74,6 @@ final tests = [ [equals('Regular'), endsWith(' testMain')], ]); - expectFrames(result.asyncCausalFrames, [ - [equals('Regular'), endsWith(' func10')], - [equals('Regular'), endsWith(' func9')], - [equals('Regular'), endsWith(' func8')], - [equals('Regular'), endsWith(' func7')], - [equals('Regular'), endsWith(' func6')], - [equals('Regular'), endsWith(' func5')], - [equals('Regular'), endsWith(' func4')], - [equals('Regular'), endsWith(' func3')], - [equals('Regular'), endsWith(' func2')], - [equals('Regular'), endsWith(' func1')], - [equals('Regular'), endsWith(' testMain')], - ]); - expectFrames(result.awaiterFrames, [ [equals('AsyncActivation'), endsWith(' func10')], [equals('AsyncActivation'), endsWith(' func9')], @@ -101,10 +88,10 @@ final tests = [ [equals('AsyncActivation'), endsWith(' testMain')], ]); }, - // After resuming the continuation - i.e. running async. resumeIsolate, hasStoppedAtBreakpoint, stoppedAtLine(LINE_B), + // After resuming the continuation - i.e. running async. (VmService service, IsolateRef isolateRef) async { final result = await service.getStack(isolateRef.id!); diff --git a/runtime/observatory/tests/service/causal_async_stack_presence_test.dart b/runtime/observatory/tests/service/causal_async_stack_presence_test.dart index 3a90e4a62b0..01331cdf9d1 100644 --- a/runtime/observatory/tests/service/causal_async_stack_presence_test.dart +++ b/runtime/observatory/tests/service/causal_async_stack_presence_test.dart @@ -11,8 +11,8 @@ import 'service_test_common.dart'; import 'test_helper.dart'; const LINE_C = 19; -const LINE_A = 24; -const LINE_B = 30; +const LINE_A = 25; +const LINE_B = 31; foobar() { debugger(); @@ -20,6 +20,7 @@ foobar() { } helper() async { + await 0; // Yield. The rest will run async. debugger(); print('helper'); // LINE_A. foobar(); @@ -36,6 +37,7 @@ var tests = [ (Isolate isolate) async { ServiceMap stack = await isolate.getStack(); // No causal frames because we are in a completely synchronous stack. + // Async function hasn't yielded yet. expect(stack['asyncCausalFrames'], isNull); }, resumeIsolate, @@ -43,7 +45,7 @@ var tests = [ stoppedAtLine(LINE_A), (Isolate isolate) async { ServiceMap stack = await isolate.getStack(); - // Has causal frames (we are inside an async function) + // Async function has yielded once, so it's now running async. expect(stack['asyncCausalFrames'], isNotNull); }, resumeIsolate, diff --git a/runtime/observatory/tests/service/causal_async_star_stack_presence_test.dart b/runtime/observatory/tests/service/causal_async_star_stack_presence_test.dart index 4d3e4486590..9b605cb96da 100644 --- a/runtime/observatory/tests/service/causal_async_star_stack_presence_test.dart +++ b/runtime/observatory/tests/service/causal_async_star_stack_presence_test.dart @@ -39,7 +39,7 @@ var tests = [ (Isolate isolate) async { ServiceMap stack = await isolate.getStack(); // No causal frames because we are in a completely synchronous stack. - expect(stack['asyncCausalFrames'], isNotNull); + expect(stack['asyncCausalFrames'], isNull); }, resumeIsolate, hasStoppedAtBreakpoint, diff --git a/runtime/observatory_2/tests/service_2/causal_async_stack_presence_test.dart b/runtime/observatory_2/tests/service_2/causal_async_stack_presence_test.dart index f52f4a1fbd2..cd9ef6ad386 100644 --- a/runtime/observatory_2/tests/service_2/causal_async_stack_presence_test.dart +++ b/runtime/observatory_2/tests/service_2/causal_async_stack_presence_test.dart @@ -11,8 +11,8 @@ import 'service_test_common.dart'; import 'test_helper.dart'; const LINE_C = 19; -const LINE_A = 24; -const LINE_B = 30; +const LINE_A = 25; +const LINE_B = 31; foobar() { debugger(); @@ -20,6 +20,7 @@ foobar() { } helper() async { + await 0; // Yield. The rest will run async. debugger(); print('helper'); // LINE_A. foobar(); diff --git a/runtime/observatory_2/tests/service_2/causal_async_star_stack_presence_test.dart b/runtime/observatory_2/tests/service_2/causal_async_star_stack_presence_test.dart index 7fb385ae89f..8acf40d5e74 100644 --- a/runtime/observatory_2/tests/service_2/causal_async_star_stack_presence_test.dart +++ b/runtime/observatory_2/tests/service_2/causal_async_star_stack_presence_test.dart @@ -39,7 +39,7 @@ var tests = [ (Isolate isolate) async { ServiceMap stack = await isolate.getStack(); // No causal frames because we are in a completely synchronous stack. - expect(stack['asyncCausalFrames'], isNotNull); + expect(stack['asyncCausalFrames'], isNull); }, resumeIsolate, hasStoppedAtBreakpoint, diff --git a/runtime/tests/vm/dart/causal_stacks/utils.dart b/runtime/tests/vm/dart/causal_stacks/utils.dart index fdebc07bb8a..16deb645ad9 100644 --- a/runtime/tests/vm/dart/causal_stacks/utils.dart +++ b/runtime/tests/vm/dart/causal_stacks/utils.dart @@ -40,7 +40,7 @@ Future allYield3() async { } // ---- -// Scenario: None of the async functions yieled before the throw: +// Scenario: None of the async functions yielded before the throw: // ---- Future noYields() async { await noYields2(); @@ -178,12 +178,22 @@ Future futureSyncWhenComplete() { return Future.sync(throwAsync).whenComplete(() => 'nop'); } +// ---- +// Scenario: Future.then: +// ---- + +Future futureThen() { + return Future.value(0).then((value) { + throwSync(); + }); +} + // Helpers: // We want lines that either start with a frame index or an async gap marker. final _lineRE = RegExp(r'^(?:#(?\d+)|)'); -void assertStack(List expects, StackTrace stackTrace, +Future assertStack(List expects, StackTrace stackTrace, [String? debugInfoFilename]) async { final original = await Stream.value(stackTrace.toString()) .transform(const LineSplitter()) @@ -253,7 +263,7 @@ Future doTestAwait(Future f(), List expectedStack, await f(); Expect.fail('No exception thrown!'); } on String catch (e, s) { - assertStack(expectedStack, s, debugInfoFilename); + return assertStack(expectedStack, s, debugInfoFilename); } } @@ -267,7 +277,7 @@ Future doTestAwaitThen(Future f(), List expectedStack, await f().then((e) => Expect.fail('No exception thrown!')); Expect.fail('No exception thrown!'); } on String catch (e, s) { - assertStack(expectedStack, s, debugInfoFilename); + return assertStack(expectedStack, s, debugInfoFilename); } } @@ -278,7 +288,7 @@ Future doTestAwaitCatchError(Future f(), List expectedStack, await f().catchError((e, s) { stackTrace = s; }); - assertStack(expectedStack, stackTrace, debugInfoFilename); + return assertStack(expectedStack, stackTrace, debugInfoFilename); } // ---- @@ -287,342 +297,262 @@ Future doTestAwaitCatchError(Future f(), List expectedStack, // For: --no-lazy-async-stacks Future doTestsNoCausalNoLazy([String? debugInfoFilename]) async { - final allYieldExpected = const [ - r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', - r'^#1 allYield3 \(.*/utils.dart:39(:3)?\)$', - r'^#2 _RootZone.runUnary ', - r'^#3 _FutureListener.handleValue ', - r'^#4 Future._propagateToListeners.handleValueCallback ', - r'^#5 Future._propagateToListeners ', - // TODO(dart-vm): Figure out why this is inconsistent: - r'^#6 Future.(_addListener|_prependListeners). ', - r'^#7 _microtaskLoop ', - r'^#8 _startMicrotaskLoop ', - r'^#9 _runPendingImmediateCallback ', - r'^#10 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait(allYield, allYieldExpected, debugInfoFilename); - await doTestAwaitThen(allYield, allYieldExpected, debugInfoFilename); - await doTestAwaitCatchError(allYield, allYieldExpected, debugInfoFilename); + { + final expected = const [ + r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'^#1 allYield3 \(.*/utils.dart:39(:3)?\)$', + r'^#2 _RootZone.runUnary ', + r'^#3 _FutureListener.handleValue ', + r'^#4 Future._propagateToListeners.handleValueCallback ', + r'^#5 Future._propagateToListeners ', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#6 Future.(_addListener|_prependListeners). ', + r'^#7 _microtaskLoop ', + r'^#8 _startMicrotaskLoop ', + r'^#9 _runPendingImmediateCallback ', + r'^#10 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(allYield, expected, debugInfoFilename); + await doTestAwaitThen(allYield, expected, debugInfoFilename); + await doTestAwaitCatchError(allYield, expected, debugInfoFilename); + } - final noYieldsExpected = const [ - r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', - r'^#1 noYields3 \(.*/utils.dart:54(:3)?\)$', - r'^#2 noYields3 \(.*/utils.dart:53(:23)?\)$', - r'^#3 noYields2 \(.*/utils.dart:50(:9)?\)$', - r'^#4 noYields2 \(.*/utils.dart:49(:23)?\)$', - r'^#5 noYields \(.*/utils.dart:46(:9)?\)$', - r'^#6 noYields \(.*/utils.dart:45(:22)?\)$', - ]; - await doTestAwait( - noYields, - noYieldsExpected + - const [ - r'^#7 doTestAwait ', - r'^#8 doTestAwait ', - r'^#9 doTestsNoCausalNoLazy ', - r'^#10 _RootZone.runUnary ', - r'^#11 _FutureListener.handleValue ', - r'^#12 Future._propagateToListeners.handleValueCallback ', - r'^#13 Future._propagateToListeners ', - r'^#14 Future._completeWithValue ', - r'^#15 _completeOnAsyncReturn ', - r'^#16 doTestAwaitCatchError ', - r'^#17 _RootZone.runUnary ', - r'^#18 _FutureListener.handleValue ', - r'^#19 Future._propagateToListeners.handleValueCallback ', - r'^#20 Future._propagateToListeners ', - r'^#21 Future._completeError ', - r'^#22 _completeOnAsyncError ', - r'^#23 allYield ', - r'^#24 _asyncErrorWrapperHelper.errorCallback ', - r'^#25 _RootZone.runBinary ', - r'^#26 _FutureListener.handleError ', - r'^#27 Future._propagateToListeners.handleError ', - r'^#28 Future._propagateToListeners ', - r'^#29 Future._completeError ', - r'^#30 _completeOnAsyncError ', - r'^#31 allYield2 ', - r'^#32 _asyncErrorWrapperHelper.errorCallback ', - r'^#33 _RootZone.runBinary ', - r'^#34 _FutureListener.handleError ', - r'^#35 Future._propagateToListeners.handleError ', - r'^#36 Future._propagateToListeners ', - r'^#37 Future._completeError ', - r'^#38 _completeOnAsyncError ', - r'^#39 allYield3 ', - r'^#40 _RootZone.runUnary ', - r'^#41 _FutureListener.handleValue ', - r'^#42 Future._propagateToListeners.handleValueCallback ', - r'^#43 Future._propagateToListeners ', - r'^#44 Future._addListener. ', - r'^#45 _microtaskLoop ', - r'^#46 _startMicrotaskLoop ', - r'^#47 _runPendingImmediateCallback ', - r'^#48 _RawReceivePortImpl._handleMessage ', - ], - debugInfoFilename); - await doTestAwaitThen( - noYields, - noYieldsExpected + - const [ - r'^#7 doTestAwaitThen ', - r'^#8 doTestAwaitThen ', - r'^#9 doTestsNoCausalNoLazy ', - r'^#10 _RootZone.runUnary ', - r'^#11 _FutureListener.handleValue ', - r'^#12 Future._propagateToListeners.handleValueCallback ', - r'^#13 Future._propagateToListeners ', - r'^#14 Future._completeWithValue ', - r'^#15 _completeOnAsyncReturn ', - r'^#16 doTestAwait ', - r'^#17 _asyncErrorWrapperHelper.errorCallback ', - r'^#18 _RootZone.runBinary ', - r'^#19 _FutureListener.handleError ', - r'^#20 Future._propagateToListeners.handleError ', - r'^#21 Future._propagateToListeners ', - r'^#22 Future._completeError ', - r'^#23 _completeOnAsyncError ', - r'^#24 noYields ', - r'^#25 _asyncErrorWrapperHelper.errorCallback ', - r'^#26 _RootZone.runBinary ', - r'^#27 _FutureListener.handleError ', - r'^#28 Future._propagateToListeners.handleError ', - r'^#29 Future._propagateToListeners ', - r'^#30 Future._completeError ', - r'^#31 _completeOnAsyncError ', - r'^#32 noYields2 ', - r'^#33 _asyncErrorWrapperHelper.errorCallback ', - r'^#34 _RootZone.runBinary ', - r'^#35 _FutureListener.handleError ', - r'^#36 Future._propagateToListeners.handleError ', - r'^#37 Future._propagateToListeners ', - r'^#38 Future._completeError ', - r'^#39 Future._asyncCompleteError. ', - r'^#40 _microtaskLoop ', - r'^#41 _startMicrotaskLoop ', - r'^#42 _runPendingImmediateCallback ', - r'^#43 _RawReceivePortImpl._handleMessage ', - ], - debugInfoFilename); - await doTestAwaitCatchError( - noYields, - noYieldsExpected + - const [ - r'^#7 doTestAwaitCatchError ', - r'^#8 doTestAwaitCatchError ', - r'^#9 doTestsNoCausalNoLazy ', - r'^#10 _RootZone.runUnary ', - r'^#11 _FutureListener.handleValue ', - r'^#12 Future._propagateToListeners.handleValueCallback ', - r'^#13 Future._propagateToListeners ', - r'^#14 Future._completeWithValue ', - r'^#15 _completeOnAsyncReturn ', - r'^#16 doTestAwaitThen ', - r'^#17 _asyncErrorWrapperHelper.errorCallback ', - r'^#18 _RootZone.runBinary ', - r'^#19 _FutureListener.handleError ', - r'^#20 Future._propagateToListeners.handleError ', - r'^#21 Future._propagateToListeners ', - r'^#22 Future._completeError ', - r'^#23 _completeOnAsyncError ', - r'^#24 noYields ', - r'^#25 _asyncErrorWrapperHelper.errorCallback ', - r'^#26 _RootZone.runBinary ', - r'^#27 _FutureListener.handleError ', - r'^#28 Future._propagateToListeners.handleError ', - r'^#29 Future._propagateToListeners ', - r'^#30 Future._completeError ', - r'^#31 _completeOnAsyncError ', - r'^#32 noYields2 ', - r'^#33 _asyncErrorWrapperHelper.errorCallback ', - r'^#34 _RootZone.runBinary ', - r'^#35 _FutureListener.handleError ', - r'^#36 Future._propagateToListeners.handleError ', - r'^#37 Future._propagateToListeners ', - r'^#38 Future._completeError ', - r'^#39 Future._asyncCompleteError. ', - r'^#40 _microtaskLoop ', - r'^#41 _startMicrotaskLoop ', - r'^#42 _runPendingImmediateCallback ', - r'^#43 _RawReceivePortImpl._handleMessage ', - ], - debugInfoFilename); + { + final expected = const [ + r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'^#1 noYields3 \(.*/utils.dart:54(:3)?\)$', + r'^#2 noYields3 \(.*/utils.dart:53(:23)?\)$', + r'^#3 noYields2 \(.*/utils.dart:50(:9)?\)$', + r'^#4 noYields2 \(.*/utils.dart:49(:23)?\)$', + r'^#5 noYields \(.*/utils.dart:46(:9)?\)$', + r'^#6 noYields \(.*/utils.dart:45(:22)?\)$', + ]; + final postfix = const [ + r'^#9 doTestsNoCausalNoLazy ', + r'^#10 _RootZone.runUnary ', + r'^#11 _FutureListener.handleValue ', + r'^#12 Future._propagateToListeners.handleValueCallback ', + r'^#13 Future._propagateToListeners ', + r'^#14 Future._addListener. ', + r'^#15 _microtaskLoop ', + r'^#16 _startMicrotaskLoop ', + r'^#17 _runPendingImmediateCallback ', + r'^#18 _RawReceivePortImpl._handleMessage ', + ]; + await 0; // Don't let the `await do..`s chain together. + await doTestAwait( + noYields, + expected + + const [ + r'^#7 doTestAwait ', + r'^#8 doTestAwait ', + ] + + postfix, + debugInfoFilename); + await 0; // Don't let the `await do..`s chain together. + await doTestAwaitThen( + noYields, + expected + + const [ + r'^#7 doTestAwaitThen ', + r'^#8 doTestAwaitThen ', + ] + + postfix, + debugInfoFilename); + await 0; // Don't let the `await do..`s chain together. + await doTestAwaitCatchError( + noYields, + expected + + const [ + r'^#7 doTestAwaitCatchError ', + r'^#8 doTestAwaitCatchError ', + ] + + postfix, + debugInfoFilename); + } - final mixedYieldsExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^#1 _RootZone.runUnary ', - r'^#2 _FutureListener.handleValue ', - r'^#3 Future._propagateToListeners.handleValueCallback ', - r'^#4 Future._propagateToListeners ', - // TODO(dart-vm): Figure out why this is inconsistent: - r'^#5 Future.(_addListener|_prependListeners). ', - r'^#6 _microtaskLoop ', - r'^#7 _startMicrotaskLoop ', - r'^#8 _runPendingImmediateCallback ', - r'^#9 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait(mixedYields, mixedYieldsExpected, debugInfoFilename); - await doTestAwaitThen(mixedYields, mixedYieldsExpected, debugInfoFilename); - await doTestAwaitCatchError( - mixedYields, mixedYieldsExpected, debugInfoFilename); + { + final expected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^#1 _RootZone.runUnary ', + r'^#2 _FutureListener.handleValue ', + r'^#3 Future._propagateToListeners.handleValueCallback ', + r'^#4 Future._propagateToListeners ', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#5 Future.(_addListener|_prependListeners). ', + r'^#6 _microtaskLoop ', + r'^#7 _startMicrotaskLoop ', + r'^#8 _runPendingImmediateCallback ', + r'^#9 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(mixedYields, expected, debugInfoFilename); + await doTestAwaitThen(mixedYields, expected, debugInfoFilename); + await doTestAwaitCatchError(mixedYields, expected, debugInfoFilename); + } - final syncSuffixExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^#1 _RootZone.runUnary ', - r'^#2 _FutureListener.handleValue ', - r'^#3 Future._propagateToListeners.handleValueCallback ', - r'^#4 Future._propagateToListeners ', - // TODO(dart-vm): Figure out why this is inconsistent: - r'^#5 Future.(_addListener|_prependListeners). ', - r'^#6 _microtaskLoop ', - r'^#7 _startMicrotaskLoop ', - r'^#8 _runPendingImmediateCallback ', - r'^#9 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait(syncSuffix, syncSuffixExpected, debugInfoFilename); - await doTestAwaitThen(syncSuffix, syncSuffixExpected, debugInfoFilename); - await doTestAwaitCatchError( - syncSuffix, syncSuffixExpected, debugInfoFilename); + { + final expected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^#1 _RootZone.runUnary ', + r'^#2 _FutureListener.handleValue ', + r'^#3 Future._propagateToListeners.handleValueCallback ', + r'^#4 Future._propagateToListeners ', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#5 Future.(_addListener|_prependListeners). ', + r'^#6 _microtaskLoop ', + r'^#7 _startMicrotaskLoop ', + r'^#8 _runPendingImmediateCallback ', + r'^#9 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(syncSuffix, expected, debugInfoFilename); + await doTestAwaitThen(syncSuffix, expected, debugInfoFilename); + await doTestAwaitCatchError(syncSuffix, expected, debugInfoFilename); + } - final nonAsyncNoStackExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^#1 _RootZone.runUnary ', - r'^#2 _FutureListener.handleValue ', - r'^#3 Future._propagateToListeners.handleValueCallback ', - r'^#4 Future._propagateToListeners ', - // TODO(dart-vm): Figure out why this is inconsistent: - r'^#5 Future.(_addListener|_prependListeners). ', - r'^#6 _microtaskLoop ', - r'^#7 _startMicrotaskLoop ', - r'^#8 _runPendingImmediateCallback ', - r'^#9 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait( - nonAsyncNoStack, nonAsyncNoStackExpected, debugInfoFilename); - await doTestAwaitThen( - nonAsyncNoStack, nonAsyncNoStackExpected, debugInfoFilename); - await doTestAwaitCatchError( - nonAsyncNoStack, nonAsyncNoStackExpected, debugInfoFilename); + { + final expected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^#1 _RootZone.runUnary ', + r'^#2 _FutureListener.handleValue ', + r'^#3 Future._propagateToListeners.handleValueCallback ', + r'^#4 Future._propagateToListeners ', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#5 Future.(_addListener|_prependListeners). ', + r'^#6 _microtaskLoop ', + r'^#7 _startMicrotaskLoop ', + r'^#8 _runPendingImmediateCallback ', + r'^#9 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(nonAsyncNoStack, expected, debugInfoFilename); + await doTestAwaitThen(nonAsyncNoStack, expected, debugInfoFilename); + await doTestAwaitCatchError(nonAsyncNoStack, expected, debugInfoFilename); + } - final asyncStarThrowSyncExpected = const [ - r'^#0 throwSync \(.+/utils.dart:16(:3)?\)$', - r'^#1 asyncStarThrowSync \(.+/utils.dart:112(:11)?\)$', - r'^#2 _RootZone.runUnary \(.+\)$', - r'^#3 _FutureListener.handleValue \(.+\)$', - r'^#4 Future._propagateToListeners.handleValueCallback \(.+\)$', - r'^#5 Future._propagateToListeners \(.+\)$', - // TODO(dart-vm): Figure out why this is inconsistent: - r'^#6 Future.(_addListener|_prependListeners). \(.+\)$', - r'^#7 _microtaskLoop \(.+\)$', - r'^#8 _startMicrotaskLoop \(.+\)$', - r'^#9 _runPendingImmediateCallback \(.+\)$', - r'^#10 _RawReceivePortImpl._handleMessage \(.+\)$', - ]; - await doTestAwait(awaitEveryAsyncStarThrowSync, asyncStarThrowSyncExpected, - debugInfoFilename); - await doTestAwaitThen(awaitEveryAsyncStarThrowSync, - asyncStarThrowSyncExpected, debugInfoFilename); - await doTestAwaitCatchError(awaitEveryAsyncStarThrowSync, - asyncStarThrowSyncExpected, debugInfoFilename); + { + final expected = const [ + r'^#0 throwSync \(.+/utils.dart:16(:3)?\)$', + r'^#1 asyncStarThrowSync \(.+/utils.dart:112(:11)?\)$', + r'^#2 _RootZone.runUnary \(.+\)$', + r'^#3 _FutureListener.handleValue \(.+\)$', + r'^#4 Future._propagateToListeners.handleValueCallback \(.+\)$', + r'^#5 Future._propagateToListeners \(.+\)$', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#6 Future.(_addListener|_prependListeners). \(.+\)$', + r'^#7 _microtaskLoop \(.+\)$', + r'^#8 _startMicrotaskLoop \(.+\)$', + r'^#9 _runPendingImmediateCallback \(.+\)$', + r'^#10 _RawReceivePortImpl._handleMessage \(.+\)$', + ]; + await doTestAwait( + awaitEveryAsyncStarThrowSync, expected, debugInfoFilename); + await doTestAwaitThen( + awaitEveryAsyncStarThrowSync, expected, debugInfoFilename); + await doTestAwaitCatchError( + awaitEveryAsyncStarThrowSync, expected, debugInfoFilename); + } - final asyncStarThrowAsyncExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^#1 _RootZone.runUnary ', - r'^#2 _FutureListener.handleValue ', - r'^#3 Future._propagateToListeners.handleValueCallback ', - r'^#4 Future._propagateToListeners ', - // TODO(dart-vm): Figure out why this is inconsistent: - r'^#5 Future.(_addListener|_prependListeners). ', - r'^#6 _microtaskLoop ', - r'^#7 _startMicrotaskLoop ', - r'^#8 _runPendingImmediateCallback ', - r'^#9 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait(awaitEveryAsyncStarThrowAsync, asyncStarThrowAsyncExpected, - debugInfoFilename); - await doTestAwaitThen(awaitEveryAsyncStarThrowAsync, - asyncStarThrowAsyncExpected, debugInfoFilename); - await doTestAwaitCatchError(awaitEveryAsyncStarThrowAsync, - asyncStarThrowAsyncExpected, debugInfoFilename); + { + final expected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^#1 _RootZone.runUnary ', + r'^#2 _FutureListener.handleValue ', + r'^#3 Future._propagateToListeners.handleValueCallback ', + r'^#4 Future._propagateToListeners ', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#5 Future.(_addListener|_prependListeners). ', + r'^#6 _microtaskLoop ', + r'^#7 _startMicrotaskLoop ', + r'^#8 _runPendingImmediateCallback ', + r'^#9 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait( + awaitEveryAsyncStarThrowAsync, expected, debugInfoFilename); + await doTestAwaitThen( + awaitEveryAsyncStarThrowAsync, expected, debugInfoFilename); + await doTestAwaitCatchError( + awaitEveryAsyncStarThrowAsync, expected, debugInfoFilename); + } - final listenAsyncStartExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^#1 _RootZone.runUnary ', - r'^#2 _FutureListener.handleValue ', - r'^#3 Future._propagateToListeners.handleValueCallback ', - r'^#4 Future._propagateToListeners ', - // TODO(dart-vm): Figure out why this is inconsistent: - r'^#5 Future.(_addListener|_prependListeners). ', - r'^#6 _microtaskLoop ', - r'^#7 _startMicrotaskLoop ', - r'^#8 _runPendingImmediateCallback ', - r'^#9 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait( - listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); - await doTestAwaitThen( - listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); - await doTestAwaitCatchError( - listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); + { + final expected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^#1 _RootZone.runUnary ', + r'^#2 _FutureListener.handleValue ', + r'^#3 Future._propagateToListeners.handleValueCallback ', + r'^#4 Future._propagateToListeners ', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#5 Future.(_addListener|_prependListeners). ', + r'^#6 _microtaskLoop ', + r'^#7 _startMicrotaskLoop ', + r'^#8 _runPendingImmediateCallback ', + r'^#9 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(listenAsyncStarThrowAsync, expected, debugInfoFilename); + await doTestAwaitThen( + listenAsyncStarThrowAsync, expected, debugInfoFilename); + await doTestAwaitCatchError( + listenAsyncStarThrowAsync, expected, debugInfoFilename); + } - final customErrorZoneExpected = const [ - r'#0 throwSync \(.*/utils.dart:16(:3)?\)$', - r'#1 allYield3 \(.*/utils.dart:39(:3)?\)$', - r'#2 _rootRunUnary ', - r'#3 _CustomZone.runUnary ', - r'#4 _FutureListener.handleValue ', - r'#5 Future._propagateToListeners.handleValueCallback ', - r'#6 Future._propagateToListeners ', - r'#7 Future.(_addListener|_prependListeners). ', - r'#8 _rootRun ', - r'#9 _CustomZone.run ', - r'#10 _CustomZone.runGuarded ', - r'#11 _CustomZone.bindCallbackGuarded. ', - r'#12 _microtaskLoop ', - r'#13 _startMicrotaskLoop ', - r'#14 _runPendingImmediateCallback ', - r'#15 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait( - customErrorZone, customErrorZoneExpected, debugInfoFilename); - await doTestAwaitThen( - customErrorZone, customErrorZoneExpected, debugInfoFilename); - await doTestAwaitCatchError( - customErrorZone, customErrorZoneExpected, debugInfoFilename); + { + final expected = const [ + r'#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'#1 allYield3 \(.*/utils.dart:39(:3)?\)$', + r'#2 _rootRunUnary ', + r'#3 _CustomZone.runUnary ', + r'#4 _FutureListener.handleValue ', + r'#5 Future._propagateToListeners.handleValueCallback ', + r'#6 Future._propagateToListeners ', + r'#7 Future.(_addListener|_prependListeners). ', + r'#8 _rootRun ', + r'#9 _CustomZone.run ', + r'#10 _CustomZone.runGuarded ', + r'#11 _CustomZone.bindCallbackGuarded. ', + r'#12 _microtaskLoop ', + r'#13 _startMicrotaskLoop ', + r'#14 _runPendingImmediateCallback ', + r'#15 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(customErrorZone, expected, debugInfoFilename); + await doTestAwaitThen(customErrorZone, expected, debugInfoFilename); + await doTestAwaitCatchError(customErrorZone, expected, debugInfoFilename); + } - final awaitTimeoutExpected = const [ - r'#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^#1 _RootZone.runUnary ', - r'^#2 _FutureListener.handleValue ', - r'^#3 Future._propagateToListeners.handleValueCallback ', - r'^#4 Future._propagateToListeners ', - r'^#5 Future.(_addListener|_prependListeners). ', - r'^#6 _microtaskLoop ', - r'^#7 _startMicrotaskLoop ', - r'^#8 _runPendingImmediateCallback ', - r'^#9 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait(awaitTimeout, awaitTimeoutExpected, debugInfoFilename); - await doTestAwaitThen(awaitTimeout, awaitTimeoutExpected, debugInfoFilename); - await doTestAwaitCatchError( - awaitTimeout, awaitTimeoutExpected, debugInfoFilename); + { + final expected = const [ + r'#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^#1 _RootZone.runUnary ', + r'^#2 _FutureListener.handleValue ', + r'^#3 Future._propagateToListeners.handleValueCallback ', + r'^#4 Future._propagateToListeners ', + r'^#5 Future.(_addListener|_prependListeners). ', + r'^#6 _microtaskLoop ', + r'^#7 _startMicrotaskLoop ', + r'^#8 _runPendingImmediateCallback ', + r'^#9 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(awaitTimeout, expected, debugInfoFilename); + await doTestAwaitThen(awaitTimeout, expected, debugInfoFilename); + await doTestAwaitCatchError(awaitTimeout, expected, debugInfoFilename); + } - final awaitWaitExpected = const [ - r'#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^#1 _RootZone.runUnary ', - r'^#2 _FutureListener.handleValue ', - r'^#3 Future._propagateToListeners.handleValueCallback ', - r'^#4 Future._propagateToListeners ', - r'^#5 Future.(_addListener|_prependListeners). ', - r'^#6 _microtaskLoop ', - r'^#7 _startMicrotaskLoop ', - r'^#8 _runPendingImmediateCallback ', - r'^#9 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait(awaitWait, awaitWaitExpected, debugInfoFilename); - await doTestAwaitThen(awaitWait, awaitWaitExpected, debugInfoFilename); - await doTestAwaitCatchError(awaitWait, awaitWaitExpected, debugInfoFilename); + { + final expected = const [ + r'#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^#1 _RootZone.runUnary ', + r'^#2 _FutureListener.handleValue ', + r'^#3 Future._propagateToListeners.handleValueCallback ', + r'^#4 Future._propagateToListeners ', + r'^#5 Future.(_addListener|_prependListeners). ', + r'^#6 _microtaskLoop ', + r'^#7 _startMicrotaskLoop ', + r'^#8 _runPendingImmediateCallback ', + r'^#9 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(awaitWait, expected, debugInfoFilename); + await doTestAwaitThen(awaitWait, expected, debugInfoFilename); + await doTestAwaitCatchError(awaitWait, expected, debugInfoFilename); + } { final expected = const [ @@ -642,333 +572,501 @@ Future doTestsNoCausalNoLazy([String? debugInfoFilename]) async { await doTestAwaitCatchError( futureSyncWhenComplete, expected, debugInfoFilename); } + + { + final expected = const [ + r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'^#1 futureThen. \(.*/utils.dart:187(:5)?\)$', + r'^#2 _RootZone.runUnary ', + r'^#3 _FutureListener.handleValue ', + r'^#4 Future._propagateToListeners.handleValueCallback ', + r'^#5 Future._propagateToListeners ', + r'^#6 Future._completeWithValue ', + r'^#7 Future._asyncCompleteWithValue. ', + r'^#8 _microtaskLoop ', + r'^#9 _startMicrotaskLoop ', + r'^#10 _runPendingImmediateCallback ', + r'^#11 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(futureThen, expected, debugInfoFilename); + await doTestAwaitThen(futureThen, expected, debugInfoFilename); + await doTestAwaitCatchError(futureThen, expected, debugInfoFilename); + } } // For: --lazy-async-stacks Future doTestsLazy([String? debugInfoFilename]) async { - final allYieldExpected = const [ - r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', - r'^#1 allYield3 \(.*/utils.dart:39(:3)?\)$', - r'^$', - r'^#2 allYield2 \(.*/utils.dart:34(:3)?\)$', - r'^$', - r'^#3 allYield \(.*/utils.dart:29(:3)?\)$', - r'^$', - ]; - await doTestAwait( - allYield, - allYieldExpected + - const [ - r'^#4 doTestAwait ', - r'^$', - r'^#5 doTestsLazy ', - r'^$', - r'^#6 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - allYield, - allYieldExpected + - const [ - r'^#4 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError(allYield, allYieldExpected, debugInfoFilename); + // allYield + { + final allYieldExpected = const [ + r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'^#1 allYield3 \(.*/utils.dart:39(:3)?\)$', + r'^$', + r'^#2 allYield2 \(.*/utils.dart:34(:3)?\)$', + r'^$', + r'^#3 allYield \(.*/utils.dart:29(:3)?\)$', + r'^$', + ]; + await doTestAwait( + allYield, + allYieldExpected + + const [ + r'^#4 doTestAwait ', + r'^$', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + allYield, + allYieldExpected + + const [ + r'^#4 doTestAwaitThen ', + r'^$', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + allYield, + allYieldExpected + + const [ + r'^#4 doTestAwaitCatchError ', + r'^$', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + } - final noYieldsExpected = const [ - r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', - r'^#1 noYields3 \(.*/utils.dart:54(:3)?\)$', - r'^#2 noYields2 \(.*/utils.dart:50(:9)?\)$', - r'^#3 noYields \(.*/utils.dart:46(:9)?\)$', - ]; - await doTestAwait( - noYields, - noYieldsExpected + - const [ - r'^#4 doTestAwait ', - r'^#5 doTestsLazy ', - r'^$', - r'^#6 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - noYields, - noYieldsExpected + - const [ - r'^#4 doTestAwaitThen ', - r'^#5 doTestsLazy ', - r'^$', - r'^#6 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError( - noYields, - noYieldsExpected + - const [ - r'^#4 doTestAwaitCatchError ', - r'^#5 doTestsLazy ', - r'^$', - r'^#6 main ', - r'^$', - ], - debugInfoFilename); + // noYields + { + final noYieldsExpected = const [ + r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'^#1 noYields3 \(.*/utils.dart:54(:3)?\)$', + r'^#2 noYields2 \(.*/utils.dart:50(:9)?\)$', + r'^#3 noYields \(.*/utils.dart:46(:9)?\)$', + ]; + await doTestAwait( + noYields, + noYieldsExpected + + const [ + r'^#4 doTestAwait ', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + noYields, + noYieldsExpected + + const [ + r'^#4 doTestAwaitThen ', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + noYields, + noYieldsExpected + + const [ + r'^#4 doTestAwaitCatchError ', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + } - final mixedYieldsExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^$', - r'^#1 mixedYields3 \(.*/utils.dart:70(:3)?\)$', - r'^$', - r'^#2 mixedYields2 \(.*/utils.dart:66(:3)?\)$', - r'^$', - r'^#3 mixedYields \(.*/utils.dart:61(:3)?\)$', - r'^$', - ]; - await doTestAwait( - mixedYields, - mixedYieldsExpected + - const [ - r'^#4 doTestAwait ', - r'^$', - r'^#5 doTestsLazy ', - r'^$', - r'^#6 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - mixedYields, - mixedYieldsExpected + - const [ - r'^#4 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError( - mixedYields, mixedYieldsExpected, debugInfoFilename); + // mixedYields + { + final mixedYieldsExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^$', + r'^#1 mixedYields3 \(.*/utils.dart:70(:3)?\)$', + r'^$', + r'^#2 mixedYields2 \(.*/utils.dart:66(:3)?\)$', + r'^$', + r'^#3 mixedYields \(.*/utils.dart:61(:3)?\)$', + r'^$', + ]; + await doTestAwait( + mixedYields, + mixedYieldsExpected + + const [ + r'^#4 doTestAwait ', + r'^$', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + mixedYields, + mixedYieldsExpected + + const [ + r'^#4 doTestAwaitThen ', + r'^$', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + mixedYields, + mixedYieldsExpected + + const [ + r'^#4 doTestAwaitCatchError ', + r'^$', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + } - final syncSuffixExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^$', - r'^#1 syncSuffix2 \(.*/utils.dart:82(:3)?\)$', - r'^$', - r'^#2 syncSuffix \(.*/utils.dart:77(:3)?\)$', - r'^$', - ]; - await doTestAwait( - syncSuffix, - syncSuffixExpected + - const [ - r'^#3 doTestAwait ', - r'^$', - r'^#4 doTestsLazy ', - r'^$', - r'^#5 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - syncSuffix, - syncSuffixExpected + - const [ - r'^#3 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError( - syncSuffix, syncSuffixExpected, debugInfoFilename); + // syncSuffix + { + final syncSuffixExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^$', + r'^#1 syncSuffix2 \(.*/utils.dart:82(:3)?\)$', + r'^$', + r'^#2 syncSuffix \(.*/utils.dart:77(:3)?\)$', + r'^$', + ]; + await doTestAwait( + syncSuffix, + syncSuffixExpected + + const [ + r'^#3 doTestAwait ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + syncSuffix, + syncSuffixExpected + + const [ + r'^#3 doTestAwaitThen ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + syncSuffix, + syncSuffixExpected + + const [ + r'^#3 doTestAwaitCatchError ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + } - final nonAsyncNoStackExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^$', - r'^#1 nonAsyncNoStack2 \(.*/utils.dart:97(:36)?\)$', - r'^$', - r'^#2 nonAsyncNoStack1 \(.*/utils.dart:95(:36)?\)$', - r'^$', - r'^#3 nonAsyncNoStack \(.*/utils.dart:93(:35)?\)$', - r'^$', - ]; - await doTestAwait( - nonAsyncNoStack, - nonAsyncNoStackExpected + - const [ - r'^#4 doTestAwait ', - r'^$', - r'^#5 doTestsLazy ', - r'^$', - r'^#6 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - nonAsyncNoStack, - nonAsyncNoStackExpected + - const [ - r'^#4 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError( - nonAsyncNoStack, nonAsyncNoStackExpected, debugInfoFilename); + // nonAsyncNoStack + { + final nonAsyncNoStackExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^$', + r'^#1 nonAsyncNoStack2 \(.*/utils.dart:97(:36)?\)$', + r'^$', + r'^#2 nonAsyncNoStack1 \(.*/utils.dart:95(:36)?\)$', + r'^$', + r'^#3 nonAsyncNoStack \(.*/utils.dart:93(:35)?\)$', + r'^$', + ]; + await doTestAwait( + nonAsyncNoStack, + nonAsyncNoStackExpected + + const [ + r'^#4 doTestAwait ', + r'^$', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + nonAsyncNoStack, + nonAsyncNoStackExpected + + const [ + r'^#4 doTestAwaitThen ', + r'^$', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + nonAsyncNoStack, + nonAsyncNoStackExpected + + const [ + r'^#4 doTestAwaitCatchError ', + r'^$', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + } - final asyncStarThrowSyncExpected = const [ - r'^#0 throwSync \(.+/utils.dart:16(:3)?\)$', - r'^#1 asyncStarThrowSync \(.+/utils.dart:112(:11)?\)$', - r'^$', - r'^#2 awaitEveryAsyncStarThrowSync \(.+/utils.dart:104(:3)?\)$', - r'^$', - ]; - await doTestAwait( - awaitEveryAsyncStarThrowSync, - asyncStarThrowSyncExpected + - const [ - r'^#3 doTestAwait ', - r'^$', - r'^#4 doTestsLazy ', - r'^$', - r'^#5 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - awaitEveryAsyncStarThrowSync, - asyncStarThrowSyncExpected + - const [ - r'^#3 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError(awaitEveryAsyncStarThrowSync, - asyncStarThrowSyncExpected, debugInfoFilename); + // awaitEveryAsyncStarThrowSync + { + final asyncStarThrowSyncExpected = const [ + r'^#0 throwSync \(.+/utils.dart:16(:3)?\)$', + r'^#1 asyncStarThrowSync \(.+/utils.dart:112(:11)?\)$', + r'^$', + r'^#2 awaitEveryAsyncStarThrowSync \(.+/utils.dart:104(:3)?\)$', + r'^$', + ]; + await doTestAwait( + awaitEveryAsyncStarThrowSync, + asyncStarThrowSyncExpected + + const [ + r'^#3 doTestAwait ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + awaitEveryAsyncStarThrowSync, + asyncStarThrowSyncExpected + + const [ + r'^#3 doTestAwaitThen ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + awaitEveryAsyncStarThrowSync, + asyncStarThrowSyncExpected + + const [ + r'^#3 doTestAwaitCatchError ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + } - final asyncStarThrowAsyncExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^$', - r'^#1 asyncStarThrowAsync \(.*/utils.dart:126(:5)?\)$', - r'^$', - r'^#2 awaitEveryAsyncStarThrowAsync \(.+/utils.dart:117(:3)?\)$', - r'^$', - ]; - await doTestAwait( - awaitEveryAsyncStarThrowAsync, - asyncStarThrowAsyncExpected + - const [ - r'^#3 doTestAwait ', - r'^$', - r'^#4 doTestsLazy ', - r'^$', - r'^#5 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - awaitEveryAsyncStarThrowAsync, - asyncStarThrowAsyncExpected + - const [ - r'^#3 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError(awaitEveryAsyncStarThrowAsync, - asyncStarThrowAsyncExpected, debugInfoFilename); + // awaitEveryAsyncStarThrowAsync + { + final asyncStarThrowAsyncExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^$', + r'^#1 asyncStarThrowAsync \(.*/utils.dart:126(:5)?\)$', + r'^$', + r'^#2 awaitEveryAsyncStarThrowAsync \(.+/utils.dart:117(:3)?\)$', + r'^$', + ]; + await doTestAwait( + awaitEveryAsyncStarThrowAsync, + asyncStarThrowAsyncExpected + + const [ + r'^#3 doTestAwait ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + awaitEveryAsyncStarThrowAsync, + asyncStarThrowAsyncExpected + + const [ + r'^#3 doTestAwaitThen ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + awaitEveryAsyncStarThrowAsync, + asyncStarThrowAsyncExpected + + const [ + r'^#3 doTestAwaitCatchError ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + } - final listenAsyncStartExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^$', - r'^#1 asyncStarThrowAsync \(.*/utils.dart:126(:5)?\)$', - r'^$', - r'^#2 listenAsyncStarThrowAsync. \(.+/utils.dart(:0)?\)$', - r'^$', - ]; - await doTestAwait( - listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); - await doTestAwaitThen( - listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); - await doTestAwaitCatchError( - listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); + // listenAsyncStarThrowAsync + { + final listenAsyncStartExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^$', + r'^#1 asyncStarThrowAsync \(.*/utils.dart:126(:5)?\)$', + r'^$', + r'^#2 listenAsyncStarThrowAsync. \(.+/utils.dart(:0)?\)$', + r'^$', + ]; + await doTestAwait( + listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); + await doTestAwaitThen( + listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); + await doTestAwaitCatchError( + listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); + } - final customErrorZoneExpected = const [ - r'#0 throwSync \(.*/utils.dart:16(:3)?\)$', - r'#1 allYield3 \(.*/utils.dart:39(:3)?\)$', - r'$', - r'#2 allYield2 \(.*/utils.dart:34(:3)?\)$', - r'$', - r'#3 allYield \(.*/utils.dart:29(:3)?\)$', - r'$', - r'#4 customErrorZone. \(.*/utils.dart:144(:5)?\)$', - r'$', - ]; - await doTestAwait( - customErrorZone, customErrorZoneExpected, debugInfoFilename); - await doTestAwaitThen( - customErrorZone, customErrorZoneExpected, debugInfoFilename); - await doTestAwaitCatchError( - customErrorZone, customErrorZoneExpected, debugInfoFilename); + // customErrorZone + { + final customErrorZoneExpected = const [ + r'#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'#1 allYield3 \(.*/utils.dart:39(:3)?\)$', + r'$', + r'#2 allYield2 \(.*/utils.dart:34(:3)?\)$', + r'$', + r'#3 allYield \(.*/utils.dart:29(:3)?\)$', + r'$', + r'#4 customErrorZone. \(.*/utils.dart:144(:5)?\)$', + r'$', + ]; + await doTestAwait( + customErrorZone, customErrorZoneExpected, debugInfoFilename); + await doTestAwaitThen( + customErrorZone, customErrorZoneExpected, debugInfoFilename); + await doTestAwaitCatchError( + customErrorZone, customErrorZoneExpected, debugInfoFilename); + } - final awaitTimeoutExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^$', - r'^#1 Future.timeout. \(dart:async/future_impl.dart', - r'^$', - r'^#2 awaitTimeout ', - r'^$', - ]; - await doTestAwait( - awaitTimeout, - awaitTimeoutExpected + - const [ - r'^#3 doTestAwait ', - r'^$', - r'^#4 doTestsLazy ', - r'^$', - r'^#5 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - awaitTimeout, - awaitTimeoutExpected + - const [ - r'^#3 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError( - awaitTimeout, awaitTimeoutExpected, debugInfoFilename); + // awaitTimeout + { + final awaitTimeoutExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^$', + r'^#1 Future.timeout. \(dart:async/future_impl.dart', + r'^$', + r'^#2 awaitTimeout ', + r'^$', + ]; + await doTestAwait( + awaitTimeout, + awaitTimeoutExpected + + const [ + r'^#3 doTestAwait ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + awaitTimeout, + awaitTimeoutExpected + + const [ + r'^#3 doTestAwaitThen ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + awaitTimeout, + awaitTimeoutExpected + + const [ + r'^#3 doTestAwaitCatchError ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + } - final awaitWaitExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^$', - r'^#1 Future.wait. \(dart:async/future.dart', - r'^$', - r'^#2 awaitWait ', - r'^$', - ]; - await doTestAwait( - awaitWait, - awaitWaitExpected + - const [ - r'^#3 doTestAwait ', - r'^$', - r'^#4 doTestsLazy ', - r'^$', - r'^#5 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - awaitWait, - awaitWaitExpected + - const [ - r'^#3 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError(awaitWait, awaitWaitExpected, debugInfoFilename); + // awaitWait + { + final awaitWaitExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^$', + r'^#1 Future.wait. \(dart:async/future.dart', + r'^$', + r'^#2 awaitWait ', + r'^$', + ]; + await doTestAwait( + awaitWait, + awaitWaitExpected + + const [ + r'^#3 doTestAwait ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + awaitWait, + awaitWaitExpected + + const [ + r'^#3 doTestAwaitThen ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + awaitWait, + awaitWaitExpected + + const [ + r'^#3 doTestAwaitCatchError ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + } + // futureSyncWhenComplete { final expected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', @@ -990,11 +1088,70 @@ Future doTestsLazy([String? debugInfoFilename]) async { futureSyncWhenComplete, expected + const [ - r'^#1 doTestAwaitThen. ', + r'^#1 doTestAwaitThen ', + r'^$', + r'^#2 doTestsLazy ', + r'^$', + r'^#3 main ', r'^$', ], debugInfoFilename); await doTestAwaitCatchError( - futureSyncWhenComplete, expected, debugInfoFilename); + futureSyncWhenComplete, + expected + + const [ + r'^#1 doTestAwaitCatchError ', + r'^$', + r'^#2 doTestsLazy ', + r'^$', + r'^#3 main ', + r'^$', + ], + debugInfoFilename); + } + + // futureThen + { + final expected = const [ + r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'^#1 futureThen. ', + r'^$', + ]; + await doTestAwait( + futureThen, + expected + + const [ + r'^#2 doTestAwait ', + r'^$', + r'^#3 doTestsLazy ', + r'^$', + r'^#4 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + futureThen, + expected + + const [ + r'^#2 doTestAwaitThen ', + r'^$', + r'^#3 doTestsLazy ', + r'^$', + r'^#4 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + futureThen, + expected + + const [ + r'^#2 doTestAwaitCatchError ', + r'^$', + r'^#3 doTestsLazy ', + r'^$', + r'^#4 main ', + r'^$', + ], + debugInfoFilename); } } diff --git a/runtime/tests/vm/dart_2/causal_stacks/utils.dart b/runtime/tests/vm/dart_2/causal_stacks/utils.dart index 192984fe79e..12083bed6b0 100644 --- a/runtime/tests/vm/dart_2/causal_stacks/utils.dart +++ b/runtime/tests/vm/dart_2/causal_stacks/utils.dart @@ -178,12 +178,22 @@ Future futureSyncWhenComplete() { return Future.sync(throwAsync).whenComplete(() => 'nop'); } +// ---- +// Scenario: Future.then: +// ---- + +Future futureThen() { + return Future.value(0).then((value) { + throwSync(); + }); +} + // Helpers: // We want lines that either start with a frame index or an async gap marker. final _lineRE = RegExp(r'^(?:#(?\d+)|)'); -void assertStack(List expects, StackTrace stackTrace, +Future assertStack(List expects, StackTrace stackTrace, [String debugInfoFilename]) async { final original = await Stream.value(stackTrace.toString()) .transform(const LineSplitter()) @@ -253,7 +263,7 @@ Future doTestAwait(Future f(), List expectedStack, await f(); Expect.fail('No exception thrown!'); } on String catch (e, s) { - assertStack(expectedStack, s, debugInfoFilename); + return assertStack(expectedStack, s, debugInfoFilename); } } @@ -267,7 +277,7 @@ Future doTestAwaitThen(Future f(), List expectedStack, await f().then((e) => Expect.fail('No exception thrown!')); Expect.fail('No exception thrown!'); } on String catch (e, s) { - assertStack(expectedStack, s, debugInfoFilename); + return assertStack(expectedStack, s, debugInfoFilename); } } @@ -278,7 +288,7 @@ Future doTestAwaitCatchError(Future f(), List expectedStack, await f().catchError((e, s) { stackTrace = s; }); - assertStack(expectedStack, stackTrace, debugInfoFilename); + return assertStack(expectedStack, stackTrace, debugInfoFilename); } // ---- @@ -287,342 +297,262 @@ Future doTestAwaitCatchError(Future f(), List expectedStack, // For: --no-lazy-async-stacks Future doTestsNoCausalNoLazy([String debugInfoFilename]) async { - final allYieldExpected = const [ - r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', - r'^#1 allYield3 \(.*/utils.dart:39(:3)?\)$', - r'^#2 _RootZone.runUnary ', - r'^#3 _FutureListener.handleValue ', - r'^#4 Future._propagateToListeners.handleValueCallback ', - r'^#5 Future._propagateToListeners ', - // TODO(dart-vm): Figure out why this is inconsistent: - r'^#6 Future.(_addListener|_prependListeners). ', - r'^#7 _microtaskLoop ', - r'^#8 _startMicrotaskLoop ', - r'^#9 _runPendingImmediateCallback ', - r'^#10 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait(allYield, allYieldExpected, debugInfoFilename); - await doTestAwaitThen(allYield, allYieldExpected, debugInfoFilename); - await doTestAwaitCatchError(allYield, allYieldExpected, debugInfoFilename); + { + final expected = const [ + r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'^#1 allYield3 \(.*/utils.dart:39(:3)?\)$', + r'^#2 _RootZone.runUnary ', + r'^#3 _FutureListener.handleValue ', + r'^#4 Future._propagateToListeners.handleValueCallback ', + r'^#5 Future._propagateToListeners ', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#6 Future.(_addListener|_prependListeners). ', + r'^#7 _microtaskLoop ', + r'^#8 _startMicrotaskLoop ', + r'^#9 _runPendingImmediateCallback ', + r'^#10 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(allYield, expected, debugInfoFilename); + await doTestAwaitThen(allYield, expected, debugInfoFilename); + await doTestAwaitCatchError(allYield, expected, debugInfoFilename); + } - final noYieldsExpected = const [ - r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', - r'^#1 noYields3 \(.*/utils.dart:54(:3)?\)$', - r'^#2 noYields3 \(.*/utils.dart:53(:23)?\)$', - r'^#3 noYields2 \(.*/utils.dart:50(:9)?\)$', - r'^#4 noYields2 \(.*/utils.dart:49(:23)?\)$', - r'^#5 noYields \(.*/utils.dart:46(:9)?\)$', - r'^#6 noYields \(.*/utils.dart:45(:22)?\)$', - ]; - await doTestAwait( - noYields, - noYieldsExpected + - const [ - r'^#7 doTestAwait ', - r'^#8 doTestAwait ', - r'^#9 doTestsNoCausalNoLazy ', - r'^#10 _RootZone.runUnary ', - r'^#11 _FutureListener.handleValue ', - r'^#12 Future._propagateToListeners.handleValueCallback ', - r'^#13 Future._propagateToListeners ', - r'^#14 Future._completeWithValue ', - r'^#15 _completeOnAsyncReturn ', - r'^#16 doTestAwaitCatchError ', - r'^#17 _RootZone.runUnary ', - r'^#18 _FutureListener.handleValue ', - r'^#19 Future._propagateToListeners.handleValueCallback ', - r'^#20 Future._propagateToListeners ', - r'^#21 Future._completeError ', - r'^#22 _completeOnAsyncError ', - r'^#23 allYield ', - r'^#24 _asyncErrorWrapperHelper.errorCallback ', - r'^#25 _RootZone.runBinary ', - r'^#26 _FutureListener.handleError ', - r'^#27 Future._propagateToListeners.handleError ', - r'^#28 Future._propagateToListeners ', - r'^#29 Future._completeError ', - r'^#30 _completeOnAsyncError ', - r'^#31 allYield2 ', - r'^#32 _asyncErrorWrapperHelper.errorCallback ', - r'^#33 _RootZone.runBinary ', - r'^#34 _FutureListener.handleError ', - r'^#35 Future._propagateToListeners.handleError ', - r'^#36 Future._propagateToListeners ', - r'^#37 Future._completeError ', - r'^#38 _completeOnAsyncError ', - r'^#39 allYield3 ', - r'^#40 _RootZone.runUnary ', - r'^#41 _FutureListener.handleValue ', - r'^#42 Future._propagateToListeners.handleValueCallback ', - r'^#43 Future._propagateToListeners ', - r'^#44 Future._addListener. ', - r'^#45 _microtaskLoop ', - r'^#46 _startMicrotaskLoop ', - r'^#47 _runPendingImmediateCallback ', - r'^#48 _RawReceivePortImpl._handleMessage ', - ], - debugInfoFilename); - await doTestAwaitThen( - noYields, - noYieldsExpected + - const [ - r'^#7 doTestAwaitThen ', - r'^#8 doTestAwaitThen ', - r'^#9 doTestsNoCausalNoLazy ', - r'^#10 _RootZone.runUnary ', - r'^#11 _FutureListener.handleValue ', - r'^#12 Future._propagateToListeners.handleValueCallback ', - r'^#13 Future._propagateToListeners ', - r'^#14 Future._completeWithValue ', - r'^#15 _completeOnAsyncReturn ', - r'^#16 doTestAwait ', - r'^#17 _asyncErrorWrapperHelper.errorCallback ', - r'^#18 _RootZone.runBinary ', - r'^#19 _FutureListener.handleError ', - r'^#20 Future._propagateToListeners.handleError ', - r'^#21 Future._propagateToListeners ', - r'^#22 Future._completeError ', - r'^#23 _completeOnAsyncError ', - r'^#24 noYields ', - r'^#25 _asyncErrorWrapperHelper.errorCallback ', - r'^#26 _RootZone.runBinary ', - r'^#27 _FutureListener.handleError ', - r'^#28 Future._propagateToListeners.handleError ', - r'^#29 Future._propagateToListeners ', - r'^#30 Future._completeError ', - r'^#31 _completeOnAsyncError ', - r'^#32 noYields2 ', - r'^#33 _asyncErrorWrapperHelper.errorCallback ', - r'^#34 _RootZone.runBinary ', - r'^#35 _FutureListener.handleError ', - r'^#36 Future._propagateToListeners.handleError ', - r'^#37 Future._propagateToListeners ', - r'^#38 Future._completeError ', - r'^#39 Future._asyncCompleteError. ', - r'^#40 _microtaskLoop ', - r'^#41 _startMicrotaskLoop ', - r'^#42 _runPendingImmediateCallback ', - r'^#43 _RawReceivePortImpl._handleMessage ', - ], - debugInfoFilename); - await doTestAwaitCatchError( - noYields, - noYieldsExpected + - const [ - r'^#7 doTestAwaitCatchError ', - r'^#8 doTestAwaitCatchError ', - r'^#9 doTestsNoCausalNoLazy ', - r'^#10 _RootZone.runUnary ', - r'^#11 _FutureListener.handleValue ', - r'^#12 Future._propagateToListeners.handleValueCallback ', - r'^#13 Future._propagateToListeners ', - r'^#14 Future._completeWithValue ', - r'^#15 _completeOnAsyncReturn ', - r'^#16 doTestAwaitThen ', - r'^#17 _asyncErrorWrapperHelper.errorCallback ', - r'^#18 _RootZone.runBinary ', - r'^#19 _FutureListener.handleError ', - r'^#20 Future._propagateToListeners.handleError ', - r'^#21 Future._propagateToListeners ', - r'^#22 Future._completeError ', - r'^#23 _completeOnAsyncError ', - r'^#24 noYields ', - r'^#25 _asyncErrorWrapperHelper.errorCallback ', - r'^#26 _RootZone.runBinary ', - r'^#27 _FutureListener.handleError ', - r'^#28 Future._propagateToListeners.handleError ', - r'^#29 Future._propagateToListeners ', - r'^#30 Future._completeError ', - r'^#31 _completeOnAsyncError ', - r'^#32 noYields2 ', - r'^#33 _asyncErrorWrapperHelper.errorCallback ', - r'^#34 _RootZone.runBinary ', - r'^#35 _FutureListener.handleError ', - r'^#36 Future._propagateToListeners.handleError ', - r'^#37 Future._propagateToListeners ', - r'^#38 Future._completeError ', - r'^#39 Future._asyncCompleteError. ', - r'^#40 _microtaskLoop ', - r'^#41 _startMicrotaskLoop ', - r'^#42 _runPendingImmediateCallback ', - r'^#43 _RawReceivePortImpl._handleMessage ', - ], - debugInfoFilename); + { + final expected = const [ + r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'^#1 noYields3 \(.*/utils.dart:54(:3)?\)$', + r'^#2 noYields3 \(.*/utils.dart:53(:23)?\)$', + r'^#3 noYields2 \(.*/utils.dart:50(:9)?\)$', + r'^#4 noYields2 \(.*/utils.dart:49(:23)?\)$', + r'^#5 noYields \(.*/utils.dart:46(:9)?\)$', + r'^#6 noYields \(.*/utils.dart:45(:22)?\)$', + ]; + final postfix = const [ + r'^#9 doTestsNoCausalNoLazy ', + r'^#10 _RootZone.runUnary ', + r'^#11 _FutureListener.handleValue ', + r'^#12 Future._propagateToListeners.handleValueCallback ', + r'^#13 Future._propagateToListeners ', + r'^#14 Future._addListener. ', + r'^#15 _microtaskLoop ', + r'^#16 _startMicrotaskLoop ', + r'^#17 _runPendingImmediateCallback ', + r'^#18 _RawReceivePortImpl._handleMessage ', + ]; + await 0; // Don't let the `await do..`s chain together. + await doTestAwait( + noYields, + expected + + const [ + r'^#7 doTestAwait ', + r'^#8 doTestAwait ', + ] + + postfix, + debugInfoFilename); + await 0; // Don't let the `await do..`s chain together. + await doTestAwaitThen( + noYields, + expected + + const [ + r'^#7 doTestAwaitThen ', + r'^#8 doTestAwaitThen ', + ] + + postfix, + debugInfoFilename); + await 0; // Don't let the `await do..`s chain together. + await doTestAwaitCatchError( + noYields, + expected + + const [ + r'^#7 doTestAwaitCatchError ', + r'^#8 doTestAwaitCatchError ', + ] + + postfix, + debugInfoFilename); + } - final mixedYieldsExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^#1 _RootZone.runUnary ', - r'^#2 _FutureListener.handleValue ', - r'^#3 Future._propagateToListeners.handleValueCallback ', - r'^#4 Future._propagateToListeners ', - // TODO(dart-vm): Figure out why this is inconsistent: - r'^#5 Future.(_addListener|_prependListeners). ', - r'^#6 _microtaskLoop ', - r'^#7 _startMicrotaskLoop ', - r'^#8 _runPendingImmediateCallback ', - r'^#9 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait(mixedYields, mixedYieldsExpected, debugInfoFilename); - await doTestAwaitThen(mixedYields, mixedYieldsExpected, debugInfoFilename); - await doTestAwaitCatchError( - mixedYields, mixedYieldsExpected, debugInfoFilename); + { + final expected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^#1 _RootZone.runUnary ', + r'^#2 _FutureListener.handleValue ', + r'^#3 Future._propagateToListeners.handleValueCallback ', + r'^#4 Future._propagateToListeners ', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#5 Future.(_addListener|_prependListeners). ', + r'^#6 _microtaskLoop ', + r'^#7 _startMicrotaskLoop ', + r'^#8 _runPendingImmediateCallback ', + r'^#9 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(mixedYields, expected, debugInfoFilename); + await doTestAwaitThen(mixedYields, expected, debugInfoFilename); + await doTestAwaitCatchError(mixedYields, expected, debugInfoFilename); + } - final syncSuffixExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^#1 _RootZone.runUnary ', - r'^#2 _FutureListener.handleValue ', - r'^#3 Future._propagateToListeners.handleValueCallback ', - r'^#4 Future._propagateToListeners ', - // TODO(dart-vm): Figure out why this is inconsistent: - r'^#5 Future.(_addListener|_prependListeners). ', - r'^#6 _microtaskLoop ', - r'^#7 _startMicrotaskLoop ', - r'^#8 _runPendingImmediateCallback ', - r'^#9 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait(syncSuffix, syncSuffixExpected, debugInfoFilename); - await doTestAwaitThen(syncSuffix, syncSuffixExpected, debugInfoFilename); - await doTestAwaitCatchError( - syncSuffix, syncSuffixExpected, debugInfoFilename); + { + final expected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^#1 _RootZone.runUnary ', + r'^#2 _FutureListener.handleValue ', + r'^#3 Future._propagateToListeners.handleValueCallback ', + r'^#4 Future._propagateToListeners ', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#5 Future.(_addListener|_prependListeners). ', + r'^#6 _microtaskLoop ', + r'^#7 _startMicrotaskLoop ', + r'^#8 _runPendingImmediateCallback ', + r'^#9 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(syncSuffix, expected, debugInfoFilename); + await doTestAwaitThen(syncSuffix, expected, debugInfoFilename); + await doTestAwaitCatchError(syncSuffix, expected, debugInfoFilename); + } - final nonAsyncNoStackExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^#1 _RootZone.runUnary ', - r'^#2 _FutureListener.handleValue ', - r'^#3 Future._propagateToListeners.handleValueCallback ', - r'^#4 Future._propagateToListeners ', - // TODO(dart-vm): Figure out why this is inconsistent: - r'^#5 Future.(_addListener|_prependListeners). ', - r'^#6 _microtaskLoop ', - r'^#7 _startMicrotaskLoop ', - r'^#8 _runPendingImmediateCallback ', - r'^#9 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait( - nonAsyncNoStack, nonAsyncNoStackExpected, debugInfoFilename); - await doTestAwaitThen( - nonAsyncNoStack, nonAsyncNoStackExpected, debugInfoFilename); - await doTestAwaitCatchError( - nonAsyncNoStack, nonAsyncNoStackExpected, debugInfoFilename); + { + final expected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^#1 _RootZone.runUnary ', + r'^#2 _FutureListener.handleValue ', + r'^#3 Future._propagateToListeners.handleValueCallback ', + r'^#4 Future._propagateToListeners ', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#5 Future.(_addListener|_prependListeners). ', + r'^#6 _microtaskLoop ', + r'^#7 _startMicrotaskLoop ', + r'^#8 _runPendingImmediateCallback ', + r'^#9 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(nonAsyncNoStack, expected, debugInfoFilename); + await doTestAwaitThen(nonAsyncNoStack, expected, debugInfoFilename); + await doTestAwaitCatchError(nonAsyncNoStack, expected, debugInfoFilename); + } - final asyncStarThrowSyncExpected = const [ - r'^#0 throwSync \(.+/utils.dart:16(:3)?\)$', - r'^#1 asyncStarThrowSync \(.+/utils.dart:112(:11)?\)$', - r'^#2 _RootZone.runUnary \(.+\)$', - r'^#3 _FutureListener.handleValue \(.+\)$', - r'^#4 Future._propagateToListeners.handleValueCallback \(.+\)$', - r'^#5 Future._propagateToListeners \(.+\)$', - // TODO(dart-vm): Figure out why this is inconsistent: - r'^#6 Future.(_addListener|_prependListeners). \(.+\)$', - r'^#7 _microtaskLoop \(.+\)$', - r'^#8 _startMicrotaskLoop \(.+\)$', - r'^#9 _runPendingImmediateCallback \(.+\)$', - r'^#10 _RawReceivePortImpl._handleMessage \(.+\)$', - ]; - await doTestAwait(awaitEveryAsyncStarThrowSync, asyncStarThrowSyncExpected, - debugInfoFilename); - await doTestAwaitThen(awaitEveryAsyncStarThrowSync, - asyncStarThrowSyncExpected, debugInfoFilename); - await doTestAwaitCatchError(awaitEveryAsyncStarThrowSync, - asyncStarThrowSyncExpected, debugInfoFilename); + { + final expected = const [ + r'^#0 throwSync \(.+/utils.dart:16(:3)?\)$', + r'^#1 asyncStarThrowSync \(.+/utils.dart:112(:11)?\)$', + r'^#2 _RootZone.runUnary \(.+\)$', + r'^#3 _FutureListener.handleValue \(.+\)$', + r'^#4 Future._propagateToListeners.handleValueCallback \(.+\)$', + r'^#5 Future._propagateToListeners \(.+\)$', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#6 Future.(_addListener|_prependListeners). \(.+\)$', + r'^#7 _microtaskLoop \(.+\)$', + r'^#8 _startMicrotaskLoop \(.+\)$', + r'^#9 _runPendingImmediateCallback \(.+\)$', + r'^#10 _RawReceivePortImpl._handleMessage \(.+\)$', + ]; + await doTestAwait( + awaitEveryAsyncStarThrowSync, expected, debugInfoFilename); + await doTestAwaitThen( + awaitEveryAsyncStarThrowSync, expected, debugInfoFilename); + await doTestAwaitCatchError( + awaitEveryAsyncStarThrowSync, expected, debugInfoFilename); + } - final asyncStarThrowAsyncExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^#1 _RootZone.runUnary ', - r'^#2 _FutureListener.handleValue ', - r'^#3 Future._propagateToListeners.handleValueCallback ', - r'^#4 Future._propagateToListeners ', - // TODO(dart-vm): Figure out why this is inconsistent: - r'^#5 Future.(_addListener|_prependListeners). ', - r'^#6 _microtaskLoop ', - r'^#7 _startMicrotaskLoop ', - r'^#8 _runPendingImmediateCallback ', - r'^#9 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait(awaitEveryAsyncStarThrowAsync, asyncStarThrowAsyncExpected, - debugInfoFilename); - await doTestAwaitThen(awaitEveryAsyncStarThrowAsync, - asyncStarThrowAsyncExpected, debugInfoFilename); - await doTestAwaitCatchError(awaitEveryAsyncStarThrowAsync, - asyncStarThrowAsyncExpected, debugInfoFilename); + { + final expected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^#1 _RootZone.runUnary ', + r'^#2 _FutureListener.handleValue ', + r'^#3 Future._propagateToListeners.handleValueCallback ', + r'^#4 Future._propagateToListeners ', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#5 Future.(_addListener|_prependListeners). ', + r'^#6 _microtaskLoop ', + r'^#7 _startMicrotaskLoop ', + r'^#8 _runPendingImmediateCallback ', + r'^#9 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait( + awaitEveryAsyncStarThrowAsync, expected, debugInfoFilename); + await doTestAwaitThen( + awaitEveryAsyncStarThrowAsync, expected, debugInfoFilename); + await doTestAwaitCatchError( + awaitEveryAsyncStarThrowAsync, expected, debugInfoFilename); + } - final listenAsyncStartExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^#1 _RootZone.runUnary ', - r'^#2 _FutureListener.handleValue ', - r'^#3 Future._propagateToListeners.handleValueCallback ', - r'^#4 Future._propagateToListeners ', - // TODO(dart-vm): Figure out why this is inconsistent: - r'^#5 Future.(_addListener|_prependListeners). ', - r'^#6 _microtaskLoop ', - r'^#7 _startMicrotaskLoop ', - r'^#8 _runPendingImmediateCallback ', - r'^#9 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait( - listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); - await doTestAwaitThen( - listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); - await doTestAwaitCatchError( - listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); + { + final expected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^#1 _RootZone.runUnary ', + r'^#2 _FutureListener.handleValue ', + r'^#3 Future._propagateToListeners.handleValueCallback ', + r'^#4 Future._propagateToListeners ', + // TODO(dart-vm): Figure out why this is inconsistent: + r'^#5 Future.(_addListener|_prependListeners). ', + r'^#6 _microtaskLoop ', + r'^#7 _startMicrotaskLoop ', + r'^#8 _runPendingImmediateCallback ', + r'^#9 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(listenAsyncStarThrowAsync, expected, debugInfoFilename); + await doTestAwaitThen( + listenAsyncStarThrowAsync, expected, debugInfoFilename); + await doTestAwaitCatchError( + listenAsyncStarThrowAsync, expected, debugInfoFilename); + } - final customErrorZoneExpected = const [ - r'#0 throwSync \(.*/utils.dart:16(:3)?\)$', - r'#1 allYield3 \(.*/utils.dart:39(:3)?\)$', - r'#2 _rootRunUnary ', - r'#3 _CustomZone.runUnary ', - r'#4 _FutureListener.handleValue ', - r'#5 Future._propagateToListeners.handleValueCallback ', - r'#6 Future._propagateToListeners ', - r'#7 Future.(_addListener|_prependListeners). ', - r'#8 _rootRun ', - r'#9 _CustomZone.run ', - r'#10 _CustomZone.runGuarded ', - r'#11 _CustomZone.bindCallbackGuarded. ', - r'#12 _microtaskLoop ', - r'#13 _startMicrotaskLoop ', - r'#14 _runPendingImmediateCallback ', - r'#15 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait( - customErrorZone, customErrorZoneExpected, debugInfoFilename); - await doTestAwaitThen( - customErrorZone, customErrorZoneExpected, debugInfoFilename); - await doTestAwaitCatchError( - customErrorZone, customErrorZoneExpected, debugInfoFilename); + { + final expected = const [ + r'#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'#1 allYield3 \(.*/utils.dart:39(:3)?\)$', + r'#2 _rootRunUnary ', + r'#3 _CustomZone.runUnary ', + r'#4 _FutureListener.handleValue ', + r'#5 Future._propagateToListeners.handleValueCallback ', + r'#6 Future._propagateToListeners ', + r'#7 Future.(_addListener|_prependListeners). ', + r'#8 _rootRun ', + r'#9 _CustomZone.run ', + r'#10 _CustomZone.runGuarded ', + r'#11 _CustomZone.bindCallbackGuarded. ', + r'#12 _microtaskLoop ', + r'#13 _startMicrotaskLoop ', + r'#14 _runPendingImmediateCallback ', + r'#15 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(customErrorZone, expected, debugInfoFilename); + await doTestAwaitThen(customErrorZone, expected, debugInfoFilename); + await doTestAwaitCatchError(customErrorZone, expected, debugInfoFilename); + } - final awaitTimeoutExpected = const [ - r'#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^#1 _RootZone.runUnary ', - r'^#2 _FutureListener.handleValue ', - r'^#3 Future._propagateToListeners.handleValueCallback ', - r'^#4 Future._propagateToListeners ', - r'^#5 Future.(_addListener|_prependListeners). ', - r'^#6 _microtaskLoop ', - r'^#7 _startMicrotaskLoop ', - r'^#8 _runPendingImmediateCallback ', - r'^#9 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait(awaitTimeout, awaitTimeoutExpected, debugInfoFilename); - await doTestAwaitThen(awaitTimeout, awaitTimeoutExpected, debugInfoFilename); - await doTestAwaitCatchError( - awaitTimeout, awaitTimeoutExpected, debugInfoFilename); + { + final expected = const [ + r'#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^#1 _RootZone.runUnary ', + r'^#2 _FutureListener.handleValue ', + r'^#3 Future._propagateToListeners.handleValueCallback ', + r'^#4 Future._propagateToListeners ', + r'^#5 Future.(_addListener|_prependListeners). ', + r'^#6 _microtaskLoop ', + r'^#7 _startMicrotaskLoop ', + r'^#8 _runPendingImmediateCallback ', + r'^#9 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(awaitTimeout, expected, debugInfoFilename); + await doTestAwaitThen(awaitTimeout, expected, debugInfoFilename); + await doTestAwaitCatchError(awaitTimeout, expected, debugInfoFilename); + } - final awaitWaitExpected = const [ - r'#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^#1 _RootZone.runUnary ', - r'^#2 _FutureListener.handleValue ', - r'^#3 Future._propagateToListeners.handleValueCallback ', - r'^#4 Future._propagateToListeners ', - r'^#5 Future.(_addListener|_prependListeners). ', - r'^#6 _microtaskLoop ', - r'^#7 _startMicrotaskLoop ', - r'^#8 _runPendingImmediateCallback ', - r'^#9 _RawReceivePortImpl._handleMessage ', - ]; - await doTestAwait(awaitWait, awaitWaitExpected, debugInfoFilename); - await doTestAwaitThen(awaitWait, awaitWaitExpected, debugInfoFilename); - await doTestAwaitCatchError(awaitWait, awaitWaitExpected, debugInfoFilename); + { + final expected = const [ + r'#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^#1 _RootZone.runUnary ', + r'^#2 _FutureListener.handleValue ', + r'^#3 Future._propagateToListeners.handleValueCallback ', + r'^#4 Future._propagateToListeners ', + r'^#5 Future.(_addListener|_prependListeners). ', + r'^#6 _microtaskLoop ', + r'^#7 _startMicrotaskLoop ', + r'^#8 _runPendingImmediateCallback ', + r'^#9 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(awaitWait, expected, debugInfoFilename); + await doTestAwaitThen(awaitWait, expected, debugInfoFilename); + await doTestAwaitCatchError(awaitWait, expected, debugInfoFilename); + } { final expected = const [ @@ -642,337 +572,505 @@ Future doTestsNoCausalNoLazy([String debugInfoFilename]) async { await doTestAwaitCatchError( futureSyncWhenComplete, expected, debugInfoFilename); } + + { + final expected = const [ + r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'^#1 futureThen. \(.*/utils.dart:187(:5)?\)$', + r'^#2 _RootZone.runUnary ', + r'^#3 _FutureListener.handleValue ', + r'^#4 Future._propagateToListeners.handleValueCallback ', + r'^#5 Future._propagateToListeners ', + r'^#6 Future._completeWithValue ', + r'^#7 Future._asyncCompleteWithValue. ', + r'^#8 _microtaskLoop ', + r'^#9 _startMicrotaskLoop ', + r'^#10 _runPendingImmediateCallback ', + r'^#11 _RawReceivePortImpl._handleMessage ', + ]; + await doTestAwait(futureThen, expected, debugInfoFilename); + await doTestAwaitThen(futureThen, expected, debugInfoFilename); + await doTestAwaitCatchError(futureThen, expected, debugInfoFilename); + } } // For: --lazy-async-stacks Future doTestsLazy([String debugInfoFilename]) async { - final allYieldExpected = const [ - r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', - r'^#1 allYield3 \(.*/utils.dart:39(:3)?\)$', - r'^$', - r'^#2 allYield2 \(.*/utils.dart:34(:3)?\)$', - r'^$', - r'^#3 allYield \(.*/utils.dart:29(:3)?\)$', - r'^$', - ]; - await doTestAwait( - allYield, - allYieldExpected + - const [ - r'^#4 doTestAwait ', - r'^$', - r'^#5 doTestsLazy ', - r'^$', - r'^#6 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - allYield, - allYieldExpected + - const [ - r'^#4 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError(allYield, allYieldExpected, debugInfoFilename); - - final noYieldsExpected = const [ - r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', - r'^#1 noYields3 \(.*/utils.dart:54(:3)?\)$', - r'^#2 noYields2 \(.*/utils.dart:50(:9)?\)$', - r'^#3 noYields \(.*/utils.dart:46(:9)?\)$', - ]; - await doTestAwait( - noYields, - noYieldsExpected + - const [ - r'^#4 doTestAwait ', - r'^#5 doTestsLazy ', - r'^$', - r'^#6 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - noYields, - noYieldsExpected + - const [ - r'^#4 doTestAwaitThen ', - r'^#5 doTestsLazy ', - r'^$', - r'^#6 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError( - noYields, - noYieldsExpected + - const [ - r'^#4 doTestAwaitCatchError ', - r'^#5 doTestsLazy ', - r'^$', - r'^#6 main ', - r'^$', - ], - debugInfoFilename); - - final mixedYieldsExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^$', - r'^#1 mixedYields2 \(.*/utils.dart:66(:3)?\)$', - r'^$', - r'^#2 mixedYields \(.*/utils.dart:61(:3)?\)$', - r'^$', - ]; - await doTestAwait( - mixedYields, - mixedYieldsExpected + - const [ - r'^#3 doTestAwait ', - r'^$', - r'^#4 doTestsLazy ', - r'^$', - r'^#5 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - mixedYields, - mixedYieldsExpected + - const [ - r'^#3 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError( - mixedYields, mixedYieldsExpected, debugInfoFilename); - - final syncSuffixExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^$', - r'^#1 syncSuffix2 \(.*/utils.dart:82(:3)?\)$', - r'^$', - r'^#2 syncSuffix \(.*/utils.dart:77(:3)?\)$', - r'^$', - ]; - await doTestAwait( - syncSuffix, - syncSuffixExpected + - const [ - r'^#3 doTestAwait ', - r'^$', - r'^#4 doTestsLazy ', - r'^$', - r'^#5 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - syncSuffix, - syncSuffixExpected + - const [ - r'^#3 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError( - syncSuffix, syncSuffixExpected, debugInfoFilename); - - final nonAsyncNoStackExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^$', - r'^#1 nonAsyncNoStack1 \(.*/utils.dart:95(:36)?\)$', - r'^$', - r'^#2 nonAsyncNoStack \(.*/utils.dart:93(:35)?\)$', - r'^$', - ]; - await doTestAwait( - nonAsyncNoStack, - nonAsyncNoStackExpected + - const [ - r'^#3 doTestAwait ', - r'^$', - r'^#4 doTestsLazy ', - r'^$', - r'^#5 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - nonAsyncNoStack, - nonAsyncNoStackExpected + - const [ - r'^#3 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError( - nonAsyncNoStack, nonAsyncNoStackExpected, debugInfoFilename); - - final asyncStarThrowSyncExpected = const [ - r'^#0 throwSync \(.+/utils.dart:16(:3)?\)$', - r'^#1 asyncStarThrowSync \(.+/utils.dart:112(:11)?\)$', - r'^$', - r'^#2 awaitEveryAsyncStarThrowSync \(.+/utils.dart:104(:3)?\)$', - r'^$', - ]; - await doTestAwait( - awaitEveryAsyncStarThrowSync, - asyncStarThrowSyncExpected + - const [ - r'^#3 doTestAwait ', - r'^$', - r'^#4 doTestsLazy ', - r'^$', - r'^#5 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - awaitEveryAsyncStarThrowSync, - asyncStarThrowSyncExpected + - const [ - r'^#3 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError(awaitEveryAsyncStarThrowSync, - asyncStarThrowSyncExpected, debugInfoFilename); - - final asyncStarThrowAsyncExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^$', - r'^#1 asyncStarThrowAsync \(.*/utils.dart:126(:5)?\)$', - r'^$', - r'^#2 awaitEveryAsyncStarThrowAsync \(.+/utils.dart:117(:3)?\)$', - r'^$', - ]; - await doTestAwait( - awaitEveryAsyncStarThrowAsync, - asyncStarThrowAsyncExpected + - const [ - r'^#3 doTestAwait ', - r'^$', - r'^#4 doTestsLazy ', - r'^$', - r'^#5 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - awaitEveryAsyncStarThrowAsync, - asyncStarThrowAsyncExpected + - const [ - r'^#3 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError(awaitEveryAsyncStarThrowAsync, - asyncStarThrowAsyncExpected, debugInfoFilename); - - final listenAsyncStartExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^$', - r'^#1 asyncStarThrowAsync \(.*/utils.dart:126(:5)?\)$', - r'^$', - r'^#2 listenAsyncStarThrowAsync. \(.+/utils.dart(:0)?\)$', - r'^$', - ]; - await doTestAwait( - listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); - await doTestAwaitThen( - listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); - await doTestAwaitCatchError( - listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); - - final customErrorZoneExpected = const [ - r'#0 throwSync \(.*/utils.dart:16(:3)?\)$', - r'#1 allYield3 \(.*/utils.dart:39(:3)?\)$', - r'$', - r'#2 allYield2 \(.*/utils.dart:34(:3)?\)$', - r'$', - r'#3 allYield \(.*/utils.dart:29(:3)?\)$', - r'$', - r'#4 customErrorZone. \(.*/utils.dart:144(:5)?\)$', - r'$', - ]; - await doTestAwait( - customErrorZone, customErrorZoneExpected, debugInfoFilename); - await doTestAwaitThen( - customErrorZone, customErrorZoneExpected, debugInfoFilename); - await doTestAwaitCatchError( - customErrorZone, customErrorZoneExpected, debugInfoFilename); - - final awaitTimeoutExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^$', - r'^#1 Future.timeout. \(dart:async/future_impl.dart', - r'^$', - r'^#2 awaitTimeout ', - r'^$', - ]; - await doTestAwait( - awaitTimeout, - awaitTimeoutExpected + - const [ - r'^#3 doTestAwait ', - r'^$', - r'^#4 doTestsLazy ', - r'^$', - r'^#5 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - awaitTimeout, - awaitTimeoutExpected + - const [ - r'^#3 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError( - awaitTimeout, awaitTimeoutExpected, debugInfoFilename); - - final awaitWaitExpected = const [ - r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', - r'^$', - r'^#1 Future.wait. \(dart:async/future.dart', - r'^$', - r'^#2 awaitWait ', - r'^$', - ]; - await doTestAwait( - awaitWait, - awaitWaitExpected + - const [ - r'^#3 doTestAwait ', - r'^$', - r'^#4 doTestsLazy ', - r'^$', - r'^#5 main ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitThen( - awaitWait, - awaitWaitExpected + - const [ - r'^#3 doTestAwaitThen. ', - r'^$', - ], - debugInfoFilename); - await doTestAwaitCatchError(awaitWait, awaitWaitExpected, debugInfoFilename); - + // allYield { - final expect = const [ + final allYieldExpected = const [ + r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'^#1 allYield3 \(.*/utils.dart:39(:3)?\)$', + r'^$', + r'^#2 allYield2 \(.*/utils.dart:34(:3)?\)$', + r'^$', + r'^#3 allYield \(.*/utils.dart:29(:3)?\)$', + r'^$', + ]; + await doTestAwait( + allYield, + allYieldExpected + + const [ + r'^#4 doTestAwait ', + r'^$', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + allYield, + allYieldExpected + + const [ + r'^#4 doTestAwaitThen ', + r'^$', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + allYield, + allYieldExpected + + const [ + r'^#4 doTestAwaitCatchError ', + r'^$', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + } + + // noYields + { + final noYieldsExpected = const [ + r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'^#1 noYields3 \(.*/utils.dart:54(:3)?\)$', + r'^#2 noYields2 \(.*/utils.dart:50(:9)?\)$', + r'^#3 noYields \(.*/utils.dart:46(:9)?\)$', + ]; + await doTestAwait( + noYields, + noYieldsExpected + + const [ + r'^#4 doTestAwait ', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + noYields, + noYieldsExpected + + const [ + r'^#4 doTestAwaitThen ', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + noYields, + noYieldsExpected + + const [ + r'^#4 doTestAwaitCatchError ', + r'^#5 doTestsLazy ', + r'^$', + r'^#6 main ', + r'^$', + ], + debugInfoFilename); + } + + // mixedYields + { + final mixedYieldsExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^$', + r'^#1 mixedYields2 \(.*/utils.dart:66(:3)?\)$', + r'^$', + r'^#2 mixedYields \(.*/utils.dart:61(:3)?\)$', + r'^$', + ]; + await doTestAwait( + mixedYields, + mixedYieldsExpected + + const [ + r'^#3 doTestAwait ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + mixedYields, + mixedYieldsExpected + + const [ + r'^#3 doTestAwaitThen ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + mixedYields, + mixedYieldsExpected + + const [ + r'^#3 doTestAwaitCatchError ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + } + + // syncSuffix + { + final syncSuffixExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^$', + r'^#1 syncSuffix2 \(.*/utils.dart:82(:3)?\)$', + r'^$', + r'^#2 syncSuffix \(.*/utils.dart:77(:3)?\)$', + r'^$', + ]; + await doTestAwait( + syncSuffix, + syncSuffixExpected + + const [ + r'^#3 doTestAwait ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + syncSuffix, + syncSuffixExpected + + const [ + r'^#3 doTestAwaitThen ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + syncSuffix, + syncSuffixExpected + + const [ + r'^#3 doTestAwaitCatchError ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + } + + // nonAsyncNoStack + { + final nonAsyncNoStackExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^$', + r'^#1 nonAsyncNoStack1 \(.*/utils.dart:95(:36)?\)$', + r'^$', + r'^#2 nonAsyncNoStack \(.*/utils.dart:93(:35)?\)$', + r'^$', + ]; + await doTestAwait( + nonAsyncNoStack, + nonAsyncNoStackExpected + + const [ + r'^#3 doTestAwait ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + nonAsyncNoStack, + nonAsyncNoStackExpected + + const [ + r'^#3 doTestAwaitThen ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + nonAsyncNoStack, + nonAsyncNoStackExpected + + const [ + r'^#3 doTestAwaitCatchError ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + } + + // awaitEveryAsyncStarThrowSync + { + final asyncStarThrowSyncExpected = const [ + r'^#0 throwSync \(.+/utils.dart:16(:3)?\)$', + r'^#1 asyncStarThrowSync \(.+/utils.dart:112(:11)?\)$', + r'^$', + r'^#2 awaitEveryAsyncStarThrowSync \(.+/utils.dart:104(:3)?\)$', + r'^$', + ]; + await doTestAwait( + awaitEveryAsyncStarThrowSync, + asyncStarThrowSyncExpected + + const [ + r'^#3 doTestAwait ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + awaitEveryAsyncStarThrowSync, + asyncStarThrowSyncExpected + + const [ + r'^#3 doTestAwaitThen ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + awaitEveryAsyncStarThrowSync, + asyncStarThrowSyncExpected + + const [ + r'^#3 doTestAwaitCatchError ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + } + + // awaitEveryAsyncStarThrowAsync + { + final asyncStarThrowAsyncExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^$', + r'^#1 asyncStarThrowAsync \(.*/utils.dart:126(:5)?\)$', + r'^$', + r'^#2 awaitEveryAsyncStarThrowAsync \(.+/utils.dart:117(:3)?\)$', + r'^$', + ]; + await doTestAwait( + awaitEveryAsyncStarThrowAsync, + asyncStarThrowAsyncExpected + + const [ + r'^#3 doTestAwait ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + awaitEveryAsyncStarThrowAsync, + asyncStarThrowAsyncExpected + + const [ + r'^#3 doTestAwaitThen ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + awaitEveryAsyncStarThrowAsync, + asyncStarThrowAsyncExpected + + const [ + r'^#3 doTestAwaitCatchError ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + } + + // listenAsyncStarThrowAsync + { + final listenAsyncStartExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^$', + r'^#1 asyncStarThrowAsync \(.*/utils.dart:126(:5)?\)$', + r'^$', + r'^#2 listenAsyncStarThrowAsync. \(.+/utils.dart(:0)?\)$', + r'^$', + ]; + await doTestAwait( + listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); + await doTestAwaitThen( + listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); + await doTestAwaitCatchError( + listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); + } + + // customErrorZone + { + final customErrorZoneExpected = const [ + r'#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'#1 allYield3 \(.*/utils.dart:39(:3)?\)$', + r'$', + r'#2 allYield2 \(.*/utils.dart:34(:3)?\)$', + r'$', + r'#3 allYield \(.*/utils.dart:29(:3)?\)$', + r'$', + r'#4 customErrorZone. \(.*/utils.dart:144(:5)?\)$', + r'$', + ]; + await doTestAwait( + customErrorZone, customErrorZoneExpected, debugInfoFilename); + await doTestAwaitThen( + customErrorZone, customErrorZoneExpected, debugInfoFilename); + await doTestAwaitCatchError( + customErrorZone, customErrorZoneExpected, debugInfoFilename); + } + + // awaitTimeout + { + final awaitTimeoutExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^$', + r'^#1 Future.timeout. \(dart:async/future_impl.dart', + r'^$', + r'^#2 awaitTimeout ', + r'^$', + ]; + await doTestAwait( + awaitTimeout, + awaitTimeoutExpected + + const [ + r'^#3 doTestAwait ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + awaitTimeout, + awaitTimeoutExpected + + const [ + r'^#3 doTestAwaitThen ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + awaitTimeout, + awaitTimeoutExpected + + const [ + r'^#3 doTestAwaitCatchError ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + } + + // awaitWait + { + final awaitWaitExpected = const [ + r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', + r'^$', + r'^#1 Future.wait. \(dart:async/future.dart', + r'^$', + r'^#2 awaitWait ', + r'^$', + ]; + await doTestAwait( + awaitWait, + awaitWaitExpected + + const [ + r'^#3 doTestAwait ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + awaitWait, + awaitWaitExpected + + const [ + r'^#3 doTestAwaitThen ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + awaitWait, + awaitWaitExpected + + const [ + r'^#3 doTestAwaitCatchError ', + r'^$', + r'^#4 doTestsLazy ', + r'^$', + r'^#5 main ', + r'^$', + ], + debugInfoFilename); + } + + // futureSyncWhenComplete + { + final expected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^$', ]; await doTestAwait( futureSyncWhenComplete, - expect + + expected + const [ r'^#1 doTestAwait ', r'^$', @@ -984,13 +1082,72 @@ Future doTestsLazy([String debugInfoFilename]) async { debugInfoFilename); await doTestAwaitThen( futureSyncWhenComplete, - expect + + expected + const [ - r'^#1 doTestAwaitThen. ', + r'^#1 doTestAwaitThen ', + r'^$', + r'^#2 doTestsLazy ', + r'^$', + r'^#3 main ', r'^$', ], debugInfoFilename); await doTestAwaitCatchError( - futureSyncWhenComplete, expect, debugInfoFilename); + futureSyncWhenComplete, + expected + + const [ + r'^#1 doTestAwaitCatchError ', + r'^$', + r'^#2 doTestsLazy ', + r'^$', + r'^#3 main ', + r'^$', + ], + debugInfoFilename); + } + + // futureThen + { + final expected = const [ + r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', + r'^#1 futureThen. ', + r'^$', + ]; + await doTestAwait( + futureThen, + expected + + const [ + r'^#2 doTestAwait ', + r'^$', + r'^#3 doTestsLazy ', + r'^$', + r'^#4 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitThen( + futureThen, + expected + + const [ + r'^#2 doTestAwaitThen ', + r'^$', + r'^#3 doTestsLazy ', + r'^$', + r'^#4 main ', + r'^$', + ], + debugInfoFilename); + await doTestAwaitCatchError( + futureThen, + expected + + const [ + r'^#2 doTestAwaitCatchError ', + r'^$', + r'^#3 doTestsLazy ', + r'^$', + r'^#4 main ', + r'^$', + ], + debugInfoFilename); } } diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h index 185af0ac35c..682200177f9 100644 --- a/runtime/vm/compiler/recognized_methods_list.h +++ b/runtime/vm/compiler/recognized_methods_list.h @@ -196,6 +196,8 @@ namespace dart { V(_Utf8Decoder, _scan, Utf8DecoderScan, 0xb35ced99) \ V(_Future, timeout, FutureTimeout, 0x6ad7d1ef) \ V(Future, wait, FutureWait, 0x264aacc2) \ + V(_RootZone, runUnary, RootZoneRunUnary, 0x76e41d34) \ + V(_FutureListener, handleValue, FutureListenerHandleValue, 0x73894d16) \ // List of intrinsics: // (class-name, function-name, intrinsification method, fingerprint). diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc index 7f6775d86a2..51975f35de3 100644 --- a/runtime/vm/debugger.cc +++ b/runtime/vm/debugger.cc @@ -1848,7 +1848,7 @@ DebuggerStackTrace* Debugger::CollectAsyncLazyStackTrace() { /*skip_frames=*/0, &on_sync_frame, &has_async); - // If the entire stack is sync, return no trace. + // If the entire stack is sync, return no (async) trace. if (!has_async) { return nullptr; } diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc index 5a6c5a9f955..96ad60dee64 100644 --- a/runtime/vm/stack_frame.cc +++ b/runtime/vm/stack_frame.cc @@ -528,6 +528,19 @@ StackFrameIterator::StackFrameIterator(uword fp, frames_.Unpoison(); } +StackFrameIterator::StackFrameIterator(const StackFrameIterator& orig) + : validate_(orig.validate_), + entry_(orig.thread_), + exit_(orig.thread_), + frames_(orig.thread_), + current_frame_(nullptr), + thread_(orig.thread_) { + frames_.fp_ = orig.frames_.fp_; + frames_.sp_ = orig.frames_.sp_; + frames_.pc_ = orig.frames_.pc_; + frames_.Unpoison(); +} + StackFrame* StackFrameIterator::NextFrame() { // When we are at the start of iteration after having created an // iterator object, current_frame_ will be NULL as we haven't seen diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h index 92f864ff53a..69696428998 100644 --- a/runtime/vm/stack_frame.h +++ b/runtime/vm/stack_frame.h @@ -236,6 +236,8 @@ class StackFrameIterator : public ValueObject { Thread* thread, CrossThreadPolicy cross_thread_policy); + StackFrameIterator(const StackFrameIterator& orig); + // Checks if a next frame exists. bool HasNextFrame() const { return frames_.fp_ != 0; } @@ -300,7 +302,6 @@ class StackFrameIterator : public ValueObject { Thread* thread_; friend class ProfilerDartStackWalker; - DISALLOW_COPY_AND_ASSIGN(StackFrameIterator); }; // Iterator for iterating over all dart frames (skips over exit frames, @@ -339,6 +340,8 @@ class DartFrameIterator : public ValueObject { thread, cross_thread_policy) {} + DartFrameIterator(const DartFrameIterator& orig) : frames_(orig.frames_) {} + // Get next dart frame. StackFrame* NextFrame() { StackFrame* frame = frames_.NextFrame(); @@ -350,8 +353,6 @@ class DartFrameIterator : public ValueObject { private: StackFrameIterator frames_; - - DISALLOW_COPY_AND_ASSIGN(DartFrameIterator); }; // Iterator for iterating over all inlined dart functions in an optimized diff --git a/runtime/vm/stack_trace.cc b/runtime/vm/stack_trace.cc index ae8849a6475..18aebc13c4f 100644 --- a/runtime/vm/stack_trace.cc +++ b/runtime/vm/stack_trace.cc @@ -10,11 +10,18 @@ namespace dart { -// Keep in sync with -// sdk/lib/async/stream_controller.dart:_StreamController._STATE_SUBSCRIBED. +// Keep in sync with: +// - sdk/lib/async/stream_controller.dart:_StreamController._STATE_SUBSCRIBED. const intptr_t k_StreamController__STATE_SUBSCRIBED = 1; -// sdk/lib/async/future_impl.dart:_FutureListener.stateWhencomplete. -const intptr_t k_FutureListener_stateWhencomplete = 8; +// - sdk/lib/async/future_impl.dart:_FutureListener.stateThen. +const intptr_t k_FutureListener_stateThen = 1; +// - sdk/lib/async/future_impl.dart:_FutureListener.stateCatchError. +const intptr_t k_FutureListener_stateCatchError = 2; +// - sdk/lib/async/future_impl.dart:_FutureListener.stateWhenComplete. +const intptr_t k_FutureListener_stateWhenComplete = 8; + +// Keep in sync with sdk/lib/async/future_impl.dart:_FutureListener.handleValue. +const intptr_t kNumArgsFutureListenerHandleValue = 1; // Find current yield index from async closure. // Async closures contains a variable, :await_jump_var that holds the index into @@ -140,21 +147,19 @@ ClosurePtr CallerClosureFinder::GetCallerInFutureImpl(const Object& future) { ASSERT(!future.IsNull()); ASSERT(future.GetClassId() == future_impl_class.id()); - listener_ = Instance::Cast(future).GetField(future_result_or_listeners_field); - if (listener_.GetClassId() != future_listener_class.id()) { + // Since this function is recursive, we have to keep a local ref. + auto& listener = Object::Handle( + Instance::Cast(future).GetField(future_result_or_listeners_field)); + if (listener.GetClassId() != future_listener_class.id()) { return Closure::null(); } - // If the _FutureListener is a whenComplete listener, follow the Future being - // completed, `result`, instead of the dangling whenComplete `callback`. - state_ = Instance::Cast(listener_).GetField(future_listener_state_field); - ASSERT(state_.IsSmi()); - if (Smi::Cast(state_).Value() == k_FutureListener_stateWhencomplete) { - future_ = Instance::Cast(listener_).GetField(future_listener_result_field); - return GetCallerInFutureImpl(future_); + callback_ = GetCallerInFutureListener(listener); + if (callback_.IsInstance() && !callback_.IsNull()) { + return Closure::Cast(callback_).ptr(); } - callback_ = Instance::Cast(listener_).GetField(callback_field); + callback_ = Instance::Cast(listener).GetField(callback_field); // This happens for e.g.: await f().catchError(..); if (callback_.IsNull()) { return Closure::null(); @@ -221,22 +226,46 @@ ClosurePtr CallerClosureFinder::FindCallerInAsyncGenClosure( UNREACHABLE(); // If no onData is found we have a bug. } +ClosurePtr CallerClosureFinder::GetCallerInFutureListener( + const Object& future_listener) { + ASSERT(future_listener.GetClassId() == future_listener_class.id()); + + state_ = + Instance::Cast(future_listener).GetField(future_listener_state_field); + + auto value = Smi::Cast(state_).Value(); + // If the _FutureListener is a `then`, `catchError`, or `whenComplete` + // listener, follow the Future being completed, `result`, instead of the + // dangling whenComplete `callback`. + if (value == k_FutureListener_stateThen || + value == k_FutureListener_stateCatchError || + value == k_FutureListener_stateWhenComplete) { + future_ = + Instance::Cast(future_listener).GetField(future_listener_result_field); + return GetCallerInFutureImpl(future_); + } + + return Closure::null(); +} + ClosurePtr CallerClosureFinder::FindCaller(const Closure& receiver_closure) { receiver_function_ = receiver_closure.function(); receiver_context_ = receiver_closure.context(); if (receiver_function_.IsAsyncClosure()) { return FindCallerInAsyncClosure(receiver_context_); - } else if (receiver_function_.IsAsyncGenClosure()) { + } + if (receiver_function_.IsAsyncGenClosure()) { return FindCallerInAsyncGenClosure(receiver_context_); - } else if (receiver_function_.IsLocalFunction()) { + } + if (receiver_function_.IsLocalFunction()) { parent_function_ = receiver_function_.parent_function(); if (parent_function_.recognized_kind() == MethodRecognizer::kFutureTimeout) { context_entry_ = receiver_context_.At(Context::kFutureTimeoutFutureIndex); return GetCallerInFutureImpl(context_entry_); - } else if (parent_function_.recognized_kind() == - MethodRecognizer::kFutureWait) { + } + if (parent_function_.recognized_kind() == MethodRecognizer::kFutureWait) { receiver_context_ = receiver_context_.parent(); ASSERT(!receiver_context_.IsNull()); context_entry_ = receiver_context_.At(Context::kFutureWaitFutureIndex); @@ -300,6 +329,110 @@ ClosurePtr StackTraceUtils::FindClosureInFrame(ObjectPtr* last_object_in_caller, UNREACHABLE(); } +ClosurePtr StackTraceUtils::ClosureFromFrameFunction( + Zone* zone, + CallerClosureFinder* caller_closure_finder, + const DartFrameIterator& frames, + StackFrame* frame, + bool* skip_frame, + bool* is_async) { + auto& closure = Closure::Handle(zone); + auto& function = Function::Handle(zone); + + function = frame->LookupDartFunction(); + if (function.IsNull()) { + return Closure::null(); + } + + if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) { + // Next, look up caller's closure on the stack and walk backwards + // through the yields. + ObjectPtr* last_caller_obj = + reinterpret_cast(frame->GetCallerSp()); + closure = FindClosureInFrame(last_caller_obj, function); + + // If this async function hasn't yielded yet, we're still dealing with a + // normal stack. Continue to next frame as usual. + if (!caller_closure_finder->IsRunningAsync(closure)) { + return Closure::null(); + } + + *is_async = true; + + // Skip: Already handled this as a sync. frame. + return caller_closure_finder->FindCaller(closure); + } + + // May have been called from `_FutureListener.handleValue`, which means its + // receiver holds the Future chain. + DartFrameIterator future_frames(frames); + if (function.recognized_kind() == MethodRecognizer::kRootZoneRunUnary) { + frame = future_frames.NextFrame(); + function = frame->LookupDartFunction(); + if (function.recognized_kind() != + MethodRecognizer::kFutureListenerHandleValue) { + return Closure::null(); + } + } + if (function.recognized_kind() == + MethodRecognizer::kFutureListenerHandleValue) { + *is_async = true; + *skip_frame = true; + + // The _FutureListener receiver is at the top of the previous frame, right + // before the arguments to the call. + Object& receiver = + Object::Handle(*(reinterpret_cast(frame->GetCallerSp()) + + kNumArgsFutureListenerHandleValue)); + + return caller_closure_finder->GetCallerInFutureListener(receiver); + } + + return Closure::null(); +} + +void StackTraceUtils::UnwindAwaiterChain( + Zone* zone, + const GrowableObjectArray& code_array, + const GrowableObjectArray& pc_offset_array, + CallerClosureFinder* caller_closure_finder, + const Closure& leaf_closure) { + auto& code = Code::Handle(zone); + auto& function = Function::Handle(zone); + auto& closure = Closure::Handle(zone, leaf_closure.ptr()); + auto& pc_descs = PcDescriptors::Handle(zone); + auto& offset = Smi::Handle(zone); + + // Inject async suspension marker. + code_array.Add(StubCode::AsynchronousGapMarker()); + offset = Smi::New(0); + pc_offset_array.Add(offset); + + // Traverse the trail of async futures all the way up. + for (; !closure.IsNull(); + closure = caller_closure_finder->FindCaller(closure)) { + function = closure.function(); + if (function.IsNull()) { + continue; + } + // In hot-reload-test-mode we sometimes have to do this: + code = function.EnsureHasCode(); + RELEASE_ASSERT(!code.IsNull()); + code_array.Add(code); + pc_descs = code.pc_descriptors(); + offset = Smi::New(FindPcOffset(pc_descs, GetYieldIndex(closure))); + // Unlike other sources of PC offsets, the offset may be 0 here if we + // reach a non-async closure receiving the yielded value. + ASSERT(offset.Value() >= 0); + pc_offset_array.Add(offset); + + // Inject async suspension marker. + code_array.Add(StubCode::AsynchronousGapMarker()); + offset = Smi::New(0); + pc_offset_array.Add(offset); + } +} + void StackTraceUtils::CollectFramesLazy( Thread* thread, const GrowableObjectArray& code_array, @@ -320,13 +453,11 @@ void StackTraceUtils::CollectFramesLazy( return; } - auto& function = Function::Handle(zone); auto& code = Code::Handle(zone); auto& offset = Smi::Handle(zone); - auto& closure = Closure::Handle(zone); + CallerClosureFinder caller_closure_finder(zone); - auto& pc_descs = PcDescriptors::Handle(); // Start by traversing the sync. part of the stack. for (; frame != nullptr; frame = frames.NextFrame()) { @@ -335,79 +466,36 @@ void StackTraceUtils::CollectFramesLazy( continue; } - function = frame->LookupDartFunction(); + // If we encounter a known part of the async/Future mechanism, unwind the + // awaiter chain from the closures. + bool skip_frame = false; + bool is_async = false; + closure = ClosureFromFrameFunction(zone, &caller_closure_finder, frames, + frame, &skip_frame, &is_async); - // Add the current synchronous frame. - code = frame->LookupDartCode(); - ASSERT(function.ptr() == code.function()); - code_array.Add(code); - const intptr_t pc_offset = frame->pc() - code.PayloadStart(); - ASSERT(pc_offset > 0 && pc_offset <= code.Size()); - offset = Smi::New(pc_offset); - pc_offset_array.Add(offset); - if (on_sync_frames != nullptr) { - (*on_sync_frames)(frame); + // This isn't a special (async) frame we should skip. + if (!skip_frame) { + // Add the current synchronous frame. + code = frame->LookupDartCode(); + code_array.Add(code); + const intptr_t pc_offset = frame->pc() - code.PayloadStart(); + ASSERT(pc_offset > 0 && pc_offset <= code.Size()); + offset = Smi::New(pc_offset); + pc_offset_array.Add(offset); + // Callback for sync frame. + if (on_sync_frames != nullptr) { + (*on_sync_frames)(frame); + } } - // Either continue the loop (sync-async case) or find all await'ers and - // return. - if (!function.IsNull() && - (function.IsAsyncClosure() || function.IsAsyncGenClosure())) { + // This frame is running async. + // Note: The closure might still be null in case it's an unawaited future. + if (is_async) { + UnwindAwaiterChain(zone, code_array, pc_offset_array, + &caller_closure_finder, closure); if (has_async != nullptr) { *has_async = true; } - - { - NoSafepointScope nsp; - - // Next, look up caller's closure on the stack and walk backwards - // through the yields. - ObjectPtr* last_caller_obj = - reinterpret_cast(frame->GetCallerSp()); - closure = FindClosureInFrame(last_caller_obj, function); - - // If this async function hasn't yielded yet, we're still dealing with a - // normal stack. Continue to next frame as usual. - if (!caller_closure_finder.IsRunningAsync(closure)) { - continue; - } - } - - // Inject async suspension marker. - code_array.Add(StubCode::AsynchronousGapMarker()); - offset = Smi::New(0); - pc_offset_array.Add(offset); - - // Skip: Already handled this frame's function above. - closure = caller_closure_finder.FindCaller(closure); - - // Traverse the trail of async futures all the way up. - for (; !closure.IsNull(); - closure = caller_closure_finder.FindCaller(closure)) { - function = closure.function(); - // In hot-reload-test-mode we sometimes have to do this: - if (!function.HasCode()) { - function.EnsureHasCode(); - } - if (function.HasCode()) { - code = function.CurrentCode(); - code_array.Add(code); - pc_descs = code.pc_descriptors(); - offset = Smi::New(FindPcOffset(pc_descs, GetYieldIndex(closure))); - } else { - UNREACHABLE(); - } - // Unlike other sources of PC offsets, the offset may be 0 here if we - // reach a non-async closure receiving the yielded value. - ASSERT(offset.Value() >= 0); - pc_offset_array.Add(offset); - - // Inject async suspension marker. - code_array.Add(StubCode::AsynchronousGapMarker()); - offset = Smi::New(0); - pc_offset_array.Add(offset); - } - // Ignore the rest of the stack; already unwound all async calls. return; } diff --git a/runtime/vm/stack_trace.h b/runtime/vm/stack_trace.h index 215da831798..2074673f1ef 100644 --- a/runtime/vm/stack_trace.h +++ b/runtime/vm/stack_trace.h @@ -21,6 +21,8 @@ class CallerClosureFinder { ClosurePtr GetCallerInFutureImpl(const Object& future_); + ClosurePtr GetCallerInFutureListener(const Object& future_listener); + ClosurePtr FindCallerInAsyncClosure(const Context& receiver_context); ClosurePtr FindCallerInAsyncGenClosure(const Context& receiver_context); @@ -61,6 +63,8 @@ class CallerClosureFinder { Field& state_field; Field& on_data_field; Field& state_data_field; + + DISALLOW_COPY_AND_ASSIGN(CallerClosureFinder); }; class StackTraceUtils : public AllStatic { @@ -69,6 +73,20 @@ class StackTraceUtils : public AllStatic { static ClosurePtr FindClosureInFrame(ObjectPtr* last_object_in_caller, const Function& function); + static ClosurePtr ClosureFromFrameFunction( + Zone* zone, + CallerClosureFinder* caller_closure_finder, + const DartFrameIterator& frames, + StackFrame* frame, + bool* skip_frame, + bool* is_async); + + static void UnwindAwaiterChain(Zone* zone, + const GrowableObjectArray& code_array, + const GrowableObjectArray& pc_offset_array, + CallerClosureFinder* caller_closure_finder, + const Closure& leaf_closure); + /// Collects all frames on the current stack until an async/async* frame is /// hit which has yielded before (i.e. is not in sync-async case). /// diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart index df8a347db97..a9f2b801bf1 100644 --- a/sdk/lib/async/future_impl.dart +++ b/sdk/lib/async/future_impl.dart @@ -63,18 +63,19 @@ class _SyncCompleter extends _Completer { } class _FutureListener { + // Keep in sync with sdk/runtime/vm/stack_trace.cc. static const int maskValue = 1; static const int maskError = 2; static const int maskTestError = 4; - static const int maskWhencomplete = 8; + static const int maskWhenComplete = 8; static const int stateChain = 0; static const int stateThen = maskValue; static const int stateThenOnerror = maskValue | maskError; - static const int stateCatcherror = maskError; - static const int stateCatcherrorTest = maskError | maskTestError; - static const int stateWhencomplete = maskWhencomplete; + static const int stateCatchError = maskError; + static const int stateCatchErrorTest = maskError | maskTestError; + static const int stateWhenComplete = maskWhenComplete; static const int maskType = - maskValue | maskError | maskTestError | maskWhencomplete; + maskValue | maskError | maskTestError | maskWhenComplete; static const int stateIsAwait = 16; // Listeners on the same future are linked through this link. @@ -109,18 +110,18 @@ class _FutureListener { stateIsAwait; _FutureListener.catchError(this.result, this.errorCallback, this.callback) - : state = (callback == null) ? stateCatcherror : stateCatcherrorTest; + : state = (callback == null) ? stateCatchError : stateCatchErrorTest; _FutureListener.whenComplete(this.result, this.callback) : errorCallback = null, - state = stateWhencomplete; + state = stateWhenComplete; _Zone get _zone => result._zone; bool get handlesValue => (state & maskValue != 0); bool get handlesError => (state & maskError != 0); - bool get hasErrorTest => (state & maskType == stateCatcherrorTest); - bool get handlesComplete => (state & maskType == stateWhencomplete); + bool get hasErrorTest => (state & maskType == stateCatchErrorTest); + bool get handlesComplete => (state & maskType == stateWhenComplete); bool get isAwait => (state & stateIsAwait != 0); FutureOr Function(S) get _onValue { @@ -148,6 +149,8 @@ class _FutureListener { return _onError != null; } + @pragma("vm:recognized", "other") + @pragma("vm:never-inline") FutureOr handleValue(S sourceResult) { return _zone.runUnary, S>(_onValue, sourceResult); } diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart index 4f0873d04c9..54008145cb1 100644 --- a/sdk/lib/async/zone.dart +++ b/sdk/lib/async/zone.dart @@ -1608,6 +1608,7 @@ class _RootZone extends _Zone { return _rootRun(null, null, this, f); } + @pragma("vm:recognized", "other") R runUnary(R f(T arg), T arg) { if (identical(Zone._current, _rootZone)) return f(arg); return _rootRunUnary(null, null, this, f, arg);