| Index: src/isolate.cc
|
| diff --git a/src/isolate.cc b/src/isolate.cc
|
| index 46805d26df30d63f2376925973ad25441c0f8c7b..9cbabef01d9859a8be2e0d3935aab0f21140ec7e 100644
|
| --- a/src/isolate.cc
|
| +++ b/src/isolate.cc
|
| @@ -1808,23 +1808,91 @@ void Isolate::PopPromise() {
|
| global_handles()->Destroy(global_promise.location());
|
| }
|
|
|
| -bool Isolate::PromiseHasUserDefinedRejectHandler(Handle<Object> promise) {
|
| - Handle<JSFunction> fun = promise_has_user_defined_reject_handler();
|
| - Handle<Object> has_reject_handler;
|
| - // If we are, e.g., overflowing the stack, don't try to call out to JS
|
| - if (!AllowJavascriptExecution::IsAllowed(this)) return false;
|
| - // Call the registered function to check for a handler
|
| - if (Execution::TryCall(this, fun, promise, 0, NULL)
|
| - .ToHandle(&has_reject_handler)) {
|
| - return has_reject_handler->IsTrue(this);
|
| - }
|
| - // If an exception is thrown in the course of execution of this built-in
|
| - // function, it indicates either a bug, or a synthetic uncatchable
|
| - // exception in the shutdown path. In either case, it's OK to predict either
|
| - // way in DevTools.
|
| +namespace {
|
| +bool InternalPromiseHasUserDefinedRejectHandler(Isolate* isolate,
|
| + Handle<JSPromise> promise);
|
| +
|
| +bool PromiseHandlerCheck(Isolate* isolate, Handle<JSReceiver> handler,
|
| + Handle<JSObject> deferred) {
|
| + // Recurse to the forwarding Promise, if any. This may be due to
|
| + // - await reaction forwarding to the throwaway Promise, which has
|
| + // a dependency edge to the outer Promise.
|
| + // - PromiseIdResolveHandler forwarding to the output of .then
|
| + // - Promise.all/Promise.race forwarding to a throwaway Promise, which
|
| + // has a dependency edge to the generated outer Promise.
|
| + Handle<Symbol> key = isolate->factory()->promise_forwarding_handler_symbol();
|
| + Handle<Object> forwarding_handler = JSReceiver::GetDataProperty(handler, key);
|
| + if (forwarding_handler->IsUndefined(isolate)) {
|
| + return true;
|
| + }
|
| +
|
| + // TODO(gsathya): Remove this once we get rid of deferred objects.
|
| + Handle<String> promise_str = isolate->factory()->promise_string();
|
| + Handle<Object> deferred_promise_obj =
|
| + JSObject::GetDataProperty(deferred, promise_str);
|
| + if (!deferred_promise_obj->IsJSPromise()) {
|
| + return true;
|
| + }
|
| +
|
| + return InternalPromiseHasUserDefinedRejectHandler(
|
| + isolate, Handle<JSPromise>::cast(deferred_promise_obj));
|
| +
|
| + // Otherwise, this is a real reject handler for the Promise
|
| + return true;
|
| +}
|
| +
|
| +bool InternalPromiseHasUserDefinedRejectHandler(Isolate* isolate,
|
| + Handle<JSPromise> promise) {
|
| + // If this promise was marked as being handled by a catch block
|
| + // in an async function, then it has a user-defined reject handler.
|
| + if (promise->handled_hint()) return true;
|
| +
|
| + // If this Promise is subsumed by another Promise (a Promise resolved
|
| + // with another Promise, or an intermediate, hidden, throwaway Promise
|
| + // within async/await), then recurse on the outer Promise.
|
| + // In this case, the dependency is one possible way that the Promise
|
| + // could be resolved, so it does not subsume the other following cases.
|
| + Handle<Symbol> key = isolate->factory()->promise_handled_by_symbol();
|
| + Handle<Object> outer_promise_obj = JSObject::GetDataProperty(promise, key);
|
| + if (outer_promise_obj->IsJSPromise() &&
|
| + InternalPromiseHasUserDefinedRejectHandler(
|
| + isolate, Handle<JSPromise>::cast(outer_promise_obj))) {
|
| + return true;
|
| + }
|
| +
|
| + Handle<Object> queue(promise->reject_reactions(), isolate);
|
| + Handle<Object> deferred(promise->deferred(), isolate);
|
| +
|
| + if (queue->IsUndefined(isolate)) {
|
| + return false;
|
| + }
|
| +
|
| + if (queue->IsCallable()) {
|
| + return PromiseHandlerCheck(isolate, Handle<JSReceiver>::cast(queue),
|
| + Handle<JSObject>::cast(deferred));
|
| + }
|
| +
|
| + Handle<FixedArray> queue_arr = Handle<FixedArray>::cast(queue);
|
| + Handle<FixedArray> deferred_arr = Handle<FixedArray>::cast(deferred);
|
| + for (int i = 0; i < deferred_arr->length(); i++) {
|
| + Handle<JSReceiver> queue_item(JSReceiver::cast(queue_arr->get(i)));
|
| + Handle<JSObject> deferred_item(JSObject::cast(deferred_arr->get(i)));
|
| + if (PromiseHandlerCheck(isolate, queue_item, deferred_item)) {
|
| + return true;
|
| + }
|
| + }
|
| +
|
| return false;
|
| }
|
|
|
| +} // namespace
|
| +
|
| +bool Isolate::PromiseHasUserDefinedRejectHandler(Handle<Object> promise) {
|
| + if (!promise->IsJSPromise()) return false;
|
| + return InternalPromiseHasUserDefinedRejectHandler(
|
| + this, Handle<JSPromise>::cast(promise));
|
| +}
|
| +
|
| Handle<Object> Isolate::GetPromiseOnStackOnThrow() {
|
| Handle<Object> undefined = factory()->undefined_value();
|
| ThreadLocalTop* tltop = thread_local_top();
|
| @@ -1842,7 +1910,7 @@ Handle<Object> Isolate::GetPromiseOnStackOnThrow() {
|
| continue;
|
| case HandlerTable::CAUGHT:
|
| case HandlerTable::DESUGARING:
|
| - if (retval->IsJSObject()) {
|
| + if (retval->IsJSPromise()) {
|
| // Caught the result of an inner async/await invocation.
|
| // Mark the inner promise as caught in the "synchronous case" so
|
| // that Debug::OnException will see. In the synchronous case,
|
| @@ -1850,10 +1918,7 @@ Handle<Object> Isolate::GetPromiseOnStackOnThrow() {
|
| // await, the function which has this exception event has not yet
|
| // returned, so the generated Promise has not yet been marked
|
| // by AsyncFunctionAwaitCaught with promiseHandledHintSymbol.
|
| - Handle<Symbol> key = factory()->promise_handled_hint_symbol();
|
| - JSObject::SetProperty(Handle<JSObject>::cast(retval), key,
|
| - factory()->true_value(), STRICT)
|
| - .Assert();
|
| + Handle<JSPromise>::cast(retval)->set_handled_hint(true);
|
| }
|
| return retval;
|
| case HandlerTable::PROMISE:
|
|
|