diff --git a/pkg/vm_service/test/get_stack_test.dart b/pkg/vm_service/test/get_stack_test.dart index 77c35956ffe..dc7c05d64f3 100644 --- a/pkg/vm_service/test/get_stack_test.dart +++ b/pkg/vm_service/test/get_stack_test.dart @@ -97,7 +97,7 @@ final tests = [ expect(result.frames, hasLength(10)); expect(result.asyncCausalFrames, hasLength(26)); - expect(result.awaiterFrames, hasLength(2)); + expect(result.awaiterFrames, hasLength(13)); expectFrames(result.frames!, [ [equals('Regular'), endsWith(' func10')], @@ -140,6 +140,17 @@ final tests = [ expectFrames(result.awaiterFrames, [ [equals('AsyncActivation'), endsWith(' func10')], [equals('AsyncActivation'), endsWith(' func9')], + [equals('AsyncActivation'), endsWith(' func8')], + [equals('AsyncActivation'), endsWith(' func7')], + [equals('AsyncActivation'), endsWith(' func6')], + [equals('AsyncActivation'), endsWith(' func5')], + [equals('AsyncActivation'), endsWith(' func4')], + [equals('AsyncActivation'), endsWith(' func3')], + [equals('AsyncActivation'), endsWith(' func2')], + [equals('AsyncActivation'), endsWith(' func1')], + [equals('AsyncActivation'), endsWith(' testMain')], + [equals('AsyncActivation'), endsWith(' _ServiceTesteeRunner.run')], + [equals('AsyncActivation'), endsWith(' runIsolateTests')], ]); }, ]; diff --git a/runtime/observatory/tests/service/get_stack_limit_rpc_test.dart b/runtime/observatory/tests/service/get_stack_limit_rpc_test.dart index b1ccb4ff817..09186aa26ee 100644 --- a/runtime/observatory/tests/service/get_stack_limit_rpc_test.dart +++ b/runtime/observatory/tests/service/get_stack_limit_rpc_test.dart @@ -55,7 +55,7 @@ var tests = [ var awaiterFrames = stack['awaiterFrames']; expect(frames.length, greaterThanOrEqualTo(20)); expect(asyncFrames.length, greaterThan(frames.length)); - expect(awaiterFrames.length, 13); + expect(awaiterFrames.length, greaterThan(frames.length)); expect(stack['truncated'], false); verifyStack(frames, [ 'bar.async_op', 'foo.async_op', 'bar.async_op', 'foo.async_op', @@ -75,7 +75,7 @@ var tests = [ expect(frames.length, fullStackLength); expect(asyncFrames.length, fullStackLength + 1); - expect(asyncFrames.length, fullStackLength + 1); + expect(awaiterFrames.length, fullStackLength + 1); expect(stack['truncated'], true); verifyStack(frames, [ 'bar.async_op', 'foo.async_op', 'bar.async_op', 'foo.async_op', diff --git a/runtime/observatory/tests/service/pause_on_unhandled_exceptions_catcherror_test.dart b/runtime/observatory/tests/service/pause_on_unhandled_exceptions_catcherror_test.dart index b8c96cb391a..a0598aad9cd 100644 --- a/runtime/observatory/tests/service/pause_on_unhandled_exceptions_catcherror_test.dart +++ b/runtime/observatory/tests/service/pause_on_unhandled_exceptions_catcherror_test.dart @@ -12,12 +12,23 @@ Future throwAsync() async { throw 'Throw from throwAsync!'; } +Future nestedThrowAsync() async { + await Future.delayed(const Duration(milliseconds: 100)); + await throwAsync(); +} + testeeMain() async { await throwAsync().then((v) { print('Hello from then()!'); }).catchError((e, st) { print('Caught in catchError: $e!'); }); + // Make sure we can chain through off-stack awaiters as well. + try { + await nestedThrowAsync(); + } catch (e) { + print('Caught in catch: $e!'); + } } var tests = [ diff --git a/runtime/observatory_2/tests/service_2/get_stack_limit_rpc_test.dart b/runtime/observatory_2/tests/service_2/get_stack_limit_rpc_test.dart index 33766da8f43..fca283d7916 100644 --- a/runtime/observatory_2/tests/service_2/get_stack_limit_rpc_test.dart +++ b/runtime/observatory_2/tests/service_2/get_stack_limit_rpc_test.dart @@ -55,7 +55,7 @@ var tests = [ var awaiterFrames = stack['awaiterFrames']; expect(frames.length, greaterThanOrEqualTo(20)); expect(asyncFrames.length, greaterThan(frames.length)); - expect(awaiterFrames.length, 13); + expect(awaiterFrames.length, greaterThan(frames.length)); expect(stack['truncated'], false); verifyStack(frames, [ 'bar.async_op', 'foo.async_op', 'bar.async_op', 'foo.async_op', @@ -75,7 +75,7 @@ var tests = [ expect(frames.length, fullStackLength); expect(asyncFrames.length, fullStackLength + 1); - expect(asyncFrames.length, fullStackLength + 1); + expect(awaiterFrames.length, fullStackLength + 1); expect(stack['truncated'], true); verifyStack(frames, [ 'bar.async_op', 'foo.async_op', 'bar.async_op', 'foo.async_op', diff --git a/runtime/observatory_2/tests/service_2/pause_on_unhandled_exceptions_catcherror_test.dart b/runtime/observatory_2/tests/service_2/pause_on_unhandled_exceptions_catcherror_test.dart index b8c96cb391a..a0598aad9cd 100644 --- a/runtime/observatory_2/tests/service_2/pause_on_unhandled_exceptions_catcherror_test.dart +++ b/runtime/observatory_2/tests/service_2/pause_on_unhandled_exceptions_catcherror_test.dart @@ -12,12 +12,23 @@ Future throwAsync() async { throw 'Throw from throwAsync!'; } +Future nestedThrowAsync() async { + await Future.delayed(const Duration(milliseconds: 100)); + await throwAsync(); +} + testeeMain() async { await throwAsync().then((v) { print('Hello from then()!'); }).catchError((e, st) { print('Caught in catchError: $e!'); }); + // Make sure we can chain through off-stack awaiters as well. + try { + await nestedThrowAsync(); + } catch (e) { + print('Caught in catch: $e!'); + } } var tests = [ diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc index b8e8b063844..2b5db6a6042 100644 --- a/runtime/vm/debugger.cc +++ b/runtime/vm/debugger.cc @@ -1935,7 +1935,6 @@ DebuggerStackTrace* DebuggerStackTrace::CollectAwaiterReturn() { Function& function = Function::Handle(zone); Code& inlined_code = Code::Handle(zone); Closure& async_activation = Closure::Handle(zone); - Object& next_async_activation = Object::Handle(zone); Array& deopt_frame = Array::Handle(zone); bool stack_has_async_function = false; Closure& closure = Closure::Handle(); @@ -2045,13 +2044,10 @@ DebuggerStackTrace* DebuggerStackTrace::CollectAwaiterReturn() { while (!async_activation.IsNull() && async_activation.context() != Object::null()) { ActivationFrame* activation = new (zone) ActivationFrame(async_activation); - - if (!(activation->function().IsAsyncClosure() || - activation->function().IsAsyncGenClosure())) { - break; + if (activation->function().IsAsyncClosure() || + activation->function().IsAsyncGenClosure()) { + activation->ExtractTokenPositionFromAsyncClosure(); } - - activation->ExtractTokenPositionFromAsyncClosure(); stack_trace->AddActivation(activation); if (FLAG_trace_debugger_stacktrace) { OS::PrintErr( @@ -2059,13 +2055,7 @@ DebuggerStackTrace* DebuggerStackTrace::CollectAwaiterReturn() { "closures:\n\t%s\n", activation->function().ToFullyQualifiedCString()); } - - next_async_activation = activation->GetAsyncAwaiter(&caller_closure_finder); - if (next_async_activation.IsNull()) { - break; - } - - async_activation = Closure::RawCast(next_async_activation.ptr()); + async_activation = caller_closure_finder.FindCaller(async_activation); } return stack_trace;