| Index: src/debug/debug.cc
|
| diff --git a/src/debug/debug.cc b/src/debug/debug.cc
|
| index a21bfde25c1c5fab931337dc0679f97ddf16e9a9..31949bb5530b02743966d0e55379932f14719933 100644
|
| --- a/src/debug/debug.cc
|
| +++ b/src/debug/debug.cc
|
| @@ -1890,8 +1890,64 @@ void ResetPromiseHandle(const v8::WeakCallbackInfo<void>& info) {
|
| GlobalHandles::Destroy(data->location);
|
| info.SetSecondPassCallback(&SendAsyncTaskEventCancel);
|
| }
|
| +
|
| +// In an async function, reuse the existing stack related to the outer
|
| +// Promise. Otherwise, e.g. in a direct call to then, save a new stack.
|
| +// Promises with multiple reactions with one or more of them being async
|
| +// functions will not get a good stack trace, as async functions require
|
| +// different stacks from direct Promise use, but we save and restore a
|
| +// stack once for all reactions.
|
| +//
|
| +// If this isn't a case of async function, we return false, otherwise
|
| +// we set the correct id and return true.
|
| +//
|
| +// TODO(littledan): Improve this case.
|
| +int GetReferenceAsyncTaskId(Isolate* isolate, Handle<JSPromise> promise) {
|
| + Handle<Symbol> handled_by_symbol =
|
| + isolate->factory()->promise_handled_by_symbol();
|
| + Handle<Object> handled_by_promise =
|
| + JSObject::GetDataProperty(promise, handled_by_symbol);
|
| + if (!handled_by_promise->IsJSPromise()) {
|
| + return isolate->debug()->NextAsyncTaskId(promise);
|
| + }
|
| + Handle<JSPromise> handled_by_promise_js =
|
| + Handle<JSPromise>::cast(handled_by_promise);
|
| + Handle<Symbol> async_stack_id_symbol =
|
| + isolate->factory()->promise_async_stack_id_symbol();
|
| + Handle<Object> async_task_id =
|
| + JSObject::GetDataProperty(handled_by_promise_js, async_stack_id_symbol);
|
| + if (!async_task_id->IsSmi()) {
|
| + return isolate->debug()->NextAsyncTaskId(promise);
|
| + }
|
| + return Handle<Smi>::cast(async_task_id)->value();
|
| +}
|
| } // namespace
|
|
|
| +void Debug::RunPromiseHook(PromiseHookType type, Handle<JSPromise> promise,
|
| + Handle<Object> parent) {
|
| + if (!debug_delegate_) return;
|
| + int id = GetReferenceAsyncTaskId(isolate_, promise);
|
| + switch (type) {
|
| + case PromiseHookType::kInit:
|
| + debug_delegate_->PromiseEventOccurred(
|
| + debug::kDebugPromiseCreated, id,
|
| + parent->IsJSPromise() ? GetReferenceAsyncTaskId(
|
| + isolate_, Handle<JSPromise>::cast(parent))
|
| + : 0);
|
| + return;
|
| + case PromiseHookType::kResolve:
|
| + // We can't use this hook because it's called before promise object will
|
| + // get resolved status.
|
| + return;
|
| + case PromiseHookType::kBefore:
|
| + OnAsyncTaskEvent(debug::kDebugWillHandle, id);
|
| + return;
|
| + case PromiseHookType::kAfter:
|
| + OnAsyncTaskEvent(debug::kDebugDidHandle, id);
|
| + return;
|
| + }
|
| +}
|
| +
|
| int Debug::NextAsyncTaskId(Handle<JSObject> promise) {
|
| LookupIterator it(promise, isolate_->factory()->promise_async_id_symbol());
|
| Maybe<bool> maybe = JSReceiver::HasProperty(&it);
|
| @@ -1958,7 +2014,7 @@ void Debug::OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id) {
|
| if (in_debug_scope() || ignore_events()) return;
|
|
|
| if (debug_delegate_) {
|
| - debug_delegate_->PromiseEventOccurred(type, id);
|
| + debug_delegate_->PromiseEventOccurred(type, id, 0);
|
| if (!non_inspector_listener_exists()) return;
|
| }
|
|
|
| @@ -2093,6 +2149,7 @@ void Debug::UpdateState() {
|
| Unload();
|
| }
|
| is_active_ = is_active;
|
| + isolate_->DebugStateUpdated();
|
| }
|
|
|
| void Debug::UpdateHookOnFunctionCall() {
|
|
|