Index: src/isolate.cc |
diff --git a/src/isolate.cc b/src/isolate.cc |
index 5876af004fc56d7be5cccb9e1d9b360e43c71f20..cb5eb1616bc23f58d082f6929786815dd194dfdd 100644 |
--- a/src/isolate.cc |
+++ b/src/isolate.cc |
@@ -1319,6 +1319,7 @@ Isolate::CatchType Isolate::PredictExceptionCatcher() { |
JavaScriptFrame* js_frame = static_cast<JavaScriptFrame*>(frame); |
HandlerTable::CatchPrediction prediction = PredictException(js_frame); |
if (prediction == HandlerTable::DESUGARING) return CAUGHT_BY_DESUGARING; |
+ if (prediction == HandlerTable::ASYNC_AWAIT) return CAUGHT_BY_ASYNC_AWAIT; |
if (prediction != HandlerTable::UNCAUGHT) return CAUGHT_BY_JAVASCRIPT; |
} |
@@ -1725,6 +1726,14 @@ void Isolate::PopPromise() { |
global_handles()->Destroy(global_promise.location()); |
} |
+bool Isolate::PromiseHasUserDefinedRejectHandler(Handle<JSObject> promise) { |
+ Handle<JSFunction> fun = promise_has_user_defined_reject_handler(); |
+ Handle<Object> has_reject_handler; |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(this, has_reject_handler, |
+ Execution::Call(this, fun, promise, 0, NULL), |
+ false); |
+ return has_reject_handler->IsTrue(this); |
+} |
Handle<Object> Isolate::GetPromiseOnStackOnThrow() { |
Handle<Object> undefined = factory()->undefined_value(); |
@@ -1744,6 +1753,47 @@ Handle<Object> Isolate::GetPromiseOnStackOnThrow() { |
return undefined; |
case HandlerTable::PROMISE: |
return tltop->promise_on_stack_->promise(); |
+ case HandlerTable::ASYNC_AWAIT: { |
+ // If in an async/await, pop up successive async/await stack frames |
+ // until an asynchronous one with dependents is found, or a non-async |
+ // stack frame is encountered, in order to handle the synchronous |
+ // async/await catch prediction case: assume that async function calls |
+ // are awaited. |
+ PromiseOnStack* promise_on_stack = tltop->promise_on_stack_; |
+ for (it.Advance(); !it.done(); it.Advance()) { |
+ if (PromiseHasUserDefinedRejectHandler(promise_on_stack->promise())) { |
+ break; |
+ } |
+ JavaScriptFrame* frame = it.frame(); |
+ if (!frame->function()->shared()->is_async()) { |
+ // Keep searching up the stack until an async function stack frame |
+ // is found, heuristically assuming that that will ultimately await |
+ // whatever is going on here. |
+ continue; |
+ } |
+ PromiseOnStack* next_promise_on_stack = promise_on_stack->prev(); |
+ if (next_promise_on_stack == nullptr) break; |
+ switch (PredictException(it.frame())) { |
+ case HandlerTable::CAUGHT: |
+ case HandlerTable::DESUGARING: { |
+ // Mark the inner promise as caught in the "synchronous case" so |
+ // that Debug::OnException will see. |
+ Handle<Symbol> key = factory()->promise_handled_hint_symbol(); |
+ JSObject::SetProperty(promise_on_stack->promise(), key, key, |
+ STRICT) |
+ .Assert(); |
+ return promise_on_stack->promise(); |
+ } |
+ case HandlerTable::ASYNC_AWAIT: |
+ promise_on_stack = next_promise_on_stack; |
+ continue; |
+ case HandlerTable::PROMISE: |
+ case HandlerTable::UNCAUGHT: |
+ UNREACHABLE(); |
+ } |
+ } |
+ return promise_on_stack->promise(); |
+ } |
} |
} |
return undefined; |