| Index: src/builtins/builtins-promise.cc
|
| diff --git a/src/builtins/builtins-promise.cc b/src/builtins/builtins-promise.cc
|
| index 9f5d7c88d7885e8bfbcefe65fdc80c729301b305..91e8d7bbe4e72a4134175a59f7e673c64b30bb07 100644
|
| --- a/src/builtins/builtins-promise.cc
|
| +++ b/src/builtins/builtins-promise.cc
|
| @@ -5,6 +5,7 @@
|
| #include "src/builtins/builtins-utils.h"
|
| #include "src/builtins/builtins.h"
|
|
|
| +#include "src/code-factory.h"
|
| #include "src/promise-utils.h"
|
|
|
| namespace v8 {
|
| @@ -80,5 +81,164 @@ BUILTIN(CreateResolvingFunctions) {
|
| 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.WordEqual(new_target, a.UndefinedConstant()),
|
| + &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);
|
| +
|
| + Label if_targetisnotmodified(&a), if_targetismodified(&a, Label::kDeferred),
|
| + run_executor(&a), debug_push(&a, Label::kDeferred);
|
| + 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 initial_map = a.LoadObjectField(
|
| + promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
|
| +
|
| + Node* const instance = a.AllocateJSObjectFromMap(initial_map);
|
| + var_result.Bind(instance);
|
| + a.Branch(a.IsDebugActive(), &debug_push, &run_executor);
|
| + }
|
| +
|
| + 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.Branch(a.IsDebugActive(), &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);
|
| +
|
| + Node* const key =
|
| + a.HeapConstant(a.isolate()->factory()->promise_state_symbol());
|
| + Node* const value = a.SmiConstant(kPromisePending);
|
| + Node* const language_mode = a.SmiConstant(STRICT);
|
| + a.CallRuntime(Runtime::kSetProperty, context, var_result.value(), key,
|
| + value, language_mode);
|
| + 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);
|
| +
|
| + a.GotoIfException(maybe_exception, &if_rejectpromise, &var_reason);
|
| + a.Branch(a.IsDebugActive(), &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(a.IsDebugActive(), &debug_pop, &out);
|
| + }
|
| +
|
| + a.Bind(&debug_pop);
|
| + a.CallRuntime(Runtime::kDebugPopPromise, context);
|
| +
|
| + a.Bind(&out);
|
| + a.Return(var_result.value());
|
| + }
|
| +
|
| + // 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.
|
| + }
|
| +
|
| + // 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.
|
| + }
|
| +}
|
| +
|
| +void Builtins::Generate_PromiseInternalConstructor(
|
| + compiler::CodeAssemblerState* state) {
|
| + typedef compiler::Node Node;
|
| + CodeStubAssembler a(state);
|
| +
|
| + Node* const context = a.Parameter(3);
|
| + Node* const native_context = a.LoadNativeContext(context);
|
| + Node* const promise_fun =
|
| + a.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
|
| + Node* const initial_map =
|
| + a.LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
|
| + Node* const instance = a.AllocateJSObjectFromMap(initial_map);
|
| + a.Return(instance);
|
| +}
|
| +
|
| +// TODO(gsathya): Refactor promise.js::IsPromise to use this.
|
| +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_ispromise(&a), if_isnotpromise(&a, Label::kDeferred);
|
| + a.GotoIf(a.TaggedIsSmi(maybe_promise), &if_isnotpromise);
|
| +
|
| + Node* const maybe_promise_type =
|
| + a.LoadMapInstanceType(a.LoadMap(maybe_promise));
|
| +
|
| + a.Branch(a.Word32Equal(maybe_promise_type, a.Int32Constant(JS_PROMISE_TYPE)),
|
| + &if_ispromise, &if_isnotpromise);
|
| +
|
| + a.Bind(&if_ispromise);
|
| + a.Return(a.BooleanConstant(true));
|
| +
|
| + a.Bind(&if_isnotpromise);
|
| + a.Return(a.BooleanConstant(false));
|
| +}
|
| +
|
| } // namespace internal
|
| } // namespace v8
|
|
|