1/* Copyright JS Foundation and other contributors, http://js.foundation 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecma-boolean-object.h" 17#include "ecma-builtins.h" 18#include "ecma-exceptions.h" 19#include "ecma-function-object.h" 20#include "ecma-gc.h" 21#include "ecma-globals.h" 22#include "ecma-helpers.h" 23#include "ecma-jobqueue.h" 24#include "ecma-objects.h" 25#include "ecma-objects-general.h" 26#include "ecma-promise-object.h" 27#include "jcontext.h" 28 29#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) 30 31/** \addtogroup ecma ECMA 32 * @{ 33 * 34 * \addtogroup ecmapromiseobject ECMA Promise object related routines 35 * @{ 36 */ 37 38/** 39 * Check if an object is promise. 40 * 41 * @return true - if the object is a promise. 42 * false - otherwise. 43 */ 44inline bool JERRY_ATTR_ALWAYS_INLINE 45ecma_is_promise (ecma_object_t *obj_p) /**< points to object */ 46{ 47 return ecma_object_class_is (obj_p, LIT_MAGIC_STRING_PROMISE_UL); 48} /* ecma_is_promise */ 49 50/** 51 * Get the result of the promise. 52 * 53 * @return ecma value of the promise result. 54 * Returned value must be freed with ecma_free_value 55 */ 56ecma_value_t 57ecma_promise_get_result (ecma_object_t *obj_p) /**< points to promise object */ 58{ 59 JERRY_ASSERT (ecma_is_promise (obj_p)); 60 61 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; 62 63 return ecma_copy_value (ext_object_p->u.class_prop.u.value); 64} /* ecma_promise_get_result */ 65 66/** 67 * Set the PromiseResult of promise. 68 */ 69static inline void JERRY_ATTR_ALWAYS_INLINE 70ecma_promise_set_result (ecma_object_t *obj_p, /**< points to promise object */ 71 ecma_value_t result) /**< the result value */ 72{ 73 JERRY_ASSERT (ecma_is_promise (obj_p)); 74 75 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; 76 77 JERRY_ASSERT (ext_object_p->u.class_prop.u.value == ECMA_VALUE_UNDEFINED); 78 79 ext_object_p->u.class_prop.u.value = result; 80} /* ecma_promise_set_result */ 81 82/** 83 * Get the PromiseState of promise. 84 * 85 * @return the state's enum value 86 */ 87uint16_t 88ecma_promise_get_flags (ecma_object_t *obj_p) /**< points to promise object */ 89{ 90 JERRY_ASSERT (ecma_is_promise (obj_p)); 91 92 return ((ecma_extended_object_t *) obj_p)->u.class_prop.extra_info; 93} /* ecma_promise_get_flags */ 94 95/** 96 * Set the PromiseState of promise. 97 */ 98static inline void JERRY_ATTR_ALWAYS_INLINE 99ecma_promise_set_state (ecma_object_t *obj_p, /**< points to promise object */ 100 bool is_fulfilled) /**< new flags */ 101{ 102 JERRY_ASSERT (ecma_is_promise (obj_p)); 103 JERRY_ASSERT (ecma_promise_get_flags (obj_p) & ECMA_PROMISE_IS_PENDING); 104 105 uint16_t flags_to_invert = (is_fulfilled ? (ECMA_PROMISE_IS_PENDING | ECMA_PROMISE_IS_FULFILLED) 106 : ECMA_PROMISE_IS_PENDING); 107 108 ((ecma_extended_object_t *) obj_p)->u.class_prop.extra_info ^= flags_to_invert; 109} /* ecma_promise_set_state */ 110 111/** 112 * Take a collection of Reactions and enqueue a new PromiseReactionJob for each Reaction. 113 * 114 * See also: ES2015 25.4.1.8 115 */ 116static void 117ecma_promise_trigger_reactions (ecma_collection_t *reactions, /**< lists of reactions */ 118 ecma_value_t value, /**< value for resolve or reject */ 119 bool is_reject) /**< true if promise is rejected, false otherwise */ 120{ 121 ecma_value_t *buffer_p = reactions->buffer_p; 122 ecma_value_t *buffer_end_p = buffer_p + reactions->item_count; 123 124 while (buffer_p < buffer_end_p) 125 { 126 ecma_value_t capability_with_tag = *buffer_p++; 127 ecma_object_t *capability_obj_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, capability_with_tag); 128 ecma_value_t capability = ecma_make_object_value (capability_obj_p); 129 130 if (!is_reject) 131 { 132 ecma_value_t handler = ECMA_VALUE_TRUE; 133 134 if (JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG (capability_with_tag)) 135 { 136 handler = *buffer_p++; 137 } 138 139 ecma_enqueue_promise_reaction_job (capability, handler, value); 140 } 141 else if (JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG (capability_with_tag)) 142 { 143 buffer_p++; 144 } 145 146 if (is_reject) 147 { 148 ecma_value_t handler = ECMA_VALUE_FALSE; 149 150 if (JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG (capability_with_tag)) 151 { 152 handler = *buffer_p++; 153 } 154 155 ecma_enqueue_promise_reaction_job (capability, handler, value); 156 } 157 else if (JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG (capability_with_tag)) 158 { 159 buffer_p++; 160 } 161 } 162} /* ecma_promise_trigger_reactions */ 163 164/** 165 * Checks whether a resolver is called before. 166 * 167 * @return true if it was called before, false otherwise 168 */ 169static bool 170ecma_is_resolver_already_called (ecma_object_t *resolver_p, /**< resolver */ 171 ecma_object_t *promise_obj_p) /**< promise */ 172{ 173 ecma_string_t *str_already_resolved_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); 174 ecma_property_t *property_p = ecma_find_named_property (resolver_p, str_already_resolved_p); 175 176 if (property_p == NULL) 177 { 178 return (ecma_promise_get_flags (promise_obj_p) & ECMA_PROMISE_ALREADY_RESOLVED) != 0; 179 } 180 181 JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); 182 183 ecma_value_t already_resolved = ECMA_PROPERTY_VALUE_PTR (property_p)->value; 184 ecma_object_t *object_p = ecma_get_object_from_value (already_resolved); 185 JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_CLASS); 186 187 ecma_extended_object_t *already_resolved_p = (ecma_extended_object_t *) object_p; 188 JERRY_ASSERT (already_resolved_p->u.class_prop.class_id == LIT_MAGIC_STRING_BOOLEAN_UL); 189 190 ecma_value_t current_value = already_resolved_p->u.class_prop.u.value; 191 already_resolved_p->u.class_prop.u.value = ECMA_VALUE_TRUE; 192 193 return current_value == ECMA_VALUE_TRUE; 194} /* ecma_is_resolver_already_called */ 195 196/** 197 * Reject a Promise with a reason. 198 * 199 * See also: ES2015 25.4.1.7 200 */ 201static void 202ecma_reject_promise (ecma_value_t promise, /**< promise */ 203 ecma_value_t reason) /**< reason for reject */ 204{ 205 ecma_object_t *obj_p = ecma_get_object_from_value (promise); 206 207 JERRY_ASSERT (ecma_promise_get_flags (obj_p) & ECMA_PROMISE_IS_PENDING); 208 209 ecma_promise_set_state (obj_p, false); 210 ecma_promise_set_result (obj_p, ecma_copy_value_if_not_object (reason)); 211 ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p; 212 213 /* GC can be triggered by ecma_new_collection so freeing the collection 214 first and creating a new one might cause a heap after use event. */ 215 ecma_collection_t *reactions = promise_p->reactions; 216 217 /* Fulfill reactions will never be triggered. */ 218 ecma_promise_trigger_reactions (reactions, reason, true); 219 220 promise_p->reactions = ecma_new_collection (); 221 222 ecma_collection_destroy (reactions); 223} /* ecma_reject_promise */ 224 225/** 226 * Fulfill a Promise with a value. 227 * 228 * See also: ES2015 25.4.1.4 229 */ 230static void 231ecma_fulfill_promise (ecma_value_t promise, /**< promise */ 232 ecma_value_t value) /**< fulfilled value */ 233{ 234 ecma_object_t *obj_p = ecma_get_object_from_value (promise); 235 236 JERRY_ASSERT (ecma_promise_get_flags (obj_p) & ECMA_PROMISE_IS_PENDING); 237 238 ecma_promise_set_state (obj_p, true); 239 ecma_promise_set_result (obj_p, ecma_copy_value_if_not_object (value)); 240 ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p; 241 242 /* GC can be triggered by ecma_new_collection so freeing the collection 243 first and creating a new one might cause a heap after use event. */ 244 ecma_collection_t *reactions = promise_p->reactions; 245 246 /* Reject reactions will never be triggered. */ 247 ecma_promise_trigger_reactions (reactions, value, false); 248 249 promise_p->reactions = ecma_new_collection (); 250 251 ecma_collection_destroy (reactions); 252} /* ecma_fulfill_promise */ 253 254/** 255 * Native handler for Promise Reject Function. 256 * 257 * See also: ES2015 25.4.1.3.1 258 * 259 * @return ecma value of undefined. 260 */ 261static ecma_value_t 262ecma_promise_reject_handler (const ecma_value_t function, /**< the function itself */ 263 const ecma_value_t this, /**< this_arg of the function */ 264 const ecma_value_t argv[], /**< argument list */ 265 const ecma_length_t argc) /**< argument number */ 266{ 267 JERRY_UNUSED (this); 268 269 ecma_object_t *function_p = ecma_get_object_from_value (function); 270 /* 2. */ 271 ecma_value_t promise = ecma_op_object_get_by_magic_id (function_p, LIT_INTERNAL_MAGIC_STRING_PROMISE); 272 /* 1. */ 273 ecma_object_t *promise_obj_p = ecma_get_object_from_value (promise); 274 JERRY_ASSERT (ecma_is_promise (promise_obj_p)); 275 276 /* 3., 4. */ 277 if (!ecma_is_resolver_already_called (function_p, promise_obj_p)) 278 { 279 /* 5. */ 280 ((ecma_extended_object_t *) promise_obj_p)->u.class_prop.extra_info |= ECMA_PROMISE_ALREADY_RESOLVED; 281 282 /* 6. */ 283 ecma_value_t reject_value = (argc == 0) ? ECMA_VALUE_UNDEFINED : argv[0]; 284 ecma_reject_promise (promise, reject_value); 285 } 286 287 ecma_free_value (promise); 288 return ECMA_VALUE_UNDEFINED; 289} /* ecma_promise_reject_handler */ 290 291/** 292 * Native handler for Promise Resolve Function. 293 * 294 * See also: ES2015 25.4.1.3.2 295 * 296 * @return ecma value of undefined. 297 */ 298static ecma_value_t 299ecma_promise_resolve_handler (const ecma_value_t function, /**< the function itself */ 300 const ecma_value_t this, /**< this_arg of the function */ 301 const ecma_value_t argv[], /**< argument list */ 302 const ecma_length_t argc) /**< argument number */ 303{ 304 JERRY_UNUSED (this); 305 306 ecma_object_t *function_p = ecma_get_object_from_value (function); 307 /* 2. */ 308 ecma_value_t promise = ecma_op_object_get_by_magic_id (function_p, LIT_INTERNAL_MAGIC_STRING_PROMISE); 309 /* 1. */ 310 ecma_object_t *promise_obj_p = ecma_get_object_from_value (promise); 311 JERRY_ASSERT (ecma_is_promise (promise_obj_p)); 312 313 /* 3., 4. */ 314 if (ecma_is_resolver_already_called (function_p, promise_obj_p)) 315 { 316 goto end_of_resolve_function; 317 } 318 319 /* 5. */ 320 ((ecma_extended_object_t *) promise_obj_p)->u.class_prop.extra_info |= ECMA_PROMISE_ALREADY_RESOLVED; 321 322 /* If the argc is 0, then fulfill the `undefined`. */ 323 if (argc == 0) 324 { 325 ecma_fulfill_promise (promise, ECMA_VALUE_UNDEFINED); 326 goto end_of_resolve_function; 327 } 328 329 /* 6. */ 330 if (argv[0] == promise) 331 { 332 ecma_object_t *error_p = ecma_new_standard_error (ECMA_ERROR_TYPE); 333 ecma_reject_promise (promise, ecma_make_object_value (error_p)); 334 ecma_deref_object (error_p); 335 goto end_of_resolve_function; 336 } 337 338 /* 7. */ 339 if (!ecma_is_value_object (argv[0])) 340 { 341 ecma_fulfill_promise (promise, argv[0]); 342 goto end_of_resolve_function; 343 } 344 345 /* 8. */ 346 ecma_value_t then = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (argv[0]), 347 LIT_MAGIC_STRING_THEN); 348 349 if (ECMA_IS_VALUE_ERROR (then)) 350 { 351 /* 9. */ 352 then = jcontext_take_exception (); 353 ecma_reject_promise (promise, then); 354 } 355 else if (!ecma_op_is_callable (then)) 356 { 357 /* 11 .*/ 358 ecma_fulfill_promise (promise, argv[0]); 359 } 360 else 361 { 362 /* 12 */ 363 ecma_enqueue_promise_resolve_thenable_job (promise, argv[0], then); 364 } 365 366 ecma_free_value (then); 367 368end_of_resolve_function: 369 ecma_free_value (promise); 370 return ECMA_VALUE_UNDEFINED; 371} /* ecma_promise_resolve_handler */ 372 373/** 374 * CapabilitiesExecutor Function. 375 * 376 * See also: ES2015 25.4.1.5.1 377 * 378 * @return ecma value of undefined or typerror. 379 * Returned value must be freed with ecma_free_value 380 */ 381static ecma_value_t 382ecma_call_builtin_executor (ecma_object_t *executor_p, /**< the executor object */ 383 ecma_value_t resolve_func, /**< the resolve function */ 384 ecma_value_t reject_func) /**< the reject function */ 385{ 386 ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY); 387 ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); 388 ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); 389 390 /* 2. */ 391 ecma_value_t capability = ecma_op_object_get (executor_p, capability_str_p); 392 /* 3. */ 393 ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), resolve_str_p); 394 395 if (resolve != ECMA_VALUE_UNDEFINED) 396 { 397 ecma_free_value (resolve); 398 ecma_free_value (capability); 399 400 return ecma_raise_type_error (ECMA_ERR_MSG ("'resolve' function should be undefined.")); 401 } 402 403 /* 4. */ 404 ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), reject_str_p); 405 406 if (reject != ECMA_VALUE_UNDEFINED) 407 { 408 ecma_free_value (reject); 409 ecma_free_value (capability); 410 411 return ecma_raise_type_error (ECMA_ERR_MSG ("'reject' function should be undefined.")); 412 } 413 414 /* 5. */ 415 ecma_op_object_put (ecma_get_object_from_value (capability), 416 resolve_str_p, 417 resolve_func, 418 false); 419 /* 6. */ 420 ecma_op_object_put (ecma_get_object_from_value (capability), 421 reject_str_p, 422 reject_func, 423 false); 424 425 ecma_free_value (capability); 426 427 return ECMA_VALUE_UNDEFINED; 428} /* ecma_call_builtin_executor */ 429 430/** 431 * Helper function for PromiseCreateResovingFucntions. 432 * 433 * See also: ES2015 25.4.1.3 2. - 7. 434 * 435 * @return pointer to the resolving function 436 */ 437static ecma_value_t 438ecma_promise_create_resolving_functions_helper (ecma_object_t *obj_p, /**< Promise Object */ 439 ecma_external_handler_t handler_cb) /**< Callback handler */ 440{ 441 ecma_string_t *str_promise_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE); 442 ecma_object_t *func_obj_p = ecma_op_create_external_function_object (handler_cb); 443 444 ecma_op_object_put (func_obj_p, 445 str_promise_p, 446 ecma_make_object_value (obj_p), 447 false); 448 449 return ecma_make_object_value (func_obj_p); 450} /* ecma_promise_create_resolving_functions_helper */ 451 452/** 453 * Create a PromiseCreateResovingFucntions. 454 * 455 * See also: ES2015 25.4.1.3 456 * 457 * @return pointer to the resolving functions 458 */ 459void 460ecma_promise_create_resolving_functions (ecma_object_t *object_p, /**< the promise object */ 461 ecma_promise_resolving_functions_t *funcs, /**< [out] resolving functions */ 462 bool create_already_resolved) /**< create already resolved flag */ 463{ 464 /* 2. - 4. */ 465 funcs->resolve = ecma_promise_create_resolving_functions_helper (object_p, 466 ecma_promise_resolve_handler); 467 468 /* 5. - 7. */ 469 funcs->reject = ecma_promise_create_resolving_functions_helper (object_p, 470 ecma_promise_reject_handler); 471 if (!create_already_resolved) 472 { 473 return; 474 } 475 476 ecma_value_t already_resolved = ecma_op_create_boolean_object (ECMA_VALUE_FALSE); 477 ecma_string_t *str_already_resolved_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); 478 ecma_property_value_t *value_p; 479 480 value_p = ecma_create_named_data_property (ecma_get_object_from_value (funcs->resolve), 481 str_already_resolved_p, 482 ECMA_PROPERTY_FIXED, 483 NULL); 484 value_p->value = already_resolved; 485 486 value_p = ecma_create_named_data_property (ecma_get_object_from_value (funcs->reject), 487 str_already_resolved_p, 488 ECMA_PROPERTY_FIXED, 489 NULL); 490 value_p->value = already_resolved; 491 492 ecma_free_value (already_resolved); 493} /* ecma_promise_create_resolving_functions */ 494 495/** 496 * Free the heap and the member of the resolving functions. 497 */ 498void 499ecma_promise_free_resolving_functions (ecma_promise_resolving_functions_t *funcs) /**< points to the functions */ 500{ 501 ecma_free_value (funcs->resolve); 502 ecma_free_value (funcs->reject); 503} /* ecma_promise_free_resolving_functions */ 504 505/** 506 * Create a promise object. 507 * 508 * See also: ES2015 25.4.3.1 509 * 510 * @return ecma value of the new promise object 511 * Returned value must be freed with ecma_free_value 512 */ 513ecma_value_t 514ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function or object */ 515 ecma_promise_executor_type_t type) /**< indicates the type of executor */ 516{ 517 JERRY_ASSERT (JERRY_CONTEXT (current_new_target) != NULL); 518 /* 3. */ 519 ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target), 520 ECMA_BUILTIN_ID_PROMISE_PROTOTYPE); 521 522 if (JERRY_UNLIKELY (proto_p == NULL)) 523 { 524 return ECMA_VALUE_ERROR; 525 } 526 527 /* Calling ecma_new_collection might trigger a GC call, so this 528 * allocation is performed before the object is constructed. */ 529 ecma_collection_t *reactions = ecma_new_collection (); 530 531 ecma_object_t *object_p = ecma_create_object (proto_p, 532 sizeof (ecma_promise_object_t), 533 ECMA_OBJECT_TYPE_CLASS); 534 ecma_deref_object (proto_p); 535 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 536 ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_PROMISE_UL; 537 /* 5 */ 538 ext_object_p->u.class_prop.extra_info = ECMA_PROMISE_IS_PENDING; 539 ext_object_p->u.class_prop.u.value = ECMA_VALUE_UNDEFINED; 540 ecma_promise_object_t *promise_object_p = (ecma_promise_object_t *) object_p; 541 542 /* 6-7. */ 543 promise_object_p->reactions = reactions; 544 /* 8. */ 545 ecma_promise_resolving_functions_t funcs; 546 ecma_promise_create_resolving_functions (object_p, &funcs, false); 547 548 ecma_string_t *str_resolve_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION); 549 ecma_string_t *str_reject_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION); 550 551 ecma_op_object_put (object_p, 552 str_resolve_p, 553 funcs.resolve, 554 false); 555 ecma_op_object_put (object_p, 556 str_reject_p, 557 funcs.reject, 558 false); 559 560 /* 9. */ 561 ecma_value_t completion = ECMA_VALUE_UNDEFINED; 562 563 if (type == ECMA_PROMISE_EXECUTOR_FUNCTION) 564 { 565 JERRY_ASSERT (ecma_op_is_callable (executor)); 566 567 ecma_value_t argv[] = { funcs.resolve, funcs.reject }; 568 completion = ecma_op_function_call (ecma_get_object_from_value (executor), 569 ECMA_VALUE_UNDEFINED, 570 argv, 571 2); 572 } 573 else if (type == ECMA_PROMISE_EXECUTOR_OBJECT) 574 { 575 JERRY_ASSERT (ecma_is_value_object (executor)); 576 577 completion = ecma_call_builtin_executor (ecma_get_object_from_value (executor), 578 funcs.resolve, 579 funcs.reject); 580 } 581 else 582 { 583 JERRY_ASSERT (type == ECMA_PROMISE_EXECUTOR_EMPTY); 584 JERRY_UNUSED (executor); 585 } 586 587 ecma_value_t status = ECMA_VALUE_EMPTY; 588 589 if (ECMA_IS_VALUE_ERROR (completion)) 590 { 591 /* 10.a. */ 592 completion = jcontext_take_exception (); 593 status = ecma_op_function_call (ecma_get_object_from_value (funcs.reject), 594 ECMA_VALUE_UNDEFINED, 595 &completion, 596 1); 597 } 598 599 ecma_promise_free_resolving_functions (&funcs); 600 ecma_free_value (completion); 601 602 /* 10.b. */ 603 if (ECMA_IS_VALUE_ERROR (status)) 604 { 605 ecma_deref_object (object_p); 606 return status; 607 } 608 609 /* 11. */ 610 ecma_free_value (status); 611 612 return ecma_make_object_value (object_p); 613} /* ecma_op_create_promise_object */ 614 615/** 616 * 25.4.1.5.1 GetCapabilitiesExecutor Functions 617 * 618 * Checks and sets a promiseCapability's resolve and reject properties. 619 * 620 * @return ECMA_VALUE_UNDEFINED or TypeError 621 * returned value must be freed with ecma_free_value 622 */ 623static ecma_value_t 624ecma_op_get_capabilities_executor_cb (const ecma_value_t function_obj, /**< the function itself */ 625 const ecma_value_t this_val, /**< this_arg of the function */ 626 const ecma_value_t args_p[], /**< argument list */ 627 const ecma_length_t args_count) /**< argument number */ 628{ 629 JERRY_UNUSED (this_val); 630 /* 1. */ 631 ecma_value_t capability = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (function_obj), 632 LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY); 633 JERRY_ASSERT (ecma_is_value_object (capability)); 634 635 /* 2. */ 636 ecma_object_t *capability_obj_p = ecma_get_object_from_value (capability); 637 638 /* 3. */ 639 ecma_value_t resolve = ecma_op_object_get_by_magic_id (capability_obj_p, 640 LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); 641 642 if (!ecma_is_value_undefined (resolve)) 643 { 644 ecma_free_value (resolve); 645 ecma_deref_object (capability_obj_p); 646 647 return ecma_raise_type_error (ECMA_ERR_MSG ("Resolve must be undefined")); 648 } 649 650 /* 4. */ 651 ecma_value_t reject = ecma_op_object_get_by_magic_id (capability_obj_p, 652 LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); 653 654 if (!ecma_is_value_undefined (reject)) 655 { 656 ecma_free_value (reject); 657 ecma_deref_object (capability_obj_p); 658 659 return ecma_raise_type_error (ECMA_ERR_MSG ("Reject must be undefined")); 660 } 661 662 /* 5. */ 663 ecma_op_object_put (capability_obj_p, 664 ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE), 665 args_count > 0 ? args_p[0] : ECMA_VALUE_UNDEFINED, 666 false); 667 668 /* 6. */ 669 ecma_op_object_put (capability_obj_p, 670 ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT), 671 args_count > 1 ? args_p[1] : ECMA_VALUE_UNDEFINED, 672 false); 673 674 ecma_deref_object (capability_obj_p); 675 676 /* 7. */ 677 return ECMA_VALUE_UNDEFINED; 678} /* ecma_op_get_capabilities_executor_cb */ 679 680/** 681 * Create a new PromiseCapability. 682 * 683 * See also: ES2015 25.4.1.5 684 * 685 * @return ecma value of the new PromiseCapability 686 * Returned value must be freed with ecma_free_value 687 */ 688ecma_value_t 689ecma_promise_new_capability (ecma_value_t constructor) 690{ 691 /* 1. */ 692 if (!ecma_is_constructor (constructor)) 693 { 694 return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid capability")); 695 } 696 697 ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor); 698 /* 3. */ 699 ecma_object_t *capability_p = ecma_op_create_object_object_noarg (); 700 701 ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY); 702 ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); 703 /* 4. */ 704 ecma_object_t *executor_p = ecma_op_create_external_function_object (ecma_op_get_capabilities_executor_cb); 705 ecma_value_t executor = ecma_make_object_value (executor_p); 706 /* 5. */ 707 ecma_op_object_put (executor_p, 708 capability_str_p, 709 ecma_make_object_value (capability_p), 710 false); 711 712 /* 6. */ 713 ecma_value_t promise = ecma_op_function_construct (constructor_obj_p, 714 constructor_obj_p, 715 &executor, 716 1); 717 ecma_deref_object (executor_p); 718 719 /* 7. */ 720 if (ECMA_IS_VALUE_ERROR (promise)) 721 { 722 ecma_deref_object (capability_p); 723 return promise; 724 } 725 726 /* 10. */ 727 ecma_op_object_put (capability_p, 728 promise_str_p, 729 promise, 730 false); 731 732 ecma_free_value (promise); 733 734 /* 8. */ 735 ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); 736 ecma_value_t resolve = ecma_op_object_get (capability_p, resolve_str_p); 737 738 if (!ecma_op_is_callable (resolve)) 739 { 740 ecma_free_value (resolve); 741 ecma_deref_object (capability_p); 742 return ecma_raise_type_error (ECMA_ERR_MSG ("'resolve' parameter must be callable.")); 743 } 744 745 ecma_free_value (resolve); 746 /* 9. */ 747 ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); 748 ecma_value_t reject = ecma_op_object_get (capability_p, reject_str_p); 749 750 if (!ecma_op_is_callable (reject)) 751 { 752 ecma_free_value (reject); 753 ecma_deref_object (capability_p); 754 return ecma_raise_type_error (ECMA_ERR_MSG ("'reject' parameter must be callable.")); 755 } 756 757 ecma_free_value (reject); 758 /* 11. */ 759 return ecma_make_object_value (capability_p); 760} /* ecma_promise_new_capability */ 761 762/** 763 * The common function for 'reject' and 'resolve'. 764 * 765 * @return ecma value 766 * Returned value must be freed with ecma_free_value. 767 */ 768ecma_value_t 769ecma_promise_reject_or_resolve (ecma_value_t this_arg, /**< "this" argument */ 770 ecma_value_t value, /**< rejected or resolved value */ 771 bool is_resolve) /**< the operation is resolve */ 772{ 773 if (!ecma_is_value_object (this_arg)) 774 { 775 return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object.")); 776 } 777 778 if (is_resolve 779 && ecma_is_value_object (value) 780 && ecma_is_promise (ecma_get_object_from_value (value))) 781 { 782 ecma_object_t *object_p = ecma_get_object_from_value (value); 783 ecma_value_t constructor = ecma_op_object_get_by_magic_id (object_p, LIT_MAGIC_STRING_CONSTRUCTOR); 784 785 if (ECMA_IS_VALUE_ERROR (constructor)) 786 { 787 return constructor; 788 } 789 790 /* The this_arg must be an object. */ 791 bool is_same_value = (constructor == this_arg); 792 ecma_free_value (constructor); 793 794 if (is_same_value) 795 { 796 return ecma_copy_value (value); 797 } 798 } 799 800 ecma_value_t capability = ecma_promise_new_capability (this_arg); 801 802 if (ECMA_IS_VALUE_ERROR (capability)) 803 { 804 return capability; 805 } 806 807 ecma_string_t *property_str_p; 808 809 if (is_resolve) 810 { 811 property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); 812 } 813 else 814 { 815 property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); 816 } 817 818 ecma_value_t func = ecma_op_object_get (ecma_get_object_from_value (capability), property_str_p); 819 820 ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (func), 821 ECMA_VALUE_UNDEFINED, 822 &value, 823 1); 824 825 ecma_free_value (func); 826 827 if (ECMA_IS_VALUE_ERROR (call_ret)) 828 { 829 return call_ret; 830 } 831 832 ecma_free_value (call_ret); 833 834 ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); 835 ecma_value_t promise = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p); 836 ecma_free_value (capability); 837 838 return promise; 839} /* ecma_promise_reject_or_resolve */ 840 841/** 842 * It performs the "then" operation on promiFulfilled 843 * and onRejected as its settlement actions. 844 * 845 * See also: 25.4.5.3.1 846 * 847 * @return ecma value of the new promise object 848 * Returned value must be freed with ecma_free_value 849 */ 850static ecma_value_t 851ecma_promise_do_then (ecma_value_t promise, /**< the promise which call 'then' */ 852 ecma_value_t on_fulfilled, /**< on_fulfilled function */ 853 ecma_value_t on_rejected, /**< on_rejected function */ 854 ecma_value_t result_capability) /**< promise capability */ 855{ 856 ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); 857 858 /* 3. boolean true indicates "indentity" */ 859 if (!ecma_op_is_callable (on_fulfilled)) 860 { 861 on_fulfilled = ECMA_VALUE_TRUE; 862 } 863 864 /* 4. boolean false indicates "thrower" */ 865 if (!ecma_op_is_callable (on_rejected)) 866 { 867 on_rejected = ECMA_VALUE_FALSE; 868 } 869 870 ecma_object_t *promise_obj_p = ecma_get_object_from_value (promise); 871 ecma_promise_object_t *promise_p = (ecma_promise_object_t *) promise_obj_p; 872 873 uint16_t flags = ecma_promise_get_flags (promise_obj_p); 874 875 if (flags & ECMA_PROMISE_IS_PENDING) 876 { 877 /* 7. */ 878 ecma_value_t capability_with_tag; 879 ECMA_SET_NON_NULL_POINTER_TAG (capability_with_tag, ecma_get_object_from_value (result_capability), 0); 880 881 if (on_fulfilled != ECMA_VALUE_TRUE) 882 { 883 ECMA_SET_FIRST_BIT_TO_POINTER_TAG (capability_with_tag); 884 } 885 886 if (on_rejected != ECMA_VALUE_FALSE) 887 { 888 ECMA_SET_SECOND_BIT_TO_POINTER_TAG (capability_with_tag); 889 } 890 891 ecma_collection_push_back (promise_p->reactions, capability_with_tag); 892 893 if (on_fulfilled != ECMA_VALUE_TRUE) 894 { 895 ecma_collection_push_back (promise_p->reactions, on_fulfilled); 896 } 897 898 if (on_rejected != ECMA_VALUE_FALSE) 899 { 900 ecma_collection_push_back (promise_p->reactions, on_rejected); 901 } 902 } 903 else if (flags & ECMA_PROMISE_IS_FULFILLED) 904 { 905 /* 8. */ 906 ecma_value_t value = ecma_promise_get_result (promise_obj_p); 907 ecma_enqueue_promise_reaction_job (result_capability, on_fulfilled, value); 908 ecma_free_value (value); 909 } 910 else 911 { 912 /* 9. */ 913 ecma_value_t reason = ecma_promise_get_result (promise_obj_p); 914 ecma_enqueue_promise_reaction_job (result_capability, on_rejected, reason); 915 ecma_free_value (reason); 916 } 917 918 /* 10. */ 919 return ecma_op_object_get (ecma_get_object_from_value (result_capability), promise_str_p); 920} /* ecma_promise_do_then */ 921 922/** 923 * The common function for ecma_builtin_promise_prototype_then 924 * and ecma_builtin_promise_prototype_catch. 925 * 926 * @return ecma value of a new promise object. 927 * Returned value must be freed with ecma_free_value. 928 */ 929ecma_value_t 930ecma_promise_then (ecma_value_t promise, /**< the promise which call 'then' */ 931 ecma_value_t on_fulfilled, /**< on_fulfilled function */ 932 ecma_value_t on_rejected) /**< on_rejected function */ 933{ 934 if (!ecma_is_value_object (promise)) 935 { 936 return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object.")); 937 } 938 939 ecma_object_t *obj = ecma_get_object_from_value (promise); 940 941 if (!ecma_is_promise (obj)) 942 { 943 return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a Promise.")); 944 } 945 946 ecma_value_t species = ecma_op_species_constructor (obj, ECMA_BUILTIN_ID_PROMISE); 947 if (ECMA_IS_VALUE_ERROR (species)) 948 { 949 return species; 950 } 951 952 ecma_value_t result_capability = ecma_promise_new_capability (species); 953 ecma_free_value (species); 954 955 if (ECMA_IS_VALUE_ERROR (result_capability)) 956 { 957 return result_capability; 958 } 959 960 ecma_value_t ret = ecma_promise_do_then (promise, on_fulfilled, on_rejected, result_capability); 961 ecma_free_value (result_capability); 962 963 return ret; 964} /* ecma_promise_then */ 965 966/** 967 * @} 968 * @} 969 */ 970#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ 971