Chromium Code Reviews

Unified Diff: src/builtins/builtins-promise.cc

Issue 2583753002: [promises] Use TF_BUILTIN (Closed)
Patch Set: rebase Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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());
}
}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine