Index: src/isolate.cc |
diff --git a/src/isolate.cc b/src/isolate.cc |
index 20ff7ff899e317ae3f62f84099117d0165e16677..d1bbabf27a46acf743256343c7e4d2bacc922e49 100644 |
--- a/src/isolate.cc |
+++ b/src/isolate.cc |
@@ -24,6 +24,7 @@ |
#include "src/crankshaft/hydrogen.h" |
#include "src/debug/debug.h" |
#include "src/deoptimizer.h" |
+#include "src/elements.h" |
#include "src/external-reference-table.h" |
#include "src/frames-inl.h" |
#include "src/ic/access-compiler-data.h" |
@@ -3008,15 +3009,80 @@ void Isolate::ReportPromiseReject(Handle<JSObject> promise, |
v8::Utils::StackTraceToLocal(stack_trace))); |
} |
+namespace { |
+class PromiseDebugEventScope { |
+ public: |
+ PromiseDebugEventScope(Isolate* isolate, Object* before, Object* after) |
+ : isolate_(isolate), |
+ after_(after, isolate_), |
+ is_debug_active_(isolate_->debug()->is_active() && |
+ before->IsJSObject() && after->IsJSObject()) { |
+ if (is_debug_active_) { |
+ isolate_->debug()->OnAsyncTaskEvent( |
+ handle(JSObject::cast(before), isolate_)); |
+ } |
+ } |
+ |
+ ~PromiseDebugEventScope() { |
+ if (is_debug_active_) { |
+ isolate_->debug()->OnAsyncTaskEvent(Handle<JSObject>::cast(after_)); |
+ } |
+ } |
+ |
+ private: |
+ Isolate* isolate_; |
+ Handle<Object> after_; |
+ bool is_debug_active_; |
+}; |
+} // namespace |
+ |
+void Isolate::PromiseReactionJob(Handle<PromiseReactionJobInfo> info, |
+ MaybeHandle<Object>* result, |
+ MaybeHandle<Object>* maybe_exception) { |
+ PromiseDebugEventScope helper(this, info->before_debug_event(), |
+ info->after_debug_event()); |
+ |
+ Handle<Object> value(info->value(), this); |
+ Handle<Object> tasks(info->tasks(), this); |
+ Handle<JSFunction> promise_handle_fn = promise_handle(); |
+ Handle<Object> undefined = factory()->undefined_value(); |
+ |
+ // If tasks is an array we have multiple onFulfilled/onRejected callbacks |
+ // associated with the promise. The deferred object for each callback |
+ // is attached to this array as well. |
+ // Otherwise, there is a single callback and the deferred object is attached |
+ // directly to PromiseReactionJobInfo. |
+ if (tasks->IsJSArray()) { |
+ Handle<JSArray> array = Handle<JSArray>::cast(tasks); |
+ DCHECK(array->length()->IsSmi()); |
+ int length = Smi::cast(array->length())->value(); |
+ ElementsAccessor* accessor = array->GetElementsAccessor(); |
+ DCHECK(length % 2 == 0); |
+ for (int i = 0; i < length; i += 2) { |
+ DCHECK(accessor->HasElement(array, i)); |
+ DCHECK(accessor->HasElement(array, i + 1)); |
+ Handle<Object> argv[] = {value, accessor->Get(array, i), |
+ accessor->Get(array, i + 1)}; |
+ *result = Execution::TryCall(this, promise_handle_fn, undefined, |
+ arraysize(argv), argv, maybe_exception); |
+ // If execution is terminating, just bail out. |
+ if (result->is_null() && maybe_exception->is_null()) { |
+ return; |
+ } |
+ } |
+ } else { |
+ Handle<Object> deferred(info->deferred(), this); |
+ Handle<Object> argv[] = {value, tasks, deferred}; |
+ *result = Execution::TryCall(this, promise_handle_fn, undefined, |
+ arraysize(argv), argv, maybe_exception); |
+ } |
+} |
+ |
void Isolate::PromiseResolveThenableJob(Handle<PromiseContainer> container, |
MaybeHandle<Object>* result, |
MaybeHandle<Object>* maybe_exception) { |
- if (debug()->is_active()) { |
- Handle<Object> before_debug_event(container->before_debug_event(), this); |
- if (before_debug_event->IsJSObject()) { |
- debug()->OnAsyncTaskEvent(Handle<JSObject>::cast(before_debug_event)); |
- } |
- } |
+ PromiseDebugEventScope helper(this, container->before_debug_event(), |
+ container->after_debug_event()); |
Handle<JSReceiver> thenable(container->thenable(), this); |
Handle<JSFunction> resolve(container->resolve(), this); |
@@ -3034,18 +3100,12 @@ void Isolate::PromiseResolveThenableJob(Handle<PromiseContainer> container, |
Execution::TryCall(this, reject, factory()->undefined_value(), |
arraysize(reason_arg), reason_arg, maybe_exception); |
} |
- |
- if (debug()->is_active()) { |
- Handle<Object> after_debug_event(container->after_debug_event(), this); |
- if (after_debug_event->IsJSObject()) { |
- debug()->OnAsyncTaskEvent(Handle<JSObject>::cast(after_debug_event)); |
- } |
- } |
} |
void Isolate::EnqueueMicrotask(Handle<Object> microtask) { |
DCHECK(microtask->IsJSFunction() || microtask->IsCallHandlerInfo() || |
- microtask->IsPromiseContainer()); |
+ microtask->IsPromiseContainer() || |
+ microtask->IsPromiseReactionJobInfo()); |
Handle<FixedArray> queue(heap()->microtask_queue(), this); |
int num_tasks = pending_microtask_count(); |
DCHECK(num_tasks <= queue->length()); |
@@ -3097,11 +3157,16 @@ void Isolate::RunMicrotasksInternal() { |
callback(data); |
} else { |
SaveContext save(this); |
- Context* context = microtask->IsJSFunction() |
- ? Handle<JSFunction>::cast(microtask)->context() |
- : Handle<PromiseContainer>::cast(microtask) |
- ->resolve() |
- ->context(); |
+ Context* context; |
+ if (microtask->IsJSFunction()) { |
+ context = Handle<JSFunction>::cast(microtask)->context(); |
+ } else if (microtask->IsPromiseContainer()) { |
+ context = |
+ Handle<PromiseContainer>::cast(microtask)->resolve()->context(); |
+ } else { |
+ context = Handle<PromiseReactionJobInfo>::cast(microtask)->context(); |
+ } |
+ |
set_context(context->native_context()); |
handle_scope_implementer_->EnterMicrotaskContext( |
Handle<Context>(context, this)); |
@@ -3115,9 +3180,12 @@ void Isolate::RunMicrotasksInternal() { |
result = Execution::TryCall(this, microtask_function, |
factory()->undefined_value(), 0, NULL, |
&maybe_exception); |
- } else { |
+ } else if (microtask->IsPromiseContainer()) { |
PromiseResolveThenableJob(Handle<PromiseContainer>::cast(microtask), |
&result, &maybe_exception); |
+ } else { |
+ PromiseReactionJob(Handle<PromiseReactionJobInfo>::cast(microtask), |
+ &result, &maybe_exception); |
} |
handle_scope_implementer_->LeaveMicrotaskContext(); |