Files
sdk/runtime/vm/stack_trace.h
T
Vyacheslav Egorov 0ea5013250 [vm] Respect catchError attached to the last async frame.
Our async unwinding code used to only respect `catchError`
which occured between async frames and ignored trailing
`catchError` like in the code below

    Future(...).catchError((_) { /* handle error */ });

This CL also simplifies how we communicate the presence of the
exception handler to the debugger: the code in the debugger did
not actually care about which frame catches the error (for async
handlers), so we don't need to precisely mark async gaps with
`has_catch_error` flag. Instead we have a single boolean
produced by unwinding which signals whether there we encountered
an asynchronous error handler or not.

Fixes https://github.com/flutter/flutter/issues/141882

TEST=service/pause_on_unhandled_async_exceptions5

Change-Id: Id6f6a97ee5444c197b2c621f68d1e47082fc8997
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/350320
Commit-Queue: Slava Egorov <vegorov@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
2024-02-05 21:09:38 +00:00

65 lines
2.1 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);
/// 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_