dart-sdk/runtime/vm/stack_trace.h
Vyacheslav Egorov df6fd34f75 [vm] Improve asynchronous unwinding through Stream methods
This CL adds @pragma('vm:awaiter-link') in various places in
Stream implementation to facilitate unwinding and expands
async unwinding logic with more information about
Stream internals.

At the same time be more conservative when checking if an
exception thrown from async method handled: failing to unwind
the stack fully creates situations when we incorrectly report
caught exceptions as uncaught, which frustrates users.

To distinguish stream subscriptions with and without error
handlers we add a state bit. Otherwise, it looks like all
subscriptions have error handlers because if no error
handler is installed we eagerly install error handler forwarding
the error to `Zone.handleUncaughtError`.

Fixes https://github.com/dart-lang/sdk/issues/53334
Fixes https://github.com/dart-lang/sdk/issues/54788
Fixes https://github.com/dart-lang/sdk/issues/47985

TEST=runtime/vm/dart/awaiter_stacks/stream_methods_test.dart,pkg/vm_service/test/pause_on_unhandled_async_exceptions6_test.dart,pkg/vm_service/test/pause_on_unhandled_async_exceptions7_test.dart

CoreLibraryReviewExempt: No behavioral change. Async changes reviewed by lrhn@
Cq-Include-Trybots: luci.dart.try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-dwarf-linux-product-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try
Change-Id: Ic51f926867092dd0adbe801b753f57c357c7ace2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/322720
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
2024-02-15 23:00:44 +00:00

72 lines
2.3 KiB
C++

// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_VM_STACK_TRACE_H_
#define RUNTIME_VM_STACK_TRACE_H_
#include <functional>
#include "vm/allocation.h"
#include "vm/flag_list.h"
#include "vm/object.h"
#include "vm/symbols.h"
namespace dart {
class StackTraceUtils : public AllStatic {
public:
static constexpr uword kFutureListenerPcOffset = 1;
struct Frame {
// Corresponding on stack frame or |nullptr| if this is an awaiter frame
// or a gap.
StackFrame* frame;
// Code object corresponding to this frame.
const Code& code;
// Offset into the code object corresponding to this frame.
//
// Will be set to |kFutureListenerPcOffset| if this frame corresponds to
// future listener that is not yet executing.
uword pc_offset;
// Closure corresponding to the awaiter frame or |null| if this is
// a synchronous frame or a gap.
const Closure& closure;
};
// Returns |true| if this function is needed to correctly unwind through
// awaiter chains. This means AOT compiler should retain |Function| object,
// its signature and the corresponding |Code| object (so that we could
// perform the reverse lookup).
static bool IsNeededForAsyncAwareUnwinding(const Function& function);
// Returns |true| if the given class might serve as an awaiter-link when
// unwinding an awaiter chain.
//
// This is used to eagerly mark tear-offs of methods on this class
// as having an awaiter-link.
static bool IsPossibleAwaiterLink(const Class& cls);
/// 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).
///
/// From there on finds the closure of the async/async* frame and starts
/// traversing the listeners.
static void CollectFrames(
Thread* thread,
int skip_frames,
const std::function<void(const Frame&)>& handle_frame,
bool* has_async_catch_error = nullptr);
// If |closure| has an awaiter-link pointing to the |SuspendState|
// the return that object.
static bool GetSuspendState(const Closure& closure, Object* suspend_state);
};
} // namespace dart
#endif // RUNTIME_VM_STACK_TRACE_H_