/* Copyright JS Foundation and other contributors, http://js.foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecma-boolean-object.h" #include "ecma-builtins.h" #include "ecma-exceptions.h" #include "ecma-function-object.h" #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-jobqueue.h" #include "ecma-objects.h" #include "ecma-objects-general.h" #include "ecma-promise-object.h" #ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN /** \addtogroup ecma ECMA * @{ * * \addtogroup ecmapromiseobject ECMA Promise object related routines * @{ */ /** * Check if an object is promise. * * @return true - if the object is a promise. * false - otherwise. */ inline bool __attr_always_inline___ ecma_is_promise (ecma_object_t *obj_p) /**< points to object */ { return ecma_object_class_is (obj_p, LIT_MAGIC_STRING_PROMISE_UL); } /* ecma_is_promise */ /** * Get the result of the promise. * * @return ecma value of the promise result. * Returned value must be freed with ecma_free_value */ inline ecma_value_t ecma_promise_get_result (ecma_object_t *obj_p) /**< points to promise object */ { JERRY_ASSERT (ecma_is_promise (obj_p)); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; return ecma_copy_value (ext_object_p->u.class_prop.u.value); } /* ecma_promise_get_result */ /** * Set the PromiseResult of promise. */ inline void __attr_always_inline___ ecma_promise_set_result (ecma_object_t *obj_p, /**< points to promise object */ ecma_value_t result) /**< the result value */ { JERRY_ASSERT (ecma_is_promise (obj_p)); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; JERRY_ASSERT (ext_object_p->u.class_prop.u.value == ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED)); ext_object_p->u.class_prop.u.value = result; } /* ecma_promise_set_result */ /** * Get the PromiseState of promise. * * @return the state's enum value */ inline uint8_t __attr_always_inline___ ecma_promise_get_state (ecma_object_t *obj_p) /**< points to promise object */ { JERRY_ASSERT (ecma_is_promise (obj_p)); return ((ecma_promise_object_t *) obj_p)->state; } /* ecma_promise_get_state */ /** * Set the PromiseState of promise. */ inline void __attr_always_inline___ ecma_promise_set_state (ecma_object_t *obj_p, /**< points to promise object */ uint8_t state) /**< the state */ { JERRY_ASSERT (ecma_is_promise (obj_p)); ((ecma_promise_object_t *) obj_p)->state = state; } /* ecma_promise_set_state */ /** * Get the bool value of alreadyResolved. * * @return bool value of alreadyResolved. */ static bool ecma_get_already_resolved_bool_value (ecma_value_t already_resolved) /**< the alreadyResolved */ { JERRY_ASSERT (ecma_is_value_object (already_resolved)); ecma_object_t *already_resolved_p = ecma_get_object_from_value (already_resolved); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) already_resolved_p; JERRY_ASSERT (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_BOOLEAN_UL); return ext_object_p->u.class_prop.u.value == ecma_make_boolean_value (true); } /* ecma_get_already_resolved_bool_value */ /** * Set the value of alreadyResolved. */ static void ecma_set_already_resolved_value (ecma_value_t already_resolved, /**< the alreadyResolved */ bool value) /**< the value to set */ { JERRY_ASSERT (ecma_is_value_object (already_resolved)); ecma_object_t *already_resolved_p = ecma_get_object_from_value (already_resolved); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) already_resolved_p; JERRY_ASSERT (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_BOOLEAN_UL); ext_object_p->u.class_prop.u.value = ecma_make_boolean_value (value); } /* ecma_set_already_resolved_value */ /** * Take a collection of Reactions and enqueue a new PromiseReactionJob for each Reaction. * * See also: ES2015 25.4.1.8 */ static void ecma_promise_trigger_reactions (ecma_collection_header_t *reactions, /**< lists of reactions */ ecma_value_t value) /**< value for resolve or reject */ { ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, reactions); while (ecma_collection_iterator_next (&iter)) { ecma_enqueue_promise_reaction_job (*iter.current_value_p, value); } ecma_free_values_collection (reactions, false); } /* ecma_promise_trigger_reactions */ /** * Reject a Promise with a reason. * * See also: ES2015 25.4.1.7 */ static void ecma_reject_promise (ecma_value_t promise, /**< promise */ ecma_value_t reason) /**< reason for reject */ { ecma_object_t *obj_p = ecma_get_object_from_value (promise); JERRY_ASSERT (ecma_promise_get_state (obj_p) == ECMA_PROMISE_STATE_PENDING); ecma_promise_set_state (obj_p, ECMA_PROMISE_STATE_REJECTED); ecma_promise_set_result (obj_p, ecma_copy_value_if_not_object (reason)); ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p; ecma_promise_trigger_reactions (promise_p->reject_reactions, reason); promise_p->reject_reactions = ecma_new_values_collection (NULL, 0, false); /* Free all fullfill_reactions. */ ecma_free_values_collection (promise_p->fulfill_reactions, false); promise_p->fulfill_reactions = ecma_new_values_collection (NULL, 0, false); } /* ecma_reject_promise */ /** * Fulfill a Promise with a value. * * See also: ES2015 25.4.1.4 */ static void ecma_fulfill_promise (ecma_value_t promise, /**< promise */ ecma_value_t value) /**< fulfilled value */ { ecma_object_t *obj_p = ecma_get_object_from_value (promise); JERRY_ASSERT (ecma_promise_get_state (obj_p) == ECMA_PROMISE_STATE_PENDING); ecma_promise_set_state (obj_p, ECMA_PROMISE_STATE_FULFILLED); ecma_promise_set_result (obj_p, ecma_copy_value_if_not_object (value)); ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p; ecma_promise_trigger_reactions (promise_p->fulfill_reactions, value); promise_p->fulfill_reactions = ecma_new_values_collection (NULL, 0, false); /* Free all reject_reactions. */ ecma_free_values_collection (promise_p->reject_reactions, false); promise_p->reject_reactions = ecma_new_values_collection (NULL, 0, false); } /* ecma_fulfill_promise */ /** * Native handler for Promise Reject Function. * * See also: ES2015 25.4.1.3.1 * * @return ecma value of undefined. */ static ecma_value_t ecma_promise_reject_handler (const ecma_value_t function, /**< the function itself */ const ecma_value_t this, /**< this_arg of the function */ const ecma_value_t argv[], /**< argument list */ const ecma_length_t argc) /**< argument number */ { JERRY_UNUSED (this); JERRY_UNUSED (argc); ecma_string_t str_promise; ecma_string_t str_already_resolved; ecma_init_ecma_magic_string (&str_promise, LIT_INTERNAL_MAGIC_STRING_PROMISE); ecma_init_ecma_magic_string (&str_already_resolved, LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); ecma_object_t *function_p = ecma_get_object_from_value (function); /* 2. */ ecma_value_t promise = ecma_op_object_get (function_p, &str_promise); /* 1. */ JERRY_ASSERT (ecma_is_promise (ecma_get_object_from_value (promise))); /* 3. */ ecma_value_t already_resolved = ecma_op_object_get (function_p, &str_already_resolved); /* 4. */ if (ecma_get_already_resolved_bool_value (already_resolved)) { ecma_free_value (promise); ecma_free_value (already_resolved); return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } /* 5. */ ecma_set_already_resolved_value (already_resolved, true); /* 6. */ ecma_reject_promise (promise, argv[0]); ecma_free_value (promise); ecma_free_value (already_resolved); return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } /* ecma_promise_reject_handler */ /** * Native handler for Promise Resolve Function. * * See also: ES2015 25.4.1.3.2 * * @return ecma value of undefined. */ static ecma_value_t ecma_promise_resolve_handler (const ecma_value_t function, /**< the function itself */ const ecma_value_t this, /**< this_arg of the function */ const ecma_value_t argv[], /**< argument list */ const ecma_length_t argc) /**< argument number */ { JERRY_UNUSED (this); JERRY_UNUSED (argc); ecma_string_t str_promise; ecma_string_t str_already_resolved; ecma_init_ecma_magic_string (&str_promise, LIT_INTERNAL_MAGIC_STRING_PROMISE); ecma_init_ecma_magic_string (&str_already_resolved, LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); ecma_object_t *function_p = ecma_get_object_from_value (function); /* 2. */ ecma_value_t promise = ecma_op_object_get (function_p, &str_promise); /* 1. */ JERRY_ASSERT (ecma_is_promise (ecma_get_object_from_value (promise))); /* 3. */ ecma_value_t already_resolved = ecma_op_object_get (function_p, &str_already_resolved); /* 4. */ if (ecma_get_already_resolved_bool_value (already_resolved)) { goto end_of_resolve_function; } /* 5. */ ecma_set_already_resolved_value (already_resolved, true); /* 6. */ if (argv[0] == promise) { ecma_object_t *error_p = ecma_new_standard_error (ECMA_ERROR_TYPE); ecma_reject_promise (promise, ecma_make_object_value (error_p)); ecma_deref_object (error_p); goto end_of_resolve_function; } /* 7. */ if (!ecma_is_value_object (argv[0])) { ecma_fulfill_promise (promise, argv[0]); goto end_of_resolve_function; } /* 8. */ ecma_string_t *str_then = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_THEN); ecma_value_t then = ecma_op_object_get (ecma_get_object_from_value (argv[0]), str_then); if (ECMA_IS_VALUE_ERROR (then)) { /* 9. */ ecma_reject_promise (promise, then); } else if (!ecma_op_is_callable (then)) { /* 11 .*/ ecma_fulfill_promise (promise, argv[0]); } else { /* 12 */ ecma_enqueue_promise_resolve_thenable_job (promise, argv[0], then); } ecma_deref_ecma_string (str_then); ecma_free_value (then); end_of_resolve_function: ecma_free_value (promise); ecma_free_value (already_resolved); return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } /* ecma_promise_resolve_handler */ /** * CapabilityiesExecutor Function. * * See also: ES2015 25.4.1.5.1 * * @return ecma value of undefined or typerror. * Returned value must be freed with ecma_free_value */ static ecma_value_t ecma_call_builtin_executor (ecma_object_t *executor_p, /**< the executor object */ ecma_value_t resolve_func, /**< the resolve function */ ecma_value_t reject_func) /**< the reject function */ { ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); ecma_string_t *str_resolve = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); ecma_string_t *str_reject = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); /* 2. */ ecma_value_t capability = ecma_op_object_get (executor_p, str_capability); /* 3. */ ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), str_resolve); if (resolve != ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED)) { ecma_free_value (resolve); ecma_free_value (capability); ecma_deref_ecma_string (str_capability); ecma_deref_ecma_string (str_resolve); ecma_deref_ecma_string (str_reject); return ecma_raise_type_error (ECMA_ERR_MSG ("'resolve' function should be undefined.")); } /* 4. */ ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), str_reject); if (reject != ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED)) { ecma_free_value (reject); ecma_free_value (capability); ecma_deref_ecma_string (str_capability); ecma_deref_ecma_string (str_resolve); ecma_deref_ecma_string (str_reject); return ecma_raise_type_error (ECMA_ERR_MSG ("'reject' function should be undefined.")); } /* 5. */ ecma_op_object_put (ecma_get_object_from_value (capability), str_resolve, resolve_func, false); /* 6. */ ecma_op_object_put (ecma_get_object_from_value (capability), str_reject, reject_func, false); ecma_free_value (capability); ecma_deref_ecma_string (str_capability); ecma_deref_ecma_string (str_resolve); ecma_deref_ecma_string (str_reject); return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } /* ecma_call_builtin_executor */ /** * Create a PromiseCreateResovingFucntions. * * See also: ES2015 25.4.1.3 * * @return pointer to the resolving functions */ static ecma_promise_resolving_functions_t * ecma_promise_create_resolving_functions (ecma_object_t *object_p) /**< the promise object */ { /* 1. */ ecma_value_t already_resolved = ecma_op_create_boolean_object (ecma_make_boolean_value (false)); ecma_string_t str_promise; ecma_string_t str_already_resolved; ecma_init_ecma_magic_string (&str_promise, LIT_INTERNAL_MAGIC_STRING_PROMISE); ecma_init_ecma_magic_string (&str_already_resolved, LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); /* 2. */ ecma_object_t *resolve_p; resolve_p = ecma_op_create_external_function_object (ecma_promise_resolve_handler); /* 3. */ ecma_op_object_put (resolve_p, &str_promise, ecma_make_object_value (object_p), false); /* 4. */ ecma_op_object_put (resolve_p, &str_already_resolved, already_resolved, false); /* 5. */ ecma_object_t *reject_p; reject_p = ecma_op_create_external_function_object (ecma_promise_reject_handler); /* 6. */ ecma_op_object_put (reject_p, &str_promise, ecma_make_object_value (object_p), false); /* 7. */ ecma_op_object_put (reject_p, &str_already_resolved, already_resolved, false); /* 8. */ ecma_promise_resolving_functions_t *funcs = jmem_heap_alloc_block (sizeof (ecma_promise_resolving_functions_t)); funcs->resolve = ecma_make_object_value (resolve_p); funcs->reject = ecma_make_object_value (reject_p); ecma_free_value (already_resolved); return funcs; } /* ecma_promise_create_resolving_functions */ /** * Free the heap and the member of the resolving functions. */ static void ecma_promise_free_resolving_functions (ecma_promise_resolving_functions_t *funcs) /**< points to the functions */ { ecma_free_value (funcs->resolve); ecma_free_value (funcs->reject); jmem_heap_free_block (funcs, sizeof (ecma_promise_resolving_functions_t)); } /* ecma_promise_free_resolving_functions */ /** * Create a promise object. * * See also: ES2015 25.4.3.1 * * @return ecma value of the new promise object * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function or object */ ecma_promise_executor_type_t type) /**< indicates the type of executor */ { /* 3. */ ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_PROMISE_PROTOTYPE); ecma_object_t *object_p = ecma_create_object (prototype_obj_p, sizeof (ecma_promise_object_t), ECMA_OBJECT_TYPE_CLASS); ecma_deref_object (prototype_obj_p); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_PROMISE_UL; ext_object_p->u.class_prop.u.value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); ecma_promise_object_t *promise_object_p = (ecma_promise_object_t *) object_p; promise_object_p->fulfill_reactions = NULL; promise_object_p->reject_reactions = NULL; /* 5 */ ecma_promise_set_state (object_p, ECMA_PROMISE_STATE_PENDING); /* 6-7. */ promise_object_p->fulfill_reactions = ecma_new_values_collection (NULL, 0, false); promise_object_p->reject_reactions = ecma_new_values_collection (NULL, 0, false); /* 8. */ ecma_promise_resolving_functions_t *funcs = ecma_promise_create_resolving_functions (object_p); ecma_string_t str_resolve, str_reject; ecma_init_ecma_magic_string (&str_resolve, LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION); ecma_init_ecma_magic_string (&str_reject, LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION); ecma_op_object_put (object_p, &str_resolve, funcs->resolve, false); ecma_op_object_put (object_p, &str_reject, funcs->reject, false); /* 9. */ ecma_value_t completion = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); if (type == ECMA_PROMISE_EXECUTOR_FUNCTION) { JERRY_ASSERT (ecma_op_is_callable (executor)); ecma_value_t argv[] = { funcs->resolve, funcs->reject }; completion = ecma_op_function_call (ecma_get_object_from_value (executor), ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), argv, 2); } else if (type == ECMA_PROMISE_EXECUTOR_OBJECT) { JERRY_ASSERT (ecma_is_value_object (executor)); completion = ecma_call_builtin_executor (ecma_get_object_from_value (executor), funcs->resolve, funcs->reject); } else { JERRY_ASSERT (type == ECMA_PROMISE_EXECUTOR_EMPTY); JERRY_UNUSED (executor); } ecma_value_t status = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); if (ECMA_IS_VALUE_ERROR (completion)) { /* 10.a. */ completion = ecma_get_value_from_error_value (completion); status = ecma_op_function_call (ecma_get_object_from_value (funcs->reject), ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), &completion, 1); } ecma_promise_free_resolving_functions (funcs); ecma_free_value (completion); /* 10.b. */ if (ECMA_IS_VALUE_ERROR (status)) { ecma_deref_object (object_p); return status; } /* 11. */ ecma_free_value (status); return ecma_make_object_value (object_p); } /* ecma_op_create_promise_object */ /** * Create a new PromiseCapability. * * See also: ES2015 25.4.1.5 * * @return ecma value of the new PromiseCapability * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_promise_new_capability (void) { /* 3. */ ecma_object_t *capability_p = ecma_op_create_object_object_noarg (); ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); ecma_string_t *str_promise = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); /* 4. */ ecma_object_t *executor_p; executor_p = ecma_op_create_object_object_noarg (); ecma_value_t executor = ecma_make_object_value (executor_p); /* 5. */ ecma_op_object_put (executor_p, str_capability, ecma_make_object_value (capability_p), false); /* 6. */ ecma_value_t promise = ecma_op_create_promise_object (executor, ECMA_PROMISE_EXECUTOR_OBJECT); /* 10. */ ecma_op_object_put (capability_p, str_promise, promise, false); ecma_deref_object (executor_p); ecma_deref_ecma_string (str_promise); ecma_deref_ecma_string (str_capability); /* 7. */ if (ECMA_IS_VALUE_ERROR (promise)) { ecma_free_value (promise); ecma_deref_object (capability_p); return promise; } ecma_free_value (promise); /* 8. */ ecma_string_t *str_resolve = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); ecma_value_t resolve = ecma_op_object_get (capability_p, str_resolve); ecma_deref_ecma_string (str_resolve); if (!ecma_op_is_callable (resolve)) { ecma_free_value (resolve); ecma_deref_object (capability_p); return ecma_raise_type_error (ECMA_ERR_MSG ("'resolve' parameter must be callable.")); } ecma_free_value (resolve); /* 9. */ ecma_string_t *str_reject = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); ecma_value_t reject = ecma_op_object_get (capability_p, str_reject); ecma_deref_ecma_string (str_reject); if (!ecma_op_is_callable (reject)) { ecma_free_value (reject); ecma_deref_object (capability_p); return ecma_raise_type_error (ECMA_ERR_MSG ("'reject' parameter must be callable.")); } ecma_free_value (reject); /* 11. */ return ecma_make_object_value (capability_p); } /* ecma_promise_new_capability */ /** * It performs the "then" operation on promiFulfilled * and onRejected as its settlement actions. * * See also: 25.4.5.3.1 * * @return ecma value of the new promise object * Returned value must be freed with ecma_free_value */ static ecma_value_t ecma_promise_do_then (ecma_value_t promise, /**< the promise which call 'then' */ ecma_value_t on_fulfilled, /**< on_fulfilled function */ ecma_value_t on_rejected, /**< on_rejected function */ ecma_value_t result_capability) /**< promise capability */ { ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); ecma_string_t *str_handler = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_HANDLER); ecma_string_t *str_promise = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); /* 3. boolean true indicates "indentity" */ if (!ecma_op_is_callable (on_fulfilled)) { on_fulfilled = ecma_make_boolean_value (true); } /* 4. boolean false indicates "thrower" */ if (!ecma_op_is_callable (on_rejected)) { on_rejected = ecma_make_boolean_value (false); } /* 5-6. */ ecma_object_t *fulfill_reaction_p = ecma_op_create_object_object_noarg (); ecma_object_t *reject_reaction_p = ecma_op_create_object_object_noarg (); ecma_op_object_put (fulfill_reaction_p, str_capability, result_capability, false); ecma_op_object_put (fulfill_reaction_p, str_handler, on_fulfilled, false); ecma_op_object_put (reject_reaction_p, str_capability, result_capability, false); ecma_op_object_put (reject_reaction_p, str_handler, on_rejected, false); ecma_object_t *obj_p = ecma_get_object_from_value (promise); ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p; if (ecma_promise_get_state (obj_p) == ECMA_PROMISE_STATE_PENDING) { /* 7. */ ecma_append_to_values_collection (promise_p->fulfill_reactions, ecma_make_object_value (fulfill_reaction_p), false); ecma_append_to_values_collection (promise_p->reject_reactions, ecma_make_object_value (reject_reaction_p), false); } else if (ecma_promise_get_state (obj_p) == ECMA_PROMISE_STATE_FULFILLED) { /* 8. */ ecma_value_t value = ecma_promise_get_result (obj_p); ecma_enqueue_promise_reaction_job (ecma_make_object_value (fulfill_reaction_p), value); ecma_free_value (value); } else { /* 9. */ ecma_value_t reason = ecma_promise_get_result (obj_p); ecma_enqueue_promise_reaction_job (ecma_make_object_value (reject_reaction_p), reason); ecma_free_value (reason); } /* 10. */ ecma_value_t ret = ecma_op_object_get (ecma_get_object_from_value (result_capability), str_promise); ecma_deref_object (fulfill_reaction_p); ecma_deref_object (reject_reaction_p); ecma_deref_ecma_string (str_capability); ecma_deref_ecma_string (str_handler); ecma_deref_ecma_string (str_promise); return ret; } /* ecma_promise_do_then */ /** * The common function for ecma_builtin_promise_prototype_then * and ecma_builtin_promise_prototype_catch. * * @return ecma value of a new promise object. * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_promise_then (ecma_value_t promise, /**< the promise which call 'then' */ ecma_value_t on_fulfilled, /**< on_fulfilled function */ ecma_value_t on_rejected) /**< on_rejected function */ { ecma_object_t *obj = ecma_get_object_from_value (promise); if (!ecma_is_promise (obj)) { return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a Promise.")); } ecma_value_t result_capability = ecma_promise_new_capability (); if (ECMA_IS_VALUE_ERROR (result_capability)) { return result_capability; } ecma_value_t ret = ecma_promise_do_then (promise, on_fulfilled, on_rejected, result_capability); ecma_free_value (result_capability); return ret; } /* ecma_promise_then */ /** * @} * @} */ #endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */