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 | |
91 void Builtins::Generate_PromiseConstructor( | 84 void Builtins::Generate_PromiseConstructor( |
92 compiler::CodeAssemblerState* state) { | 85 compiler::CodeAssemblerState* state) { |
93 CodeStubAssembler a(state); | 86 CodeStubAssembler a(state); |
94 typedef CodeStubAssembler::Variable Variable; | 87 typedef CodeStubAssembler::Variable Variable; |
95 typedef CodeStubAssembler::Label Label; | 88 typedef CodeStubAssembler::Label Label; |
96 typedef compiler::Node Node; | 89 typedef compiler::Node Node; |
97 | 90 |
98 Node* const executor = a.Parameter(1); | 91 Node* const executor = a.Parameter(1); |
99 Node* const new_target = a.Parameter(2); | 92 Node* const new_target = a.Parameter(2); |
100 Node* const context = a.Parameter(4); | 93 Node* const context = a.Parameter(4); |
101 Isolate* isolate = a.isolate(); | 94 Isolate* isolate = a.isolate(); |
102 | 95 |
103 Label if_targetisundefined(&a, Label::kDeferred); | 96 Label if_targetisundefined(&a, Label::kDeferred); |
104 | 97 |
105 a.GotoIf(a.IsUndefined(new_target), &if_targetisundefined); | 98 a.GotoIf(a.IsUndefined(new_target), &if_targetisundefined); |
106 | 99 |
107 Label if_notcallable(&a, Label::kDeferred); | 100 Label if_notcallable(&a, Label::kDeferred); |
108 | 101 |
109 a.GotoIf(a.TaggedIsSmi(executor), &if_notcallable); | 102 a.GotoIf(a.TaggedIsSmi(executor), &if_notcallable); |
110 | 103 |
111 Node* const executor_map = a.LoadMap(executor); | 104 Node* const executor_map = a.LoadMap(executor); |
112 a.GotoUnless(a.IsCallableMap(executor_map), &if_notcallable); | 105 a.GotoUnless(a.IsCallableMap(executor_map), &if_notcallable); |
113 | 106 |
114 Node* const native_context = a.LoadNativeContext(context); | 107 Node* const native_context = a.LoadNativeContext(context); |
115 Node* const promise_fun = | 108 Node* const promise_fun = |
116 a.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); | 109 a.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
117 Node* const is_debug_active = a.IsDebugActive(); | 110 Node* const is_debug_active = a.IsDebugActive(); |
| 111 |
118 Label if_targetisnotmodified(&a), if_targetismodified(&a, Label::kDeferred), | 112 Label if_targetisnotmodified(&a), if_targetismodified(&a, Label::kDeferred), |
119 run_executor(&a), debug_push(&a, Label::kDeferred), init(&a); | 113 run_executor(&a), debug_push(&a, Label::kDeferred); |
120 | |
121 a.Branch(a.WordEqual(promise_fun, new_target), &if_targetisnotmodified, | 114 a.Branch(a.WordEqual(promise_fun, new_target), &if_targetisnotmodified, |
122 &if_targetismodified); | 115 &if_targetismodified); |
123 | 116 |
124 Variable var_result(&a, MachineRepresentation::kTagged), | 117 Variable var_result(&a, MachineRepresentation::kTagged), |
125 var_reject_call(&a, MachineRepresentation::kTagged), | 118 var_reject_call(&a, MachineRepresentation::kTagged), |
126 var_reason(&a, MachineRepresentation::kTagged); | 119 var_reason(&a, MachineRepresentation::kTagged); |
127 | 120 |
128 a.Bind(&if_targetisnotmodified); | 121 a.Bind(&if_targetisnotmodified); |
129 { | 122 { |
130 Node* const initial_map = a.LoadObjectField( | 123 Node* const initial_map = a.LoadObjectField( |
131 promise_fun, JSFunction::kPrototypeOrInitialMapOffset); | 124 promise_fun, JSFunction::kPrototypeOrInitialMapOffset); |
132 | 125 |
133 Node* const instance = a.AllocateJSObjectFromMap(initial_map); | 126 Node* const instance = a.AllocateJSObjectFromMap(initial_map); |
134 var_result.Bind(instance); | 127 var_result.Bind(instance); |
135 a.Goto(&init); | 128 a.Branch(is_debug_active, &debug_push, &run_executor); |
136 } | 129 } |
137 | 130 |
138 a.Bind(&if_targetismodified); | 131 a.Bind(&if_targetismodified); |
139 { | 132 { |
140 Callable fast_new_object_stub = CodeFactory::FastNewObject(isolate); | 133 Callable fast_new_object_stub = CodeFactory::FastNewObject(isolate); |
141 Node* const instance = | 134 Node* const instance = |
142 a.CallStub(fast_new_object_stub, context, promise_fun, new_target); | 135 a.CallStub(fast_new_object_stub, context, promise_fun, new_target); |
143 | 136 |
144 var_result.Bind(instance); | 137 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()); | |
152 a.Branch(is_debug_active, &debug_push, &run_executor); | 138 a.Branch(is_debug_active, &debug_push, &run_executor); |
153 } | 139 } |
154 | 140 |
155 a.Bind(&debug_push); | 141 a.Bind(&debug_push); |
156 { | 142 { |
157 a.CallRuntime(Runtime::kDebugPushPromise, context, var_result.value()); | 143 a.CallRuntime(Runtime::kDebugPushPromise, context, var_result.value()); |
158 a.Goto(&run_executor); | 144 a.Goto(&run_executor); |
159 } | 145 } |
160 | 146 |
161 a.Bind(&run_executor); | 147 a.Bind(&run_executor); |
162 { | 148 { |
163 Label out(&a), if_rejectpromise(&a), debug_pop(&a, Label::kDeferred); | 149 Label out(&a), if_rejectpromise(&a), debug_pop(&a, Label::kDeferred); |
164 | 150 |
165 // TODO(gsathya): Move this to TF. | 151 Node* const key = a.LoadRoot(Heap::kpromise_state_symbolRootIndex); |
| 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); |
166 Node* const resolving_functions = a.CallRuntime( | 157 Node* const resolving_functions = a.CallRuntime( |
167 Runtime::kCreateResolvingFunctions, context, var_result.value()); | 158 Runtime::kCreateResolvingFunctions, context, var_result.value()); |
168 Node* const resolve = | 159 Node* const resolve = |
169 a.LoadFixedArrayElement(resolving_functions, a.IntPtrConstant(0)); | 160 a.LoadFixedArrayElement(resolving_functions, a.IntPtrConstant(0)); |
170 Node* const reject = | 161 Node* const reject = |
171 a.LoadFixedArrayElement(resolving_functions, a.IntPtrConstant(1)); | 162 a.LoadFixedArrayElement(resolving_functions, a.IntPtrConstant(1)); |
172 Callable call_callable = CodeFactory::Call(isolate); | 163 Callable call_callable = CodeFactory::Call(isolate); |
173 | 164 |
174 Node* const maybe_exception = | 165 Node* const maybe_exception = |
175 a.CallJS(call_callable, context, executor, a.UndefinedConstant(), | 166 a.CallJS(call_callable, context, executor, a.UndefinedConstant(), |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 typedef compiler::Node Node; | 209 typedef compiler::Node Node; |
219 CodeStubAssembler a(state); | 210 CodeStubAssembler a(state); |
220 | 211 |
221 Node* const context = a.Parameter(3); | 212 Node* const context = a.Parameter(3); |
222 Node* const native_context = a.LoadNativeContext(context); | 213 Node* const native_context = a.LoadNativeContext(context); |
223 Node* const promise_fun = | 214 Node* const promise_fun = |
224 a.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); | 215 a.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
225 Node* const initial_map = | 216 Node* const initial_map = |
226 a.LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); | 217 a.LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); |
227 Node* const instance = a.AllocateJSObjectFromMap(initial_map); | 218 Node* const instance = a.AllocateJSObjectFromMap(initial_map); |
228 | |
229 PromiseInit(&a, instance, a.SmiConstant(kPromisePending), | |
230 a.UndefinedConstant()); | |
231 a.Return(instance); | 219 a.Return(instance); |
232 } | 220 } |
233 | 221 |
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 | |
291 void Builtins::Generate_IsPromise(compiler::CodeAssemblerState* state) { | 222 void Builtins::Generate_IsPromise(compiler::CodeAssemblerState* state) { |
292 CodeStubAssembler a(state); | 223 CodeStubAssembler a(state); |
293 typedef compiler::Node Node; | 224 typedef compiler::Node Node; |
294 typedef CodeStubAssembler::Label Label; | 225 typedef CodeStubAssembler::Label Label; |
295 | 226 |
296 Node* const maybe_promise = a.Parameter(1); | 227 Node* const maybe_promise = a.Parameter(1); |
297 Label if_notpromise(&a, Label::kDeferred); | 228 Label if_ispromise(&a), if_isnotpromise(&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, |
| 232 &if_isnotpromise); |
300 | 233 |
301 Node* const result = a.SelectBooleanConstant( | 234 a.Bind(&if_ispromise); |
302 a.HasInstanceType(maybe_promise, JS_PROMISE_TYPE)); | 235 a.Return(a.BooleanConstant(true)); |
303 a.Return(result); | |
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); | |
663 } | 239 } |
664 | 240 |
665 } // namespace internal | 241 } // namespace internal |
666 } // namespace v8 | 242 } // namespace v8 |
OLD | NEW |