Index: src/builtins/builtins-promise.cc |
diff --git a/src/builtins/builtins-promise.cc b/src/builtins/builtins-promise.cc |
index d9635755c304d2ad8cbb84918990f5379478d881..a7e78a6ca46322376c85a17a575c68dda3e39e4b 100644 |
--- a/src/builtins/builtins-promise.cc |
+++ b/src/builtins/builtins-promise.cc |
@@ -11,345 +11,142 @@ |
namespace v8 { |
namespace internal { |
-// ES#sec-promise-reject-functions |
-// Promise Reject Functions |
-BUILTIN(PromiseRejectClosure) { |
- HandleScope scope(isolate); |
- |
- Handle<Context> context(isolate->context(), isolate); |
- |
- if (PromiseUtils::HasAlreadyVisited(context)) { |
- return isolate->heap()->undefined_value(); |
- } |
- |
- PromiseUtils::SetAlreadyVisited(context); |
- Handle<Object> value = args.atOrUndefined(isolate, 1); |
- Handle<JSObject> promise = handle(PromiseUtils::GetPromise(context), isolate); |
- Handle<Object> debug_event = |
- handle(PromiseUtils::GetDebugEvent(context), isolate); |
- MaybeHandle<Object> maybe_result; |
- Handle<Object> argv[] = {promise, value, debug_event}; |
- RETURN_FAILURE_ON_EXCEPTION( |
- isolate, Execution::Call(isolate, isolate->promise_internal_reject(), |
- isolate->factory()->undefined_value(), |
- arraysize(argv), argv)); |
- return isolate->heap()->undefined_value(); |
-} |
- |
-// ES#sec-createresolvingfunctions |
-// CreateResolvingFunctions ( promise ) |
-BUILTIN(CreateResolvingFunctions) { |
- HandleScope scope(isolate); |
- DCHECK_EQ(3, args.length()); |
- |
- Handle<JSObject> promise = args.at<JSObject>(1); |
- Handle<Object> debug_event = args.at(2); |
- Handle<JSFunction> resolve, reject; |
- |
- PromiseUtils::CreateResolvingFunctions(isolate, promise, debug_event, |
- &resolve, &reject); |
- |
- Handle<FixedArray> result = isolate->factory()->NewFixedArray(2); |
- result->set(0, *resolve); |
- result->set(1, *reject); |
- |
- return *isolate->factory()->NewJSArrayWithElements(result, FAST_ELEMENTS, 2, |
- NOT_TENURED); |
-} |
- |
-void Builtins::Generate_PromiseConstructor( |
- compiler::CodeAssemblerState* state) { |
- CodeStubAssembler a(state); |
- typedef CodeStubAssembler::Variable Variable; |
- typedef CodeStubAssembler::Label Label; |
- typedef compiler::Node Node; |
- |
- Node* const executor = a.Parameter(1); |
- Node* const new_target = a.Parameter(2); |
- Node* const context = a.Parameter(4); |
- Isolate* isolate = a.isolate(); |
- |
- Label if_targetisundefined(&a, Label::kDeferred); |
- |
- a.GotoIf(a.IsUndefined(new_target), &if_targetisundefined); |
- |
- Label if_notcallable(&a, Label::kDeferred); |
- |
- a.GotoIf(a.TaggedIsSmi(executor), &if_notcallable); |
- |
- Node* const executor_map = a.LoadMap(executor); |
- a.GotoUnless(a.IsCallableMap(executor_map), &if_notcallable); |
- |
- Node* const native_context = a.LoadNativeContext(context); |
- Node* const promise_fun = |
- a.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
- Node* const is_debug_active = a.IsDebugActive(); |
- Label if_targetisnotmodified(&a), if_targetismodified(&a, Label::kDeferred), |
- run_executor(&a), debug_push(&a, Label::kDeferred), init(&a); |
- |
- a.Branch(a.WordEqual(promise_fun, new_target), &if_targetisnotmodified, |
- &if_targetismodified); |
- |
- Variable var_result(&a, MachineRepresentation::kTagged), |
- var_reject_call(&a, MachineRepresentation::kTagged), |
- var_reason(&a, MachineRepresentation::kTagged); |
- |
- a.Bind(&if_targetisnotmodified); |
- { |
- Node* const instance = a.AllocateJSPromise(context); |
- var_result.Bind(instance); |
- a.Goto(&init); |
- } |
- |
- a.Bind(&if_targetismodified); |
- { |
- Callable fast_new_object_stub = CodeFactory::FastNewObject(isolate); |
- Node* const instance = |
- a.CallStub(fast_new_object_stub, context, promise_fun, new_target); |
- |
- var_result.Bind(instance); |
- a.Goto(&init); |
- } |
- |
- a.Bind(&init); |
- { |
- a.PromiseInit(var_result.value()); |
- a.Branch(is_debug_active, &debug_push, &run_executor); |
- } |
- |
- a.Bind(&debug_push); |
- { |
- a.CallRuntime(Runtime::kDebugPushPromise, context, var_result.value()); |
- a.Goto(&run_executor); |
- } |
- |
- a.Bind(&run_executor); |
- { |
- Label out(&a), if_rejectpromise(&a), debug_pop(&a, Label::kDeferred); |
- |
- // TODO(gsathya): Move this to TF. |
- Node* const resolving_functions = a.CallRuntime( |
- Runtime::kCreateResolvingFunctions, context, var_result.value()); |
- Node* const resolve = |
- a.LoadFixedArrayElement(resolving_functions, a.IntPtrConstant(0)); |
- Node* const reject = |
- a.LoadFixedArrayElement(resolving_functions, a.IntPtrConstant(1)); |
- Callable call_callable = CodeFactory::Call(isolate); |
- |
- Node* const maybe_exception = |
- a.CallJS(call_callable, context, executor, a.UndefinedConstant(), |
- resolve, reject); |
+typedef compiler::Node Node; |
+typedef CodeStubAssembler::ParameterMode ParameterMode; |
+typedef compiler::CodeAssemblerState CodeAssemblerState; |
- a.GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); |
- a.Branch(is_debug_active, &debug_pop, &out); |
- |
- a.Bind(&if_rejectpromise); |
- { |
- Callable call_callable = CodeFactory::Call(isolate); |
- a.CallJS(call_callable, context, reject, a.UndefinedConstant(), |
- var_reason.value()); |
- a.Branch(is_debug_active, &debug_pop, &out); |
- } |
+class PromiseBuiltinsAssembler : public CodeStubAssembler { |
+ public: |
+ explicit PromiseBuiltinsAssembler(CodeAssemblerState* state) |
+ : CodeStubAssembler(state) {} |
- a.Bind(&debug_pop); |
- { |
- a.CallRuntime(Runtime::kDebugPopPromise, context); |
- a.Goto(&out); |
- } |
- a.Bind(&out); |
- a.Return(var_result.value()); |
- } |
+ protected: |
+ Node* ThrowIfNotJSReceiver(Node* context, Node* value, |
+ MessageTemplate::Template msg_template); |
- // 1. If NewTarget is undefined, throw a TypeError exception. |
- a.Bind(&if_targetisundefined); |
- { |
- Node* const message_id = a.SmiConstant(MessageTemplate::kNotAPromise); |
- a.CallRuntime(Runtime::kThrowTypeError, context, message_id, new_target); |
- a.Return(a.UndefinedConstant()); // Never reached. |
- } |
+ Node* SpeciesConstructor(Node* context, Node* object, |
+ Node* default_constructor); |
- // 2. If IsCallable(executor) is false, throw a TypeError exception. |
- a.Bind(&if_notcallable); |
- { |
- Node* const message_id = |
- a.SmiConstant(MessageTemplate::kResolverNotAFunction); |
- a.CallRuntime(Runtime::kThrowTypeError, context, message_id, executor); |
- a.Return(a.UndefinedConstant()); // Never reached. |
- } |
-} |
+ Node* PromiseHasHandler(Node* promise); |
-void Builtins::Generate_PromiseInternalConstructor( |
- compiler::CodeAssemblerState* state) { |
- typedef compiler::Node Node; |
- CodeStubAssembler a(state); |
+ void PromiseSetHasHandler(Node* promise); |
- Node* const context = a.Parameter(3); |
- Node* const instance = a.AllocateJSPromise(context); |
- a.PromiseInit(instance); |
- a.Return(instance); |
-} |
+ void AppendPromiseCallback(int offset, compiler::Node* promise, |
+ compiler::Node* value); |
-void Builtins::Generate_PromiseCreateAndSet( |
- compiler::CodeAssemblerState* state) { |
- typedef compiler::Node Node; |
- CodeStubAssembler a(state); |
+ Node* InternalPerformPromiseThen(Node* context, Node* promise, |
+ Node* on_resolve, Node* on_reject, |
+ Node* deferred); |
- Node* const status = a.Parameter(1); |
- Node* const result = a.Parameter(2); |
- Node* const context = a.Parameter(5); |
+ void InternalResolvePromise(Node* context, Node* promise, Node* result, |
+ Label* out); |
- Node* const instance = a.AllocateJSPromise(context); |
- a.PromiseSet(instance, status, result); |
- a.Return(instance); |
-} |
+ void BranchIfFastPath(Node* context, Node* promise, Label* if_isunmodified, |
+ Label* if_ismodified); |
+}; |
-namespace { |
+Node* PromiseBuiltinsAssembler::ThrowIfNotJSReceiver( |
+ Node* context, Node* value, MessageTemplate::Template msg_template) { |
+ Label out(this), throw_exception(this, Label::kDeferred); |
+ Variable var_value_map(this, MachineRepresentation::kTagged); |
-compiler::Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, |
- compiler::Node* context, |
- compiler::Node* value, |
- MessageTemplate::Template msg_template) { |
- typedef compiler::Node Node; |
- typedef CodeStubAssembler::Label Label; |
- typedef CodeStubAssembler::Variable Variable; |
- |
- Label out(a), throw_exception(a, Label::kDeferred); |
- Variable var_value_map(a, MachineRepresentation::kTagged); |
- |
- a->GotoIf(a->TaggedIsSmi(value), &throw_exception); |
+ GotoIf(TaggedIsSmi(value), &throw_exception); |
// Load the instance type of the {value}. |
- var_value_map.Bind(a->LoadMap(value)); |
- Node* const value_instance_type = |
- a->LoadMapInstanceType(var_value_map.value()); |
+ var_value_map.Bind(LoadMap(value)); |
+ Node* const value_instance_type = LoadMapInstanceType(var_value_map.value()); |
- a->Branch(a->IsJSReceiverInstanceType(value_instance_type), &out, |
- &throw_exception); |
+ Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception); |
// The {value} is not a compatible receiver for this method. |
- a->Bind(&throw_exception); |
+ Bind(&throw_exception); |
{ |
- Node* const message_id = a->SmiConstant(msg_template); |
- a->CallRuntime(Runtime::kThrowTypeError, context, message_id); |
- var_value_map.Bind(a->UndefinedConstant()); |
- a->Goto(&out); // Never reached. |
+ Node* const message_id = SmiConstant(msg_template); |
+ CallRuntime(Runtime::kThrowTypeError, context, message_id); |
+ var_value_map.Bind(UndefinedConstant()); |
+ Goto(&out); // Never reached. |
} |
- a->Bind(&out); |
+ Bind(&out); |
return var_value_map.value(); |
} |
-} // namespace |
- |
-void Builtins::Generate_IsPromise(compiler::CodeAssemblerState* state) { |
- CodeStubAssembler a(state); |
- typedef compiler::Node Node; |
- typedef CodeStubAssembler::Label Label; |
- |
- Node* const maybe_promise = a.Parameter(1); |
- Label if_notpromise(&a, Label::kDeferred); |
- |
- a.GotoIf(a.TaggedIsSmi(maybe_promise), &if_notpromise); |
- |
- Node* const result = a.SelectBooleanConstant( |
- a.HasInstanceType(maybe_promise, JS_PROMISE_TYPE)); |
- a.Return(result); |
- |
- a.Bind(&if_notpromise); |
- a.Return(a.FalseConstant()); |
+Node* PromiseBuiltinsAssembler::PromiseHasHandler(Node* promise) { |
+ Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset); |
+ return IsSetWord(SmiUntag(flags), 1 << JSPromise::kHasHandlerBit); |
} |
-namespace { |
- |
-compiler::Node* PromiseHasHandler(CodeStubAssembler* a, |
- compiler::Node* promise) { |
- typedef compiler::Node Node; |
- |
- Node* const flags = a->LoadObjectField(promise, JSPromise::kFlagsOffset); |
- return a->IsSetWord(a->SmiUntag(flags), 1 << JSPromise::kHasHandlerBit); |
-} |
- |
-void PromiseSetHasHandler(CodeStubAssembler* a, compiler::Node* promise) { |
- typedef compiler::Node Node; |
- |
+void PromiseBuiltinsAssembler::PromiseSetHasHandler(Node* promise) { |
Node* const flags = |
- a->SmiUntag(a->LoadObjectField(promise, JSPromise::kFlagsOffset)); |
+ SmiUntag(LoadObjectField(promise, JSPromise::kFlagsOffset)); |
Node* const new_flags = |
- a->WordOr(flags, a->IntPtrConstant(1 << JSPromise::kHasHandlerBit)); |
- a->StoreObjectField(promise, JSPromise::kFlagsOffset, a->SmiTag(new_flags)); |
+ WordOr(flags, IntPtrConstant(1 << JSPromise::kHasHandlerBit)); |
+ StoreObjectField(promise, JSPromise::kFlagsOffset, SmiTag(new_flags)); |
} |
-compiler::Node* SpeciesConstructor(CodeStubAssembler* a, Isolate* isolate, |
- compiler::Node* context, |
- compiler::Node* object, |
- compiler::Node* default_constructor) { |
- typedef compiler::Node Node; |
- typedef CodeStubAssembler::Label Label; |
- typedef CodeStubAssembler::Variable Variable; |
- |
- Variable var_result(a, MachineRepresentation::kTagged); |
+Node* PromiseBuiltinsAssembler::SpeciesConstructor(Node* context, Node* object, |
+ Node* default_constructor) { |
+ Isolate* isolate = this->isolate(); |
+ Variable var_result(this, MachineRepresentation::kTagged); |
var_result.Bind(default_constructor); |
// 2. Let C be ? Get(O, "constructor"). |
Node* const constructor_str = |
- a->HeapConstant(isolate->factory()->constructor_string()); |
- Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
+ HeapConstant(isolate->factory()->constructor_string()); |
+ Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
Node* const constructor = |
- a->CallStub(getproperty_callable, context, object, constructor_str); |
+ CallStub(getproperty_callable, context, object, constructor_str); |
// 3. If C is undefined, return defaultConstructor. |
- Label out(a); |
- a->GotoIf(a->IsUndefined(constructor), &out); |
+ Label out(this); |
+ GotoIf(IsUndefined(constructor), &out); |
// 4. If Type(C) is not Object, throw a TypeError exception. |
- ThrowIfNotJSReceiver(a, a->isolate(), context, constructor, |
+ ThrowIfNotJSReceiver(context, constructor, |
MessageTemplate::kConstructorNotReceiver); |
// 5. Let S be ? Get(C, @@species). |
Node* const species_symbol = |
- a->HeapConstant(isolate->factory()->species_symbol()); |
+ HeapConstant(isolate->factory()->species_symbol()); |
Node* const species = |
- a->CallStub(getproperty_callable, context, constructor, species_symbol); |
+ CallStub(getproperty_callable, context, constructor, species_symbol); |
// 6. If S is either undefined or null, return defaultConstructor. |
- a->GotoIf(a->IsUndefined(species), &out); |
- a->GotoIf(a->WordEqual(species, a->NullConstant()), &out); |
+ GotoIf(IsUndefined(species), &out); |
+ GotoIf(WordEqual(species, NullConstant()), &out); |
// 7. If IsConstructor(S) is true, return S. |
- Label throw_error(a); |
- Node* species_bitfield = a->LoadMapBitField(a->LoadMap(species)); |
- a->GotoUnless( |
- a->Word32Equal(a->Word32And(species_bitfield, |
- a->Int32Constant((1 << Map::kIsConstructor))), |
- a->Int32Constant(1 << Map::kIsConstructor)), |
- &throw_error); |
+ Label throw_error(this); |
+ Node* species_bitfield = LoadMapBitField(LoadMap(species)); |
+ GotoUnless(Word32Equal(Word32And(species_bitfield, |
+ Int32Constant((1 << Map::kIsConstructor))), |
+ Int32Constant(1 << Map::kIsConstructor)), |
+ &throw_error); |
var_result.Bind(species); |
- a->Goto(&out); |
+ Goto(&out); |
// 8. Throw a TypeError exception. |
- a->Bind(&throw_error); |
+ Bind(&throw_error); |
{ |
Node* const message_id = |
- a->SmiConstant(MessageTemplate::kSpeciesNotConstructor); |
- a->CallRuntime(Runtime::kThrowTypeError, context, message_id); |
- a->Goto(&out); |
+ SmiConstant(MessageTemplate::kSpeciesNotConstructor); |
+ CallRuntime(Runtime::kThrowTypeError, context, message_id); |
+ Goto(&out); |
} |
- a->Bind(&out); |
+ Bind(&out); |
return var_result.value(); |
} |
-void AppendPromiseCallback(CodeStubAssembler* a, int offset, |
- compiler::Node* promise, compiler::Node* value) { |
- typedef compiler::Node Node; |
- |
- Node* elements = a->LoadObjectField(promise, offset); |
- Node* length = a->LoadFixedArrayBaseLength(elements); |
- CodeStubAssembler::ParameterMode mode = a->OptimalParameterMode(); |
- length = a->TaggedToParameter(length, mode); |
+void PromiseBuiltinsAssembler::AppendPromiseCallback(int offset, Node* promise, |
+ Node* value) { |
+ Node* elements = LoadObjectField(promise, offset); |
+ Node* length = LoadFixedArrayBaseLength(elements); |
+ CodeStubAssembler::ParameterMode mode = OptimalParameterMode(); |
+ length = TaggedToParameter(length, mode); |
- Node* delta = a->IntPtrOrSmiConstant(1, mode); |
- Node* new_capacity = a->IntPtrOrSmiAdd(length, delta, mode); |
+ Node* delta = IntPtrOrSmiConstant(1, mode); |
+ Node* new_capacity = IntPtrOrSmiAdd(length, delta, mode); |
const ElementsKind kind = FAST_ELEMENTS; |
const WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER; |
@@ -357,636 +154,779 @@ void AppendPromiseCallback(CodeStubAssembler* a, int offset, |
CodeStubAssembler::kAllowLargeObjectAllocation; |
int additional_offset = 0; |
- Node* new_elements = a->AllocateFixedArray(kind, new_capacity, mode, flags); |
+ Node* new_elements = AllocateFixedArray(kind, new_capacity, mode, flags); |
- a->CopyFixedArrayElements(kind, elements, new_elements, length, barrier_mode, |
- mode); |
- a->StoreFixedArrayElement(new_elements, length, value, barrier_mode, |
- additional_offset, mode); |
+ CopyFixedArrayElements(kind, elements, new_elements, length, barrier_mode, |
+ mode); |
+ StoreFixedArrayElement(new_elements, length, value, barrier_mode, |
+ additional_offset, mode); |
- a->StoreObjectField(promise, offset, new_elements); |
+ StoreObjectField(promise, offset, new_elements); |
} |
-compiler::Node* InternalPerformPromiseThen(CodeStubAssembler* a, |
- compiler::Node* context, |
- compiler::Node* promise, |
- compiler::Node* on_resolve, |
- compiler::Node* on_reject, |
- compiler::Node* deferred) { |
- typedef CodeStubAssembler::Variable Variable; |
- typedef CodeStubAssembler::Label Label; |
- typedef compiler::Node Node; |
- Isolate* isolate = a->isolate(); |
- Node* const native_context = a->LoadNativeContext(context); |
- |
- Variable var_on_resolve(a, MachineRepresentation::kTagged), |
- var_on_reject(a, MachineRepresentation::kTagged); |
+Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context, |
+ Node* promise, |
+ Node* on_resolve, |
+ Node* on_reject, |
+ Node* deferred) { |
+ Node* const native_context = LoadNativeContext(context); |
+ |
+ Variable var_on_resolve(this, MachineRepresentation::kTagged), |
+ var_on_reject(this, MachineRepresentation::kTagged); |
var_on_resolve.Bind(on_resolve); |
var_on_reject.Bind(on_reject); |
- Label out(a), if_onresolvenotcallable(a), onrejectcheck(a), |
- append_callbacks(a); |
- a->GotoIf(a->TaggedIsSmi(on_resolve), &if_onresolvenotcallable); |
+ Label out(this), if_onresolvenotcallable(this), onrejectcheck(this), |
+ append_callbacks(this); |
+ GotoIf(TaggedIsSmi(on_resolve), &if_onresolvenotcallable); |
- Node* const on_resolve_map = a->LoadMap(on_resolve); |
- a->Branch(a->IsCallableMap(on_resolve_map), &onrejectcheck, |
- &if_onresolvenotcallable); |
+ Node* const on_resolve_map = LoadMap(on_resolve); |
+ Branch(IsCallableMap(on_resolve_map), &onrejectcheck, |
+ &if_onresolvenotcallable); |
- a->Bind(&if_onresolvenotcallable); |
+ Bind(&if_onresolvenotcallable); |
{ |
- var_on_resolve.Bind(a->LoadContextElement( |
+ var_on_resolve.Bind(LoadContextElement( |
native_context, Context::PROMISE_ID_RESOLVE_HANDLER_INDEX)); |
- a->Goto(&onrejectcheck); |
+ Goto(&onrejectcheck); |
} |
- a->Bind(&onrejectcheck); |
+ Bind(&onrejectcheck); |
{ |
- Label if_onrejectnotcallable(a); |
- a->GotoIf(a->TaggedIsSmi(on_reject), &if_onrejectnotcallable); |
+ Label if_onrejectnotcallable(this); |
+ GotoIf(TaggedIsSmi(on_reject), &if_onrejectnotcallable); |
- Node* const on_reject_map = a->LoadMap(on_reject); |
- a->Branch(a->IsCallableMap(on_reject_map), &append_callbacks, |
- &if_onrejectnotcallable); |
+ Node* const on_reject_map = LoadMap(on_reject); |
+ Branch(IsCallableMap(on_reject_map), &append_callbacks, |
+ &if_onrejectnotcallable); |
- a->Bind(&if_onrejectnotcallable); |
+ Bind(&if_onrejectnotcallable); |
{ |
- var_on_reject.Bind(a->LoadContextElement( |
+ var_on_reject.Bind(LoadContextElement( |
native_context, Context::PROMISE_ID_REJECT_HANDLER_INDEX)); |
- a->Goto(&append_callbacks); |
+ Goto(&append_callbacks); |
} |
} |
- a->Bind(&append_callbacks); |
+ Bind(&append_callbacks); |
{ |
- Label fulfilled_check(a); |
- Node* const status = a->LoadObjectField(promise, JSPromise::kStatusOffset); |
- a->GotoUnless(a->SmiEqual(status, a->SmiConstant(kPromisePending)), |
- &fulfilled_check); |
+ Label fulfilled_check(this); |
+ Node* const status = LoadObjectField(promise, JSPromise::kStatusOffset); |
+ GotoUnless(SmiEqual(status, SmiConstant(kPromisePending)), |
+ &fulfilled_check); |
Node* const existing_deferred = |
- a->LoadObjectField(promise, JSPromise::kDeferredOffset); |
+ LoadObjectField(promise, JSPromise::kDeferredOffset); |
- Label if_noexistingcallbacks(a), if_existingcallbacks(a); |
- a->Branch(a->IsUndefined(existing_deferred), &if_noexistingcallbacks, |
- &if_existingcallbacks); |
+ Label if_noexistingcallbacks(this), if_existingcallbacks(this); |
+ Branch(IsUndefined(existing_deferred), &if_noexistingcallbacks, |
+ &if_existingcallbacks); |
- a->Bind(&if_noexistingcallbacks); |
+ Bind(&if_noexistingcallbacks); |
{ |
// Store callbacks directly in the slots. |
- a->StoreObjectField(promise, JSPromise::kDeferredOffset, deferred); |
- a->StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, |
- var_on_resolve.value()); |
- a->StoreObjectField(promise, JSPromise::kRejectReactionsOffset, |
- var_on_reject.value()); |
- a->Goto(&out); |
+ StoreObjectField(promise, JSPromise::kDeferredOffset, deferred); |
+ StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, |
+ var_on_resolve.value()); |
+ StoreObjectField(promise, JSPromise::kRejectReactionsOffset, |
+ var_on_reject.value()); |
+ Goto(&out); |
} |
- a->Bind(&if_existingcallbacks); |
+ Bind(&if_existingcallbacks); |
{ |
- Label if_singlecallback(a), if_multiplecallbacks(a); |
- a->BranchIfJSObject(existing_deferred, &if_singlecallback, |
- &if_multiplecallbacks); |
+ Label if_singlecallback(this), if_multiplecallbacks(this); |
+ BranchIfJSObject(existing_deferred, &if_singlecallback, |
+ &if_multiplecallbacks); |
- a->Bind(&if_singlecallback); |
+ Bind(&if_singlecallback); |
{ |
// Create new FixedArrays to store callbacks, and migrate |
// existing callbacks. |
Node* const deferreds = |
- a->AllocateFixedArray(FAST_ELEMENTS, a->IntPtrConstant(2)); |
- a->StoreFixedArrayElement(deferreds, 0, existing_deferred); |
- a->StoreFixedArrayElement(deferreds, 1, deferred); |
+ AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); |
+ StoreFixedArrayElement(deferreds, 0, existing_deferred); |
+ StoreFixedArrayElement(deferreds, 1, deferred); |
Node* const fulfill_reactions = |
- a->AllocateFixedArray(FAST_ELEMENTS, a->IntPtrConstant(2)); |
- a->StoreFixedArrayElement( |
+ AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); |
+ StoreFixedArrayElement( |
fulfill_reactions, 0, |
- a->LoadObjectField(promise, JSPromise::kFulfillReactionsOffset)); |
- a->StoreFixedArrayElement(fulfill_reactions, 1, var_on_resolve.value()); |
+ LoadObjectField(promise, JSPromise::kFulfillReactionsOffset)); |
+ StoreFixedArrayElement(fulfill_reactions, 1, var_on_resolve.value()); |
Node* const reject_reactions = |
- a->AllocateFixedArray(FAST_ELEMENTS, a->IntPtrConstant(2)); |
- a->StoreFixedArrayElement( |
+ AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); |
+ StoreFixedArrayElement( |
reject_reactions, 0, |
- a->LoadObjectField(promise, JSPromise::kRejectReactionsOffset)); |
- a->StoreFixedArrayElement(reject_reactions, 1, var_on_reject.value()); |
+ LoadObjectField(promise, JSPromise::kRejectReactionsOffset)); |
+ StoreFixedArrayElement(reject_reactions, 1, var_on_reject.value()); |
// Store new FixedArrays in promise. |
- a->StoreObjectField(promise, JSPromise::kDeferredOffset, deferreds); |
- a->StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, |
- fulfill_reactions); |
- a->StoreObjectField(promise, JSPromise::kRejectReactionsOffset, |
- reject_reactions); |
- a->Goto(&out); |
+ StoreObjectField(promise, JSPromise::kDeferredOffset, deferreds); |
+ StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, |
+ fulfill_reactions); |
+ StoreObjectField(promise, JSPromise::kRejectReactionsOffset, |
+ reject_reactions); |
+ Goto(&out); |
} |
- a->Bind(&if_multiplecallbacks); |
+ Bind(&if_multiplecallbacks); |
{ |
- AppendPromiseCallback(a, JSPromise::kDeferredOffset, promise, deferred); |
- AppendPromiseCallback(a, JSPromise::kFulfillReactionsOffset, promise, |
+ AppendPromiseCallback(JSPromise::kDeferredOffset, promise, deferred); |
+ AppendPromiseCallback(JSPromise::kFulfillReactionsOffset, promise, |
var_on_resolve.value()); |
- AppendPromiseCallback(a, JSPromise::kRejectReactionsOffset, promise, |
+ AppendPromiseCallback(JSPromise::kRejectReactionsOffset, promise, |
var_on_reject.value()); |
- a->Goto(&out); |
+ Goto(&out); |
} |
} |
- a->Bind(&fulfilled_check); |
+ Bind(&fulfilled_check); |
{ |
- Label reject(a); |
- Node* const result = |
- a->LoadObjectField(promise, JSPromise::kResultOffset); |
- a->GotoUnless(a->WordEqual(status, a->SmiConstant(kPromiseFulfilled)), |
- &reject); |
+ Label reject(this); |
+ Node* const result = LoadObjectField(promise, JSPromise::kResultOffset); |
+ GotoUnless(WordEqual(status, SmiConstant(kPromiseFulfilled)), &reject); |
// TODO(gsathya): Move this to TF. |
- a->CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, promise, |
- result, var_on_resolve.value(), deferred, |
- a->SmiConstant(kPromiseFulfilled)); |
- a->Goto(&out); |
+ CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, promise, result, |
+ var_on_resolve.value(), deferred, |
+ SmiConstant(kPromiseFulfilled)); |
+ Goto(&out); |
- a->Bind(&reject); |
+ Bind(&reject); |
{ |
- Node* const has_handler = PromiseHasHandler(a, promise); |
- Label enqueue(a); |
+ Node* const has_handler = PromiseHasHandler(promise); |
+ Label enqueue(this); |
// TODO(gsathya): Fold these runtime calls and move to TF. |
- a->GotoIf(has_handler, &enqueue); |
- a->CallRuntime(Runtime::kPromiseRevokeReject, context, promise); |
- a->Goto(&enqueue); |
+ GotoIf(has_handler, &enqueue); |
+ CallRuntime(Runtime::kPromiseRevokeReject, context, promise); |
+ Goto(&enqueue); |
- a->Bind(&enqueue); |
+ Bind(&enqueue); |
{ |
- a->CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, promise, |
- result, var_on_reject.value(), deferred, |
- a->SmiConstant(kPromiseRejected)); |
+ CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, promise, |
+ result, var_on_reject.value(), deferred, |
+ SmiConstant(kPromiseRejected)); |
- a->Goto(&out); |
+ Goto(&out); |
} |
} |
} |
} |
- a->Bind(&out); |
- PromiseSetHasHandler(a, promise); |
+ 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 = |
- a->HeapConstant(isolate->factory()->NewStringFromAsciiChecked("promise")); |
- Node* const result = |
- a->CallStub(getproperty_callable, context, deferred, key); |
+ HeapConstant(isolate->factory()->NewStringFromAsciiChecked("promise")); |
+ Node* const result = CallStub(getproperty_callable, context, deferred, key); |
return result; |
} |
-} // namespace |
- |
-void Builtins::Generate_PerformPromiseThen( |
- compiler::CodeAssemblerState* state) { |
- CodeStubAssembler a(state); |
- typedef compiler::Node Node; |
- |
- Node* const promise = a.Parameter(1); |
- Node* const on_resolve = a.Parameter(2); |
- Node* const on_reject = a.Parameter(3); |
- Node* const deferred = a.Parameter(4); |
- Node* const context = a.Parameter(7); |
- |
- Node* const result = InternalPerformPromiseThen( |
- &a, context, promise, on_resolve, on_reject, deferred); |
- |
- // TODO(gsathya): This is unused, but value is returned according to spec. |
- a.Return(result); |
-} |
- |
-void Builtins::Generate_PromiseThen(compiler::CodeAssemblerState* state) { |
- CodeStubAssembler a(state); |
- typedef compiler::Node Node; |
- typedef CodeStubAssembler::Label Label; |
- typedef CodeStubAssembler::Variable Variable; |
- |
- // 1. Let promise be the this value. |
- Node* const promise = a.Parameter(0); |
- Node* const on_resolve = a.Parameter(1); |
- Node* const on_reject = a.Parameter(2); |
- Node* const context = a.Parameter(5); |
- Isolate* isolate = a.isolate(); |
- |
- // 2. If IsPromise(promise) is false, throw a TypeError exception. |
- a.ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE, |
- "Promise.prototype.then"); |
- |
- Node* const native_context = a.LoadNativeContext(context); |
- Node* const promise_fun = |
- a.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
- |
- // 3. Let C be ? SpeciesConstructor(promise, %Promise%). |
- Node* constructor = |
- SpeciesConstructor(&a, isolate, context, promise, promise_fun); |
- |
- // 4. Let resultCapability be ? NewPromiseCapability(C). |
- Callable call_callable = CodeFactory::Call(isolate); |
- Label fast_promise_capability(&a), promise_capability(&a), |
- perform_promise_then(&a); |
- Variable var_deferred(&a, MachineRepresentation::kTagged); |
- |
- a.Branch(a.WordEqual(promise_fun, constructor), &fast_promise_capability, |
- &promise_capability); |
- |
- // TODO(gsathya): Remove deferred object and move |
- // NewPromiseCapbability functions to TF. |
- a.Bind(&fast_promise_capability); |
- { |
- // TODO(gsathya): Move this to TF. |
- Node* const promise_internal_capability = a.LoadContextElement( |
- native_context, Context::INTERNAL_PROMISE_CAPABILITY_INDEX); |
- Node* const capability = |
- a.CallJS(call_callable, context, promise_internal_capability, |
- a.UndefinedConstant()); |
- var_deferred.Bind(capability); |
- a.Goto(&perform_promise_then); |
- } |
- |
- a.Bind(&promise_capability); |
- { |
- // TODO(gsathya): Move this to TF. |
- Node* const new_promise_capability = a.LoadContextElement( |
- native_context, Context::NEW_PROMISE_CAPABILITY_INDEX); |
- Node* const capability = |
- a.CallJS(call_callable, context, new_promise_capability, |
- a.UndefinedConstant(), constructor); |
- var_deferred.Bind(capability); |
- a.Goto(&perform_promise_then); |
- } |
- |
- // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, |
- // resultCapability). |
- a.Bind(&perform_promise_then); |
- Node* const result = InternalPerformPromiseThen( |
- &a, context, promise, on_resolve, on_reject, var_deferred.value()); |
- a.Return(result); |
-} |
- |
-namespace { |
- |
// Promise fast path implementations rely on unmodified JSPromise instances. |
// We use a fairly coarse granularity for this and simply check whether both |
// the promise itself is unmodified (i.e. its map has not changed) and its |
// prototype is unmodified. |
// TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp |
-void BranchIfFastPath(CodeStubAssembler* a, compiler::Node* context, |
- compiler::Node* promise, |
- CodeStubAssembler::Label* if_isunmodified, |
- CodeStubAssembler::Label* if_ismodified) { |
- typedef compiler::Node Node; |
- |
+void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise, |
+ Label* if_isunmodified, |
+ Label* if_ismodified) { |
// TODO(gsathya): Assert if promise is receiver |
- Node* const map = a->LoadMap(promise); |
- Node* const native_context = a->LoadNativeContext(context); |
+ Node* const map = LoadMap(promise); |
+ Node* const native_context = LoadNativeContext(context); |
Node* const promise_fun = |
- a->LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
+ LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
Node* const initial_map = |
- a->LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); |
- Node* const has_initialmap = a->WordEqual(map, initial_map); |
+ LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); |
+ Node* const has_initialmap = WordEqual(map, initial_map); |
- a->GotoUnless(has_initialmap, if_ismodified); |
+ GotoUnless(has_initialmap, if_ismodified); |
- Node* const initial_proto_initial_map = a->LoadContextElement( |
- native_context, Context::PROMISE_PROTOTYPE_MAP_INDEX); |
- Node* const proto_map = a->LoadMap(a->LoadMapPrototype(map)); |
+ Node* const initial_proto_initial_map = |
+ LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_MAP_INDEX); |
+ Node* const proto_map = LoadMap(LoadMapPrototype(map)); |
Node* const proto_has_initialmap = |
- a->WordEqual(proto_map, initial_proto_initial_map); |
+ WordEqual(proto_map, initial_proto_initial_map); |
- a->Branch(proto_has_initialmap, if_isunmodified, if_ismodified); |
+ Branch(proto_has_initialmap, if_isunmodified, if_ismodified); |
} |
-void InternalResolvePromise(CodeStubAssembler* a, compiler::Node* context, |
- compiler::Node* promise, compiler::Node* result, |
- CodeStubAssembler::Label* out) { |
- typedef CodeStubAssembler::Variable Variable; |
- typedef CodeStubAssembler::Label Label; |
- typedef compiler::Node Node; |
- |
- Isolate* isolate = a->isolate(); |
+void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context, |
+ Node* promise, |
+ Node* result, |
+ Label* out) { |
+ Isolate* isolate = this->isolate(); |
- Variable var_reason(a, MachineRepresentation::kTagged), |
- var_then(a, MachineRepresentation::kTagged); |
+ Variable var_reason(this, MachineRepresentation::kTagged), |
+ var_then(this, MachineRepresentation::kTagged); |
- Label do_enqueue(a), fulfill(a), if_cycle(a, Label::kDeferred), |
- if_rejectpromise(a, Label::kDeferred); |
+ Label do_enqueue(this), fulfill(this), if_cycle(this, Label::kDeferred), |
+ if_rejectpromise(this, Label::kDeferred); |
// 6. If SameValue(resolution, promise) is true, then |
- a->GotoIf(a->SameValue(promise, result, context), &if_cycle); |
+ GotoIf(SameValue(promise, result, context), &if_cycle); |
// 7. If Type(resolution) is not Object, then |
- a->GotoIf(a->TaggedIsSmi(result), &fulfill); |
- a->GotoUnless(a->IsJSReceiver(result), &fulfill); |
+ GotoIf(TaggedIsSmi(result), &fulfill); |
+ GotoUnless(IsJSReceiver(result), &fulfill); |
- Label if_nativepromise(a), if_notnativepromise(a, Label::kDeferred); |
- BranchIfFastPath(a, context, result, &if_nativepromise, &if_notnativepromise); |
+ Label if_nativepromise(this), if_notnativepromise(this, Label::kDeferred); |
+ BranchIfFastPath(context, result, &if_nativepromise, &if_notnativepromise); |
// Resolution is a native promise and if it's already resolved or |
// rejected, shortcircuit the resolution procedure by directly |
// reusing the value from the promise. |
- a->Bind(&if_nativepromise); |
+ Bind(&if_nativepromise); |
{ |
Node* const thenable_status = |
- a->LoadObjectField(result, JSPromise::kStatusOffset); |
+ LoadObjectField(result, JSPromise::kStatusOffset); |
Node* const thenable_value = |
- a->LoadObjectField(result, JSPromise::kResultOffset); |
+ LoadObjectField(result, JSPromise::kResultOffset); |
- Label if_isnotpending(a); |
- a->GotoUnless(a->SmiEqual(a->SmiConstant(kPromisePending), thenable_status), |
- &if_isnotpending); |
+ Label if_isnotpending(this); |
+ GotoUnless(SmiEqual(SmiConstant(kPromisePending), thenable_status), |
+ &if_isnotpending); |
// TODO(gsathya): Use a marker here instead of the actual then |
// callback, and check for the marker in PromiseResolveThenableJob |
// and perform PromiseThen. |
- Node* const native_context = a->LoadNativeContext(context); |
+ Node* const native_context = LoadNativeContext(context); |
Node* const then = |
- a->LoadContextElement(native_context, Context::PROMISE_THEN_INDEX); |
+ LoadContextElement(native_context, Context::PROMISE_THEN_INDEX); |
var_then.Bind(then); |
- a->Goto(&do_enqueue); |
+ Goto(&do_enqueue); |
- a->Bind(&if_isnotpending); |
+ Bind(&if_isnotpending); |
{ |
- Label if_fulfilled(a), if_rejected(a); |
- a->Branch(a->SmiEqual(a->SmiConstant(kPromiseFulfilled), thenable_status), |
- &if_fulfilled, &if_rejected); |
+ Label if_fulfilled(this), if_rejected(this); |
+ Branch(SmiEqual(SmiConstant(kPromiseFulfilled), thenable_status), |
+ &if_fulfilled, &if_rejected); |
- a->Bind(&if_fulfilled); |
+ Bind(&if_fulfilled); |
{ |
- a->CallRuntime(Runtime::kPromiseFulfill, context, promise, |
- a->SmiConstant(kPromiseFulfilled), thenable_value); |
- PromiseSetHasHandler(a, promise); |
- a->Goto(out); |
+ CallRuntime(Runtime::kPromiseFulfill, context, promise, |
+ SmiConstant(kPromiseFulfilled), thenable_value); |
+ PromiseSetHasHandler(promise); |
+ Goto(out); |
} |
- a->Bind(&if_rejected); |
+ Bind(&if_rejected); |
{ |
- Label reject(a); |
- Node* const has_handler = PromiseHasHandler(a, result); |
+ Label reject(this); |
+ Node* const has_handler = PromiseHasHandler(result); |
// Promise has already been rejected, but had no handler. |
// Revoke previously triggered reject event. |
- a->GotoIf(has_handler, &reject); |
- a->CallRuntime(Runtime::kPromiseRevokeReject, context, result); |
- a->Goto(&reject); |
+ GotoIf(has_handler, &reject); |
+ CallRuntime(Runtime::kPromiseRevokeReject, context, result); |
+ Goto(&reject); |
- a->Bind(&reject); |
+ Bind(&reject); |
// Don't cause a debug event as this case is forwarding a rejection |
- a->CallRuntime(Runtime::kPromiseReject, context, promise, |
- thenable_value, a->FalseConstant()); |
- PromiseSetHasHandler(a, result); |
- a->Goto(out); |
+ CallRuntime(Runtime::kPromiseReject, context, promise, thenable_value, |
+ FalseConstant()); |
+ PromiseSetHasHandler(result); |
+ Goto(out); |
} |
} |
} |
- a->Bind(&if_notnativepromise); |
+ Bind(&if_notnativepromise); |
{ |
// 8. Let then be Get(resolution, "then"). |
- Node* const then_str = a->HeapConstant(isolate->factory()->then_string()); |
- Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
+ Node* const then_str = HeapConstant(isolate->factory()->then_string()); |
+ Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
Node* const then = |
- a->CallStub(getproperty_callable, context, result, then_str); |
+ CallStub(getproperty_callable, context, result, then_str); |
// 9. If then is an abrupt completion, then |
- a->GotoIfException(then, &if_rejectpromise, &var_reason); |
+ GotoIfException(then, &if_rejectpromise, &var_reason); |
// 11. If IsCallable(thenAction) is false, then |
- a->GotoIf(a->TaggedIsSmi(then), &fulfill); |
- Node* const then_map = a->LoadMap(then); |
- a->GotoUnless(a->IsCallableMap(then_map), &fulfill); |
+ GotoIf(TaggedIsSmi(then), &fulfill); |
+ Node* const then_map = LoadMap(then); |
+ GotoUnless(IsCallableMap(then_map), &fulfill); |
var_then.Bind(then); |
- a->Goto(&do_enqueue); |
+ Goto(&do_enqueue); |
} |
- a->Bind(&do_enqueue); |
+ Bind(&do_enqueue); |
{ |
- Label enqueue(a); |
- a->GotoUnless(a->IsDebugActive(), &enqueue); |
- a->GotoIf(a->TaggedIsSmi(result), &enqueue); |
- a->GotoUnless(a->HasInstanceType(result, JS_PROMISE_TYPE), &enqueue); |
+ Label enqueue(this); |
+ GotoUnless(IsDebugActive(), &enqueue); |
+ GotoIf(TaggedIsSmi(result), &enqueue); |
+ GotoUnless(HasInstanceType(result, JS_PROMISE_TYPE), &enqueue); |
// Mark the dependency of the new promise on the resolution |
Node* const key = |
- a->HeapConstant(isolate->factory()->promise_handled_by_symbol()); |
- a->CallRuntime(Runtime::kSetProperty, context, result, key, promise, |
- a->SmiConstant(STRICT)); |
- a->Goto(&enqueue); |
+ HeapConstant(isolate->factory()->promise_handled_by_symbol()); |
+ CallRuntime(Runtime::kSetProperty, context, result, key, promise, |
+ SmiConstant(STRICT)); |
+ Goto(&enqueue); |
// 12. Perform EnqueueJob("PromiseJobs", |
// PromiseResolveThenableJob, « promise, resolution, thenAction |
// »). |
- a->Bind(&enqueue); |
- a->CallRuntime(Runtime::kEnqueuePromiseResolveThenableJob, context, promise, |
- result, var_then.value()); |
- a->Goto(out); |
+ Bind(&enqueue); |
+ CallRuntime(Runtime::kEnqueuePromiseResolveThenableJob, context, promise, |
+ result, var_then.value()); |
+ Goto(out); |
} |
+ |
// 7.b Return FulfillPromise(promise, resolution). |
- a->Bind(&fulfill); |
+ Bind(&fulfill); |
{ |
- a->CallRuntime(Runtime::kPromiseFulfill, context, promise, |
- a->SmiConstant(kPromiseFulfilled), result); |
- a->Goto(out); |
+ CallRuntime(Runtime::kPromiseFulfill, context, promise, |
+ SmiConstant(kPromiseFulfilled), result); |
+ Goto(out); |
} |
- a->Bind(&if_cycle); |
+ Bind(&if_cycle); |
{ |
// 6.a Let selfResolutionError be a newly created TypeError object. |
- Node* const message_id = a->SmiConstant(MessageTemplate::kPromiseCyclic); |
+ Node* const message_id = SmiConstant(MessageTemplate::kPromiseCyclic); |
Node* const error = |
- a->CallRuntime(Runtime::kNewTypeError, context, message_id, result); |
+ CallRuntime(Runtime::kNewTypeError, context, message_id, result); |
var_reason.Bind(error); |
// 6.b Return RejectPromise(promise, selfResolutionError). |
- a->Goto(&if_rejectpromise); |
+ Goto(&if_rejectpromise); |
} |
// 9.a Return RejectPromise(promise, then.[[Value]]). |
- a->Bind(&if_rejectpromise); |
+ Bind(&if_rejectpromise); |
{ |
- a->CallRuntime(Runtime::kPromiseReject, context, promise, |
- var_reason.value(), a->TrueConstant()); |
- a->Goto(out); |
+ CallRuntime(Runtime::kPromiseReject, context, promise, var_reason.value(), |
+ TrueConstant()); |
+ Goto(out); |
+ } |
+} |
+ |
+// ES#sec-promise-reject-functions |
+// Promise Reject Functions |
+BUILTIN(PromiseRejectClosure) { |
+ HandleScope scope(isolate); |
+ |
+ Handle<Context> context(isolate->context(), isolate); |
+ |
+ if (PromiseUtils::HasAlreadyVisited(context)) { |
+ return isolate->heap()->undefined_value(); |
} |
+ |
+ PromiseUtils::SetAlreadyVisited(context); |
+ Handle<Object> value = args.atOrUndefined(isolate, 1); |
+ Handle<JSObject> promise = handle(PromiseUtils::GetPromise(context), isolate); |
+ Handle<Object> debug_event = |
+ handle(PromiseUtils::GetDebugEvent(context), isolate); |
+ MaybeHandle<Object> maybe_result; |
+ Handle<Object> argv[] = {promise, value, debug_event}; |
+ RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, Execution::Call(isolate, isolate->promise_internal_reject(), |
+ isolate->factory()->undefined_value(), |
+ arraysize(argv), argv)); |
+ return isolate->heap()->undefined_value(); |
+} |
+ |
+// ES#sec-createresolvingfunctions |
+// CreateResolvingFunctions ( promise ) |
+BUILTIN(CreateResolvingFunctions) { |
+ HandleScope scope(isolate); |
+ DCHECK_EQ(3, args.length()); |
+ |
+ Handle<JSObject> promise = args.at<JSObject>(1); |
+ Handle<Object> debug_event = args.at<Object>(2); |
+ Handle<JSFunction> resolve, reject; |
+ |
+ PromiseUtils::CreateResolvingFunctions(isolate, promise, debug_event, |
+ &resolve, &reject); |
+ |
+ Handle<FixedArray> result = isolate->factory()->NewFixedArray(2); |
+ result->set(0, *resolve); |
+ result->set(1, *reject); |
+ |
+ return *isolate->factory()->NewJSArrayWithElements(result, FAST_ELEMENTS, 2, |
+ NOT_TENURED); |
} |
-} // namespace |
+TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) { |
+ Node* const executor = Parameter(1); |
+ Node* const new_target = Parameter(2); |
+ Node* const context = Parameter(4); |
+ Isolate* isolate = this->isolate(); |
+ |
+ Label if_targetisundefined(this, Label::kDeferred); |
+ |
+ GotoIf(IsUndefined(new_target), &if_targetisundefined); |
+ |
+ Label if_notcallable(this, Label::kDeferred); |
+ |
+ GotoIf(TaggedIsSmi(executor), &if_notcallable); |
+ |
+ Node* const executor_map = LoadMap(executor); |
+ GotoUnless(IsCallableMap(executor_map), &if_notcallable); |
+ |
+ Node* const native_context = LoadNativeContext(context); |
+ Node* const promise_fun = |
+ LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
+ Node* const is_debug_active = IsDebugActive(); |
+ Label if_targetisnotmodified(this), |
+ if_targetismodified(this, Label::kDeferred), run_executor(this), |
+ debug_push(this, Label::kDeferred), init(this); |
+ |
+ Branch(WordEqual(promise_fun, new_target), &if_targetisnotmodified, |
+ &if_targetismodified); |
+ |
+ Variable var_result(this, MachineRepresentation::kTagged), |
+ var_reject_call(this, MachineRepresentation::kTagged), |
+ var_reason(this, MachineRepresentation::kTagged); |
+ |
+ Bind(&if_targetisnotmodified); |
+ { |
+ Node* const instance = AllocateJSPromise(context); |
+ var_result.Bind(instance); |
+ Goto(&init); |
+ } |
+ |
+ Bind(&if_targetismodified); |
+ { |
+ Callable fast_new_object_stub = CodeFactory::FastNewObject(isolate); |
+ Node* const instance = |
+ CallStub(fast_new_object_stub, context, promise_fun, new_target); |
+ |
+ var_result.Bind(instance); |
+ Goto(&init); |
+ } |
+ |
+ Bind(&init); |
+ { |
+ PromiseInit(var_result.value()); |
+ Branch(is_debug_active, &debug_push, &run_executor); |
+ } |
+ |
+ Bind(&debug_push); |
+ { |
+ CallRuntime(Runtime::kDebugPushPromise, context, var_result.value()); |
+ Goto(&run_executor); |
+ } |
+ |
+ Bind(&run_executor); |
+ { |
+ Label out(this), if_rejectpromise(this), debug_pop(this, Label::kDeferred); |
+ |
+ // TODO(gsathya): Move this to TF. |
+ Node* const resolving_functions = CallRuntime( |
+ Runtime::kCreateResolvingFunctions, context, var_result.value()); |
+ Node* const resolve = |
+ LoadFixedArrayElement(resolving_functions, IntPtrConstant(0)); |
+ Node* const reject = |
+ LoadFixedArrayElement(resolving_functions, IntPtrConstant(1)); |
+ Callable call_callable = CodeFactory::Call(isolate); |
+ |
+ Node* const maybe_exception = CallJS(call_callable, context, executor, |
+ UndefinedConstant(), resolve, reject); |
+ |
+ GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); |
+ Branch(is_debug_active, &debug_pop, &out); |
+ |
+ Bind(&if_rejectpromise); |
+ { |
+ Callable call_callable = CodeFactory::Call(isolate); |
+ CallJS(call_callable, context, reject, UndefinedConstant(), |
+ var_reason.value()); |
+ Branch(is_debug_active, &debug_pop, &out); |
+ } |
+ |
+ Bind(&debug_pop); |
+ { |
+ CallRuntime(Runtime::kDebugPopPromise, context); |
+ Goto(&out); |
+ } |
+ Bind(&out); |
+ Return(var_result.value()); |
+ } |
+ |
+ // 1. If NewTarget is undefined, throw a TypeError exception. |
+ Bind(&if_targetisundefined); |
+ { |
+ Node* const message_id = SmiConstant(MessageTemplate::kNotAPromise); |
+ CallRuntime(Runtime::kThrowTypeError, context, message_id, new_target); |
+ Return(UndefinedConstant()); // Never reached. |
+ } |
+ |
+ // 2. If IsCallable(executor) is false, throw a TypeError exception. |
+ Bind(&if_notcallable); |
+ { |
+ Node* const message_id = |
+ SmiConstant(MessageTemplate::kResolverNotAFunction); |
+ CallRuntime(Runtime::kThrowTypeError, context, message_id, executor); |
+ Return(UndefinedConstant()); // Never reached. |
+ } |
+} |
+ |
+TF_BUILTIN(PromiseInternalConstructor, PromiseBuiltinsAssembler) { |
+ Node* const context = Parameter(3); |
+ Node* const instance = AllocateJSPromise(context); |
+ PromiseInit(instance); |
+ Return(instance); |
+} |
+ |
+TF_BUILTIN(PromiseCreateAndSet, PromiseBuiltinsAssembler) { |
+ Node* const status = Parameter(1); |
+ Node* const result = Parameter(2); |
+ Node* const context = Parameter(5); |
+ |
+ Node* const instance = AllocateJSPromise(context); |
+ PromiseSet(instance, status, result); |
+ Return(instance); |
+} |
+ |
+TF_BUILTIN(IsPromise, PromiseBuiltinsAssembler) { |
+ Node* const maybe_promise = Parameter(1); |
+ Label if_notpromise(this, Label::kDeferred); |
+ |
+ GotoIf(TaggedIsSmi(maybe_promise), &if_notpromise); |
+ |
+ Node* const result = |
+ SelectBooleanConstant(HasInstanceType(maybe_promise, JS_PROMISE_TYPE)); |
+ Return(result); |
+ |
+ Bind(&if_notpromise); |
+ Return(FalseConstant()); |
+} |
+ |
+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 context = Parameter(7); |
+ |
+ Node* const result = InternalPerformPromiseThen(context, promise, on_resolve, |
+ on_reject, deferred); |
+ |
+ // TODO(gsathya): This is unused, but value is returned according to spec. |
+ Return(result); |
+} |
+ |
+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()); |
+ 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); |
+} |
// ES#sec-promise-resolve-functions |
// Promise Resolve Functions |
-void Builtins::Generate_PromiseResolveClosure( |
- compiler::CodeAssemblerState* state) { |
- CodeStubAssembler a(state); |
- typedef compiler::Node Node; |
- typedef CodeStubAssembler::Label Label; |
+TF_BUILTIN(PromiseResolveClosure, PromiseBuiltinsAssembler) { |
+ Node* const value = Parameter(1); |
+ Node* const context = Parameter(4); |
- Node* const value = a.Parameter(1); |
- Node* const context = a.Parameter(4); |
- |
- Label out(&a); |
+ Label out(this); |
// 3. Let alreadyResolved be F.[[AlreadyResolved]]. |
Node* const has_already_visited_slot = |
- a.IntPtrConstant(PromiseUtils::kAlreadyVisitedSlot); |
+ IntPtrConstant(PromiseUtils::kAlreadyVisitedSlot); |
Node* const has_already_visited = |
- a.LoadFixedArrayElement(context, has_already_visited_slot); |
+ LoadFixedArrayElement(context, has_already_visited_slot); |
// 4. If alreadyResolved.[[Value]] is true, return undefined. |
- a.GotoIf(a.SmiEqual(has_already_visited, a.SmiConstant(1)), &out); |
+ GotoIf(SmiEqual(has_already_visited, SmiConstant(1)), &out); |
// 5.Set alreadyResolved.[[Value]] to true. |
- a.StoreFixedArrayElement(context, has_already_visited_slot, a.SmiConstant(1)); |
+ StoreFixedArrayElement(context, has_already_visited_slot, SmiConstant(1)); |
// 2. Let promise be F.[[Promise]]. |
- Node* const promise = a.LoadFixedArrayElement( |
- context, a.IntPtrConstant(PromiseUtils::kPromiseSlot)); |
+ Node* const promise = LoadFixedArrayElement( |
+ context, IntPtrConstant(PromiseUtils::kPromiseSlot)); |
- InternalResolvePromise(&a, context, promise, value, &out); |
+ InternalResolvePromise(context, promise, value, &out); |
- a.Bind(&out); |
- a.Return(a.UndefinedConstant()); |
+ Bind(&out); |
+ Return(UndefinedConstant()); |
} |
-void Builtins::Generate_ResolvePromise(compiler::CodeAssemblerState* state) { |
- CodeStubAssembler a(state); |
- typedef compiler::Node Node; |
- typedef CodeStubAssembler::Label Label; |
- |
- Node* const promise = a.Parameter(1); |
- Node* const result = a.Parameter(2); |
- Node* const context = a.Parameter(5); |
+TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) { |
+ Node* const promise = Parameter(1); |
+ Node* const result = Parameter(2); |
+ Node* const context = Parameter(5); |
- Label out(&a); |
- InternalResolvePromise(&a, context, promise, result, &out); |
+ Label out(this); |
+ InternalResolvePromise(context, promise, result, &out); |
- a.Bind(&out); |
- a.Return(a.UndefinedConstant()); |
+ Bind(&out); |
+ Return(UndefinedConstant()); |
} |
-void Builtins::Generate_PromiseHandleReject( |
- compiler::CodeAssemblerState* state) { |
- CodeStubAssembler a(state); |
- typedef compiler::Node Node; |
- typedef CodeStubAssembler::Label Label; |
- typedef CodeStubAssembler::Variable Variable; |
+TF_BUILTIN(PromiseHandleReject, PromiseBuiltinsAssembler) { |
typedef PromiseHandleRejectDescriptor Descriptor; |
- Node* const promise = a.Parameter(Descriptor::kPromise); |
- Node* const on_reject = a.Parameter(Descriptor::kOnReject); |
- Node* const exception = a.Parameter(Descriptor::kException); |
- Node* const context = a.Parameter(Descriptor::kContext); |
- Isolate* isolate = a.isolate(); |
+ Node* const promise = Parameter(Descriptor::kPromise); |
+ Node* const on_reject = Parameter(Descriptor::kOnReject); |
+ Node* const exception = Parameter(Descriptor::kException); |
+ Node* const context = Parameter(Descriptor::kContext); |
- Callable call_callable = CodeFactory::Call(isolate); |
- Variable var_unused(&a, MachineRepresentation::kTagged); |
+ Callable call_callable = CodeFactory::Call(isolate()); |
+ Variable var_unused(this, MachineRepresentation::kTagged); |
- Label if_internalhandler(&a), if_customhandler(&a, Label::kDeferred); |
- a.Branch(a.IsUndefined(on_reject), &if_internalhandler, &if_customhandler); |
+ Label if_internalhandler(this), if_customhandler(this, Label::kDeferred); |
+ Branch(IsUndefined(on_reject), &if_internalhandler, &if_customhandler); |
- a.Bind(&if_internalhandler); |
+ Bind(&if_internalhandler); |
{ |
- a.CallRuntime(Runtime::kPromiseReject, context, promise, exception, |
- a.FalseConstant()); |
- a.Return(a.UndefinedConstant()); |
+ CallRuntime(Runtime::kPromiseReject, context, promise, exception, |
+ FalseConstant()); |
+ Return(UndefinedConstant()); |
} |
- a.Bind(&if_customhandler); |
+ Bind(&if_customhandler); |
{ |
- a.CallJS(call_callable, context, on_reject, a.UndefinedConstant(), |
- exception); |
- a.Return(a.UndefinedConstant()); |
+ CallJS(call_callable, context, on_reject, UndefinedConstant(), exception); |
+ Return(UndefinedConstant()); |
} |
} |
-void Builtins::Generate_PromiseHandle(compiler::CodeAssemblerState* state) { |
- CodeStubAssembler a(state); |
- typedef compiler::Node Node; |
- typedef CodeStubAssembler::Label Label; |
- typedef CodeStubAssembler::Variable Variable; |
- |
- Node* const value = a.Parameter(2); |
- Node* const handler = a.Parameter(3); |
- Node* const deferred = a.Parameter(4); |
- Node* const context = a.Parameter(7); |
- Isolate* isolate = a.isolate(); |
+TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) { |
+ Node* const value = Parameter(2); |
+ Node* const handler = Parameter(3); |
+ Node* const deferred = Parameter(4); |
+ Node* const context = Parameter(7); |
+ 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 = a.HeapConstant(isolate->factory()->promise_string()); |
+ Node* const key = HeapConstant(isolate->factory()->promise_string()); |
Node* const deferred_promise = |
- a.CallStub(getproperty_callable, context, deferred, key); |
+ CallStub(getproperty_callable, context, deferred, key); |
- Variable var_reason(&a, MachineRepresentation::kTagged); |
+ Variable var_reason(this, MachineRepresentation::kTagged); |
- Node* const is_debug_active = a.IsDebugActive(); |
- Label run_handler(&a), if_rejectpromise(&a), debug_push(&a, Label::kDeferred), |
- debug_pop(&a, Label::kDeferred); |
- a.Branch(is_debug_active, &debug_push, &run_handler); |
+ Node* const is_debug_active = IsDebugActive(); |
+ Label run_handler(this), if_rejectpromise(this), |
+ debug_push(this, Label::kDeferred), debug_pop(this, Label::kDeferred); |
+ Branch(is_debug_active, &debug_push, &run_handler); |
- a.Bind(&debug_push); |
+ Bind(&debug_push); |
{ |
- a.CallRuntime(Runtime::kDebugPushPromise, context, deferred_promise); |
- a.Goto(&run_handler); |
+ CallRuntime(Runtime::kDebugPushPromise, context, deferred_promise); |
+ Goto(&run_handler); |
} |
- a.Bind(&run_handler); |
+ Bind(&run_handler); |
{ |
Callable call_callable = CodeFactory::Call(isolate); |
Node* const result = |
- a.CallJS(call_callable, context, handler, a.UndefinedConstant(), value); |
+ CallJS(call_callable, context, handler, UndefinedConstant(), value); |
- a.GotoIfException(result, &if_rejectpromise, &var_reason); |
+ GotoIfException(result, &if_rejectpromise, &var_reason); |
// TODO(gsathya): Remove this lookup by getting rid of the deferred object. |
- Node* const key = a.HeapConstant(isolate->factory()->resolve_string()); |
+ Node* const key = HeapConstant(isolate->factory()->resolve_string()); |
Node* const on_resolve = |
- a.CallStub(getproperty_callable, context, deferred, key); |
+ CallStub(getproperty_callable, context, deferred, key); |
- Label if_internalhandler(&a), if_customhandler(&a, Label::kDeferred); |
- a.Branch(a.IsUndefined(on_resolve), &if_internalhandler, &if_customhandler); |
+ Label if_internalhandler(this), if_customhandler(this, Label::kDeferred); |
+ Branch(IsUndefined(on_resolve), &if_internalhandler, &if_customhandler); |
- a.Bind(&if_internalhandler); |
- InternalResolvePromise(&a, context, deferred_promise, result, &debug_pop); |
+ Bind(&if_internalhandler); |
+ InternalResolvePromise(context, deferred_promise, result, &debug_pop); |
- a.Bind(&if_customhandler); |
+ Bind(&if_customhandler); |
{ |
- Node* const maybe_exception = a.CallJS(call_callable, context, on_resolve, |
- a.UndefinedConstant(), result); |
- a.GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); |
- a.Goto(&debug_pop); |
+ Node* const maybe_exception = CallJS(call_callable, context, on_resolve, |
+ UndefinedConstant(), result); |
+ GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); |
+ Goto(&debug_pop); |
} |
} |
- a.Bind(&if_rejectpromise); |
+ Bind(&if_rejectpromise); |
{ |
// TODO(gsathya): Remove this lookup by getting rid of the deferred object. |
- Node* const key = a.HeapConstant(isolate->factory()->reject_string()); |
+ Node* const key = HeapConstant(isolate->factory()->reject_string()); |
Node* const on_reject = |
- a.CallStub(getproperty_callable, context, deferred, key); |
+ CallStub(getproperty_callable, context, deferred, key); |
Callable promise_handle_reject = CodeFactory::PromiseHandleReject(isolate); |
- a.CallStub(promise_handle_reject, context, deferred_promise, on_reject, |
- var_reason.value()); |
- a.Goto(&debug_pop); |
+ CallStub(promise_handle_reject, context, deferred_promise, on_reject, |
+ var_reason.value()); |
+ Goto(&debug_pop); |
} |
- a.Bind(&debug_pop); |
+ Bind(&debug_pop); |
{ |
- Label out(&a); |
+ Label out(this); |
- a.GotoUnless(is_debug_active, &out); |
- a.CallRuntime(Runtime::kDebugPopPromise, context); |
- a.Goto(&out); |
+ GotoUnless(is_debug_active, &out); |
+ CallRuntime(Runtime::kDebugPopPromise, context); |
+ Goto(&out); |
- a.Bind(&out); |
- a.Return(a.UndefinedConstant()); |
+ Bind(&out); |
+ Return(UndefinedConstant()); |
} |
} |