Version 2.13.0-83.0.dev

Merge commit 'f2dfe3a8be24db64c924541c2775ef496171c02b' into 'dev'
diff --git a/pkg/vm_service/test/get_stack_test.dart b/pkg/vm_service/test/get_stack_test.dart
index 77c3595..dc7c05d 100644
--- a/pkg/vm_service/test/get_stack_test.dart
+++ b/pkg/vm_service/test/get_stack_test.dart
@@ -97,7 +97,7 @@
 
     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 @@
     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 b1ccb4f..09186aa 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 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 @@
 
     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 b8c96cb..a0598aa 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 @@
   throw 'Throw from throwAsync!';
 }
 
+Future<void> 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 = <IsolateTest>[
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 33766da..fca283d 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 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 @@
 
     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 b8c96cb..a0598aa 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 @@
   throw 'Throw from throwAsync!';
 }
 
+Future<void> 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 = <IsolateTest>[
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index b8e8b06..2b5db6a 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -1935,7 +1935,6 @@
   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 @@
   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 @@
           "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;
diff --git a/tools/VERSION b/tools/VERSION
index 40d7e5d..8306513 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 82
+PRERELEASE 83
 PRERELEASE_PATCH 0
\ No newline at end of file