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-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 | 7 |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/promise-utils.h" | 9 #include "src/promise-utils.h" |
10 | 10 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 &resolve, &reject); | 74 &resolve, &reject); |
75 | 75 |
76 Handle<FixedArray> result = isolate->factory()->NewFixedArray(2); | 76 Handle<FixedArray> result = isolate->factory()->NewFixedArray(2); |
77 result->set(0, *resolve); | 77 result->set(0, *resolve); |
78 result->set(1, *reject); | 78 result->set(1, *reject); |
79 | 79 |
80 return *isolate->factory()->NewJSArrayWithElements(result, FAST_ELEMENTS, 2, | 80 return *isolate->factory()->NewJSArrayWithElements(result, FAST_ELEMENTS, 2, |
81 NOT_TENURED); | 81 NOT_TENURED); |
82 } | 82 } |
83 | 83 |
| 84 void PromiseInit(CodeStubAssembler* a, compiler::Node* promise, |
| 85 compiler::Node* status, compiler::Node* result) { |
| 86 CSA_ASSERT(a, a->TaggedIsSmi(status)); |
| 87 a->StoreObjectField(promise, JSPromise::kStatusOffset, status); |
| 88 a->StoreObjectField(promise, JSPromise::kResultOffset, result); |
| 89 } |
| 90 |
84 void Builtins::Generate_PromiseConstructor( | 91 void Builtins::Generate_PromiseConstructor( |
85 compiler::CodeAssemblerState* state) { | 92 compiler::CodeAssemblerState* state) { |
86 CodeStubAssembler a(state); | 93 CodeStubAssembler a(state); |
87 typedef CodeStubAssembler::Variable Variable; | 94 typedef CodeStubAssembler::Variable Variable; |
88 typedef CodeStubAssembler::Label Label; | 95 typedef CodeStubAssembler::Label Label; |
89 typedef compiler::Node Node; | 96 typedef compiler::Node Node; |
90 | 97 |
91 Node* const executor = a.Parameter(1); | 98 Node* const executor = a.Parameter(1); |
92 Node* const new_target = a.Parameter(2); | 99 Node* const new_target = a.Parameter(2); |
93 Node* const context = a.Parameter(4); | 100 Node* const context = a.Parameter(4); |
94 Isolate* isolate = a.isolate(); | 101 Isolate* isolate = a.isolate(); |
95 | 102 |
96 Label if_targetisundefined(&a, Label::kDeferred); | 103 Label if_targetisundefined(&a, Label::kDeferred); |
97 | 104 |
98 a.GotoIf(a.IsUndefined(new_target), &if_targetisundefined); | 105 a.GotoIf(a.IsUndefined(new_target), &if_targetisundefined); |
99 | 106 |
100 Label if_notcallable(&a, Label::kDeferred); | 107 Label if_notcallable(&a, Label::kDeferred); |
101 | 108 |
102 a.GotoIf(a.TaggedIsSmi(executor), &if_notcallable); | 109 a.GotoIf(a.TaggedIsSmi(executor), &if_notcallable); |
103 | 110 |
104 Node* const executor_map = a.LoadMap(executor); | 111 Node* const executor_map = a.LoadMap(executor); |
105 a.GotoUnless(a.IsCallableMap(executor_map), &if_notcallable); | 112 a.GotoUnless(a.IsCallableMap(executor_map), &if_notcallable); |
106 | 113 |
107 Node* const native_context = a.LoadNativeContext(context); | 114 Node* const native_context = a.LoadNativeContext(context); |
108 Node* const promise_fun = | 115 Node* const promise_fun = |
109 a.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); | 116 a.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
110 Node* const is_debug_active = a.IsDebugActive(); | 117 Node* const is_debug_active = a.IsDebugActive(); |
| 118 Label if_targetisnotmodified(&a), if_targetismodified(&a, Label::kDeferred), |
| 119 run_executor(&a), debug_push(&a, Label::kDeferred), init(&a); |
111 | 120 |
112 Label if_targetisnotmodified(&a), if_targetismodified(&a, Label::kDeferred), | |
113 run_executor(&a), debug_push(&a, Label::kDeferred); | |
114 a.Branch(a.WordEqual(promise_fun, new_target), &if_targetisnotmodified, | 121 a.Branch(a.WordEqual(promise_fun, new_target), &if_targetisnotmodified, |
115 &if_targetismodified); | 122 &if_targetismodified); |
116 | 123 |
117 Variable var_result(&a, MachineRepresentation::kTagged), | 124 Variable var_result(&a, MachineRepresentation::kTagged), |
118 var_reject_call(&a, MachineRepresentation::kTagged), | 125 var_reject_call(&a, MachineRepresentation::kTagged), |
119 var_reason(&a, MachineRepresentation::kTagged); | 126 var_reason(&a, MachineRepresentation::kTagged); |
120 | 127 |
121 a.Bind(&if_targetisnotmodified); | 128 a.Bind(&if_targetisnotmodified); |
122 { | 129 { |
123 Node* const initial_map = a.LoadObjectField( | 130 Node* const initial_map = a.LoadObjectField( |
124 promise_fun, JSFunction::kPrototypeOrInitialMapOffset); | 131 promise_fun, JSFunction::kPrototypeOrInitialMapOffset); |
125 | 132 |
126 Node* const instance = a.AllocateJSObjectFromMap(initial_map); | 133 Node* const instance = a.AllocateJSObjectFromMap(initial_map); |
127 var_result.Bind(instance); | 134 var_result.Bind(instance); |
128 a.Branch(is_debug_active, &debug_push, &run_executor); | 135 a.Goto(&init); |
129 } | 136 } |
130 | 137 |
131 a.Bind(&if_targetismodified); | 138 a.Bind(&if_targetismodified); |
132 { | 139 { |
133 Callable fast_new_object_stub = CodeFactory::FastNewObject(isolate); | 140 Callable fast_new_object_stub = CodeFactory::FastNewObject(isolate); |
134 Node* const instance = | 141 Node* const instance = |
135 a.CallStub(fast_new_object_stub, context, promise_fun, new_target); | 142 a.CallStub(fast_new_object_stub, context, promise_fun, new_target); |
136 | 143 |
137 var_result.Bind(instance); | 144 var_result.Bind(instance); |
| 145 a.Goto(&init); |
| 146 } |
| 147 |
| 148 a.Bind(&init); |
| 149 { |
| 150 PromiseInit(&a, var_result.value(), a.SmiConstant(kPromisePending), |
| 151 a.UndefinedConstant()); |
138 a.Branch(is_debug_active, &debug_push, &run_executor); | 152 a.Branch(is_debug_active, &debug_push, &run_executor); |
139 } | 153 } |
140 | 154 |
141 a.Bind(&debug_push); | 155 a.Bind(&debug_push); |
142 { | 156 { |
143 a.CallRuntime(Runtime::kDebugPushPromise, context, var_result.value()); | 157 a.CallRuntime(Runtime::kDebugPushPromise, context, var_result.value()); |
144 a.Goto(&run_executor); | 158 a.Goto(&run_executor); |
145 } | 159 } |
146 | 160 |
147 a.Bind(&run_executor); | 161 a.Bind(&run_executor); |
148 { | 162 { |
149 Label out(&a), if_rejectpromise(&a), debug_pop(&a, Label::kDeferred); | 163 Label out(&a), if_rejectpromise(&a), debug_pop(&a, Label::kDeferred); |
150 | 164 |
151 Node* const key = a.LoadRoot(Heap::kpromise_state_symbolRootIndex); | 165 // TODO(gsathya): Move this to TF. |
152 Node* const value = a.SmiConstant(kPromisePending); | |
153 Node* const language_mode = a.SmiConstant(STRICT); | |
154 // TODO(ishell): Use SetProperty stub once available. | |
155 a.CallRuntime(Runtime::kSetProperty, context, var_result.value(), key, | |
156 value, language_mode); | |
157 Node* const resolving_functions = a.CallRuntime( | 166 Node* const resolving_functions = a.CallRuntime( |
158 Runtime::kCreateResolvingFunctions, context, var_result.value()); | 167 Runtime::kCreateResolvingFunctions, context, var_result.value()); |
159 Node* const resolve = | 168 Node* const resolve = |
160 a.LoadFixedArrayElement(resolving_functions, a.IntPtrConstant(0)); | 169 a.LoadFixedArrayElement(resolving_functions, a.IntPtrConstant(0)); |
161 Node* const reject = | 170 Node* const reject = |
162 a.LoadFixedArrayElement(resolving_functions, a.IntPtrConstant(1)); | 171 a.LoadFixedArrayElement(resolving_functions, a.IntPtrConstant(1)); |
163 Callable call_callable = CodeFactory::Call(isolate); | 172 Callable call_callable = CodeFactory::Call(isolate); |
164 | 173 |
165 Node* const maybe_exception = | 174 Node* const maybe_exception = |
166 a.CallJS(call_callable, context, executor, a.UndefinedConstant(), | 175 a.CallJS(call_callable, context, executor, a.UndefinedConstant(), |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 typedef compiler::Node Node; | 218 typedef compiler::Node Node; |
210 CodeStubAssembler a(state); | 219 CodeStubAssembler a(state); |
211 | 220 |
212 Node* const context = a.Parameter(3); | 221 Node* const context = a.Parameter(3); |
213 Node* const native_context = a.LoadNativeContext(context); | 222 Node* const native_context = a.LoadNativeContext(context); |
214 Node* const promise_fun = | 223 Node* const promise_fun = |
215 a.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); | 224 a.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
216 Node* const initial_map = | 225 Node* const initial_map = |
217 a.LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); | 226 a.LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); |
218 Node* const instance = a.AllocateJSObjectFromMap(initial_map); | 227 Node* const instance = a.AllocateJSObjectFromMap(initial_map); |
| 228 |
| 229 PromiseInit(&a, instance, a.SmiConstant(kPromisePending), |
| 230 a.UndefinedConstant()); |
219 a.Return(instance); | 231 a.Return(instance); |
220 } | 232 } |
221 | 233 |
| 234 void Builtins::Generate_PromiseCreateAndSet( |
| 235 compiler::CodeAssemblerState* state) { |
| 236 typedef compiler::Node Node; |
| 237 CodeStubAssembler a(state); |
| 238 |
| 239 Node* const status = a.Parameter(1); |
| 240 Node* const result = a.Parameter(2); |
| 241 Node* const context = a.Parameter(5); |
| 242 Node* const native_context = a.LoadNativeContext(context); |
| 243 |
| 244 Node* const promise_fun = |
| 245 a.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
| 246 Node* const initial_map = |
| 247 a.LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); |
| 248 Node* const instance = a.AllocateJSObjectFromMap(initial_map); |
| 249 |
| 250 PromiseInit(&a, instance, status, result); |
| 251 a.Return(instance); |
| 252 } |
| 253 |
| 254 namespace { |
| 255 |
| 256 compiler::Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, |
| 257 compiler::Node* context, |
| 258 compiler::Node* value, |
| 259 MessageTemplate::Template msg_template) { |
| 260 typedef compiler::Node Node; |
| 261 typedef CodeStubAssembler::Label Label; |
| 262 typedef CodeStubAssembler::Variable Variable; |
| 263 |
| 264 Label out(a), throw_exception(a, Label::kDeferred); |
| 265 Variable var_value_map(a, MachineRepresentation::kTagged); |
| 266 |
| 267 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); |
| 268 |
| 269 // Load the instance type of the {value}. |
| 270 var_value_map.Bind(a->LoadMap(value)); |
| 271 Node* const value_instance_type = |
| 272 a->LoadMapInstanceType(var_value_map.value()); |
| 273 |
| 274 a->Branch(a->IsJSReceiverInstanceType(value_instance_type), &out, |
| 275 &throw_exception); |
| 276 |
| 277 // The {value} is not a compatible receiver for this method. |
| 278 a->Bind(&throw_exception); |
| 279 { |
| 280 Node* const message_id = a->SmiConstant(msg_template); |
| 281 a->CallRuntime(Runtime::kThrowTypeError, context, message_id); |
| 282 var_value_map.Bind(a->UndefinedConstant()); |
| 283 a->Goto(&out); // Never reached. |
| 284 } |
| 285 |
| 286 a->Bind(&out); |
| 287 return var_value_map.value(); |
| 288 } |
| 289 } // namespace |
| 290 |
222 void Builtins::Generate_IsPromise(compiler::CodeAssemblerState* state) { | 291 void Builtins::Generate_IsPromise(compiler::CodeAssemblerState* state) { |
223 CodeStubAssembler a(state); | 292 CodeStubAssembler a(state); |
224 typedef compiler::Node Node; | 293 typedef compiler::Node Node; |
225 typedef CodeStubAssembler::Label Label; | 294 typedef CodeStubAssembler::Label Label; |
226 | 295 |
227 Node* const maybe_promise = a.Parameter(1); | 296 Node* const maybe_promise = a.Parameter(1); |
228 Label if_ispromise(&a), if_isnotpromise(&a, Label::kDeferred); | 297 Label if_notpromise(&a, Label::kDeferred); |
229 a.GotoIf(a.TaggedIsSmi(maybe_promise), &if_isnotpromise); | 298 |
230 | 299 a.GotoIf(a.TaggedIsSmi(maybe_promise), &if_notpromise); |
231 a.Branch(a.HasInstanceType(maybe_promise, JS_PROMISE_TYPE), &if_ispromise, | 300 |
232 &if_isnotpromise); | 301 Node* const result = a.SelectBooleanConstant( |
233 | 302 a.HasInstanceType(maybe_promise, JS_PROMISE_TYPE)); |
234 a.Bind(&if_ispromise); | 303 a.Return(result); |
235 a.Return(a.BooleanConstant(true)); | 304 |
236 | 305 a.Bind(&if_notpromise); |
237 a.Bind(&if_isnotpromise); | 306 a.Return(a.FalseConstant()); |
238 a.Return(a.BooleanConstant(false)); | 307 } |
| 308 |
| 309 namespace { |
| 310 compiler::Node* SpeciesConstructor(CodeStubAssembler* a, Isolate* isolate, |
| 311 compiler::Node* context, |
| 312 compiler::Node* object, |
| 313 compiler::Node* default_constructor) { |
| 314 typedef compiler::Node Node; |
| 315 typedef CodeStubAssembler::Label Label; |
| 316 typedef CodeStubAssembler::Variable Variable; |
| 317 |
| 318 Variable var_result(a, MachineRepresentation::kTagged); |
| 319 var_result.Bind(default_constructor); |
| 320 |
| 321 // 2. Let C be ? Get(O, "constructor"). |
| 322 Node* const constructor_str = |
| 323 a->HeapConstant(isolate->factory()->constructor_string()); |
| 324 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
| 325 Node* const constructor = |
| 326 a->CallStub(getproperty_callable, context, object, constructor_str); |
| 327 |
| 328 // 3. If C is undefined, return defaultConstructor. |
| 329 Label out(a); |
| 330 a->GotoIf(a->IsUndefined(constructor), &out); |
| 331 |
| 332 // 4. If Type(C) is not Object, throw a TypeError exception. |
| 333 ThrowIfNotJSReceiver(a, a->isolate(), context, constructor, |
| 334 MessageTemplate::kConstructorNotReceiver); |
| 335 |
| 336 // 5. Let S be ? Get(C, @@species). |
| 337 Node* const species_symbol = |
| 338 a->HeapConstant(isolate->factory()->species_symbol()); |
| 339 Node* const species = |
| 340 a->CallStub(getproperty_callable, context, constructor, species_symbol); |
| 341 |
| 342 // 6. If S is either undefined or null, return defaultConstructor. |
| 343 a->GotoIf(a->IsUndefined(species), &out); |
| 344 a->GotoIf(a->WordEqual(species, a->NullConstant()), &out); |
| 345 |
| 346 // 7. If IsConstructor(S) is true, return S. |
| 347 Label throw_error(a); |
| 348 Node* species_bitfield = a->LoadMapBitField(a->LoadMap(species)); |
| 349 a->GotoUnless( |
| 350 a->Word32Equal(a->Word32And(species_bitfield, |
| 351 a->Int32Constant((1 << Map::kIsConstructor))), |
| 352 a->Int32Constant(1 << Map::kIsConstructor)), |
| 353 &throw_error); |
| 354 var_result.Bind(species); |
| 355 a->Goto(&out); |
| 356 |
| 357 // 8. Throw a TypeError exception. |
| 358 a->Bind(&throw_error); |
| 359 { |
| 360 Node* const message_id = |
| 361 a->SmiConstant(MessageTemplate::kSpeciesNotConstructor); |
| 362 a->CallRuntime(Runtime::kThrowTypeError, context, message_id); |
| 363 a->Goto(&out); |
| 364 } |
| 365 |
| 366 a->Bind(&out); |
| 367 return var_result.value(); |
| 368 } |
| 369 |
| 370 void AppendPromiseCallback(CodeStubAssembler* a, int offset, |
| 371 compiler::Node* promise, compiler::Node* value) { |
| 372 typedef compiler::Node Node; |
| 373 |
| 374 Node* elements = a->LoadObjectField(promise, offset); |
| 375 Node* length = a->LoadFixedArrayBaseLength(elements); |
| 376 CodeStubAssembler::ParameterMode mode = a->OptimalParameterMode(); |
| 377 length = a->UntagParameter(length, mode); |
| 378 |
| 379 Node* delta = a->IntPtrOrSmiConstant(1, mode); |
| 380 Node* new_capacity = a->IntPtrAdd(length, delta); |
| 381 ElementsKind kind = FAST_ELEMENTS; |
| 382 |
| 383 Node* new_elements = a->AllocateFixedArray(kind, new_capacity, mode); |
| 384 |
| 385 a->CopyFixedArrayElements(kind, elements, new_elements, length, |
| 386 UPDATE_WRITE_BARRIER, mode); |
| 387 a->StoreFixedArrayElement(new_elements, length, value, UPDATE_WRITE_BARRIER, |
| 388 0, mode); |
| 389 |
| 390 a->StoreObjectField(promise, offset, new_elements); |
| 391 } |
| 392 |
| 393 void InternalPerformPromiseThen(CodeStubAssembler* a, compiler::Node* context, |
| 394 compiler::Node* promise, |
| 395 compiler::Node* on_resolve, |
| 396 compiler::Node* on_reject, |
| 397 compiler::Node* deferred) { |
| 398 typedef CodeStubAssembler::Variable Variable; |
| 399 typedef CodeStubAssembler::Label Label; |
| 400 typedef compiler::Node Node; |
| 401 |
| 402 Isolate* isolate = a->isolate(); |
| 403 Node* const native_context = a->LoadNativeContext(context); |
| 404 |
| 405 Variable var_on_resolve(a, MachineRepresentation::kTagged), |
| 406 var_on_reject(a, MachineRepresentation::kTagged); |
| 407 |
| 408 var_on_resolve.Bind(on_resolve); |
| 409 var_on_reject.Bind(on_reject); |
| 410 |
| 411 Label out(a), if_onresolvenotcallable(a), onrejectcheck(a), |
| 412 append_callbacks(a); |
| 413 a->GotoIf(a->TaggedIsSmi(on_resolve), &if_onresolvenotcallable); |
| 414 |
| 415 Node* const on_resolve_map = a->LoadMap(on_resolve); |
| 416 a->Branch(a->IsCallableMap(on_resolve_map), &onrejectcheck, |
| 417 &if_onresolvenotcallable); |
| 418 |
| 419 a->Bind(&if_onresolvenotcallable); |
| 420 { |
| 421 var_on_resolve.Bind(a->LoadContextElement( |
| 422 native_context, Context::PROMISE_ID_RESOLVE_HANDLER_INDEX)); |
| 423 a->Goto(&onrejectcheck); |
| 424 } |
| 425 |
| 426 a->Bind(&onrejectcheck); |
| 427 { |
| 428 Label if_onrejectnotcallable(a); |
| 429 a->GotoIf(a->TaggedIsSmi(on_reject), &if_onrejectnotcallable); |
| 430 |
| 431 Node* const on_reject_map = a->LoadMap(on_reject); |
| 432 a->Branch(a->IsCallableMap(on_reject_map), &append_callbacks, |
| 433 &if_onrejectnotcallable); |
| 434 |
| 435 a->Bind(&if_onrejectnotcallable); |
| 436 { |
| 437 var_on_reject.Bind(a->LoadContextElement( |
| 438 native_context, Context::PROMISE_ID_REJECT_HANDLER_INDEX)); |
| 439 a->Goto(&append_callbacks); |
| 440 } |
| 441 } |
| 442 |
| 443 a->Bind(&append_callbacks); |
| 444 { |
| 445 Label fulfilled_check(a); |
| 446 Node* const status = a->LoadObjectField(promise, JSPromise::kStatusOffset); |
| 447 a->GotoUnless(a->SmiEqual(status, a->SmiConstant(kPromisePending)), |
| 448 &fulfilled_check); |
| 449 |
| 450 Node* const existing_deferred = |
| 451 a->LoadObjectField(promise, JSPromise::kDeferredOffset); |
| 452 |
| 453 Label if_noexistingcallbacks(a), if_existingcallbacks(a); |
| 454 a->Branch(a->IsUndefined(existing_deferred), &if_noexistingcallbacks, |
| 455 &if_existingcallbacks); |
| 456 |
| 457 a->Bind(&if_noexistingcallbacks); |
| 458 { |
| 459 // Store callbacks directly in the slots. |
| 460 a->StoreObjectField(promise, JSPromise::kDeferredOffset, deferred); |
| 461 a->StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, |
| 462 var_on_resolve.value()); |
| 463 a->StoreObjectField(promise, JSPromise::kRejectReactionsOffset, |
| 464 var_on_reject.value()); |
| 465 a->Goto(&out); |
| 466 } |
| 467 |
| 468 a->Bind(&if_existingcallbacks); |
| 469 { |
| 470 Label if_singlecallback(a), if_multiplecallbacks(a); |
| 471 a->BranchIfJSObject(existing_deferred, &if_singlecallback, |
| 472 &if_multiplecallbacks); |
| 473 |
| 474 a->Bind(&if_singlecallback); |
| 475 { |
| 476 // Create new FixedArrays to store callbacks. |
| 477 Node* const deferreds = |
| 478 a->AllocateFixedArray(FAST_ELEMENTS, a->Int32Constant(2)); |
| 479 Node* const fulfill_reactions = |
| 480 a->AllocateFixedArray(FAST_ELEMENTS, a->Int32Constant(2)); |
| 481 Node* const reject_reactions = |
| 482 a->AllocateFixedArray(FAST_ELEMENTS, a->Int32Constant(2)); |
| 483 |
| 484 // Store existing callbacks in FixedArrays. |
| 485 a->StoreFixedArrayElement(deferreds, 0, existing_deferred); |
| 486 a->StoreFixedArrayElement( |
| 487 fulfill_reactions, 0, |
| 488 a->LoadObjectField(promise, JSPromise::kFulfillReactionsOffset)); |
| 489 a->StoreFixedArrayElement( |
| 490 reject_reactions, 0, |
| 491 a->LoadObjectField(promise, JSPromise::kRejectReactionsOffset)); |
| 492 |
| 493 // Store new callbacks in FixedArrays. |
| 494 a->StoreFixedArrayElement(deferreds, 1, deferred); |
| 495 a->StoreFixedArrayElement(fulfill_reactions, 1, var_on_resolve.value()); |
| 496 a->StoreFixedArrayElement(reject_reactions, 1, var_on_reject.value()); |
| 497 |
| 498 // Store new FixedArrays in promise. |
| 499 a->StoreObjectField(promise, JSPromise::kDeferredOffset, deferreds); |
| 500 a->StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, |
| 501 fulfill_reactions); |
| 502 a->StoreObjectField(promise, JSPromise::kRejectReactionsOffset, |
| 503 reject_reactions); |
| 504 a->Goto(&out); |
| 505 } |
| 506 |
| 507 a->Bind(&if_multiplecallbacks); |
| 508 { |
| 509 AppendPromiseCallback(a, JSPromise::kDeferredOffset, promise, deferred); |
| 510 AppendPromiseCallback(a, JSPromise::kFulfillReactionsOffset, promise, |
| 511 var_on_resolve.value()); |
| 512 AppendPromiseCallback(a, JSPromise::kRejectReactionsOffset, promise, |
| 513 var_on_reject.value()); |
| 514 a->Goto(&out); |
| 515 } |
| 516 } |
| 517 |
| 518 a->Bind(&fulfilled_check); |
| 519 { |
| 520 Label reject(a); |
| 521 Node* const result = |
| 522 a->LoadObjectField(promise, JSPromise::kResultOffset); |
| 523 a->GotoUnless(a->WordEqual(status, a->SmiConstant(kPromiseFulfilled)), |
| 524 &reject); |
| 525 |
| 526 // TODO(gsathya): Move this to TF. |
| 527 a->CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, result, |
| 528 var_on_resolve.value(), deferred, |
| 529 a->SmiConstant(kPromiseFulfilled)); |
| 530 a->Goto(&out); |
| 531 |
| 532 a->Bind(&reject); |
| 533 { |
| 534 Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
| 535 Node* const key = |
| 536 a->HeapConstant(isolate->factory()->promise_has_handler_symbol()); |
| 537 Node* const has_handler = |
| 538 a->CallStub(getproperty_callable, context, promise, key); |
| 539 |
| 540 Label enqueue(a); |
| 541 |
| 542 // TODO(gsathya): Fold these runtime calls and move to TF. |
| 543 a->GotoIf(a->WordEqual(has_handler, a->TrueConstant()), &enqueue); |
| 544 a->CallRuntime(Runtime::kPromiseRevokeReject, context, promise); |
| 545 a->Goto(&enqueue); |
| 546 |
| 547 a->Bind(&enqueue); |
| 548 { |
| 549 a->CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, result, |
| 550 var_on_reject.value(), deferred, |
| 551 a->SmiConstant(kPromiseRejected)); |
| 552 |
| 553 a->Goto(&out); |
| 554 } |
| 555 } |
| 556 } |
| 557 } |
| 558 |
| 559 a->Bind(&out); |
| 560 } |
| 561 |
| 562 } // namespace |
| 563 |
| 564 void Builtins::Generate_PerformPromiseThen( |
| 565 compiler::CodeAssemblerState* state) { |
| 566 CodeStubAssembler a(state); |
| 567 typedef compiler::Node Node; |
| 568 |
| 569 Node* const promise = a.Parameter(1); |
| 570 Node* const on_resolve = a.Parameter(2); |
| 571 Node* const on_reject = a.Parameter(3); |
| 572 Node* const deferred = a.Parameter(4); |
| 573 Node* const context = a.Parameter(7); |
| 574 |
| 575 InternalPerformPromiseThen(&a, context, promise, on_resolve, on_reject, |
| 576 deferred); |
| 577 |
| 578 // TODO(gsathya): This is unused, but value is returned according to spec. |
| 579 a.Return(promise); |
| 580 } |
| 581 |
| 582 void Builtins::Generate_PromiseThen(compiler::CodeAssemblerState* state) { |
| 583 CodeStubAssembler a(state); |
| 584 typedef compiler::Node Node; |
| 585 typedef CodeStubAssembler::Label Label; |
| 586 typedef CodeStubAssembler::Variable Variable; |
| 587 |
| 588 // 1. Let promise be the this value. |
| 589 Node* const promise = a.Parameter(0); |
| 590 Node* const on_resolve = a.Parameter(1); |
| 591 Node* const on_reject = a.Parameter(2); |
| 592 Node* const context = a.Parameter(5); |
| 593 Isolate* isolate = a.isolate(); |
| 594 |
| 595 // 2. If IsPromise(promise) is false, throw a TypeError exception. |
| 596 a.ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE, |
| 597 "Promise.prototype.then"); |
| 598 |
| 599 Node* const native_context = a.LoadNativeContext(context); |
| 600 Node* const promise_fun = |
| 601 a.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
| 602 |
| 603 // 3. Let C be ? SpeciesConstructor(promise, %Promise%). |
| 604 Node* constructor = |
| 605 SpeciesConstructor(&a, isolate, context, promise, promise_fun); |
| 606 |
| 607 // 4. Let resultCapability be ? NewPromiseCapability(C). |
| 608 Callable call_callable = CodeFactory::Call(isolate); |
| 609 Label fast_promise_capability(&a), promise_capability(&a), |
| 610 perform_promise_then(&a); |
| 611 Variable var_deferred(&a, MachineRepresentation::kTagged); |
| 612 |
| 613 a.Branch(a.WordEqual(promise_fun, constructor), &fast_promise_capability, |
| 614 &promise_capability); |
| 615 |
| 616 // TODO(gsathya): Remove deferred object and move |
| 617 // NewPromiseCapbability functions to TF. |
| 618 a.Bind(&fast_promise_capability); |
| 619 { |
| 620 // TODO(gsathya): Move this to TF. |
| 621 Node* const promise_internal_capability = a.LoadContextElement( |
| 622 native_context, Context::INTERNAL_PROMISE_CAPABILITY_INDEX); |
| 623 Node* const capability = |
| 624 a.CallJS(call_callable, context, promise_internal_capability, |
| 625 a.UndefinedConstant()); |
| 626 var_deferred.Bind(capability); |
| 627 a.Goto(&perform_promise_then); |
| 628 } |
| 629 |
| 630 a.Bind(&promise_capability); |
| 631 { |
| 632 // TODO(gsathya): Move this to TF. |
| 633 Node* const new_promise_capability = a.LoadContextElement( |
| 634 native_context, Context::NEW_PROMISE_CAPABILITY_INDEX); |
| 635 Node* const capability = |
| 636 a.CallJS(call_callable, context, new_promise_capability, |
| 637 a.UndefinedConstant(), constructor); |
| 638 var_deferred.Bind(capability); |
| 639 a.Goto(&perform_promise_then); |
| 640 } |
| 641 |
| 642 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, |
| 643 // resultCapability). |
| 644 a.Bind(&perform_promise_then); |
| 645 InternalPerformPromiseThen(&a, context, promise, on_resolve, on_reject, |
| 646 var_deferred.value()); |
| 647 |
| 648 // TODO(gsathya): Protect with debug check. |
| 649 a.CallRuntime( |
| 650 Runtime::kSetProperty, context, promise, |
| 651 a.HeapConstant(isolate->factory()->promise_has_handler_symbol()), |
| 652 a.TrueConstant(), a.SmiConstant(STRICT)); |
| 653 |
| 654 // TODO(gsathya): This call will be removed once we don't have to |
| 655 // deal with deferred objects. |
| 656 Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
| 657 Node* const key = |
| 658 a.HeapConstant(isolate->factory()->NewStringFromAsciiChecked("promise")); |
| 659 Node* const result = |
| 660 a.CallStub(getproperty_callable, context, var_deferred.value(), key); |
| 661 |
| 662 a.Return(result); |
239 } | 663 } |
240 | 664 |
241 } // namespace internal | 665 } // namespace internal |
242 } // namespace v8 | 666 } // namespace v8 |
OLD | NEW |