Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/builtins/builtins-promise.h" | 5 #include "src/builtins/builtins-promise.h" |
| 6 #include "src/builtins/builtins-utils.h" | 6 #include "src/builtins/builtins-utils.h" |
| 7 #include "src/builtins/builtins.h" | 7 #include "src/builtins/builtins.h" |
| 8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
| 9 #include "src/code-stub-assembler.h" | 9 #include "src/code-stub-assembler.h" |
| 10 #include "src/promise-utils.h" | 10 #include "src/promise-utils.h" |
| 11 | 11 |
| 12 namespace v8 { | 12 namespace v8 { |
| 13 namespace internal { | 13 namespace internal { |
| 14 | 14 |
| 15 typedef compiler::Node Node; | 15 typedef compiler::Node Node; |
| 16 typedef CodeStubAssembler::ParameterMode ParameterMode; | 16 typedef CodeStubAssembler::ParameterMode ParameterMode; |
| 17 typedef compiler::CodeAssemblerState CodeAssemblerState; | 17 typedef compiler::CodeAssemblerState CodeAssemblerState; |
| 18 | 18 |
| 19 Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext( | 19 Node* PromiseBuiltinsAssembler::NewPromiseCapability(Node* context, |
| 20 Node* promise, Node* debug_event, Node* native_context) { | 20 Node* constructor, |
| 21 Node* const context = | 21 Node* debug_event) { |
| 22 Allocate(FixedArray::SizeFor(PromiseUtils::kPromiseContextLength)); | 22 if (debug_event == nullptr) { |
| 23 StoreMapNoWriteBarrier(context, Heap::kFunctionContextMapRootIndex); | 23 debug_event = TrueConstant(); |
| 24 } | |
| 25 | |
| 26 Node* native_context = LoadNativeContext(context); | |
| 27 | |
| 28 Node* map = LoadRoot(Heap::kJSPromiseCapabilityMapRootIndex); | |
| 29 Node* capability = AllocateJSObjectFromMap(map); | |
| 30 | |
| 24 StoreObjectFieldNoWriteBarrier( | 31 StoreObjectFieldNoWriteBarrier( |
| 25 context, FixedArray::kLengthOffset, | 32 capability, JSPromiseCapability::kPromiseOffset, UndefinedConstant()); |
| 26 SmiConstant(PromiseUtils::kPromiseContextLength)); | 33 StoreObjectFieldNoWriteBarrier( |
| 34 capability, JSPromiseCapability::kResolveOffset, UndefinedConstant()); | |
| 35 StoreObjectFieldNoWriteBarrier(capability, JSPromiseCapability::kRejectOffset, | |
| 36 UndefinedConstant()); | |
| 27 | 37 |
| 28 Node* const empty_fn = | 38 Variable var_result(this, MachineRepresentation::kTagged); |
| 29 LoadContextElement(native_context, Context::CLOSURE_INDEX); | 39 var_result.Bind(capability); |
| 30 StoreContextElementNoWriteBarrier(context, Context::CLOSURE_INDEX, empty_fn); | 40 |
| 41 Label if_builtin_promise(this), if_custom_promise(this), out(this); | |
|
gsathya
2016/12/29 21:48:47
if_custom_promise can be deferred
| |
| 42 Branch(WordEqual(constructor, | |
| 43 LoadContextElement(native_context, | |
| 44 Context::PROMISE_FUNCTION_INDEX)), | |
| 45 &if_builtin_promise, &if_custom_promise); | |
| 46 | |
| 47 Bind(&if_builtin_promise); | |
| 48 { | |
| 49 Node* promise = AllocateJSPromise(context); | |
| 50 PromiseInit(promise); | |
| 51 StoreObjectFieldNoWriteBarrier( | |
| 52 capability, JSPromiseCapability::kPromiseOffset, promise); | |
| 53 | |
| 54 Node* resolve = nullptr; | |
| 55 Node* reject = nullptr; | |
| 56 | |
| 57 std::tie(resolve, reject) = | |
| 58 CreatePromiseResolvingFunctions(promise, debug_event, native_context); | |
| 59 StoreObjectField(capability, JSPromiseCapability::kResolveOffset, resolve); | |
| 60 StoreObjectField(capability, JSPromiseCapability::kRejectOffset, reject); | |
| 61 | |
| 62 GotoUnless(IsPromiseHookEnabled(), &out); | |
| 63 CallRuntime(Runtime::kPromiseHookInit, context, promise, | |
| 64 UndefinedConstant()); | |
| 65 Goto(&out); | |
| 66 } | |
| 67 | |
| 68 Bind(&if_custom_promise); | |
| 69 { | |
| 70 Label if_notcallable(this, Label::kDeferred); | |
| 71 Node* executor_context = | |
| 72 CreatePromiseGetCapabilitiesExecutorContext(capability, native_context); | |
| 73 Node* executor_info = LoadContextElement( | |
| 74 native_context, Context::PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN); | |
| 75 Node* function_map = LoadContextElement( | |
| 76 native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX); | |
| 77 Node* executor = AllocateFunctionWithMapAndContext( | |
| 78 function_map, executor_info, executor_context); | |
| 79 | |
| 80 Node* promise = ConstructJS(CodeFactory::Construct(isolate()), context, | |
| 81 constructor, executor); | |
| 82 | |
| 83 Node* resolve = | |
| 84 LoadObjectField(capability, JSPromiseCapability::kResolveOffset); | |
| 85 GotoIf(TaggedIsSmi(resolve), &if_notcallable); | |
| 86 GotoUnless(IsCallableMap(LoadMap(resolve)), &if_notcallable); | |
| 87 | |
| 88 Node* reject = | |
| 89 LoadObjectField(capability, JSPromiseCapability::kRejectOffset); | |
| 90 GotoIf(TaggedIsSmi(reject), &if_notcallable); | |
| 91 GotoUnless(IsCallableMap(LoadMap(reject)), &if_notcallable); | |
| 92 | |
| 93 StoreObjectField(capability, JSPromiseCapability::kPromiseOffset, promise); | |
| 94 | |
| 95 Goto(&out); | |
| 96 | |
| 97 Bind(&if_notcallable); | |
| 98 Node* message = SmiConstant(MessageTemplate::kPromiseNonCallable); | |
| 99 StoreObjectField(capability, JSPromiseCapability::kPromiseOffset, | |
| 100 UndefinedConstant()); | |
| 101 StoreObjectField(capability, JSPromiseCapability::kResolveOffset, | |
| 102 UndefinedConstant()); | |
| 103 StoreObjectField(capability, JSPromiseCapability::kRejectOffset, | |
| 104 UndefinedConstant()); | |
| 105 CallRuntime(Runtime::kThrowTypeError, context, message); | |
| 106 var_result.Bind(UndefinedConstant()); | |
| 107 Goto(&out); | |
| 108 } | |
| 109 | |
| 110 Bind(&out); | |
| 111 return var_result.value(); | |
| 112 } | |
| 113 | |
| 114 Node* PromiseBuiltinsAssembler::NewInternalPromiseCapability(Node* context, | |
| 115 Node* parent) { | |
| 116 Node* promise = AllocateJSPromise(context); | |
| 117 PromiseInit(promise); | |
| 118 | |
| 119 Label out(this); | |
| 120 | |
| 121 Node* map = LoadRoot(Heap::kJSPromiseCapabilityMapRootIndex); | |
| 122 Node* capability = AllocateJSObjectFromMap(map); | |
| 123 StoreObjectFieldNoWriteBarrier(capability, | |
| 124 JSPromiseCapability::kPromiseOffset, promise); | |
| 125 StoreObjectFieldNoWriteBarrier( | |
| 126 capability, JSPromiseCapability::kResolveOffset, UndefinedConstant()); | |
| 127 StoreObjectFieldNoWriteBarrier(capability, JSPromiseCapability::kRejectOffset, | |
| 128 UndefinedConstant()); | |
| 129 | |
| 130 GotoUnless(IsPromiseHookEnabled(), &out); | |
| 131 CallRuntime(Runtime::kPromiseHookInit, context, promise, parent); | |
| 132 Goto(&out); | |
| 133 | |
| 134 Bind(&out); | |
| 135 return capability; | |
| 136 } | |
| 137 | |
| 138 Node* PromiseBuiltinsAssembler::CreatePromiseContext(Node* native_context, | |
| 139 int slots) { | |
| 140 DCHECK_GE(slots, Context::MIN_CONTEXT_SLOTS); | |
| 141 Node* script = LoadContextElement(native_context, Context::CLOSURE_INDEX); | |
| 142 Node* map = HeapConstant(isolate()->factory()->function_context_map()); | |
| 143 Node* context = Allocate(FixedArray::SizeFor(slots)); | |
| 144 StoreMapNoWriteBarrier(context, map); | |
| 145 StoreObjectFieldNoWriteBarrier(context, FixedArray::kLengthOffset, | |
| 146 SmiConstant(slots)); | |
| 147 StoreContextElementNoWriteBarrier(context, Context::CLOSURE_INDEX, script); | |
| 31 StoreContextElementNoWriteBarrier(context, Context::PREVIOUS_INDEX, | 148 StoreContextElementNoWriteBarrier(context, Context::PREVIOUS_INDEX, |
| 32 UndefinedConstant()); | 149 UndefinedConstant()); |
| 33 StoreContextElementNoWriteBarrier(context, Context::EXTENSION_INDEX, | 150 StoreContextElementNoWriteBarrier(context, Context::EXTENSION_INDEX, |
| 34 TheHoleConstant()); | 151 TheHoleConstant()); |
| 35 StoreContextElementNoWriteBarrier(context, Context::NATIVE_CONTEXT_INDEX, | 152 StoreContextElementNoWriteBarrier(context, Context::NATIVE_CONTEXT_INDEX, |
| 36 native_context); | 153 native_context); |
| 154 return context; | |
| 155 } | |
| 156 | |
| 157 Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext( | |
| 158 Node* promise, Node* debug_event, Node* native_context) { | |
| 159 Node* const context = | |
| 160 CreatePromiseContext(native_context, PromiseUtils::kPromiseContextLength); | |
| 37 StoreContextElementNoWriteBarrier(context, PromiseUtils::kAlreadyVisitedSlot, | 161 StoreContextElementNoWriteBarrier(context, PromiseUtils::kAlreadyVisitedSlot, |
| 38 SmiConstant(0)); | 162 SmiConstant(0)); |
| 39 StoreContextElementNoWriteBarrier(context, PromiseUtils::kPromiseSlot, | 163 StoreContextElementNoWriteBarrier(context, PromiseUtils::kPromiseSlot, |
| 40 promise); | 164 promise); |
| 41 StoreContextElementNoWriteBarrier(context, PromiseUtils::kDebugEventSlot, | 165 StoreContextElementNoWriteBarrier(context, PromiseUtils::kDebugEventSlot, |
| 42 debug_event); | 166 debug_event); |
| 43 return context; | 167 return context; |
| 44 } | 168 } |
| 45 | 169 |
| 170 Node* PromiseBuiltinsAssembler::CreatePromiseGetCapabilitiesExecutorContext( | |
| 171 Node* promise_capability, Node* native_context) { | |
| 172 int kSize = GetPromiseCapabilityExecutor::kContextLength; | |
| 173 Node* context = CreatePromiseContext(native_context, kSize); | |
| 174 StoreContextElementNoWriteBarrier( | |
| 175 context, GetPromiseCapabilityExecutor::kCapabilitySlot, | |
| 176 promise_capability); | |
| 177 return context; | |
| 178 } | |
| 179 | |
| 46 std::pair<Node*, Node*> | 180 std::pair<Node*, Node*> |
| 47 PromiseBuiltinsAssembler::CreatePromiseResolvingFunctions( | 181 PromiseBuiltinsAssembler::CreatePromiseResolvingFunctions( |
| 48 Node* promise, Node* debug_event, Node* native_context) { | 182 Node* promise, Node* debug_event, Node* native_context) { |
| 49 Node* const promise_context = CreatePromiseResolvingFunctionsContext( | 183 Node* const promise_context = CreatePromiseResolvingFunctionsContext( |
| 50 promise, debug_event, native_context); | 184 promise, debug_event, native_context); |
| 51 Node* const map = LoadContextElement( | 185 Node* const map = LoadContextElement( |
| 52 native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX); | 186 native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX); |
| 53 Node* const resolve_info = | 187 Node* const resolve_info = |
| 54 LoadContextElement(native_context, Context::PROMISE_RESOLVE_SHARED_FUN); | 188 LoadContextElement(native_context, Context::PROMISE_RESOLVE_SHARED_FUN); |
| 55 Node* const resolve = | 189 Node* const resolve = |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 199 | 333 |
| 200 // 4. Let resultCapability be ? NewPromiseCapability(C). | 334 // 4. Let resultCapability be ? NewPromiseCapability(C). |
| 201 Callable call_callable = CodeFactory::Call(isolate); | 335 Callable call_callable = CodeFactory::Call(isolate); |
| 202 Label fast_promise_capability(this), promise_capability(this), | 336 Label fast_promise_capability(this), promise_capability(this), |
| 203 perform_promise_then(this); | 337 perform_promise_then(this); |
| 204 Variable var_deferred(this, MachineRepresentation::kTagged); | 338 Variable var_deferred(this, MachineRepresentation::kTagged); |
| 205 | 339 |
| 206 Branch(WordEqual(promise_fun, constructor), &fast_promise_capability, | 340 Branch(WordEqual(promise_fun, constructor), &fast_promise_capability, |
| 207 &promise_capability); | 341 &promise_capability); |
| 208 | 342 |
| 209 // TODO(gsathya): Remove deferred object and move | 343 // TODO(gsathya): Remove deferred object. |
| 210 // NewPromiseCapabability functions to TF. | |
| 211 Bind(&fast_promise_capability); | 344 Bind(&fast_promise_capability); |
| 212 { | 345 { |
| 213 // TODO(gsathya): Move this to TF. | 346 Node* const capability = NewInternalPromiseCapability(context, promise); |
| 214 Node* const promise_internal_capability = LoadContextElement( | |
| 215 native_context, Context::INTERNAL_PROMISE_CAPABILITY_INDEX); | |
| 216 Node* const capability = | |
| 217 CallJS(call_callable, context, promise_internal_capability, | |
| 218 UndefinedConstant(), promise); | |
| 219 var_deferred.Bind(capability); | 347 var_deferred.Bind(capability); |
| 220 Goto(&perform_promise_then); | 348 Goto(&perform_promise_then); |
| 221 } | 349 } |
| 222 | 350 |
| 223 Bind(&promise_capability); | 351 Bind(&promise_capability); |
| 224 { | 352 { |
| 225 // TODO(gsathya): Move this to TF. | 353 Node* const capability = NewPromiseCapability(context, constructor); |
| 226 Node* const new_promise_capability = LoadContextElement( | |
| 227 native_context, Context::NEW_PROMISE_CAPABILITY_INDEX); | |
| 228 Node* const capability = | |
| 229 CallJS(call_callable, context, new_promise_capability, | |
| 230 UndefinedConstant(), constructor); | |
| 231 var_deferred.Bind(capability); | 354 var_deferred.Bind(capability); |
| 232 Goto(&perform_promise_then); | 355 Goto(&perform_promise_then); |
| 233 } | 356 } |
| 234 | 357 |
| 235 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, | 358 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, |
| 236 // resultCapability). | 359 // resultCapability). |
| 237 Bind(&perform_promise_then); | 360 Bind(&perform_promise_then); |
| 238 Node* const result = InternalPerformPromiseThen( | 361 Node* const result = InternalPerformPromiseThen( |
| 239 context, promise, on_resolve, on_reject, var_deferred.value()); | 362 context, promise, on_resolve, on_reject, var_deferred.value()); |
| 240 return result; | 363 return result; |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 390 | 513 |
| 391 Goto(&out); | 514 Goto(&out); |
| 392 } | 515 } |
| 393 } | 516 } |
| 394 } | 517 } |
| 395 } | 518 } |
| 396 | 519 |
| 397 Bind(&out); | 520 Bind(&out); |
| 398 PromiseSetHasHandler(promise); | 521 PromiseSetHasHandler(promise); |
| 399 | 522 |
| 400 // TODO(gsathya): This call will be removed once we don't have to | 523 CSA_ASSERT(this, HasInstanceType(deferred, JS_PROMISE_CAPABILITY_TYPE)); |
| 401 // deal with deferred objects. | 524 Node* then_promise = |
| 402 Isolate* isolate = this->isolate(); | 525 LoadObjectField(deferred, JSPromiseCapability::kPromiseOffset); |
| 403 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | 526 return then_promise; |
| 404 Node* const key = | |
| 405 HeapConstant(isolate->factory()->NewStringFromAsciiChecked("promise")); | |
| 406 Node* const result = CallStub(getproperty_callable, context, deferred, key); | |
| 407 | |
| 408 return result; | |
| 409 } | 527 } |
| 410 | 528 |
| 411 // Promise fast path implementations rely on unmodified JSPromise instances. | 529 // Promise fast path implementations rely on unmodified JSPromise instances. |
| 412 // We use a fairly coarse granularity for this and simply check whether both | 530 // We use a fairly coarse granularity for this and simply check whether both |
| 413 // the promise itself is unmodified (i.e. its map has not changed) and its | 531 // the promise itself is unmodified (i.e. its map has not changed) and its |
| 414 // prototype is unmodified. | 532 // prototype is unmodified. |
| 415 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp | 533 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp |
| 416 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise, | 534 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise, |
| 417 Label* if_isunmodified, | 535 Label* if_isunmodified, |
| 418 Label* if_ismodified) { | 536 Label* if_ismodified) { |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 611 handle(PromiseUtils::GetDebugEvent(context), isolate); | 729 handle(PromiseUtils::GetDebugEvent(context), isolate); |
| 612 MaybeHandle<Object> maybe_result; | 730 MaybeHandle<Object> maybe_result; |
| 613 Handle<Object> argv[] = {promise, value, debug_event}; | 731 Handle<Object> argv[] = {promise, value, debug_event}; |
| 614 RETURN_FAILURE_ON_EXCEPTION( | 732 RETURN_FAILURE_ON_EXCEPTION( |
| 615 isolate, Execution::Call(isolate, isolate->promise_internal_reject(), | 733 isolate, Execution::Call(isolate, isolate->promise_internal_reject(), |
| 616 isolate->factory()->undefined_value(), | 734 isolate->factory()->undefined_value(), |
| 617 arraysize(argv), argv)); | 735 arraysize(argv), argv)); |
| 618 return isolate->heap()->undefined_value(); | 736 return isolate->heap()->undefined_value(); |
| 619 } | 737 } |
| 620 | 738 |
| 621 // ES#sec-createresolvingfunctions | |
| 622 // CreateResolvingFunctions ( promise ) | |
| 623 TF_BUILTIN(CreateResolvingFunctions, PromiseBuiltinsAssembler) { | |
| 624 Node* const promise = Parameter(1); | |
| 625 Node* const debug_event = Parameter(2); | |
| 626 Node* const context = Parameter(5); | |
| 627 Node* const native_context = LoadNativeContext(context); | |
| 628 | |
| 629 Node* resolve = nullptr; | |
| 630 Node* reject = nullptr; | |
| 631 | |
| 632 std::tie(resolve, reject) = | |
| 633 CreatePromiseResolvingFunctions(promise, debug_event, native_context); | |
| 634 | |
| 635 Node* const kSize = IntPtrConstant(2); | |
| 636 const ElementsKind kind = FAST_ELEMENTS; | |
| 637 const WriteBarrierMode barrier_mode = SKIP_WRITE_BARRIER; | |
| 638 const ParameterMode parameter_mode = INTPTR_PARAMETERS; | |
| 639 Node* const arr = AllocateFixedArray(kind, kSize, parameter_mode); | |
| 640 StoreFixedArrayElement(arr, 0, resolve, barrier_mode); | |
| 641 StoreFixedArrayElement(arr, 1, reject, barrier_mode); | |
| 642 | |
| 643 Node* const array_map = LoadJSArrayElementsMap(kind, native_context); | |
| 644 Node* const length = SmiTag(kSize); | |
| 645 Node* const result = AllocateUninitializedJSArrayWithoutElements( | |
| 646 kind, array_map, length, nullptr); | |
| 647 | |
| 648 StoreObjectField(result, JSObject::kElementsOffset, arr); | |
| 649 Return(result); | |
| 650 } | |
| 651 | |
| 652 TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) { | 739 TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) { |
| 653 Node* const executor = Parameter(1); | 740 Node* const executor = Parameter(1); |
| 654 Node* const new_target = Parameter(2); | 741 Node* const new_target = Parameter(2); |
| 655 Node* const context = Parameter(4); | 742 Node* const context = Parameter(4); |
| 656 Isolate* isolate = this->isolate(); | 743 Isolate* isolate = this->isolate(); |
| 657 | 744 |
| 658 Label if_targetisundefined(this, Label::kDeferred); | 745 Label if_targetisundefined(this, Label::kDeferred); |
| 659 | 746 |
| 660 GotoIf(IsUndefined(new_target), &if_targetisundefined); | 747 GotoIf(IsUndefined(new_target), &if_targetisundefined); |
| 661 | 748 |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 908 | 995 |
| 909 TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) { | 996 TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) { |
| 910 Node* const promise = Parameter(1); | 997 Node* const promise = Parameter(1); |
| 911 Node* const value = Parameter(2); | 998 Node* const value = Parameter(2); |
| 912 Node* const handler = Parameter(3); | 999 Node* const handler = Parameter(3); |
| 913 Node* const deferred = Parameter(4); | 1000 Node* const deferred = Parameter(4); |
| 914 Node* const context = Parameter(7); | 1001 Node* const context = Parameter(7); |
| 915 Isolate* isolate = this->isolate(); | 1002 Isolate* isolate = this->isolate(); |
| 916 | 1003 |
| 917 // Get promise from deferred | 1004 // Get promise from deferred |
| 918 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. | 1005 CSA_ASSERT(this, HasInstanceType(deferred, JS_PROMISE_CAPABILITY_TYPE)); |
| 919 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | |
| 920 Node* const key = HeapConstant(isolate->factory()->promise_string()); | |
| 921 Node* const deferred_promise = | 1006 Node* const deferred_promise = |
| 922 CallStub(getproperty_callable, context, deferred, key); | 1007 LoadObjectField(deferred, JSPromiseCapability::kPromiseOffset); |
| 923 | 1008 |
| 924 Variable var_reason(this, MachineRepresentation::kTagged); | 1009 Variable var_reason(this, MachineRepresentation::kTagged); |
| 925 | 1010 |
| 926 Node* const is_debug_active = IsDebugActive(); | 1011 Node* const is_debug_active = IsDebugActive(); |
| 927 Label run_handler(this), if_rejectpromise(this), promisehook_before(this), | 1012 Label run_handler(this), if_rejectpromise(this), promisehook_before(this), |
| 928 promisehook_after(this), debug_pop(this); | 1013 promisehook_after(this), debug_pop(this); |
| 929 | 1014 |
| 930 GotoUnless(is_debug_active, &promisehook_before); | 1015 GotoUnless(is_debug_active, &promisehook_before); |
| 931 CallRuntime(Runtime::kDebugPushPromise, context, deferred_promise); | 1016 CallRuntime(Runtime::kDebugPushPromise, context, deferred_promise); |
| 932 Goto(&promisehook_before); | 1017 Goto(&promisehook_before); |
| 933 | 1018 |
| 934 Bind(&promisehook_before); | 1019 Bind(&promisehook_before); |
| 935 { | 1020 { |
| 936 GotoUnless(IsPromiseHookEnabled(), &run_handler); | 1021 GotoUnless(IsPromiseHookEnabled(), &run_handler); |
| 937 CallRuntime(Runtime::kPromiseHookBefore, context, promise); | 1022 CallRuntime(Runtime::kPromiseHookBefore, context, promise); |
| 938 Goto(&run_handler); | 1023 Goto(&run_handler); |
| 939 } | 1024 } |
| 940 | 1025 |
| 941 Bind(&run_handler); | 1026 Bind(&run_handler); |
| 942 { | 1027 { |
| 943 Callable call_callable = CodeFactory::Call(isolate); | 1028 Callable call_callable = CodeFactory::Call(isolate); |
| 944 | 1029 |
| 945 Node* const result = | 1030 Node* const result = |
| 946 CallJS(call_callable, context, handler, UndefinedConstant(), value); | 1031 CallJS(call_callable, context, handler, UndefinedConstant(), value); |
| 947 | 1032 |
| 948 GotoIfException(result, &if_rejectpromise, &var_reason); | 1033 GotoIfException(result, &if_rejectpromise, &var_reason); |
| 949 | 1034 |
| 950 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. | |
| 951 Node* const key = HeapConstant(isolate->factory()->resolve_string()); | |
| 952 Node* const on_resolve = | 1035 Node* const on_resolve = |
| 953 CallStub(getproperty_callable, context, deferred, key); | 1036 LoadObjectField(deferred, JSPromiseCapability::kResolveOffset); |
| 954 | 1037 |
| 955 Label if_internalhandler(this), if_customhandler(this, Label::kDeferred); | 1038 Label if_internalhandler(this), if_customhandler(this, Label::kDeferred); |
| 956 Branch(IsUndefined(on_resolve), &if_internalhandler, &if_customhandler); | 1039 Branch(IsUndefined(on_resolve), &if_internalhandler, &if_customhandler); |
| 957 | 1040 |
| 958 Bind(&if_internalhandler); | 1041 Bind(&if_internalhandler); |
| 959 InternalResolvePromise(context, deferred_promise, result); | 1042 InternalResolvePromise(context, deferred_promise, result); |
| 960 Goto(&promisehook_after); | 1043 Goto(&promisehook_after); |
| 961 | 1044 |
| 962 Bind(&if_customhandler); | 1045 Bind(&if_customhandler); |
| 963 { | 1046 { |
| 964 Node* const maybe_exception = CallJS(call_callable, context, on_resolve, | 1047 Node* const maybe_exception = CallJS(call_callable, context, on_resolve, |
| 965 UndefinedConstant(), result); | 1048 UndefinedConstant(), result); |
| 966 GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); | 1049 GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); |
| 967 Goto(&promisehook_after); | 1050 Goto(&promisehook_after); |
| 968 } | 1051 } |
| 969 } | 1052 } |
| 970 | 1053 |
| 971 Bind(&if_rejectpromise); | 1054 Bind(&if_rejectpromise); |
| 972 { | 1055 { |
| 973 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. | |
| 974 Node* const key = HeapConstant(isolate->factory()->reject_string()); | |
| 975 Node* const on_reject = | 1056 Node* const on_reject = |
| 976 CallStub(getproperty_callable, context, deferred, key); | 1057 LoadObjectField(deferred, JSPromiseCapability::kRejectOffset); |
| 977 | 1058 |
| 978 Callable promise_handle_reject = CodeFactory::PromiseHandleReject(isolate); | 1059 Callable promise_handle_reject = CodeFactory::PromiseHandleReject(isolate); |
| 979 CallStub(promise_handle_reject, context, deferred_promise, on_reject, | 1060 CallStub(promise_handle_reject, context, deferred_promise, on_reject, |
| 980 var_reason.value()); | 1061 var_reason.value()); |
| 981 Goto(&promisehook_after); | 1062 Goto(&promisehook_after); |
| 982 } | 1063 } |
| 983 | 1064 |
| 984 Bind(&promisehook_after); | 1065 Bind(&promisehook_after); |
| 985 { | 1066 { |
| 986 GotoUnless(IsPromiseHookEnabled(), &debug_pop); | 1067 GotoUnless(IsPromiseHookEnabled(), &debug_pop); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1027 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | 1108 Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
| 1028 Node* const then = | 1109 Node* const then = |
| 1029 CallStub(getproperty_callable, context, promise, then_str); | 1110 CallStub(getproperty_callable, context, promise, then_str); |
| 1030 Callable call_callable = CodeFactory::Call(isolate); | 1111 Callable call_callable = CodeFactory::Call(isolate); |
| 1031 Node* const result = | 1112 Node* const result = |
| 1032 CallJS(call_callable, context, then, promise, on_resolve, on_reject); | 1113 CallJS(call_callable, context, then, promise, on_resolve, on_reject); |
| 1033 Return(result); | 1114 Return(result); |
| 1034 } | 1115 } |
| 1035 } | 1116 } |
| 1036 | 1117 |
| 1118 TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) { | |
| 1119 Node* const resolve = Parameter(1); | |
| 1120 Node* const reject = Parameter(2); | |
| 1121 Node* const context = Parameter(5); | |
| 1122 | |
| 1123 Node* const capability = LoadContextElement( | |
| 1124 context, GetPromiseCapabilityExecutor::kCapabilitySlot); | |
| 1125 | |
| 1126 Label if_alreadyinvoked(this, Label::kDeferred); | |
| 1127 GotoIf(WordNotEqual( | |
| 1128 LoadObjectField(capability, JSPromiseCapability::kResolveOffset), | |
| 1129 UndefinedConstant()), | |
| 1130 &if_alreadyinvoked); | |
| 1131 GotoIf(WordNotEqual( | |
| 1132 LoadObjectField(capability, JSPromiseCapability::kRejectOffset), | |
| 1133 UndefinedConstant()), | |
| 1134 &if_alreadyinvoked); | |
| 1135 | |
| 1136 StoreObjectField(capability, JSPromiseCapability::kResolveOffset, resolve); | |
| 1137 StoreObjectField(capability, JSPromiseCapability::kRejectOffset, reject); | |
| 1138 | |
| 1139 Return(UndefinedConstant()); | |
| 1140 | |
| 1141 Bind(&if_alreadyinvoked); | |
| 1142 Node* message = SmiConstant(MessageTemplate::kPromiseExecutorAlreadyInvoked); | |
| 1143 Return(CallRuntime(Runtime::kThrowTypeError, context, message)); | |
| 1144 } | |
| 1145 | |
| 1146 TF_BUILTIN(NewPromiseCapability, PromiseBuiltinsAssembler) { | |
| 1147 Node* constructor = Parameter(1); | |
| 1148 Node* debug_event = Parameter(2); | |
| 1149 Node* context = Parameter(5); | |
| 1150 | |
| 1151 CSA_ASSERT_JS_ARGC_EQ(this, 2); | |
| 1152 | |
| 1153 Return(NewPromiseCapability(context, constructor, debug_event)); | |
| 1154 } | |
| 1155 | |
| 1156 TF_BUILTIN(NewInternalPromiseCapability, PromiseBuiltinsAssembler) { | |
| 1157 Node* parent = Parameter(1); | |
| 1158 Node* context = Parameter(4); | |
| 1159 CSA_ASSERT_JS_ARGC_EQ(this, 1); | |
| 1160 | |
| 1161 Return(NewInternalPromiseCapability(context, parent)); | |
| 1162 } | |
| 1163 | |
| 1037 } // namespace internal | 1164 } // namespace internal |
| 1038 } // namespace v8 | 1165 } // namespace v8 |
| OLD | NEW |