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::AllocateAndInitPromise(Node* context, | |
| 20 Node* parent) { | |
| 21 Node* const instance = AllocateJSPromise(context); | |
| 22 PromiseInit(instance); | |
| 23 | |
| 24 Label out(this); | |
| 25 GotoUnless(IsPromiseHookEnabled(), &out); | |
| 26 CallRuntime(Runtime::kPromiseHookInit, context, instance, parent); | |
| 27 Goto(&out); | |
| 28 | |
| 29 Bind(&out); | |
| 30 return instance; | |
| 31 } | |
| 32 | |
| 19 Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext( | 33 Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext( |
| 20 Node* promise, Node* debug_event, Node* native_context) { | 34 Node* promise, Node* debug_event, Node* native_context) { |
| 21 Node* const context = | 35 Node* const context = |
| 22 Allocate(FixedArray::SizeFor(PromiseUtils::kPromiseContextLength)); | 36 Allocate(FixedArray::SizeFor(PromiseUtils::kPromiseContextLength)); |
| 23 StoreMapNoWriteBarrier(context, Heap::kFunctionContextMapRootIndex); | 37 StoreMapNoWriteBarrier(context, Heap::kFunctionContextMapRootIndex); |
| 24 StoreObjectFieldNoWriteBarrier( | 38 StoreObjectFieldNoWriteBarrier( |
| 25 context, FixedArray::kLengthOffset, | 39 context, FixedArray::kLengthOffset, |
| 26 SmiConstant(PromiseUtils::kPromiseContextLength)); | 40 SmiConstant(PromiseUtils::kPromiseContextLength)); |
| 27 | 41 |
| 28 Node* const empty_fn = | 42 Node* const empty_fn = |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 174 Node* new_elements = AllocateFixedArray(kind, new_capacity, mode, flags); | 188 Node* new_elements = AllocateFixedArray(kind, new_capacity, mode, flags); |
| 175 | 189 |
| 176 CopyFixedArrayElements(kind, elements, new_elements, length, barrier_mode, | 190 CopyFixedArrayElements(kind, elements, new_elements, length, barrier_mode, |
| 177 mode); | 191 mode); |
| 178 StoreFixedArrayElement(new_elements, length, value, barrier_mode, | 192 StoreFixedArrayElement(new_elements, length, value, barrier_mode, |
| 179 additional_offset, mode); | 193 additional_offset, mode); |
| 180 | 194 |
| 181 StoreObjectField(promise, offset, new_elements); | 195 StoreObjectField(promise, offset, new_elements); |
| 182 } | 196 } |
| 183 | 197 |
| 184 Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context, | 198 Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen( |
| 185 Node* promise, | 199 Node* context, Node* promise, Node* on_resolve, Node* on_reject, |
| 186 Node* on_resolve, | 200 Node* deferred_promise, Node* deferred_on_resolve, |
| 187 Node* on_reject, | 201 Node* deferred_on_reject) { |
| 188 Node* deferred) { | |
| 189 Node* const native_context = LoadNativeContext(context); | 202 Node* const native_context = LoadNativeContext(context); |
| 190 | 203 |
| 191 Variable var_on_resolve(this, MachineRepresentation::kTagged), | 204 Variable var_on_resolve(this, MachineRepresentation::kTagged), |
| 192 var_on_reject(this, MachineRepresentation::kTagged); | 205 var_on_reject(this, MachineRepresentation::kTagged); |
| 193 | 206 |
| 194 var_on_resolve.Bind(on_resolve); | 207 var_on_resolve.Bind(on_resolve); |
| 195 var_on_reject.Bind(on_reject); | 208 var_on_reject.Bind(on_reject); |
| 196 | 209 |
| 197 Label out(this), if_onresolvenotcallable(this), onrejectcheck(this), | 210 Label out(this), if_onresolvenotcallable(this), onrejectcheck(this), |
| 198 append_callbacks(this); | 211 append_callbacks(this); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 226 } | 239 } |
| 227 } | 240 } |
| 228 | 241 |
| 229 Bind(&append_callbacks); | 242 Bind(&append_callbacks); |
| 230 { | 243 { |
| 231 Label fulfilled_check(this); | 244 Label fulfilled_check(this); |
| 232 Node* const status = LoadObjectField(promise, JSPromise::kStatusOffset); | 245 Node* const status = LoadObjectField(promise, JSPromise::kStatusOffset); |
| 233 GotoUnless(SmiEqual(status, SmiConstant(v8::Promise::kPending)), | 246 GotoUnless(SmiEqual(status, SmiConstant(v8::Promise::kPending)), |
| 234 &fulfilled_check); | 247 &fulfilled_check); |
| 235 | 248 |
| 236 Node* const existing_deferred = | 249 Node* const existing_deferred_promise = |
| 237 LoadObjectField(promise, JSPromise::kDeferredOffset); | 250 LoadObjectField(promise, JSPromise::kDeferredPromiseOffset); |
| 238 | 251 |
| 239 Label if_noexistingcallbacks(this), if_existingcallbacks(this); | 252 Label if_noexistingcallbacks(this), if_existingcallbacks(this); |
| 240 Branch(IsUndefined(existing_deferred), &if_noexistingcallbacks, | 253 Branch(IsUndefined(existing_deferred_promise), &if_noexistingcallbacks, |
| 241 &if_existingcallbacks); | 254 &if_existingcallbacks); |
| 242 | 255 |
| 243 Bind(&if_noexistingcallbacks); | 256 Bind(&if_noexistingcallbacks); |
| 244 { | 257 { |
| 245 // Store callbacks directly in the slots. | 258 // Store callbacks directly in the slots. |
| 246 StoreObjectField(promise, JSPromise::kDeferredOffset, deferred); | 259 StoreObjectField(promise, JSPromise::kDeferredPromiseOffset, |
| 260 deferred_promise); | |
| 261 StoreObjectField(promise, JSPromise::kDeferredOnResolveOffset, | |
| 262 deferred_on_resolve); | |
| 263 StoreObjectField(promise, JSPromise::kDeferredOnRejectOffset, | |
| 264 deferred_on_reject); | |
| 247 StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, | 265 StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, |
| 248 var_on_resolve.value()); | 266 var_on_resolve.value()); |
| 249 StoreObjectField(promise, JSPromise::kRejectReactionsOffset, | 267 StoreObjectField(promise, JSPromise::kRejectReactionsOffset, |
| 250 var_on_reject.value()); | 268 var_on_reject.value()); |
| 251 Goto(&out); | 269 Goto(&out); |
| 252 } | 270 } |
| 253 | 271 |
| 254 Bind(&if_existingcallbacks); | 272 Bind(&if_existingcallbacks); |
| 255 { | 273 { |
| 256 Label if_singlecallback(this), if_multiplecallbacks(this); | 274 Label if_singlecallback(this), if_multiplecallbacks(this); |
| 257 BranchIfJSObject(existing_deferred, &if_singlecallback, | 275 BranchIfJSObject(existing_deferred_promise, &if_singlecallback, |
| 258 &if_multiplecallbacks); | 276 &if_multiplecallbacks); |
| 259 | 277 |
| 260 Bind(&if_singlecallback); | 278 Bind(&if_singlecallback); |
| 261 { | 279 { |
| 262 // Create new FixedArrays to store callbacks, and migrate | 280 // Create new FixedArrays to store callbacks, and migrate |
| 263 // existing callbacks. | 281 // existing callbacks. |
| 264 Node* const deferreds = | 282 Node* const deferred_promise_arr = |
| 265 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); | 283 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); |
| 266 StoreFixedArrayElement(deferreds, 0, existing_deferred); | 284 StoreFixedArrayElement(deferred_promise_arr, 0, |
| 267 StoreFixedArrayElement(deferreds, 1, deferred); | 285 existing_deferred_promise); |
| 286 StoreFixedArrayElement(deferred_promise_arr, 1, deferred_promise); | |
|
jgruber
2016/12/21 08:08:28
Maybe refactor this into a NewFixedArrayWithElemen
gsathya
2016/12/21 19:26:28
This is slightly tricky and doesn't conform togeth
| |
| 287 | |
| 288 Node* const deferred_on_resolve_arr = | |
| 289 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); | |
| 290 StoreFixedArrayElement( | |
| 291 deferred_on_resolve_arr, 0, | |
| 292 LoadObjectField(promise, JSPromise::kDeferredOnResolveOffset)); | |
| 293 StoreFixedArrayElement(deferred_on_resolve_arr, 1, deferred_on_resolve); | |
| 294 | |
| 295 Node* const deferred_on_reject_arr = | |
| 296 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); | |
| 297 StoreFixedArrayElement( | |
| 298 deferred_on_reject_arr, 0, | |
| 299 LoadObjectField(promise, JSPromise::kDeferredOnRejectOffset)); | |
| 300 StoreFixedArrayElement(deferred_on_reject_arr, 1, deferred_on_reject); | |
| 268 | 301 |
| 269 Node* const fulfill_reactions = | 302 Node* const fulfill_reactions = |
| 270 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); | 303 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); |
| 271 StoreFixedArrayElement( | 304 StoreFixedArrayElement( |
| 272 fulfill_reactions, 0, | 305 fulfill_reactions, 0, |
| 273 LoadObjectField(promise, JSPromise::kFulfillReactionsOffset)); | 306 LoadObjectField(promise, JSPromise::kFulfillReactionsOffset)); |
| 274 StoreFixedArrayElement(fulfill_reactions, 1, var_on_resolve.value()); | 307 StoreFixedArrayElement(fulfill_reactions, 1, var_on_resolve.value()); |
| 275 | 308 |
| 276 Node* const reject_reactions = | 309 Node* const reject_reactions = |
| 277 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); | 310 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); |
| 278 StoreFixedArrayElement( | 311 StoreFixedArrayElement( |
| 279 reject_reactions, 0, | 312 reject_reactions, 0, |
| 280 LoadObjectField(promise, JSPromise::kRejectReactionsOffset)); | 313 LoadObjectField(promise, JSPromise::kRejectReactionsOffset)); |
| 281 StoreFixedArrayElement(reject_reactions, 1, var_on_reject.value()); | 314 StoreFixedArrayElement(reject_reactions, 1, var_on_reject.value()); |
| 282 | 315 |
| 283 // Store new FixedArrays in promise. | 316 // Store new FixedArrays in promise. |
| 284 StoreObjectField(promise, JSPromise::kDeferredOffset, deferreds); | 317 StoreObjectField(promise, JSPromise::kDeferredPromiseOffset, |
| 318 deferred_promise_arr); | |
| 319 StoreObjectField(promise, JSPromise::kDeferredOnResolveOffset, | |
| 320 deferred_on_resolve_arr); | |
| 321 StoreObjectField(promise, JSPromise::kDeferredOnRejectOffset, | |
| 322 deferred_on_reject_arr); | |
| 285 StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, | 323 StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, |
| 286 fulfill_reactions); | 324 fulfill_reactions); |
| 287 StoreObjectField(promise, JSPromise::kRejectReactionsOffset, | 325 StoreObjectField(promise, JSPromise::kRejectReactionsOffset, |
| 288 reject_reactions); | 326 reject_reactions); |
| 289 Goto(&out); | 327 Goto(&out); |
| 290 } | 328 } |
| 291 | 329 |
| 292 Bind(&if_multiplecallbacks); | 330 Bind(&if_multiplecallbacks); |
| 293 { | 331 { |
| 294 AppendPromiseCallback(JSPromise::kDeferredOffset, promise, deferred); | 332 AppendPromiseCallback(JSPromise::kDeferredPromiseOffset, promise, |
| 333 deferred_promise); | |
| 334 AppendPromiseCallback(JSPromise::kDeferredOnResolveOffset, promise, | |
| 335 deferred_on_resolve); | |
| 336 AppendPromiseCallback(JSPromise::kDeferredOnRejectOffset, promise, | |
| 337 deferred_on_reject); | |
| 295 AppendPromiseCallback(JSPromise::kFulfillReactionsOffset, promise, | 338 AppendPromiseCallback(JSPromise::kFulfillReactionsOffset, promise, |
| 296 var_on_resolve.value()); | 339 var_on_resolve.value()); |
| 297 AppendPromiseCallback(JSPromise::kRejectReactionsOffset, promise, | 340 AppendPromiseCallback(JSPromise::kRejectReactionsOffset, promise, |
| 298 var_on_reject.value()); | 341 var_on_reject.value()); |
| 299 Goto(&out); | 342 Goto(&out); |
| 300 } | 343 } |
| 301 } | 344 } |
| 302 | 345 |
| 303 Bind(&fulfilled_check); | 346 Bind(&fulfilled_check); |
| 304 { | 347 { |
| 305 Label reject(this); | 348 Label reject(this); |
| 306 Node* const result = LoadObjectField(promise, JSPromise::kResultOffset); | 349 Node* const result = LoadObjectField(promise, JSPromise::kResultOffset); |
| 307 GotoUnless(WordEqual(status, SmiConstant(v8::Promise::kFulfilled)), | 350 GotoUnless(WordEqual(status, SmiConstant(v8::Promise::kFulfilled)), |
| 308 &reject); | 351 &reject); |
| 309 | 352 |
| 310 // TODO(gsathya): Move this to TF. | 353 Node* info = AllocatePromiseReactionJobInfo( |
| 311 CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, promise, result, | 354 promise, result, var_on_resolve.value(), deferred_promise, |
| 312 var_on_resolve.value(), deferred, | 355 deferred_on_resolve, deferred_on_reject, context); |
| 356 CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info, | |
|
jgruber
2016/12/21 08:08:28
It'd be awesome to move this to CSA as well at som
gsathya
2016/12/21 19:26:28
Done.
| |
| 313 SmiConstant(v8::Promise::kFulfilled)); | 357 SmiConstant(v8::Promise::kFulfilled)); |
| 314 Goto(&out); | 358 Goto(&out); |
| 315 | 359 |
| 316 Bind(&reject); | 360 Bind(&reject); |
| 317 { | 361 { |
| 318 Node* const has_handler = PromiseHasHandler(promise); | 362 Node* const has_handler = PromiseHasHandler(promise); |
| 319 Label enqueue(this); | 363 Label enqueue(this); |
| 320 | 364 |
| 321 // TODO(gsathya): Fold these runtime calls and move to TF. | 365 // TODO(gsathya): Fold these runtime calls and move to TF. |
| 322 GotoIf(has_handler, &enqueue); | 366 GotoIf(has_handler, &enqueue); |
| 323 CallRuntime(Runtime::kPromiseRevokeReject, context, promise); | 367 CallRuntime(Runtime::kPromiseRevokeReject, context, promise); |
| 324 Goto(&enqueue); | 368 Goto(&enqueue); |
| 325 | 369 |
| 326 Bind(&enqueue); | 370 Bind(&enqueue); |
| 327 { | 371 { |
| 328 CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, promise, | 372 Node* info = AllocatePromiseReactionJobInfo( |
| 329 result, var_on_reject.value(), deferred, | 373 promise, result, var_on_reject.value(), deferred_promise, |
| 374 deferred_on_resolve, deferred_on_reject, context); | |
| 375 CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info, | |
| 330 SmiConstant(v8::Promise::kRejected)); | 376 SmiConstant(v8::Promise::kRejected)); |
| 331 | |
| 332 Goto(&out); | 377 Goto(&out); |
| 333 } | 378 } |
| 334 } | 379 } |
| 335 } | 380 } |
| 336 } | 381 } |
| 337 | 382 |
| 338 Bind(&out); | 383 Bind(&out); |
| 339 PromiseSetHasHandler(promise); | 384 PromiseSetHasHandler(promise); |
|
jgruber
2016/12/21 08:08:28
By the way, we could make PromiseSetHasHandler che
jgruber
2016/12/21 08:45:07
CL for that here: https://codereview.chromium.org/
gsathya
2016/12/21 19:26:28
Thanks!
| |
| 340 | 385 return deferred_promise; |
| 341 // TODO(gsathya): This call will be removed once we don't have to | |
| 342 // deal with deferred objects. | |
| 343 Isolate* isolate = this->isolate(); | |
| 344 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | |
| 345 Node* const key = | |
| 346 HeapConstant(isolate->factory()->NewStringFromAsciiChecked("promise")); | |
| 347 Node* const result = CallStub(getproperty_callable, context, deferred, key); | |
| 348 | |
| 349 return result; | |
| 350 } | 386 } |
| 351 | 387 |
| 352 // Promise fast path implementations rely on unmodified JSPromise instances. | 388 // Promise fast path implementations rely on unmodified JSPromise instances. |
| 353 // We use a fairly coarse granularity for this and simply check whether both | 389 // We use a fairly coarse granularity for this and simply check whether both |
| 354 // the promise itself is unmodified (i.e. its map has not changed) and its | 390 // the promise itself is unmodified (i.e. its map has not changed) and its |
| 355 // prototype is unmodified. | 391 // prototype is unmodified. |
| 356 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp | 392 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp |
| 357 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise, | 393 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise, |
| 358 Label* if_isunmodified, | 394 Label* if_isunmodified, |
| 359 Label* if_ismodified) { | 395 Label* if_ismodified) { |
| (...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 699 Node* const message_id = | 735 Node* const message_id = |
| 700 SmiConstant(MessageTemplate::kResolverNotAFunction); | 736 SmiConstant(MessageTemplate::kResolverNotAFunction); |
| 701 CallRuntime(Runtime::kThrowTypeError, context, message_id, executor); | 737 CallRuntime(Runtime::kThrowTypeError, context, message_id, executor); |
| 702 Return(UndefinedConstant()); // Never reached. | 738 Return(UndefinedConstant()); // Never reached. |
| 703 } | 739 } |
| 704 } | 740 } |
| 705 | 741 |
| 706 TF_BUILTIN(PromiseInternalConstructor, PromiseBuiltinsAssembler) { | 742 TF_BUILTIN(PromiseInternalConstructor, PromiseBuiltinsAssembler) { |
| 707 Node* const parent = Parameter(1); | 743 Node* const parent = Parameter(1); |
| 708 Node* const context = Parameter(4); | 744 Node* const context = Parameter(4); |
| 709 Node* const instance = AllocateJSPromise(context); | 745 Return(AllocateAndInitPromise(context, parent)); |
| 710 PromiseInit(instance); | |
| 711 | |
| 712 Label out(this); | |
| 713 GotoUnless(IsPromiseHookEnabled(), &out); | |
| 714 CallRuntime(Runtime::kPromiseHookInit, context, instance, parent); | |
| 715 Goto(&out); | |
| 716 Bind(&out); | |
| 717 | |
| 718 Return(instance); | |
| 719 } | 746 } |
| 720 | 747 |
| 721 TF_BUILTIN(PromiseCreateAndSet, PromiseBuiltinsAssembler) { | 748 TF_BUILTIN(PromiseCreateAndSet, PromiseBuiltinsAssembler) { |
| 722 Node* const status = Parameter(1); | 749 Node* const status = Parameter(1); |
| 723 Node* const result = Parameter(2); | 750 Node* const result = Parameter(2); |
| 724 Node* const context = Parameter(5); | 751 Node* const context = Parameter(5); |
| 725 | 752 |
| 726 Node* const instance = AllocateJSPromise(context); | 753 Node* const instance = AllocateJSPromise(context); |
| 727 PromiseSet(instance, status, result); | 754 PromiseSet(instance, status, result); |
| 728 | 755 |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 746 Return(result); | 773 Return(result); |
| 747 | 774 |
| 748 Bind(&if_notpromise); | 775 Bind(&if_notpromise); |
| 749 Return(FalseConstant()); | 776 Return(FalseConstant()); |
| 750 } | 777 } |
| 751 | 778 |
| 752 TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) { | 779 TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) { |
| 753 Node* const promise = Parameter(1); | 780 Node* const promise = Parameter(1); |
| 754 Node* const on_resolve = Parameter(2); | 781 Node* const on_resolve = Parameter(2); |
| 755 Node* const on_reject = Parameter(3); | 782 Node* const on_reject = Parameter(3); |
| 756 Node* const deferred = Parameter(4); | 783 Node* const deferred_promise = Parameter(4); |
| 757 Node* const context = Parameter(7); | 784 Node* const context = Parameter(7); |
| 758 | 785 |
| 759 Node* const result = InternalPerformPromiseThen(context, promise, on_resolve, | 786 // No deferred_on_resolve/deferred_on_reject because this is just an |
| 760 on_reject, deferred); | 787 // internal promise created by async-await. |
| 788 Node* const result = InternalPerformPromiseThen( | |
| 789 context, promise, on_resolve, on_reject, deferred_promise, | |
| 790 UndefinedConstant(), UndefinedConstant()); | |
| 761 | 791 |
| 762 // TODO(gsathya): This is unused, but value is returned according to spec. | 792 // TODO(gsathya): This is unused, but value is returned according to spec. |
| 763 Return(result); | 793 Return(result); |
| 764 } | 794 } |
| 765 | 795 |
| 766 TF_BUILTIN(PromiseThen, PromiseBuiltinsAssembler) { | 796 TF_BUILTIN(PromiseThen, PromiseBuiltinsAssembler) { |
| 767 // 1. Let promise be the this value. | 797 // 1. Let promise be the this value. |
| 768 Node* const promise = Parameter(0); | 798 Node* const promise = Parameter(0); |
| 769 Node* const on_resolve = Parameter(1); | 799 Node* const on_resolve = Parameter(1); |
| 770 Node* const on_reject = Parameter(2); | 800 Node* const on_reject = Parameter(2); |
| 771 Node* const context = Parameter(5); | 801 Node* const context = Parameter(5); |
| 772 Isolate* isolate = this->isolate(); | 802 Isolate* isolate = this->isolate(); |
| 773 | 803 |
| 774 // 2. If IsPromise(promise) is false, throw a TypeError exception. | 804 // 2. If IsPromise(promise) is false, throw a TypeError exception. |
| 775 ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE, | 805 ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE, |
| 776 "Promise.prototype.then"); | 806 "Promise.prototype.then"); |
| 777 | 807 |
| 778 Node* const native_context = LoadNativeContext(context); | 808 Node* const native_context = LoadNativeContext(context); |
| 779 Node* const promise_fun = | 809 Node* const promise_fun = |
| 780 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); | 810 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
| 781 | 811 |
| 782 // 3. Let C be ? SpeciesConstructor(promise, %Promise%). | 812 // 3. Let C be ? SpeciesConstructor(promise, %Promise%). |
| 783 Node* constructor = SpeciesConstructor(context, promise, promise_fun); | 813 Node* constructor = SpeciesConstructor(context, promise, promise_fun); |
| 784 | 814 |
| 785 // 4. Let resultCapability be ? NewPromiseCapability(C). | 815 // 4. Let resultCapability be ? NewPromiseCapability(C). |
| 786 Callable call_callable = CodeFactory::Call(isolate); | 816 Callable call_callable = CodeFactory::Call(isolate); |
| 787 Label fast_promise_capability(this), promise_capability(this), | 817 Label fast_promise_capability(this), promise_capability(this), |
| 788 perform_promise_then(this); | 818 perform_promise_then(this); |
| 789 Variable var_deferred(this, MachineRepresentation::kTagged); | 819 Variable var_deferred_promise(this, MachineRepresentation::kTagged), |
| 820 var_deferred_on_resolve(this, MachineRepresentation::kTagged), | |
| 821 var_deferred_on_reject(this, MachineRepresentation::kTagged); | |
| 790 | 822 |
| 791 Branch(WordEqual(promise_fun, constructor), &fast_promise_capability, | 823 Branch(WordEqual(promise_fun, constructor), &fast_promise_capability, |
| 792 &promise_capability); | 824 &promise_capability); |
| 793 | 825 |
| 794 // TODO(gsathya): Remove deferred object and move | |
| 795 // NewPromiseCapabability functions to TF. | |
| 796 Bind(&fast_promise_capability); | 826 Bind(&fast_promise_capability); |
| 797 { | 827 { |
| 798 // TODO(gsathya): Move this to TF. | 828 Node* const deferred_promise = AllocateAndInitPromise(context, promise); |
| 799 Node* const promise_internal_capability = LoadContextElement( | 829 PromiseInit(deferred_promise); |
| 800 native_context, Context::INTERNAL_PROMISE_CAPABILITY_INDEX); | 830 var_deferred_promise.Bind(deferred_promise); |
| 801 Node* const capability = | 831 var_deferred_on_resolve.Bind(UndefinedConstant()); |
| 802 CallJS(call_callable, context, promise_internal_capability, | 832 var_deferred_on_reject.Bind(UndefinedConstant()); |
| 803 UndefinedConstant(), promise); | |
| 804 var_deferred.Bind(capability); | |
| 805 Goto(&perform_promise_then); | 833 Goto(&perform_promise_then); |
| 806 } | 834 } |
| 807 | 835 |
| 808 Bind(&promise_capability); | 836 Bind(&promise_capability); |
| 809 { | 837 { |
| 810 // TODO(gsathya): Move this to TF. | 838 // TODO(gsathya): Move this to TF. |
| 811 Node* const new_promise_capability = LoadContextElement( | 839 Node* const new_promise_capability = LoadContextElement( |
| 812 native_context, Context::NEW_PROMISE_CAPABILITY_INDEX); | 840 native_context, Context::NEW_PROMISE_CAPABILITY_INDEX); |
| 813 Node* const capability = | 841 Node* const deferred = |
| 814 CallJS(call_callable, context, new_promise_capability, | 842 CallJS(call_callable, context, new_promise_capability, |
| 815 UndefinedConstant(), constructor); | 843 UndefinedConstant(), constructor); |
| 816 var_deferred.Bind(capability); | 844 Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
| 845 Node* key = HeapConstant(isolate->factory()->promise_string()); | |
| 846 Node* const deferred_promise = | |
| 847 CallStub(getproperty_callable, context, deferred, key); | |
| 848 var_deferred_promise.Bind(deferred_promise); | |
| 849 | |
| 850 key = HeapConstant(isolate->factory()->resolve_string()); | |
| 851 Node* const deferred_on_resolve = | |
| 852 CallStub(getproperty_callable, context, deferred, key); | |
| 853 var_deferred_on_resolve.Bind(deferred_on_resolve); | |
| 854 | |
| 855 key = HeapConstant(isolate->factory()->reject_string()); | |
| 856 Node* const deferred_on_reject = | |
| 857 CallStub(getproperty_callable, context, deferred, key); | |
| 858 var_deferred_on_reject.Bind(deferred_on_reject); | |
| 859 | |
| 817 Goto(&perform_promise_then); | 860 Goto(&perform_promise_then); |
| 818 } | 861 } |
| 819 | 862 |
| 820 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, | 863 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, |
| 821 // resultCapability). | 864 // resultCapability). |
| 822 Bind(&perform_promise_then); | 865 Bind(&perform_promise_then); |
| 823 Node* const result = InternalPerformPromiseThen( | 866 Node* const result = InternalPerformPromiseThen( |
| 824 context, promise, on_resolve, on_reject, var_deferred.value()); | 867 context, promise, on_resolve, on_reject, var_deferred_promise.value(), |
| 868 var_deferred_on_resolve.value(), var_deferred_on_reject.value()); | |
| 825 Return(result); | 869 Return(result); |
| 826 } | 870 } |
| 827 | 871 |
| 828 // ES#sec-promise-resolve-functions | 872 // ES#sec-promise-resolve-functions |
| 829 // Promise Resolve Functions | 873 // Promise Resolve Functions |
| 830 TF_BUILTIN(PromiseResolveClosure, PromiseBuiltinsAssembler) { | 874 TF_BUILTIN(PromiseResolveClosure, PromiseBuiltinsAssembler) { |
| 831 Node* const value = Parameter(1); | 875 Node* const value = Parameter(1); |
| 832 Node* const context = Parameter(4); | 876 Node* const context = Parameter(4); |
| 833 | 877 |
| 834 Label out(this); | 878 Label out(this); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 893 { | 937 { |
| 894 CallJS(call_callable, context, on_reject, UndefinedConstant(), exception); | 938 CallJS(call_callable, context, on_reject, UndefinedConstant(), exception); |
| 895 Return(UndefinedConstant()); | 939 Return(UndefinedConstant()); |
| 896 } | 940 } |
| 897 } | 941 } |
| 898 | 942 |
| 899 TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) { | 943 TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) { |
| 900 Node* const promise = Parameter(1); | 944 Node* const promise = Parameter(1); |
| 901 Node* const value = Parameter(2); | 945 Node* const value = Parameter(2); |
| 902 Node* const handler = Parameter(3); | 946 Node* const handler = Parameter(3); |
| 903 Node* const deferred = Parameter(4); | 947 Node* const deferred_promise = Parameter(4); |
| 904 Node* const context = Parameter(7); | 948 Node* const deferred_on_resolve = Parameter(5); |
| 949 Node* const deferred_on_reject = Parameter(6); | |
| 950 Node* const context = Parameter(9); | |
| 905 Isolate* isolate = this->isolate(); | 951 Isolate* isolate = this->isolate(); |
| 906 | 952 |
| 907 // Get promise from deferred | 953 // Get promise from deferred |
|
jgruber
2016/12/21 08:08:28
Leftover comment?
gsathya
2016/12/21 19:26:28
Done.
| |
| 908 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. | |
| 909 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | |
| 910 Node* const key = HeapConstant(isolate->factory()->promise_string()); | |
| 911 Node* const deferred_promise = | |
| 912 CallStub(getproperty_callable, context, deferred, key); | |
| 913 | |
| 914 Variable var_reason(this, MachineRepresentation::kTagged); | 954 Variable var_reason(this, MachineRepresentation::kTagged); |
| 915 | 955 |
| 916 Node* const is_debug_active = IsDebugActive(); | 956 Node* const is_debug_active = IsDebugActive(); |
| 917 Label run_handler(this), if_rejectpromise(this), promisehook_before(this), | 957 Label run_handler(this), if_rejectpromise(this), promisehook_before(this), |
| 918 promisehook_after(this), debug_pop(this); | 958 promisehook_after(this), debug_pop(this); |
| 919 | 959 |
| 920 GotoUnless(is_debug_active, &promisehook_before); | 960 GotoUnless(is_debug_active, &promisehook_before); |
| 921 CallRuntime(Runtime::kDebugPushPromise, context, deferred_promise); | 961 CallRuntime(Runtime::kDebugPushPromise, context, deferred_promise); |
| 922 Goto(&promisehook_before); | 962 Goto(&promisehook_before); |
| 923 | 963 |
| 924 Bind(&promisehook_before); | 964 Bind(&promisehook_before); |
| 925 { | 965 { |
| 926 GotoUnless(IsPromiseHookEnabled(), &run_handler); | 966 GotoUnless(IsPromiseHookEnabled(), &run_handler); |
| 927 CallRuntime(Runtime::kPromiseHookBefore, context, promise); | 967 CallRuntime(Runtime::kPromiseHookBefore, context, promise); |
| 928 Goto(&run_handler); | 968 Goto(&run_handler); |
| 929 } | 969 } |
| 930 | 970 |
| 931 Bind(&run_handler); | 971 Bind(&run_handler); |
| 932 { | 972 { |
| 933 Callable call_callable = CodeFactory::Call(isolate); | 973 Callable call_callable = CodeFactory::Call(isolate); |
| 934 | |
| 935 Node* const result = | 974 Node* const result = |
| 936 CallJS(call_callable, context, handler, UndefinedConstant(), value); | 975 CallJS(call_callable, context, handler, UndefinedConstant(), value); |
| 937 | 976 |
| 938 GotoIfException(result, &if_rejectpromise, &var_reason); | 977 GotoIfException(result, &if_rejectpromise, &var_reason); |
| 939 | 978 |
| 940 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. | |
| 941 Node* const key = HeapConstant(isolate->factory()->resolve_string()); | |
| 942 Node* const on_resolve = | |
| 943 CallStub(getproperty_callable, context, deferred, key); | |
| 944 | |
| 945 Label if_internalhandler(this), if_customhandler(this, Label::kDeferred); | 979 Label if_internalhandler(this), if_customhandler(this, Label::kDeferred); |
| 946 Branch(IsUndefined(on_resolve), &if_internalhandler, &if_customhandler); | 980 Branch(IsUndefined(deferred_on_resolve), &if_internalhandler, |
| 981 &if_customhandler); | |
| 947 | 982 |
| 948 Bind(&if_internalhandler); | 983 Bind(&if_internalhandler); |
| 949 InternalResolvePromise(context, deferred_promise, result, | 984 InternalResolvePromise(context, deferred_promise, result, |
| 950 &promisehook_after); | 985 &promisehook_after); |
| 951 | 986 |
| 952 Bind(&if_customhandler); | 987 Bind(&if_customhandler); |
| 953 { | 988 { |
| 954 Node* const maybe_exception = CallJS(call_callable, context, on_resolve, | 989 Node* const maybe_exception = |
| 955 UndefinedConstant(), result); | 990 CallJS(call_callable, context, deferred_on_resolve, |
| 991 UndefinedConstant(), result); | |
| 956 GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); | 992 GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); |
| 957 Goto(&promisehook_after); | 993 Goto(&promisehook_after); |
| 958 } | 994 } |
| 959 } | 995 } |
| 960 | 996 |
| 961 Bind(&if_rejectpromise); | 997 Bind(&if_rejectpromise); |
| 962 { | 998 { |
| 963 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. | |
| 964 Node* const key = HeapConstant(isolate->factory()->reject_string()); | |
| 965 Node* const on_reject = | |
| 966 CallStub(getproperty_callable, context, deferred, key); | |
| 967 | |
| 968 Callable promise_handle_reject = CodeFactory::PromiseHandleReject(isolate); | 999 Callable promise_handle_reject = CodeFactory::PromiseHandleReject(isolate); |
| 969 CallStub(promise_handle_reject, context, deferred_promise, on_reject, | 1000 CallStub(promise_handle_reject, context, deferred_promise, |
| 970 var_reason.value()); | 1001 deferred_on_reject, var_reason.value()); |
| 971 Goto(&promisehook_after); | 1002 Goto(&promisehook_after); |
| 972 } | 1003 } |
| 973 | 1004 |
| 974 Bind(&promisehook_after); | 1005 Bind(&promisehook_after); |
| 975 { | 1006 { |
| 976 GotoUnless(IsPromiseHookEnabled(), &debug_pop); | 1007 GotoUnless(IsPromiseHookEnabled(), &debug_pop); |
| 977 CallRuntime(Runtime::kPromiseHookAfter, context, promise); | 1008 CallRuntime(Runtime::kPromiseHookAfter, context, promise); |
| 978 Goto(&debug_pop); | 1009 Goto(&debug_pop); |
| 979 } | 1010 } |
| 980 | 1011 |
| 981 Bind(&debug_pop); | 1012 Bind(&debug_pop); |
| 982 { | 1013 { |
| 983 Label out(this); | 1014 Label out(this); |
| 984 | 1015 |
| 985 GotoUnless(is_debug_active, &out); | 1016 GotoUnless(is_debug_active, &out); |
| 986 CallRuntime(Runtime::kDebugPopPromise, context); | 1017 CallRuntime(Runtime::kDebugPopPromise, context); |
| 987 Goto(&out); | 1018 Goto(&out); |
| 988 | 1019 |
| 989 Bind(&out); | 1020 Bind(&out); |
| 990 Return(UndefinedConstant()); | 1021 Return(UndefinedConstant()); |
| 991 } | 1022 } |
| 992 } | 1023 } |
| 993 | 1024 |
| 994 } // namespace internal | 1025 } // namespace internal |
| 995 } // namespace v8 | 1026 } // namespace v8 |
| OLD | NEW |