| Index: src/builtins/builtins-promise.cc
|
| diff --git a/src/builtins/builtins-promise.cc b/src/builtins/builtins-promise.cc
|
| index c0411d90f56aad1a87b5749e95660aba36b7c3b7..49e9d6de2ed0d4906f96c254177a1bbd4ab2db8e 100644
|
| --- a/src/builtins/builtins-promise.cc
|
| +++ b/src/builtins/builtins-promise.cc
|
| @@ -180,6 +180,66 @@ void PromiseBuiltinsAssembler::AppendPromiseCallback(int offset, Node* promise,
|
| StoreObjectField(promise, offset, new_elements);
|
| }
|
|
|
| +Node* PromiseBuiltinsAssembler::InternalPromiseThen(Node* context,
|
| + Node* promise,
|
| + Node* on_resolve,
|
| + Node* on_reject) {
|
| + Isolate* isolate = this->isolate();
|
| +
|
| + // 2. If IsPromise(promise) is false, throw a TypeError exception.
|
| + ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE,
|
| + "Promise.prototype.then");
|
| +
|
| + Node* const native_context = LoadNativeContext(context);
|
| + Node* const promise_fun =
|
| + LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
|
| +
|
| + // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
|
| + Node* constructor = SpeciesConstructor(context, promise, promise_fun);
|
| +
|
| + // 4. Let resultCapability be ? NewPromiseCapability(C).
|
| + Callable call_callable = CodeFactory::Call(isolate);
|
| + Label fast_promise_capability(this), promise_capability(this),
|
| + perform_promise_then(this);
|
| + Variable var_deferred(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);
|
| + Goto(&perform_promise_then);
|
| + }
|
| +
|
| + Bind(&promise_capability);
|
| + {
|
| + // TODO(gsathya): Move this to TF.
|
| + Node* const new_promise_capability = LoadContextElement(
|
| + native_context, Context::NEW_PROMISE_CAPABILITY_INDEX);
|
| + Node* const capability =
|
| + CallJS(call_callable, context, new_promise_capability,
|
| + UndefinedConstant(), constructor);
|
| + var_deferred.Bind(capability);
|
| + Goto(&perform_promise_then);
|
| + }
|
| +
|
| + // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,
|
| + // resultCapability).
|
| + Bind(&perform_promise_then);
|
| + Node* const result = InternalPerformPromiseThen(
|
| + context, promise, on_resolve, on_reject, var_deferred.value());
|
| + return result;
|
| +}
|
| +
|
| Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context,
|
| Node* promise,
|
| Node* on_resolve,
|
| @@ -378,15 +438,14 @@ void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise,
|
|
|
| void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context,
|
| Node* promise,
|
| - Node* result,
|
| - Label* out) {
|
| + Node* result) {
|
| Isolate* isolate = this->isolate();
|
|
|
| Variable var_reason(this, MachineRepresentation::kTagged),
|
| var_then(this, MachineRepresentation::kTagged);
|
|
|
| Label do_enqueue(this), fulfill(this), if_cycle(this, Label::kDeferred),
|
| - if_rejectpromise(this, Label::kDeferred);
|
| + if_rejectpromise(this, Label::kDeferred), out(this);
|
|
|
| Label cycle_check(this);
|
| GotoUnless(IsPromiseHookEnabled(), &cycle_check);
|
| @@ -438,7 +497,7 @@ void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context,
|
| CallRuntime(Runtime::kPromiseFulfill, context, promise,
|
| SmiConstant(v8::Promise::kFulfilled), thenable_value);
|
| PromiseSetHasHandler(promise);
|
| - Goto(out);
|
| + Goto(&out);
|
| }
|
|
|
| Bind(&if_rejected);
|
| @@ -457,7 +516,7 @@ void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context,
|
| CallRuntime(Runtime::kPromiseReject, context, promise, thenable_value,
|
| FalseConstant());
|
| PromiseSetHasHandler(result);
|
| - Goto(out);
|
| + Goto(&out);
|
| }
|
| }
|
| }
|
| @@ -500,7 +559,7 @@ void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context,
|
| Bind(&enqueue);
|
| CallRuntime(Runtime::kEnqueuePromiseResolveThenableJob, context, promise,
|
| result, var_then.value());
|
| - Goto(out);
|
| + Goto(&out);
|
| }
|
|
|
| // 7.b Return FulfillPromise(promise, resolution).
|
| @@ -508,7 +567,7 @@ void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context,
|
| {
|
| CallRuntime(Runtime::kPromiseFulfill, context, promise,
|
| SmiConstant(v8::Promise::kFulfilled), result);
|
| - Goto(out);
|
| + Goto(&out);
|
| }
|
|
|
| Bind(&if_cycle);
|
| @@ -528,8 +587,10 @@ void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context,
|
| {
|
| CallRuntime(Runtime::kPromiseReject, context, promise, var_reason.value(),
|
| TrueConstant());
|
| - Goto(out);
|
| + Goto(&out);
|
| }
|
| +
|
| + Bind(&out);
|
| }
|
|
|
| // ES#sec-promise-reject-functions
|
| @@ -762,65 +823,17 @@ TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) {
|
| Return(result);
|
| }
|
|
|
| +// ES#sec-promise.prototype.then
|
| +// Promise.prototype.catch ( onFulfilled, onRejected )
|
| TF_BUILTIN(PromiseThen, PromiseBuiltinsAssembler) {
|
| // 1. Let promise be the this value.
|
| Node* const promise = Parameter(0);
|
| Node* const on_resolve = Parameter(1);
|
| Node* const on_reject = Parameter(2);
|
| Node* const context = Parameter(5);
|
| - Isolate* isolate = this->isolate();
|
| -
|
| - // 2. If IsPromise(promise) is false, throw a TypeError exception.
|
| - ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE,
|
| - "Promise.prototype.then");
|
|
|
| - Node* const native_context = LoadNativeContext(context);
|
| - Node* const promise_fun =
|
| - LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
|
| -
|
| - // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
|
| - Node* constructor = SpeciesConstructor(context, promise, promise_fun);
|
| -
|
| - // 4. Let resultCapability be ? NewPromiseCapability(C).
|
| - Callable call_callable = CodeFactory::Call(isolate);
|
| - Label fast_promise_capability(this), promise_capability(this),
|
| - perform_promise_then(this);
|
| - Variable var_deferred(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);
|
| - Goto(&perform_promise_then);
|
| - }
|
| -
|
| - Bind(&promise_capability);
|
| - {
|
| - // TODO(gsathya): Move this to TF.
|
| - Node* const new_promise_capability = LoadContextElement(
|
| - native_context, Context::NEW_PROMISE_CAPABILITY_INDEX);
|
| - Node* const capability =
|
| - CallJS(call_callable, context, new_promise_capability,
|
| - UndefinedConstant(), constructor);
|
| - var_deferred.Bind(capability);
|
| - Goto(&perform_promise_then);
|
| - }
|
| -
|
| - // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,
|
| - // resultCapability).
|
| - Bind(&perform_promise_then);
|
| - Node* const result = InternalPerformPromiseThen(
|
| - context, promise, on_resolve, on_reject, var_deferred.value());
|
| + Node* const result =
|
| + InternalPromiseThen(context, promise, on_resolve, on_reject);
|
| Return(result);
|
| }
|
|
|
| @@ -849,7 +862,8 @@ TF_BUILTIN(PromiseResolveClosure, PromiseBuiltinsAssembler) {
|
| Node* const promise = LoadFixedArrayElement(
|
| context, IntPtrConstant(PromiseUtils::kPromiseSlot));
|
|
|
| - InternalResolvePromise(context, promise, value, &out);
|
| + InternalResolvePromise(context, promise, value);
|
| + Return(UndefinedConstant());
|
|
|
| Bind(&out);
|
| Return(UndefinedConstant());
|
| @@ -860,10 +874,7 @@ TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) {
|
| Node* const result = Parameter(2);
|
| Node* const context = Parameter(5);
|
|
|
| - Label out(this);
|
| - InternalResolvePromise(context, promise, result, &out);
|
| -
|
| - Bind(&out);
|
| + InternalResolvePromise(context, promise, result);
|
| Return(UndefinedConstant());
|
| }
|
|
|
| @@ -945,8 +956,8 @@ TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) {
|
| Branch(IsUndefined(on_resolve), &if_internalhandler, &if_customhandler);
|
|
|
| Bind(&if_internalhandler);
|
| - InternalResolvePromise(context, deferred_promise, result,
|
| - &promisehook_after);
|
| + InternalResolvePromise(context, deferred_promise, result);
|
| + Goto(&promisehook_after);
|
|
|
| Bind(&if_customhandler);
|
| {
|
| @@ -990,5 +1001,38 @@ TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) {
|
| }
|
| }
|
|
|
| +// ES#sec-promise.prototype.catch
|
| +// Promise.prototype.catch ( onRejected )
|
| +TF_BUILTIN(PromiseCatch, PromiseBuiltinsAssembler) {
|
| + // 1. Let promise be the this value.
|
| + Node* const promise = Parameter(0);
|
| + Node* const on_resolve = UndefinedConstant();
|
| + Node* const on_reject = Parameter(1);
|
| + Node* const context = Parameter(4);
|
| +
|
| + Label if_internalthen(this), if_customthen(this, Label::kDeferred);
|
| + BranchIfFastPath(context, promise, &if_internalthen, &if_customthen);
|
| +
|
| + Bind(&if_internalthen);
|
| + {
|
| + Node* const result =
|
| + InternalPromiseThen(context, promise, on_resolve, on_reject);
|
| + Return(result);
|
| + }
|
| +
|
| + Bind(&if_customthen);
|
| + {
|
| + Isolate* isolate = this->isolate();
|
| + Node* const then_str = HeapConstant(isolate->factory()->then_string());
|
| + Callable getproperty_callable = CodeFactory::GetProperty(isolate);
|
| + Node* const then =
|
| + CallStub(getproperty_callable, context, promise, then_str);
|
| + Callable call_callable = CodeFactory::Call(isolate);
|
| + Node* const result =
|
| + CallJS(call_callable, context, then, promise, on_resolve, on_reject);
|
| + Return(result);
|
| + }
|
| +}
|
| +
|
| } // namespace internal
|
| } // namespace v8
|
|
|