| Index: src/builtins/builtins-promise.cc
|
| diff --git a/src/builtins/builtins-promise.cc b/src/builtins/builtins-promise.cc
|
| index 9a6a8fe275a0783e8c253313b982898db83a50de..323bfea5b5a74268d4b4665b8de7b46a0516cbcf 100644
|
| --- a/src/builtins/builtins-promise.cc
|
| +++ b/src/builtins/builtins-promise.cc
|
| @@ -31,14 +31,128 @@ Node* PromiseBuiltinsAssembler::AllocateAndInitPromise(Node* context,
|
| return instance;
|
| }
|
|
|
| -Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext(
|
| +std::pair<Node*, Node*>
|
| +PromiseBuiltinsAssembler::CreatePromiseResolvingFunctions(
|
| Node* promise, Node* debug_event, Node* native_context) {
|
| - Node* const context =
|
| - Allocate(FixedArray::SizeFor(PromiseUtils::kPromiseContextLength));
|
| - StoreMapNoWriteBarrier(context, Heap::kFunctionContextMapRootIndex);
|
| + Node* const promise_context = CreatePromiseResolvingFunctionsContext(
|
| + promise, debug_event, native_context);
|
| + Node* const map = LoadContextElement(
|
| + native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
|
| + Node* const resolve_info =
|
| + LoadContextElement(native_context, Context::PROMISE_RESOLVE_SHARED_FUN);
|
| + Node* const resolve =
|
| + AllocateFunctionWithMapAndContext(map, resolve_info, promise_context);
|
| + Node* const reject_info =
|
| + LoadContextElement(native_context, Context::PROMISE_REJECT_SHARED_FUN);
|
| + Node* const reject =
|
| + AllocateFunctionWithMapAndContext(map, reject_info, promise_context);
|
| + return std::make_pair(resolve, reject);
|
| +}
|
| +
|
| +Node* PromiseBuiltinsAssembler::NewPromiseCapability(Node* context,
|
| + Node* constructor,
|
| + Node* debug_event) {
|
| + if (debug_event == nullptr) {
|
| + debug_event = TrueConstant();
|
| + }
|
| +
|
| + Node* native_context = LoadNativeContext(context);
|
| +
|
| + Node* map = LoadRoot(Heap::kJSPromiseCapabilityMapRootIndex);
|
| + Node* capability = AllocateJSObjectFromMap(map);
|
| +
|
| + StoreObjectFieldNoWriteBarrier(
|
| + capability, JSPromiseCapability::kPromiseOffset, UndefinedConstant());
|
| StoreObjectFieldNoWriteBarrier(
|
| - context, FixedArray::kLengthOffset,
|
| - SmiConstant(PromiseUtils::kPromiseContextLength));
|
| + capability, JSPromiseCapability::kResolveOffset, UndefinedConstant());
|
| + StoreObjectFieldNoWriteBarrier(capability, JSPromiseCapability::kRejectOffset,
|
| + UndefinedConstant());
|
| +
|
| + Variable var_result(this, MachineRepresentation::kTagged);
|
| + var_result.Bind(capability);
|
| +
|
| + Label if_builtin_promise(this), if_custom_promise(this, Label::kDeferred),
|
| + out(this);
|
| + Branch(WordEqual(constructor,
|
| + LoadContextElement(native_context,
|
| + Context::PROMISE_FUNCTION_INDEX)),
|
| + &if_builtin_promise, &if_custom_promise);
|
| +
|
| + Bind(&if_builtin_promise);
|
| + {
|
| + Node* promise = AllocateJSPromise(context);
|
| + PromiseInit(promise);
|
| + StoreObjectFieldNoWriteBarrier(
|
| + capability, JSPromiseCapability::kPromiseOffset, promise);
|
| +
|
| + Node* resolve = nullptr;
|
| + Node* reject = nullptr;
|
| +
|
| + std::tie(resolve, reject) =
|
| + CreatePromiseResolvingFunctions(promise, debug_event, native_context);
|
| + StoreObjectField(capability, JSPromiseCapability::kResolveOffset, resolve);
|
| + StoreObjectField(capability, JSPromiseCapability::kRejectOffset, reject);
|
| +
|
| + GotoUnless(IsPromiseHookEnabled(), &out);
|
| + CallRuntime(Runtime::kPromiseHookInit, context, promise,
|
| + UndefinedConstant());
|
| + Goto(&out);
|
| + }
|
| +
|
| + Bind(&if_custom_promise);
|
| + {
|
| + Label if_notcallable(this, Label::kDeferred);
|
| + Node* executor_context =
|
| + CreatePromiseGetCapabilitiesExecutorContext(capability, native_context);
|
| + Node* executor_info = LoadContextElement(
|
| + native_context, Context::PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN);
|
| + Node* function_map = LoadContextElement(
|
| + native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
|
| + Node* executor = AllocateFunctionWithMapAndContext(
|
| + function_map, executor_info, executor_context);
|
| +
|
| + Node* promise = ConstructJS(CodeFactory::Construct(isolate()), context,
|
| + constructor, executor);
|
| +
|
| + Node* resolve =
|
| + LoadObjectField(capability, JSPromiseCapability::kResolveOffset);
|
| + GotoIf(TaggedIsSmi(resolve), &if_notcallable);
|
| + GotoUnless(IsCallableMap(LoadMap(resolve)), &if_notcallable);
|
| +
|
| + Node* reject =
|
| + LoadObjectField(capability, JSPromiseCapability::kRejectOffset);
|
| + GotoIf(TaggedIsSmi(reject), &if_notcallable);
|
| + GotoUnless(IsCallableMap(LoadMap(reject)), &if_notcallable);
|
| +
|
| + StoreObjectField(capability, JSPromiseCapability::kPromiseOffset, promise);
|
| +
|
| + Goto(&out);
|
| +
|
| + Bind(&if_notcallable);
|
| + Node* message = SmiConstant(MessageTemplate::kPromiseNonCallable);
|
| + StoreObjectField(capability, JSPromiseCapability::kPromiseOffset,
|
| + UndefinedConstant());
|
| + StoreObjectField(capability, JSPromiseCapability::kResolveOffset,
|
| + UndefinedConstant());
|
| + StoreObjectField(capability, JSPromiseCapability::kRejectOffset,
|
| + UndefinedConstant());
|
| + CallRuntime(Runtime::kThrowTypeError, context, message);
|
| + var_result.Bind(UndefinedConstant());
|
| + Goto(&out);
|
| + }
|
| +
|
| + Bind(&out);
|
| + return var_result.value();
|
| +}
|
| +
|
| +Node* PromiseBuiltinsAssembler::CreatePromiseContext(Node* native_context,
|
| + int slots) {
|
| + DCHECK_GE(slots, Context::MIN_CONTEXT_SLOTS);
|
| +
|
| + Node* const context = Allocate(FixedArray::SizeFor(slots));
|
| + StoreMapNoWriteBarrier(context, Heap::kFunctionContextMapRootIndex);
|
| + StoreObjectFieldNoWriteBarrier(context, FixedArray::kLengthOffset,
|
| + SmiConstant(slots));
|
|
|
| Node* const empty_fn =
|
| LoadContextElement(native_context, Context::CLOSURE_INDEX);
|
| @@ -49,6 +163,13 @@ Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext(
|
| TheHoleConstant());
|
| StoreContextElementNoWriteBarrier(context, Context::NATIVE_CONTEXT_INDEX,
|
| native_context);
|
| + return context;
|
| +}
|
| +
|
| +Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext(
|
| + Node* promise, Node* debug_event, Node* native_context) {
|
| + Node* const context =
|
| + CreatePromiseContext(native_context, PromiseUtils::kPromiseContextLength);
|
| StoreContextElementNoWriteBarrier(context, PromiseUtils::kAlreadyVisitedSlot,
|
| SmiConstant(0));
|
| StoreContextElementNoWriteBarrier(context, PromiseUtils::kPromiseSlot,
|
| @@ -58,23 +179,14 @@ Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext(
|
| return context;
|
| }
|
|
|
| -std::pair<Node*, Node*>
|
| -PromiseBuiltinsAssembler::CreatePromiseResolvingFunctions(
|
| - Node* promise, Node* debug_event, Node* native_context) {
|
| - Node* const promise_context = CreatePromiseResolvingFunctionsContext(
|
| - promise, debug_event, native_context);
|
| - Node* const map = LoadContextElement(
|
| - native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
|
| - Node* const resolve_info =
|
| - LoadContextElement(native_context, Context::PROMISE_RESOLVE_SHARED_FUN);
|
| - Node* const resolve =
|
| - AllocateFunctionWithMapAndContext(map, resolve_info, promise_context);
|
| - Node* const reject_info =
|
| - LoadContextElement(native_context, Context::PROMISE_REJECT_SHARED_FUN);
|
| - Node* const reject =
|
| - AllocateFunctionWithMapAndContext(map, reject_info, promise_context);
|
| -
|
| - return std::make_pair(resolve, reject);
|
| +Node* PromiseBuiltinsAssembler::CreatePromiseGetCapabilitiesExecutorContext(
|
| + Node* promise_capability, Node* native_context) {
|
| + int kContextLength = GetPromiseCapabilityExecutor::kContextLength;
|
| + Node* context = CreatePromiseContext(native_context, kContextLength);
|
| + StoreContextElementNoWriteBarrier(
|
| + context, GetPromiseCapabilityExecutor::kCapabilitySlot,
|
| + promise_capability);
|
| + return context;
|
| }
|
|
|
| Node* PromiseBuiltinsAssembler::ThrowIfNotJSReceiver(
|
| @@ -234,28 +346,13 @@ Node* PromiseBuiltinsAssembler::InternalPromiseThen(Node* context,
|
|
|
| Bind(&promise_capability);
|
| {
|
| - // TODO(gsathya): Move this to TF.
|
| - Node* const new_promise_capability = LoadContextElement(
|
| - native_context, Context::NEW_PROMISE_CAPABILITY_INDEX);
|
| - Node* const deferred =
|
| - CallJS(call_callable, context, new_promise_capability,
|
| - UndefinedConstant(), constructor);
|
| - 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);
|
| -
|
| + Node* const capability = NewPromiseCapability(context, constructor);
|
| + var_deferred_promise.Bind(
|
| + LoadObjectField(capability, JSPromiseCapability::kPromiseOffset));
|
| + var_deferred_on_resolve.Bind(
|
| + LoadObjectField(capability, JSPromiseCapability::kResolveOffset));
|
| + var_deferred_on_reject.Bind(
|
| + LoadObjectField(capability, JSPromiseCapability::kRejectOffset));
|
| Goto(&perform_promise_then);
|
| }
|
|
|
| @@ -671,37 +768,6 @@ BUILTIN(PromiseRejectClosure) {
|
| return isolate->heap()->undefined_value();
|
| }
|
|
|
| -// ES#sec-createresolvingfunctions
|
| -// CreateResolvingFunctions ( promise )
|
| -TF_BUILTIN(CreateResolvingFunctions, PromiseBuiltinsAssembler) {
|
| - Node* const promise = Parameter(1);
|
| - Node* const debug_event = Parameter(2);
|
| - Node* const context = Parameter(5);
|
| - Node* const native_context = LoadNativeContext(context);
|
| -
|
| - Node* resolve = nullptr;
|
| - Node* reject = nullptr;
|
| -
|
| - std::tie(resolve, reject) =
|
| - CreatePromiseResolvingFunctions(promise, debug_event, native_context);
|
| -
|
| - Node* const kSize = IntPtrConstant(2);
|
| - const ElementsKind kind = FAST_ELEMENTS;
|
| - const WriteBarrierMode barrier_mode = SKIP_WRITE_BARRIER;
|
| - const ParameterMode parameter_mode = INTPTR_PARAMETERS;
|
| - Node* const arr = AllocateFixedArray(kind, kSize, parameter_mode);
|
| - StoreFixedArrayElement(arr, 0, resolve, barrier_mode);
|
| - StoreFixedArrayElement(arr, 1, reject, barrier_mode);
|
| -
|
| - Node* const array_map = LoadJSArrayElementsMap(kind, native_context);
|
| - Node* const length = SmiTag(kSize);
|
| - Node* const result = AllocateUninitializedJSArrayWithoutElements(
|
| - kind, array_map, length, nullptr);
|
| -
|
| - StoreObjectField(result, JSObject::kElementsOffset, arr);
|
| - Return(result);
|
| -}
|
| -
|
| TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) {
|
| Node* const executor = Parameter(1);
|
| Node* const new_target = Parameter(2);
|
| @@ -1069,5 +1135,43 @@ TF_BUILTIN(PromiseCatch, PromiseBuiltinsAssembler) {
|
| }
|
| }
|
|
|
| +TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) {
|
| + Node* const resolve = Parameter(1);
|
| + Node* const reject = Parameter(2);
|
| + Node* const context = Parameter(5);
|
| +
|
| + Node* const capability = LoadContextElement(
|
| + context, GetPromiseCapabilityExecutor::kCapabilitySlot);
|
| +
|
| + Label if_alreadyinvoked(this, Label::kDeferred);
|
| + GotoIf(WordNotEqual(
|
| + LoadObjectField(capability, JSPromiseCapability::kResolveOffset),
|
| + UndefinedConstant()),
|
| + &if_alreadyinvoked);
|
| + GotoIf(WordNotEqual(
|
| + LoadObjectField(capability, JSPromiseCapability::kRejectOffset),
|
| + UndefinedConstant()),
|
| + &if_alreadyinvoked);
|
| +
|
| + StoreObjectField(capability, JSPromiseCapability::kResolveOffset, resolve);
|
| + StoreObjectField(capability, JSPromiseCapability::kRejectOffset, reject);
|
| +
|
| + Return(UndefinedConstant());
|
| +
|
| + Bind(&if_alreadyinvoked);
|
| + Node* message = SmiConstant(MessageTemplate::kPromiseExecutorAlreadyInvoked);
|
| + Return(CallRuntime(Runtime::kThrowTypeError, context, message));
|
| +}
|
| +
|
| +TF_BUILTIN(NewPromiseCapability, PromiseBuiltinsAssembler) {
|
| + Node* constructor = Parameter(1);
|
| + Node* debug_event = Parameter(2);
|
| + Node* context = Parameter(5);
|
| +
|
| + CSA_ASSERT_JS_ARGC_EQ(this, 2);
|
| +
|
| + Return(NewPromiseCapability(context, constructor, debug_event));
|
| +}
|
| +
|
| } // namespace internal
|
| } // namespace v8
|
|
|