| Index: src/debug/debug.cc
|
| diff --git a/src/debug/debug.cc b/src/debug/debug.cc
|
| index 8b411b688696d37132b7d4caf4774d6461c987b6..bbeefff486d34b5923b41f8f5f831fd278d6924f 100644
|
| --- a/src/debug/debug.cc
|
| +++ b/src/debug/debug.cc
|
| @@ -401,6 +401,7 @@ void Debug::ThreadInit() {
|
| thread_local_.last_fp_ = 0;
|
| thread_local_.target_fp_ = 0;
|
| thread_local_.return_value_ = Handle<Object>();
|
| + thread_local_.async_task_count_ = 0;
|
| clear_suspended_generator();
|
| // TODO(isolates): frames_are_dropped_?
|
| base::NoBarrier_Store(&thread_local_.current_debug_scope_,
|
| @@ -1778,7 +1779,63 @@ void Debug::OnAfterCompile(Handle<Script> script) {
|
| ProcessCompileEvent(v8::AfterCompile, script);
|
| }
|
|
|
| -void Debug::OnAsyncTaskEvent(PromiseDebugActionType type, int id,
|
| +namespace {
|
| +struct CollectedCallbackData {
|
| + Object** location;
|
| + int id;
|
| + Debug* debug;
|
| + Isolate* isolate;
|
| +
|
| + CollectedCallbackData(Object** location, int id, Debug* debug,
|
| + Isolate* isolate)
|
| + : location(location), id(id), debug(debug), isolate(isolate) {}
|
| +};
|
| +
|
| +void SendAsyncTaskEventCancel(const v8::WeakCallbackInfo<void>& info) {
|
| + std::unique_ptr<CollectedCallbackData> data(
|
| + reinterpret_cast<CollectedCallbackData*>(info.GetParameter()));
|
| + if (!data->debug->is_active()) return;
|
| + HandleScope scope(data->isolate);
|
| + data->debug->OnAsyncTaskEvent(debug::kDebugCancel, data->id,
|
| + kDebugPromiseCollected);
|
| +}
|
| +
|
| +void ResetPromiseHandle(const v8::WeakCallbackInfo<void>& info) {
|
| + CollectedCallbackData* data =
|
| + reinterpret_cast<CollectedCallbackData*>(info.GetParameter());
|
| + GlobalHandles::Destroy(data->location);
|
| + info.SetSecondPassCallback(&SendAsyncTaskEventCancel);
|
| +}
|
| +} // namespace
|
| +
|
| +int Debug::NextAsyncTaskId(Handle<JSObject> promise) {
|
| + LookupIterator it(promise, isolate_->factory()->promise_async_id_symbol());
|
| + Maybe<bool> maybe = JSReceiver::HasProperty(&it);
|
| + if (maybe.ToChecked()) {
|
| + MaybeHandle<Object> result = Object::GetProperty(&it);
|
| + return Handle<Smi>::cast(result.ToHandleChecked())->value();
|
| + }
|
| + Handle<Smi> async_id =
|
| + handle(Smi::FromInt(++thread_local_.async_task_count_), isolate_);
|
| + Object::SetProperty(&it, async_id, SLOPPY, Object::MAY_BE_STORE_FROM_KEYED)
|
| + .ToChecked();
|
| + Handle<Object> global_handle = isolate_->global_handles()->Create(*promise);
|
| + // We send EnqueueRecurring async task event when promise is fulfilled or
|
| + // rejected, WillHandle and DidHandle for every scheduled microtask for this
|
| + // promise.
|
| + // We need to send a cancel event when no other microtasks can be
|
| + // started for this promise and all current microtasks are finished.
|
| + // Since we holding promise when at least one microtask is scheduled (inside
|
| + // PromiseReactionJobInfo), we can send cancel event in weak callback.
|
| + GlobalHandles::MakeWeak(
|
| + global_handle.location(),
|
| + new CollectedCallbackData(global_handle.location(), async_id->value(),
|
| + this, isolate_),
|
| + &ResetPromiseHandle, v8::WeakCallbackType::kParameter);
|
| + return async_id->value();
|
| +}
|
| +
|
| +void Debug::OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id,
|
| PromiseDebugActionName name) {
|
| if (in_debug_scope() || ignore_events()) return;
|
|
|
|
|