Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
stack_trace.cc
Go to the documentation of this file.
1// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/stack_trace.h"
6
7#include "vm/dart_api_impl.h"
8#include "vm/object_store.h"
9#include "vm/stack_frame.h"
10#include "vm/symbols.h"
11
12namespace dart {
13
14namespace {
15
16// Keep in sync with:
17// - _StreamController._STATE_SUBSCRIBED.
18const intptr_t k_StreamController__STATE_SUBSCRIBED = 1;
19// - _StreamController._STATE_SUBSCRIPTION_MASK.
20const intptr_t k_StreamController__STATE_SUBSCRIPTION_MASK = 3;
21// - _StreamController._STATE_ADDSTREAM.
22const intptr_t k_StreamController__STATE_ADDSTREAM = 8;
23// - _BufferingStreamSubscription._STATE_HAS_ERROR_HANDLER.
24const intptr_t k_BufferingStreamSubscription__STATE_HAS_ERROR_HANDLER = 1 << 5;
25// - _Future._stateIgnoreError
26const intptr_t k_Future__stateIgnoreError = 1;
27// - _FutureListener.stateThen.
28const intptr_t k_FutureListener_stateThen = 1;
29// - _FutureListener.stateCatchError.
30const intptr_t k_FutureListener_stateCatchError = 2;
31// - _FutureListener.stateWhenComplete.
32const intptr_t k_FutureListener_stateWhenComplete = 8;
33// - sdk/lib/async/future_impl.dart:_FutureListener.maskAwait.
34const intptr_t k_FutureListener_maskAwait = 16;
35
36bool WasPreviouslySuspended(const Function& function,
37 const Object& suspend_state_var) {
38 if (!suspend_state_var.IsSuspendState()) {
39 return false;
40 }
41 if (function.IsAsyncFunction()) {
42 // Error callback is set after both 'then' and 'error' callbacks are
43 // registered with the Zone. Callback registration may query
44 // stack trace and should still collect the synchronous stack trace.
45 return SuspendState::Cast(suspend_state_var).error_callback() !=
47 } else if (function.IsAsyncGenerator()) {
48 return true;
49 } else {
51 }
52}
53
54bool TryGetAwaiterLink(const Closure& closure, Object* link) {
55 *link = Object::null();
56 const auto& function = Function::Handle(closure.function());
57 const auto awaiter_link = function.awaiter_link();
58 if (awaiter_link.depth != ClosureData::kNoAwaiterLinkDepth) {
59 if (function.IsImplicitClosureFunction()) {
60 ASSERT(awaiter_link.depth == 0 && awaiter_link.index == 0);
61 *link = closure.GetImplicitClosureReceiver();
62 return true;
63 }
64
65 auto& context = Context::Handle(closure.GetContext());
66 intptr_t depth = awaiter_link.depth;
67 while (depth-- > 0) {
68 context = context.parent();
69 }
70
71 *link = context.At(awaiter_link.index);
72 return true;
73 }
74 return false;
75}
76
77// Unwinder which starts by unwinding the synchronous portion of the stack
78// until it reaches a frame which has an asynchronous awaiter (e.g. an
79// activation of the async function which has a listener attached to the
80// corresponding Future object) and then unwinds through the chain
81// of awaiters.
82class AsyncAwareStackUnwinder : public ValueObject {
83 public:
84 explicit AsyncAwareStackUnwinder(Thread* thread,
85 bool* encountered_async_catch_error)
86 : zone_(thread->zone()),
87 sync_frames_(thread, StackFrameIterator::kNoCrossThreadIteration),
88 sync_frame_(nullptr),
89 awaiter_frame_{Closure::Handle(zone_), Object::Handle(zone_)},
90 encountered_async_catch_error_(encountered_async_catch_error),
91 closure_(Closure::Handle(zone_)),
92 code_(Code::Handle(zone_)),
93 context_(Context::Handle(zone_)),
94 function_(Function::Handle(zone_)),
95 parent_function_(Function::Handle(zone_)),
96 object_(Object::Handle(zone_)),
97 result_future_(Object::Handle(zone_)),
98 suspend_state_(SuspendState::Handle(zone_)),
99 controller_(Object::Handle(zone_)),
100 subscription_(Object::Handle(zone_)),
101 stream_iterator_(Object::Handle(zone_)),
102 async_lib_(Library::Handle(zone_, Library::AsyncLibrary())),
103 null_closure_(Closure::Handle(zone_)) {
104 if (encountered_async_catch_error_ != nullptr) {
105 *encountered_async_catch_error_ = false;
106 }
107 }
108
109 void Unwind(intptr_t skip_frames,
110 std::function<void(const StackTraceUtils::Frame&)> handle_frame);
111
112 private:
113 bool HandleSynchronousFrame();
114
115 void UnwindAwaiterFrame();
116
117 // Returns either the `onData` or the Future awaiter.
118 ObjectPtr FindCallerInAsyncStarStreamController(
119 const Object& async_star_stream_controller);
120
121 void InitializeAwaiterFrameFromSuspendState();
122
123 void InitializeAwaiterFrameFromFutureListener(const Object& listener);
124
125 void UnwindToAwaiter();
126
127 // |frame.next| is a |_Future| instance. Unwind to the next frame.
128 void UnwindFrameToFutureListener();
129
130 // |frame.next| is an |_SyncStreamController| instance.
131 void UnwindFrameToStreamController();
132
133 // Follow awaiter-links from the given closure until the first
134 // non-closure awaiter-link is encountered.
135 //
136 // |link| will contain the first non-closure awaiter-link or `null`.
137 // |closure| will be updated to point to the last closure in the chain.
138 void FollowAwaiterLinks(Closure* closure, Object* link);
139
140 // Update |awaiter_frame| by unwinding awaiter links of the current closure.
141 void ComputeNextFrameFromAwaiterLink();
142
143 ObjectPtr GetReceiver() const;
144
145 // Returns |true| if propagating an error to the listeners of this `_Future`
146 // will always encounter an error handler. Future handles error iff:
147 //
148 // * It has no listeners and is marked as ignoring errors
149 // * All of its listeners either have an error handler or corresponding
150 // result future handles error.
151 //
152 // Note: this ignores simple error forwarding/rethrow which occurs in `await`
153 // or patterns like `fut.then(onError: c.completeError)`.
154 bool WillFutureHandleError(const Object& future, intptr_t depth = 0);
155
156 void MarkAsHandlingAsyncError() const {
157 if (ShouldComputeIfAsyncErrorIsHandled()) {
158 *encountered_async_catch_error_ = true;
159 }
160 }
161
162 bool ShouldComputeIfAsyncErrorIsHandled() const {
163 return encountered_async_catch_error_ != nullptr &&
164 !*encountered_async_catch_error_;
165 }
166
167#define USED_CLASS_LIST(V) \
168 V(_AsyncStarStreamController) \
169 V(_BufferingStreamSubscription) \
170 V(_Completer) \
171 V(_AsyncCompleter) \
172 V(_SyncCompleter) \
173 V(_ControllerSubscription) \
174 V(_Future) \
175 V(_FutureListener) \
176 V(_StreamController) \
177 V(_StreamIterator) \
178 V(_SyncStreamController) \
179 V(_StreamControllerAddStreamState) \
180 V(_AddStreamState)
181
182 enum ClassId {
183#define DECLARE_CONSTANT(symbol) k##symbol,
185#undef DECLARE_CONSTANT
186 };
187
188#define USED_FIELD_LIST(V) \
189 V(_AsyncStarStreamController, asyncStarBody) \
190 V(_AsyncStarStreamController, controller) \
191 V(_BufferingStreamSubscription, _onData) \
192 V(_BufferingStreamSubscription, _onDone) \
193 V(_BufferingStreamSubscription, _onError) \
194 V(_BufferingStreamSubscription, _state) \
195 V(_Completer, future) \
196 V(_Future, _resultOrListeners) \
197 V(_Future, _state) \
198 V(_FutureListener, callback) \
199 V(_FutureListener, result) \
200 V(_FutureListener, state) \
201 V(_FutureListener, _nextListener) \
202 V(_StreamController, _state) \
203 V(_StreamController, _varData) \
204 V(_StreamControllerAddStreamState, _varData) \
205 V(_StreamIterator, _hasValue) \
206 V(_StreamIterator, _stateData) \
207 V(_AddStreamState, addStreamFuture)
208
209 enum FieldId {
210#define DECLARE_CONSTANT(class_symbol, field_symbol) \
211 k##class_symbol##_##field_symbol,
213#undef DECLARE_CONSTANT
214 };
215
216#define PLUS_ONE(...) +1
217 static constexpr intptr_t kUsedClassCount = 0 USED_CLASS_LIST(PLUS_ONE);
218 static constexpr intptr_t kUsedFieldCount = 0 USED_FIELD_LIST(PLUS_ONE);
219#undef PLUS_ONE
220
221#define DECLARE_GETTER(symbol) \
222 const Class& symbol() { \
223 auto& cls = classes_[k##symbol]; \
224 if (cls == nullptr) { \
225 cls = &Class::Handle( \
226 zone_, async_lib_.LookupClassAllowPrivate(Symbols::symbol())); \
227 ASSERT(!cls->IsNull()); \
228 } \
229 return *cls; \
230 }
232#undef DECLARE_GETTER
233
234#define DECLARE_GETTER(class_symbol, field_symbol) \
235 ObjectPtr Get##class_symbol##_##field_symbol(const Object& obj) { \
236 auto& field = fields_[k##class_symbol##_##field_symbol]; \
237 if (field == nullptr) { \
238 field = &Field::Handle(zone_, class_symbol().LookupFieldAllowPrivate( \
239 Symbols::field_symbol())); \
240 ASSERT(!field->IsNull()); \
241 } \
242 return Instance::Cast(obj).GetField(*field); \
243 }
245#undef DECLARE_GETTER
246
247 struct AwaiterFrame {
248 Closure& closure;
249 Object& next;
250 };
251
252 Zone* zone_;
253 DartFrameIterator sync_frames_;
254
255 StackFrame* sync_frame_;
256 AwaiterFrame awaiter_frame_;
257
258 bool* encountered_async_catch_error_;
259
260 Closure& closure_;
261 Code& code_;
262 Context& context_;
263 Function& function_;
264 Function& parent_function_;
265 Object& object_;
266 Object& result_future_;
267 SuspendState& suspend_state_;
268
269 Object& controller_;
270 Object& subscription_;
271 Object& stream_iterator_;
272
273 const Library& async_lib_;
274 Class* classes_[kUsedClassCount] = {};
275 Field* fields_[kUsedFieldCount] = {};
276
277 const Closure& null_closure_;
278
279 DISALLOW_COPY_AND_ASSIGN(AsyncAwareStackUnwinder);
280};
281
282void AsyncAwareStackUnwinder::Unwind(
283 intptr_t skip_frames,
284 std::function<void(const StackTraceUtils::Frame&)> handle_frame) {
285 // First skip the given number of synchronous frames.
286 sync_frame_ = sync_frames_.NextFrame();
287 while (skip_frames > 0 && sync_frame_ != nullptr) {
288 sync_frame_ = sync_frames_.NextFrame();
289 skip_frames--;
290 }
291
292 // Continue unwinding synchronous portion of the stack looking for
293 // a synchronous frame which has an awaiter.
294 while (sync_frame_ != nullptr && awaiter_frame_.closure.IsNull()) {
295 const bool was_handled = HandleSynchronousFrame();
296 if (!was_handled) {
297 code_ = sync_frame_->LookupDartCode();
298 const uword pc_offset = sync_frame_->pc() - code_.PayloadStart();
299 handle_frame({sync_frame_, code_, pc_offset, null_closure_});
300 }
301 sync_frame_ = sync_frames_.NextFrame();
302 }
303
304 const StackTraceUtils::Frame gap_frame = {nullptr,
305 StubCode::AsynchronousGapMarker(),
306 /*pc_offset=*/0, null_closure_};
307
308 // Traverse awaiter frames.
309 bool any_async = false;
310 for (; !awaiter_frame_.closure.IsNull(); UnwindToAwaiter()) {
311 function_ = awaiter_frame_.closure.function();
312 if (function_.IsNull()) {
313 continue;
314 }
315
316 any_async = true;
317 uword pc_offset;
318 if (awaiter_frame_.next.IsSuspendState()) {
319 const uword pc = SuspendState::Cast(awaiter_frame_.next).pc();
320 if (pc == 0) {
321 // Async function is already resumed.
322 continue;
323 }
324
325 code_ = SuspendState::Cast(awaiter_frame_.next).GetCodeObject();
326 pc_offset = pc - code_.PayloadStart();
327 } else {
328 // This is an asynchronous continuation represented by a closure which
329 // will handle successful completion. This function is not yet executing
330 // so we have to use artificial marker offset (1).
331 code_ = function_.EnsureHasCode();
332 RELEASE_ASSERT(!code_.IsNull());
333 pc_offset =
334 (function_.entry_point() + StackTraceUtils::kFutureListenerPcOffset) -
335 code_.PayloadStart();
336 }
337
338 handle_frame(gap_frame);
339 handle_frame({nullptr, code_, pc_offset, awaiter_frame_.closure});
340 }
341
342 if (any_async) {
343 handle_frame(gap_frame);
344 }
345}
346
347ObjectPtr AsyncAwareStackUnwinder::GetReceiver() const {
348 return *(reinterpret_cast<ObjectPtr*>(sync_frame_->GetCallerSp()) +
349 function_.num_fixed_parameters() - 1);
350}
351
352bool AsyncAwareStackUnwinder::HandleSynchronousFrame() {
353 function_ = sync_frame_->LookupDartFunction();
354 if (function_.IsNull()) {
355 return false;
356 }
357
358 // This is an invocation of an `async` or `async*` function.
359 if (function_.IsAsyncFunction() || function_.IsAsyncGenerator()) {
360 InitializeAwaiterFrameFromSuspendState();
361 return false;
362 }
363
364 // This is an invocation of a closure which has a variable marked
365 // with `@pragma('vm:awaiter-link')` which points to the awaiter.
366 if (function_.HasAwaiterLink()) {
367 object_ = GetReceiver();
368 if (object_.IsClosure() &&
369 StackTraceUtils::GetSuspendState(Closure::Cast(object_),
370 &awaiter_frame_.next)) {
371 awaiter_frame_.closure ^= object_.ptr();
372 return true; // Hide this frame from the stack trace.
373 }
374 }
375
376 // This is `_FutureListener.handleValue(...)` invocation.
377 if (function_.recognized_kind() ==
378 MethodRecognizer::kFutureListenerHandleValue) {
379 object_ = GetReceiver();
380 InitializeAwaiterFrameFromFutureListener(object_);
381 UnwindToAwaiter();
382 return true; // Hide this frame from the stack trace.
383 }
384
385 return false;
386}
387
388void AsyncAwareStackUnwinder::InitializeAwaiterFrameFromSuspendState() {
389 if (function_.IsAsyncFunction() || function_.IsAsyncGenerator()) {
390 // Check if we reached a resumed asynchronous function. In this case we
391 // are going to start following async frames after we emit this frame.
392 object_ = *reinterpret_cast<ObjectPtr*>(LocalVarAddress(
395
396 awaiter_frame_.closure = Closure::null();
397 if (WasPreviouslySuspended(function_, object_)) {
398 awaiter_frame_.next = object_.ptr();
399 UnwindToAwaiter();
400 }
401 }
402}
403
404void AsyncAwareStackUnwinder::UnwindToAwaiter() {
405 do {
406 UnwindAwaiterFrame();
407 } while (awaiter_frame_.closure.IsNull() && !awaiter_frame_.next.IsNull());
408}
409
410void AsyncAwareStackUnwinder::FollowAwaiterLinks(Closure* closure,
411 Object* link) {
412 *link = Object::null();
413 while (!closure->IsNull() && TryGetAwaiterLink(*closure, link) &&
414 link->IsClosure()) {
415 *closure ^= link->ptr();
416 }
417}
418
419void AsyncAwareStackUnwinder::ComputeNextFrameFromAwaiterLink() {
420 FollowAwaiterLinks(&awaiter_frame_.closure, &object_);
421 if (!object_.IsNull()) {
422 awaiter_frame_.next = object_.ptr();
423 }
424}
425
426void AsyncAwareStackUnwinder::UnwindAwaiterFrame() {
427 if (awaiter_frame_.next.IsSuspendState()) {
428 awaiter_frame_.next =
429 SuspendState::Cast(awaiter_frame_.next).function_data();
430 } else if (awaiter_frame_.next.GetClassId() == _SyncCompleter().id() ||
431 awaiter_frame_.next.GetClassId() == _AsyncCompleter().id()) {
432 awaiter_frame_.next = Get_Completer_future(awaiter_frame_.next);
433 }
434
435 if (awaiter_frame_.next.GetClassId() == _AsyncStarStreamController().id()) {
436 awaiter_frame_.next =
437 Get_AsyncStarStreamController_controller(awaiter_frame_.next);
438 }
439
440 if (awaiter_frame_.next.GetClassId() == _Future().id()) {
441 UnwindFrameToFutureListener();
442 } else if (awaiter_frame_.next.GetClassId() == _SyncStreamController().id()) {
443 UnwindFrameToStreamController();
444 ComputeNextFrameFromAwaiterLink();
445 } else {
446 awaiter_frame_.closure = Closure::null();
447 awaiter_frame_.next = Object::null();
448 }
449}
450
451void AsyncAwareStackUnwinder::UnwindFrameToFutureListener() {
452 object_ = Get_Future__resultOrListeners(awaiter_frame_.next);
453 if (object_.GetClassId() == _FutureListener().id()) {
454 InitializeAwaiterFrameFromFutureListener(object_);
455 } else {
456 if (ShouldComputeIfAsyncErrorIsHandled()) {
457 // Check if error on this future was ignored through |Future.ignore|.
458 const auto state =
459 Smi::Value(Smi::RawCast(Get_Future__state(awaiter_frame_.next)));
460 if ((state & k_Future__stateIgnoreError) != 0) {
461 MarkAsHandlingAsyncError();
462 }
463 }
464
465 awaiter_frame_.closure = Closure::null();
466 awaiter_frame_.next = Object::null();
467 }
468}
469
470bool AsyncAwareStackUnwinder::WillFutureHandleError(const Object& future,
471 intptr_t depth /* = 0 */) {
472 if (depth > 100 || future.GetClassId() != _Future().id()) {
473 return true; // Conservative.
474 }
475
476 if (Get_Future__resultOrListeners(future) == Object::null()) {
477 // No listeners: check if future is simply ignoring errors.
478 const auto state = Smi::Value(Smi::RawCast(Get_Future__state(future)));
479 return (state & k_Future__stateIgnoreError) != 0;
480 }
481
482 for (auto& listener = Object::Handle(Get_Future__resultOrListeners(future));
483 listener.GetClassId() == _FutureListener().id();
484 listener = Get_FutureListener__nextListener(listener)) {
485 const auto state =
486 Smi::Value(Smi::RawCast(Get_FutureListener_state(listener)));
487 if ((state & k_FutureListener_stateCatchError) == 0 &&
488 !WillFutureHandleError(
489 Object::Handle(Get_FutureListener_result(listener)), depth + 1)) {
490 return false;
491 }
492 }
493
494 return true;
495}
496
497void AsyncAwareStackUnwinder::InitializeAwaiterFrameFromFutureListener(
498 const Object& listener) {
499 if (listener.GetClassId() != _FutureListener().id()) {
500 awaiter_frame_.closure = Closure::null();
501 awaiter_frame_.next = Object::null();
502 return;
503 }
504
505 const auto state =
506 Smi::Value(Smi::RawCast(Get_FutureListener_state(listener)));
507 if (state == k_FutureListener_stateThen ||
508 state == k_FutureListener_stateCatchError ||
509 state == k_FutureListener_stateWhenComplete ||
510 state ==
511 (k_FutureListener_stateThen | k_FutureListener_stateCatchError) ||
512 state == (k_FutureListener_stateThen | k_FutureListener_stateCatchError |
513 k_FutureListener_maskAwait)) {
514 result_future_ = Get_FutureListener_result(listener);
515 } else {
516 result_future_ = Object::null();
517 }
518 awaiter_frame_.closure =
519 Closure::RawCast(Get_FutureListener_callback(listener));
520 awaiter_frame_.next = result_future_.ptr();
521
522 ComputeNextFrameFromAwaiterLink();
523
524 if (ShouldComputeIfAsyncErrorIsHandled() && !result_future_.IsNull() &&
525 result_future_.ptr() != awaiter_frame_.next.ptr()) {
526 // We have unwound through closure rather than followed result future, this
527 // can be caused by unwinding through `await` or code like
528 // `fut.whenComplete(c.complete)`. If the current future does not
529 // catch the error then the error will be forwarded into result_future_.
530 // Check if result_future_ handles it and set
531 // encountered_async_catch_error_ respectively.
532 if ((state & k_FutureListener_stateCatchError) == 0 &&
533 WillFutureHandleError(result_future_)) {
534 MarkAsHandlingAsyncError();
535 }
536 }
537
538 // If the Future has catchError callback attached through either
539 // `Future.catchError` or `Future.then(..., onError: ...)` then we should
540 // treat this listener as a catch all exception handler. However we should
541 // ignore the case when these callbacks are simply forwarding errors into a
542 // suspended async function, because it will be represented by its own async
543 // frame.
544 //
545 // However if we fail to unwind this frame (e.g. because there is some
546 // Zone wrapping callbacks and obstructing unwinding) then we conservatively
547 // treat this error handler as handling all errors to prevent user
548 // unfriendly situations where debugger stops on handled exceptions.
549 if ((state & k_FutureListener_stateCatchError) != 0 &&
550 ((state & k_FutureListener_maskAwait) == 0 ||
551 !awaiter_frame_.next.IsSuspendState())) {
552 MarkAsHandlingAsyncError();
553 }
554}
555
556void AsyncAwareStackUnwinder::UnwindFrameToStreamController() {
557 controller_ = awaiter_frame_.next.ptr();
558
559 // Clear the frame.
560 awaiter_frame_.closure = Closure::null();
561 awaiter_frame_.next = Object::null();
562
563 const auto state =
564 Smi::Value(Smi::RawCast(Get_StreamController__state(controller_)));
565
566 if ((state & k_StreamController__STATE_SUBSCRIPTION_MASK) !=
567 k_StreamController__STATE_SUBSCRIBED) {
568 return;
569 }
570
571 subscription_ = Get_StreamController__varData(controller_);
572 if ((state & k_StreamController__STATE_ADDSTREAM) != 0) {
573 subscription_ = Get_StreamControllerAddStreamState__varData(subscription_);
574 }
575
576 closure_ ^= Get_BufferingStreamSubscription__onData(subscription_);
577
578 const auto subscription_state = Smi::Value(
579 Smi::RawCast(Get_BufferingStreamSubscription__state(subscription_)));
580
581 const auto has_error_handler =
582 ((subscription_state &
583 k_BufferingStreamSubscription__STATE_HAS_ERROR_HANDLER) != 0);
584
585 // If this is not the "_StreamIterator._onData" tear-off, we return the
586 // callback we found.
587 function_ = closure_.function();
588 if (function_.IsImplicitClosureFunction()) {
589 // Handle `await for` case. In this case onData is calling
590 // _StreamIterator._onData which then notifies awaiter by completing
591 // _StreamIterator.moveNextFuture.
592 if (function_.Owner() == _StreamIterator().ptr()) {
593 // All implicit closure functions (tear-offs) have the "this" receiver
594 // captured in the context.
595 stream_iterator_ = closure_.GetImplicitClosureReceiver();
596
597 if (stream_iterator_.GetClassId() != _StreamIterator().id()) {
598 UNREACHABLE();
599 }
600
601 // If `_hasValue` is true then the `StreamIterator._stateData` field
602 // contains the iterator's value. In that case we cannot unwind anymore.
603 //
604 // Notice: With correct async* semantics this may never be true: the
605 // async* generator should only be invoked to produce a value if there's
606 // an in-progress `await streamIterator.moveNext()` call. Once such call
607 // has finished the async* generator should be paused/yielded until the
608 // next such call - and being paused/yielded means it should not appear
609 // in stack traces.
610 //
611 // See dartbug.com/48695.
612 if (Get_StreamIterator__hasValue(stream_iterator_) ==
613 Object::bool_true().ptr()) {
614 if (has_error_handler) {
615 MarkAsHandlingAsyncError();
616 }
617 return;
618 }
619
620 // If we have an await'er for `await streamIterator.moveNext()` we
621 // continue unwinding there.
622 //
623 // Notice: With correct async* semantics this may always contain a Future
624 // See also comment above as well as dartbug.com/48695.
625 object_ = Get_StreamIterator__stateData(stream_iterator_);
626 if (object_.GetClassId() == _Future().id()) {
627 awaiter_frame_.next = object_.ptr();
628 } else {
629 if (has_error_handler) {
630 MarkAsHandlingAsyncError();
631 }
632 }
633 return;
634 }
635
636 // Handle `yield*` case. Here one stream controller will be forwarding
637 // to another one. If the destination controller is
638 // _AsyncStarStreamController, then we should make sure to reflect
639 // its asyncStarBody in the stack trace.
640 if (function_.Owner() == _StreamController().ptr()) {
641 // Get the controller to which we are forwarding and check if it is
642 // in the ADD_STREAM state.
643 object_ = closure_.GetImplicitClosureReceiver();
644 const auto state =
645 Smi::Value(Smi::RawCast(Get_StreamController__state(object_)));
646 if ((state & k_StreamController__STATE_ADDSTREAM) != 0) {
647 // Get to the addStreamFuture - if this is yield* internals we
648 // will be able to get original _AsyncStarStreamController from
649 // handler attached to that future.
650 object_ = Get_StreamController__varData(object_);
651 object_ = Get_AddStreamState_addStreamFuture(object_);
652 object_ = Get_Future__resultOrListeners(object_);
653 if (object_.GetClassId() == _FutureListener().id()) {
654 const auto state =
655 Smi::Value(Smi::RawCast(Get_FutureListener_state(object_)));
656 if (state == k_FutureListener_stateThen) {
657 auto& handler = Closure::Handle(
658 Closure::RawCast(Get_FutureListener_callback(object_)));
659 FollowAwaiterLinks(&handler, &object_);
660 if (object_.GetClassId() == _AsyncStarStreamController().id()) {
661 awaiter_frame_.closure = Closure::RawCast(
662 Get_AsyncStarStreamController_asyncStarBody(object_));
663 return;
664 }
665 }
666 }
667 }
668 }
669 }
670
671 awaiter_frame_.closure = closure_.ptr();
672
673 bool found_awaiter_link_in_sibling_handler = false;
674
675 if (!function_.HasAwaiterLink()) {
676 // If we don't have awaiter-link in the `onData` handler, try checking
677 // if either onError or onDone have an awaiter link.
678 closure_ ^= Get_BufferingStreamSubscription__onError(subscription_);
679 function_ = closure_.function();
680 found_awaiter_link_in_sibling_handler = function_.HasAwaiterLink();
681 }
682
683 if (!function_.HasAwaiterLink()) {
684 closure_ ^= Get_BufferingStreamSubscription__onDone(subscription_);
685 function_ = closure_.function();
686 found_awaiter_link_in_sibling_handler = function_.HasAwaiterLink();
687 }
688
689 if (has_error_handler || found_awaiter_link_in_sibling_handler) {
690 FollowAwaiterLinks(&closure_, &object_);
691 }
692
693 if (has_error_handler && object_.GetClassId() != _Future().id() &&
694 object_.GetClassId() != _SyncStreamController().id()) {
695 MarkAsHandlingAsyncError();
696 }
697
698 if (found_awaiter_link_in_sibling_handler) {
699 if (object_.GetClassId() == _AsyncStarStreamController().id() ||
700 object_.GetClassId() == _SyncStreamController().id()) {
701 // We can continue unwinding from here.
702 awaiter_frame_.closure = closure_.ptr();
703 } else {
704 awaiter_frame_.next = object_.ptr();
705 }
706 }
707}
708
709} // namespace
710
712 if (cls.library() != Library::AsyncLibrary()) {
713 return false;
714 }
715
717 const auto is_class = [&](const String& name) {
718 class_name = cls.Name();
720 };
721
722 return is_class(Symbols::_AsyncStarStreamController()) ||
723 is_class(Symbols::_SyncStreamController()) ||
724 is_class(Symbols::_StreamController()) ||
725 is_class(Symbols::_Completer()) ||
726 is_class(Symbols::_AsyncCompleter()) ||
727 is_class(Symbols::_SyncCompleter()) || is_class(Symbols::_Future());
728}
729
731 // If this is a closure function which specifies an awaiter-link then
732 // we need to retain both function and the corresponding code.
733 if (function.HasAwaiterLink()) {
734 return true;
735 }
736
737 if (function.recognized_kind() ==
738 MethodRecognizer::kFutureListenerHandleValue) {
739 return true;
740 }
741
742 return false;
743}
744
746 Thread* thread,
747 int skip_frames,
748 const std::function<void(const StackTraceUtils::Frame&)>& handle_frame,
749 bool* has_async_catch_error /* = null */) {
750 AsyncAwareStackUnwinder it(thread, has_async_catch_error);
751 it.Unwind(skip_frames, handle_frame);
752}
753
755 Object* suspend_state) {
756 if (TryGetAwaiterLink(closure, suspend_state)) {
757 return suspend_state->IsSuspendState();
758 }
759 return false;
760}
761
762} // namespace dart
#define UNREACHABLE()
Definition assert.h:248
#define RELEASE_ASSERT(cond)
Definition assert.h:327
LibraryPtr library() const
Definition object.h:1335
StringPtr Name() const
Definition object.cc:3038
static constexpr uint8_t kNoAwaiterLinkDepth
Definition object.h:4304
static LibraryPtr AsyncLibrary()
Definition object.cc:14826
static ObjectPtr null()
Definition object.h:433
intptr_t GetClassId() const
Definition object.h:341
static Object & Handle()
Definition object.h:407
static ObjectPtr RawCast(ObjectPtr obj)
Definition object.h:325
intptr_t Value() const
Definition object.h:9969
static bool IsNeededForAsyncAwareUnwinding(const Function &function)
static bool GetSuspendState(const Closure &closure, Object *suspend_state)
static void CollectFrames(Thread *thread, int skip_frames, const std::function< void(const Frame &)> &handle_frame, bool *has_async_catch_error=nullptr)
static bool IsPossibleAwaiterLink(const Class &cls)
static constexpr uword kFutureListenerPcOffset
Definition stack_trace.h:19
static bool EqualsIgnoringPrivateKey(const String &str1, const String &str2)
Definition object.cc:24378
static constexpr intptr_t kSuspendStateVarIndex
Definition object.h:12591
#define ASSERT(E)
AtkStateType state
Dart_NativeFunction function
Definition fuchsia.cc:51
#define DECLARE_GETTER(when, name, bitname, isolate_flag_name, flag_name)
Definition isolate.h:433
link(from_root, to_root)
Definition dart_pkg.py:44
const char *const name
const char *const class_name
uintptr_t uword
Definition globals.h:501
FrameLayout runtime_frame_layout
static DART_FORCE_INLINE uword LocalVarAddress(uword fp, intptr_t index)
std::function< void()> closure
Definition closure.h:14
T * GetReceiver(Dart_NativeArguments args)
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition globals.h:581
#define PLUS_ONE(...)
#define DECLARE_CONSTANT(symbol)
#define USED_CLASS_LIST(V)
#define USED_FIELD_LIST(V)
intptr_t FrameSlotForVariableIndex(intptr_t index) const