| Index: src/runtime/runtime-promise.cc
|
| diff --git a/src/runtime/runtime-promise.cc b/src/runtime/runtime-promise.cc
|
| index 8da5568b1d3d76315c595c33522be80d64d0e6f6..655b9fa43d279d6ef1ba5c5888a026cf7feaf703 100644
|
| --- a/src/runtime/runtime-promise.cc
|
| +++ b/src/runtime/runtime-promise.cc
|
| @@ -60,33 +60,81 @@ RUNTIME_FUNCTION(Runtime_PromiseRevokeReject) {
|
| }
|
|
|
| namespace {
|
| +
|
| +// 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.
|
| +bool GetDebugIdForAsyncFunction(Isolate* isolate,
|
| + Handle<PromiseReactionJobInfo> info,
|
| + int* debug_id) {
|
| + // deferred_promise can be Undefined, FixedArray or userland promise object.
|
| + if (!info->deferred_promise()->IsJSPromise()) {
|
| + return false;
|
| + }
|
| +
|
| + Handle<JSPromise> deferred_promise(JSPromise::cast(info->deferred_promise()),
|
| + isolate);
|
| + Handle<Symbol> handled_by_symbol =
|
| + isolate->factory()->promise_handled_by_symbol();
|
| + Handle<Object> handled_by_promise =
|
| + JSObject::GetDataProperty(deferred_promise, handled_by_symbol);
|
| +
|
| + if (!handled_by_promise->IsJSPromise()) {
|
| + return false;
|
| + }
|
| +
|
| + 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> id =
|
| + JSObject::GetDataProperty(handled_by_promise_js, async_stack_id_symbol);
|
| +
|
| + // id can be Undefined or Smi.
|
| + if (!id->IsSmi()) {
|
| + return false;
|
| + }
|
| +
|
| + *debug_id = Handle<Smi>::cast(id)->value();
|
| + return true;
|
| +}
|
| +
|
| +void SetDebugInfo(Isolate* isolate, Handle<PromiseReactionJobInfo> info,
|
| + int status) {
|
| + int id;
|
| + PromiseDebugActionName name;
|
| +
|
| + if (GetDebugIdForAsyncFunction(isolate, info, &id)) {
|
| + name = kDebugAsyncFunction;
|
| + } else {
|
| + id = isolate->GetNextDebugMicrotaskId();
|
| +
|
| + DCHECK(status != v8::Promise::kPending);
|
| + name = status == v8::Promise::kFulfilled ? kDebugPromiseResolve
|
| + : kDebugPromiseReject;
|
| +
|
| + isolate->debug()->OnAsyncTaskEvent(kDebugEnqueue, id, name);
|
| + }
|
| +
|
| + info->set_debug_id(id);
|
| + info->set_debug_name(name);
|
| +}
|
| +
|
| void EnqueuePromiseReactionJob(Isolate* isolate,
|
| Handle<PromiseReactionJobInfo> info,
|
| - Handle<Object> status) {
|
| + int status) {
|
| if (isolate->debug()->is_active()) {
|
| - MaybeHandle<Object> maybe_result;
|
| - Handle<Object> deferred_obj(info->deferred_promise(), isolate);
|
| -
|
| - if (info->deferred_promise()->IsFixedArray()) {
|
| - deferred_obj = isolate->factory()->undefined_value();
|
| - }
|
| -
|
| - Handle<Object> argv[] = {deferred_obj, status};
|
| - maybe_result = Execution::TryCall(
|
| - isolate, isolate->promise_debug_get_info(),
|
| - isolate->factory()->undefined_value(), arraysize(argv), argv);
|
| -
|
| - Handle<Object> result;
|
| - if ((maybe_result).ToHandle(&result)) {
|
| - CHECK(result->IsJSArray());
|
| - Handle<JSArray> array = Handle<JSArray>::cast(result);
|
| - ElementsAccessor* accessor = array->GetElementsAccessor();
|
| - DCHECK(accessor->HasElement(array, 0));
|
| - DCHECK(accessor->HasElement(array, 1));
|
| - info->set_debug_id(*accessor->Get(array, 0));
|
| - info->set_debug_name(*accessor->Get(array, 1));
|
| - }
|
| + SetDebugInfo(isolate, info, status);
|
| }
|
| +
|
| isolate->EnqueueMicrotask(info);
|
| }
|
|
|
| @@ -101,11 +149,11 @@ void PromiseSet(Isolate* isolate, Handle<JSPromise> promise, int status,
|
| promise->set_reject_reactions(isolate->heap()->undefined_value());
|
| }
|
|
|
| -void PromiseFulfill(Isolate* isolate, Handle<JSPromise> promise,
|
| - Handle<Smi> status, Handle<Object> value) {
|
| +void PromiseFulfill(Isolate* isolate, Handle<JSPromise> promise, int status,
|
| + Handle<Object> value) {
|
| // Check if there are any callbacks.
|
| if (!promise->deferred_promise()->IsUndefined(isolate)) {
|
| - Handle<Object> tasks((status->value() == v8::Promise::kFulfilled)
|
| + Handle<Object> tasks((status == v8::Promise::kFulfilled)
|
| ? promise->fulfill_reactions()
|
| : promise->reject_reactions(),
|
| isolate);
|
| @@ -118,7 +166,7 @@ void PromiseFulfill(Isolate* isolate, Handle<JSPromise> promise,
|
| EnqueuePromiseReactionJob(isolate, info, status);
|
| }
|
|
|
| - PromiseSet(isolate, promise, status->value(), value);
|
| + PromiseSet(isolate, promise, status, value);
|
| }
|
|
|
| } // namespace
|
| @@ -131,9 +179,8 @@ RUNTIME_FUNCTION(Runtime_PromiseReject) {
|
| CONVERT_BOOLEAN_ARG_CHECKED(debug_event, 2);
|
|
|
| PromiseRejectEvent(isolate, promise, promise, reason, debug_event);
|
| + PromiseFulfill(isolate, promise, v8::Promise::kRejected, reason);
|
|
|
| - Handle<Smi> status(Smi::FromInt(v8::Promise::kRejected), isolate);
|
| - PromiseFulfill(isolate, promise, status, reason);
|
| return isolate->heap()->undefined_value();
|
| }
|
|
|
| @@ -141,7 +188,7 @@ RUNTIME_FUNCTION(Runtime_PromiseFulfill) {
|
| DCHECK(args.length() == 3);
|
| HandleScope scope(isolate);
|
| CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Smi, status, 1);
|
| + CONVERT_SMI_ARG_CHECKED(status, 1);
|
| CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
|
| PromiseFulfill(isolate, promise, status, value);
|
| return isolate->heap()->undefined_value();
|
| @@ -151,7 +198,7 @@ RUNTIME_FUNCTION(Runtime_EnqueuePromiseReactionJob) {
|
| HandleScope scope(isolate);
|
| DCHECK(args.length() == 2);
|
| CONVERT_ARG_HANDLE_CHECKED(PromiseReactionJobInfo, info, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, status, 1);
|
| + CONVERT_SMI_ARG_CHECKED(status, 1);
|
| EnqueuePromiseReactionJob(isolate, info, status);
|
| return isolate->heap()->undefined_value();
|
| }
|
| @@ -170,17 +217,12 @@ RUNTIME_FUNCTION(Runtime_EnqueuePromiseResolveThenableJob) {
|
| PromiseUtils::CreateResolvingFunctions(
|
| isolate, promise, isolate->factory()->false_value(), &resolve, &reject);
|
|
|
| - Handle<Object> debug_id, debug_name;
|
| + int debug_id = kDebugPromiseFirstID;
|
| + PromiseDebugActionName debug_name = kDebugNotActive;
|
| if (isolate->debug()->is_active()) {
|
| - debug_id =
|
| - handle(Smi::FromInt(isolate->GetNextDebugMicrotaskId()), isolate);
|
| - debug_name = isolate->factory()->PromiseResolveThenableJob_string();
|
| - isolate->debug()->OnAsyncTaskEvent(isolate->factory()->enqueue_string(),
|
| - debug_id,
|
| - Handle<String>::cast(debug_name));
|
| - } else {
|
| - debug_id = isolate->factory()->undefined_value();
|
| - debug_name = isolate->factory()->undefined_value();
|
| + debug_id = isolate->GetNextDebugMicrotaskId();
|
| + debug_name = kDebugPromiseResolveThenableJob;
|
| + isolate->debug()->OnAsyncTaskEvent(kDebugEnqueue, debug_id, debug_name);
|
| }
|
|
|
| Handle<PromiseResolveThenableJobInfo> info =
|
|
|