Chromium Code Reviews| Index: src/builtins/builtins-promise.cc |
| diff --git a/src/builtins/builtins-promise.cc b/src/builtins/builtins-promise.cc |
| index baa6253aecdd2f3d62f2ab69599a813cb06b8fda..fea937b75d2209e04785c6c7bcbd52195495ed1b 100644 |
| --- a/src/builtins/builtins-promise.cc |
| +++ b/src/builtins/builtins-promise.cc |
| @@ -16,6 +16,20 @@ typedef compiler::Node Node; |
| typedef CodeStubAssembler::ParameterMode ParameterMode; |
| typedef compiler::CodeAssemblerState CodeAssemblerState; |
| +Node* PromiseBuiltinsAssembler::AllocateAndInitPromise(Node* context, |
| + Node* parent) { |
| + Node* const instance = AllocateJSPromise(context); |
| + PromiseInit(instance); |
| + |
| + Label out(this); |
| + GotoUnless(IsPromiseHookEnabled(), &out); |
| + CallRuntime(Runtime::kPromiseHookInit, context, instance, parent); |
| + Goto(&out); |
| + |
| + Bind(&out); |
| + return instance; |
| +} |
| + |
| Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext( |
| Node* promise, Node* debug_event, Node* native_context) { |
| Node* const context = |
| @@ -181,11 +195,10 @@ void PromiseBuiltinsAssembler::AppendPromiseCallback(int offset, Node* promise, |
| StoreObjectField(promise, offset, new_elements); |
| } |
| -Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context, |
| - Node* promise, |
| - Node* on_resolve, |
| - Node* on_reject, |
| - Node* deferred) { |
| +Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen( |
| + Node* context, Node* promise, Node* on_resolve, Node* on_reject, |
| + Node* deferred_promise, Node* deferred_on_resolve, |
| + Node* deferred_on_reject) { |
| Node* const native_context = LoadNativeContext(context); |
| Variable var_on_resolve(this, MachineRepresentation::kTagged), |
| @@ -233,17 +246,22 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context, |
| GotoUnless(SmiEqual(status, SmiConstant(kPromisePending)), |
| &fulfilled_check); |
| - Node* const existing_deferred = |
| - LoadObjectField(promise, JSPromise::kDeferredOffset); |
| + Node* const existing_deferred_promise = |
| + LoadObjectField(promise, JSPromise::kDeferredPromiseOffset); |
| Label if_noexistingcallbacks(this), if_existingcallbacks(this); |
| - Branch(IsUndefined(existing_deferred), &if_noexistingcallbacks, |
| + Branch(IsUndefined(existing_deferred_promise), &if_noexistingcallbacks, |
| &if_existingcallbacks); |
| Bind(&if_noexistingcallbacks); |
| { |
| // Store callbacks directly in the slots. |
| - StoreObjectField(promise, JSPromise::kDeferredOffset, deferred); |
| + StoreObjectField(promise, JSPromise::kDeferredPromiseOffset, |
| + deferred_promise); |
| + StoreObjectField(promise, JSPromise::kDeferredOnResolveOffset, |
| + deferred_on_resolve); |
| + StoreObjectField(promise, JSPromise::kDeferredOnRejectOffset, |
| + deferred_on_reject); |
| StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, |
| var_on_resolve.value()); |
| StoreObjectField(promise, JSPromise::kRejectReactionsOffset, |
| @@ -254,17 +272,31 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context, |
| Bind(&if_existingcallbacks); |
| { |
| Label if_singlecallback(this), if_multiplecallbacks(this); |
| - BranchIfJSObject(existing_deferred, &if_singlecallback, |
| + BranchIfJSObject(existing_deferred_promise, &if_singlecallback, |
| &if_multiplecallbacks); |
| Bind(&if_singlecallback); |
| { |
| // Create new FixedArrays to store callbacks, and migrate |
| // existing callbacks. |
| - Node* const deferreds = |
| + Node* const deferred_promises = |
| + AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); |
| + StoreFixedArrayElement(deferred_promises, 0, existing_deferred_promise); |
| + StoreFixedArrayElement(deferred_promises, 1, deferred_promise); |
| + |
| + Node* const deferred_on_resolves = |
| + AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); |
| + StoreFixedArrayElement( |
| + deferred_on_resolves, 0, |
| + LoadObjectField(promise, JSPromise::kDeferredOnResolveOffset)); |
| + StoreFixedArrayElement(deferred_on_resolve, 1, deferred_on_resolve); |
| + |
| + Node* const deferred_on_rejects = |
| AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); |
| - StoreFixedArrayElement(deferreds, 0, existing_deferred); |
| - StoreFixedArrayElement(deferreds, 1, deferred); |
| + StoreFixedArrayElement( |
| + deferred_on_rejects, 0, |
| + LoadObjectField(promise, JSPromise::kDeferredOnRejectOffset)); |
| + StoreFixedArrayElement(deferred_on_rejects, 1, deferred_on_reject); |
| Node* const fulfill_reactions = |
| AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); |
| @@ -281,7 +313,12 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context, |
| StoreFixedArrayElement(reject_reactions, 1, var_on_reject.value()); |
| // Store new FixedArrays in promise. |
| - StoreObjectField(promise, JSPromise::kDeferredOffset, deferreds); |
| + StoreObjectField(promise, JSPromise::kDeferredPromiseOffset, |
|
caitp
2016/12/20 02:53:01
The multiple chains case seems likely to regress w
|
| + deferred_promises); |
| + StoreObjectField(promise, JSPromise::kDeferredOnResolveOffset, |
| + deferred_on_resolves); |
| + StoreObjectField(promise, JSPromise::kDeferredOnRejectOffset, |
| + deferred_on_rejects); |
| StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, |
| fulfill_reactions); |
| StoreObjectField(promise, JSPromise::kRejectReactionsOffset, |
| @@ -291,7 +328,12 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context, |
| Bind(&if_multiplecallbacks); |
| { |
| - AppendPromiseCallback(JSPromise::kDeferredOffset, promise, deferred); |
| + AppendPromiseCallback(JSPromise::kDeferredPromiseOffset, promise, |
| + deferred_promise); |
| + AppendPromiseCallback(JSPromise::kDeferredOnResolveOffset, promise, |
| + deferred_on_resolve); |
| + AppendPromiseCallback(JSPromise::kDeferredOnRejectOffset, promise, |
| + deferred_on_reject); |
| AppendPromiseCallback(JSPromise::kFulfillReactionsOffset, promise, |
| var_on_resolve.value()); |
| AppendPromiseCallback(JSPromise::kRejectReactionsOffset, promise, |
| @@ -306,9 +348,10 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context, |
| Node* const result = LoadObjectField(promise, JSPromise::kResultOffset); |
| GotoUnless(WordEqual(status, SmiConstant(kPromiseFulfilled)), &reject); |
| - // TODO(gsathya): Move this to TF. |
| - CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, promise, result, |
| - var_on_resolve.value(), deferred, |
| + Node* info = AllocatePromiseReactionJobInfo( |
| + promise, result, var_on_resolve.value(), deferred_promise, |
| + deferred_on_resolve, deferred_on_reject, context); |
| + CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info, |
| SmiConstant(kPromiseFulfilled)); |
| Goto(&out); |
| @@ -324,8 +367,10 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context, |
| Bind(&enqueue); |
| { |
| - CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, promise, |
| - result, var_on_reject.value(), deferred, |
| + Node* info = AllocatePromiseReactionJobInfo( |
| + promise, result, var_on_reject.value(), deferred_promise, |
| + deferred_on_resolve, deferred_on_reject, context); |
| + CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info, |
| SmiConstant(kPromiseRejected)); |
| Goto(&out); |
| @@ -336,16 +381,7 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context, |
| Bind(&out); |
| PromiseSetHasHandler(promise); |
| - |
| - // TODO(gsathya): This call will be removed once we don't have to |
| - // deal with deferred objects. |
| - Isolate* isolate = this->isolate(); |
| - Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
| - Node* const key = |
| - HeapConstant(isolate->factory()->NewStringFromAsciiChecked("promise")); |
| - Node* const result = CallStub(getproperty_callable, context, deferred, key); |
| - |
| - return result; |
| + return deferred_promise; |
| } |
| // Promise fast path implementations rely on unmodified JSPromise instances. |
| @@ -705,16 +741,7 @@ TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) { |
| TF_BUILTIN(PromiseInternalConstructor, PromiseBuiltinsAssembler) { |
| Node* const parent = Parameter(1); |
| Node* const context = Parameter(4); |
| - Node* const instance = AllocateJSPromise(context); |
| - PromiseInit(instance); |
| - |
| - Label out(this); |
| - GotoUnless(IsPromiseHookEnabled(), &out); |
| - CallRuntime(Runtime::kPromiseHookInit, context, instance, parent); |
| - Goto(&out); |
| - Bind(&out); |
| - |
| - Return(instance); |
| + Return(AllocateAndInitPromise(context, parent)); |
| } |
| TF_BUILTIN(PromiseCreateAndSet, PromiseBuiltinsAssembler) { |
| @@ -752,11 +779,14 @@ TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) { |
| Node* const promise = Parameter(1); |
| Node* const on_resolve = Parameter(2); |
| Node* const on_reject = Parameter(3); |
| - Node* const deferred = Parameter(4); |
| + Node* const deferred_promise = Parameter(4); |
| Node* const context = Parameter(7); |
| - Node* const result = InternalPerformPromiseThen(context, promise, on_resolve, |
| - on_reject, deferred); |
| + // No deferred_on_resolve/deferred_on_reject because this is just an |
| + // internal promise created by async-await. |
| + Node* const result = InternalPerformPromiseThen( |
| + context, promise, on_resolve, on_reject, deferred_promise, |
| + UndefinedConstant(), UndefinedConstant()); |
| // TODO(gsathya): This is unused, but value is returned according to spec. |
| Return(result); |
| @@ -785,22 +815,20 @@ TF_BUILTIN(PromiseThen, PromiseBuiltinsAssembler) { |
| Callable call_callable = CodeFactory::Call(isolate); |
| Label fast_promise_capability(this), promise_capability(this), |
| perform_promise_then(this); |
| - Variable var_deferred(this, MachineRepresentation::kTagged); |
| + Variable var_deferred_promise(this, MachineRepresentation::kTagged), |
| + var_deferred_on_resolve(this, MachineRepresentation::kTagged), |
| + var_deferred_on_reject(this, MachineRepresentation::kTagged); |
| Branch(WordEqual(promise_fun, constructor), &fast_promise_capability, |
| &promise_capability); |
| - // TODO(gsathya): Remove deferred object and move |
| - // NewPromiseCapabability functions to TF. |
| Bind(&fast_promise_capability); |
| { |
| - // TODO(gsathya): Move this to TF. |
| - Node* const promise_internal_capability = LoadContextElement( |
| - native_context, Context::INTERNAL_PROMISE_CAPABILITY_INDEX); |
| - Node* const capability = |
| - CallJS(call_callable, context, promise_internal_capability, |
| - UndefinedConstant(), promise); |
| - var_deferred.Bind(capability); |
| + Node* const deferred_promise = AllocateAndInitPromise(context, promise); |
| + PromiseInit(deferred_promise); |
| + var_deferred_promise.Bind(deferred_promise); |
| + var_deferred_on_resolve.Bind(UndefinedConstant()); |
| + var_deferred_on_reject.Bind(UndefinedConstant()); |
| Goto(&perform_promise_then); |
| } |
| @@ -809,10 +837,25 @@ TF_BUILTIN(PromiseThen, PromiseBuiltinsAssembler) { |
| // TODO(gsathya): Move this to TF. |
| Node* const new_promise_capability = LoadContextElement( |
| native_context, Context::NEW_PROMISE_CAPABILITY_INDEX); |
| - Node* const capability = |
| + Node* const deferred = |
| CallJS(call_callable, context, new_promise_capability, |
| UndefinedConstant(), constructor); |
| - var_deferred.Bind(capability); |
| + Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
| + Node* key = HeapConstant(isolate->factory()->promise_string()); |
| + Node* const deferred_promise = |
| + CallStub(getproperty_callable, context, deferred, key); |
| + var_deferred_promise.Bind(deferred_promise); |
| + |
| + key = HeapConstant(isolate->factory()->resolve_string()); |
| + Node* const deferred_on_resolve = |
| + CallStub(getproperty_callable, context, deferred, key); |
| + var_deferred_on_resolve.Bind(deferred_on_resolve); |
| + |
| + key = HeapConstant(isolate->factory()->reject_string()); |
| + Node* const deferred_on_reject = |
| + CallStub(getproperty_callable, context, deferred, key); |
| + var_deferred_on_reject.Bind(deferred_on_reject); |
| + |
| Goto(&perform_promise_then); |
| } |
| @@ -820,7 +863,8 @@ TF_BUILTIN(PromiseThen, PromiseBuiltinsAssembler) { |
| // resultCapability). |
| Bind(&perform_promise_then); |
| Node* const result = InternalPerformPromiseThen( |
| - context, promise, on_resolve, on_reject, var_deferred.value()); |
| + context, promise, on_resolve, on_reject, var_deferred_promise.value(), |
| + var_deferred_on_resolve.value(), var_deferred_on_reject.value()); |
| Return(result); |
| } |
| @@ -899,17 +943,13 @@ TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) { |
| Node* const promise = Parameter(1); |
| Node* const value = Parameter(2); |
| Node* const handler = Parameter(3); |
| - Node* const deferred = Parameter(4); |
| - Node* const context = Parameter(7); |
| + Node* const deferred_promise = Parameter(4); |
| + Node* const deferred_on_resolve = Parameter(5); |
| + Node* const deferred_on_reject = Parameter(6); |
| + Node* const context = Parameter(9); |
| Isolate* isolate = this->isolate(); |
| // Get promise from deferred |
| - // TODO(gsathya): Remove this lookup by getting rid of the deferred object. |
| - Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
| - Node* const key = HeapConstant(isolate->factory()->promise_string()); |
| - Node* const deferred_promise = |
| - CallStub(getproperty_callable, context, deferred, key); |
| - |
| Variable var_reason(this, MachineRepresentation::kTagged); |
| Node* const is_debug_active = IsDebugActive(); |
| @@ -930,16 +970,12 @@ TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) { |
| Bind(&run_handler); |
| { |
| Callable call_callable = CodeFactory::Call(isolate); |
| - |
| Node* const result = |
| CallJS(call_callable, context, handler, UndefinedConstant(), value); |
| GotoIfException(result, &if_rejectpromise, &var_reason); |
| - // TODO(gsathya): Remove this lookup by getting rid of the deferred object. |
| - Node* const key = HeapConstant(isolate->factory()->resolve_string()); |
| - Node* const on_resolve = |
| - CallStub(getproperty_callable, context, deferred, key); |
| + Node* const on_resolve = deferred_on_resolve; |
| Label if_internalhandler(this), if_customhandler(this, Label::kDeferred); |
| Branch(IsUndefined(on_resolve), &if_internalhandler, &if_customhandler); |
| @@ -959,11 +995,7 @@ TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) { |
| Bind(&if_rejectpromise); |
| { |
| - // TODO(gsathya): Remove this lookup by getting rid of the deferred object. |
| - Node* const key = HeapConstant(isolate->factory()->reject_string()); |
| - Node* const on_reject = |
| - CallStub(getproperty_callable, context, deferred, key); |
| - |
| + Node* const on_reject = deferred_on_reject; |
| Callable promise_handle_reject = CodeFactory::PromiseHandleReject(isolate); |
| CallStub(promise_handle_reject, context, deferred_promise, on_reject, |
| var_reason.value()); |