Chromium Code Reviews| Index: src/isolate.cc |
| diff --git a/src/isolate.cc b/src/isolate.cc |
| index 20ff7ff899e317ae3f62f84099117d0165e16677..82beb7cefbab3fb114df62801b9a671bc7127128 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,82 @@ void Isolate::ReportPromiseReject(Handle<JSObject> promise, |
| v8::Utils::StackTraceToLocal(stack_trace))); |
| } |
| +namespace { |
| +class PromiseDebugEventHelper { |
|
adamk
2016/10/12 16:18:11
We often name these things scopes, so how about Pr
gsathya
2016/10/12 20:08:53
Done.
|
| + public: |
| + PromiseDebugEventHelper(Isolate* isolate, Handle<Object> before, |
|
adamk
2016/10/12 16:18:11
You could reduce the lines-of-code (or at least en
gsathya
2016/10/12 20:08:53
Done.
|
| + Handle<Object> after) |
| + : isolate_(isolate), before_(before), after_(after) { |
| + if (isolate_->debug()->is_active() && before_->IsJSObject()) { |
| + isolate_->debug()->OnAsyncTaskEvent(Handle<JSObject>::cast(before_)); |
| + } |
| + } |
| + |
| + ~PromiseDebugEventHelper() { |
| + if (isolate_->debug()->is_active() && after_->IsJSObject()) { |
| + isolate_->debug()->OnAsyncTaskEvent(Handle<JSObject>::cast(after_)); |
| + } |
| + } |
| + |
| + private: |
| + Isolate* isolate_; |
| + Handle<Object> before_; |
| + Handle<Object> after_; |
| +}; |
| +} // namespace |
| + |
| +void Isolate::PromiseReactionJob( |
| + Handle<PromiseReactionJobInfo> promise_reaction_job_info, |
| + MaybeHandle<Object>* result, MaybeHandle<Object>* maybe_exception) { |
| + Handle<Object> before(promise_reaction_job_info->before_debug_event(), this); |
| + Handle<Object> after(promise_reaction_job_info->after_debug_event(), this); |
| + PromiseDebugEventHelper helper(this, before, after); |
| + |
| + Handle<Object> value(promise_reaction_job_info->value(), this); |
| + Handle<Object> tasks(promise_reaction_job_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 (result->is_null() && maybe_exception->is_null()) { |
|
adamk
2016/10/12 16:18:11
Copy and paste a comment with this, too:
// If ex
gsathya
2016/10/12 20:08:53
Done.
|
| + return; |
| + } |
| + } |
| + } else { |
| + Handle<Object> deferred(promise_reaction_job_info->deferred(), this); |
| + Handle<Object> argv[] = {value, tasks, deferred}; |
| + *result = |
| + Execution::TryCall(this, promise_handle(), factory()->undefined_value(), |
|
adamk
2016/10/12 16:18:11
You can pass promise_handle_fn and undefined here
gsathya
2016/10/12 20:08:53
Done.
|
| + arraysize(argv), argv, maybe_exception); |
| + if (result->is_null() && maybe_exception->is_null()) { |
|
adamk
2016/10/12 16:18:11
No need to do anything special in this case, right
gsathya
2016/10/12 20:08:53
Done.
|
| + return; |
| + } |
| + } |
| +} |
| + |
| 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)); |
| - } |
| - } |
| + Handle<Object> before(container->before_debug_event(), this); |
| + Handle<Object> after(container->after_debug_event(), this); |
| + PromiseDebugEventHelper helper(this, before, after); |
| Handle<JSReceiver> thenable(container->thenable(), this); |
| Handle<JSFunction> resolve(container->resolve(), this); |
| @@ -3034,18 +3102,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 +3159,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 +3182,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(); |