Chromium Code Reviews| Index: src/builtins/builtins-promise.cc |
| diff --git a/src/builtins/builtins-promise.cc b/src/builtins/builtins-promise.cc |
| index 9f5d7c88d7885e8bfbcefe65fdc80c729301b305..a4043a4fbe19a0c870109126645053b4e8c1451d 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,169 @@ 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), |
| + if_rejectpromise(&a, Label::kDeferred); |
|
jgruber
2016/11/22 08:55:55
if_rejectpromise could be moved into the run_execu
gsathya
2016/11/23 14:31:18
Done.
|
| + |
| + 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), out(&a), debug_push(&a, Label::kDeferred), |
| + debug_pop(&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); |
| + { |
| + Node* const instance = |
| + a.CallRuntime(Runtime::kNewObject, context, promise_fun, new_target); |
|
jgruber
2016/11/22 08:55:55
Just curious, why is it not possible to call a.All
gsathya
2016/11/23 14:31:18
The subclass setup seemed more involved and I wasn
|
| + |
| + 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); |
| + { |
| + Node* const key = |
| + a.HeapConstant(a.isolate()->factory()->promise_state_symbol()); |
| + Node* const value = a.SmiConstant(Smi::FromInt(kPromisePending)); |
| + Node* const language_mode = a.SmiConstant(Smi::FromInt(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)); |
| + var_reject_call.Bind(reject); |
|
jgruber
2016/11/22 08:55:55
Seems like you can just use the Node* reject varia
gsathya
2016/11/23 14:31:18
Done.
|
| + 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, var_reject_call.value(), |
| + a.UndefinedConstant(), var_reason.value()); |
| + a.Branch(a.IsDebugActive(), &debug_pop, &out); |
| + } |
| + |
| + a.Bind(&debug_pop); |
| + { |
| + a.CallRuntime(Runtime::kDebugPopPromise, context); |
| + a.Goto(&out); |
| + } |
| + |
| + 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(Smi::FromInt(MessageTemplate::kNotAPromise)); |
|
jgruber
2016/11/22 08:55:55
Here and elsewhere: since recently you can just ca
gsathya
2016/11/23 14:31:18
Done.
|
| + a.CallRuntime(Runtime::kThrowTypeError, context, message_id, new_target); |
| + // a.ToString(a, new_target)); |
|
jgruber
2016/11/22 08:55:55
Please remove comment.
gsathya
2016/11/23 14:31:18
Done.
|
| + 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(Smi::FromInt(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 |