mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Support iterable objects in Promise.all and Promise.race functions (#3496)
JerryScript-DCO-1.0-Signed-off-by: Daniel Balla dballa@inf.u-szeged.hu
This commit is contained in:
parent
c407e8a04c
commit
1725e014b8
@ -19,6 +19,7 @@
|
||||
#include "ecma-function-object.h"
|
||||
#include "ecma-gc.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-iterator-object.h"
|
||||
#include "ecma-number-object.h"
|
||||
#include "ecma-promise-object.h"
|
||||
#include "jcontext.h"
|
||||
@ -52,12 +53,17 @@
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
inline static ecma_value_t
|
||||
ecma_builtin_promise_reject_abrupt (ecma_value_t capability) /**< reject description */
|
||||
ecma_builtin_promise_reject_abrupt (ecma_value_t value, /**< value */
|
||||
ecma_value_t capability) /**< capability */
|
||||
{
|
||||
ecma_raise_type_error (ECMA_ERR_MSG ("Second argument is not an array."));
|
||||
if (!ECMA_IS_VALUE_ERROR (value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
ecma_value_t reason = jcontext_take_exception ();
|
||||
ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
|
||||
ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), reject_str_p);
|
||||
ecma_value_t reject = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (capability),
|
||||
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
|
||||
|
||||
ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (reject),
|
||||
ECMA_VALUE_UNDEFINED,
|
||||
@ -73,10 +79,8 @@ ecma_builtin_promise_reject_abrupt (ecma_value_t capability) /**< reject descrip
|
||||
|
||||
ecma_free_value (call_ret);
|
||||
|
||||
ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
|
||||
ecma_value_t promise_new = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p);
|
||||
|
||||
return promise_new;
|
||||
return ecma_op_object_get_by_magic_id (ecma_get_object_from_value (capability),
|
||||
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
|
||||
} /* ecma_builtin_promise_reject_abrupt */
|
||||
|
||||
/**
|
||||
@ -121,82 +125,81 @@ ecma_builtin_promise_resolve (ecma_value_t this_arg, /**< 'this' argument */
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
inline static ecma_value_t
|
||||
ecma_builtin_promise_do_race (ecma_value_t array, /**< the array for race */
|
||||
ecma_value_t capability, /**< PromiseCapability record */
|
||||
ecma_value_t ctor) /**< the caller of Promise.race */
|
||||
ecma_builtin_promise_perform_race (ecma_value_t iterator, /**< the iterator for race */
|
||||
ecma_value_t capability, /**< PromiseCapability record */
|
||||
ecma_value_t ctor, /**< Constructor value */
|
||||
bool *done_p) /**< [out] iteratorRecord[[done]] */
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_value_object (capability)
|
||||
&& ecma_is_value_object (array)
|
||||
&& ecma_is_value_object (ctor));
|
||||
JERRY_ASSERT (ecma_get_object_builtin_id (ecma_get_object_from_value (ctor)) == ECMA_BUILTIN_ID_PROMISE);
|
||||
JERRY_ASSERT (ecma_get_object_type (ecma_get_object_from_value (array)) == ECMA_OBJECT_TYPE_ARRAY);
|
||||
JERRY_ASSERT (ecma_is_value_object (iterator)
|
||||
&& ecma_is_value_object (capability));
|
||||
|
||||
ecma_value_t ret = ECMA_VALUE_EMPTY;
|
||||
ecma_object_t *array_p = ecma_get_object_from_value (array);
|
||||
ecma_extended_object_t *ext_array_p = (ecma_extended_object_t *) array_p;
|
||||
|
||||
ecma_length_t len = ext_array_p->u.array.length;
|
||||
|
||||
ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
|
||||
ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
|
||||
ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
|
||||
|
||||
ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability),
|
||||
resolve_str_p);
|
||||
ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability),
|
||||
reject_str_p);
|
||||
|
||||
for (ecma_length_t index = 0; index <= len; index++)
|
||||
ecma_object_t *capability_obj_p = ecma_get_object_from_value (capability);
|
||||
/* 1. */
|
||||
while (true)
|
||||
{
|
||||
/* b-d. */
|
||||
if (index == len)
|
||||
/* a. */
|
||||
ecma_value_t next = ecma_op_iterator_step (iterator);
|
||||
/* b, c. */
|
||||
if (ECMA_IS_VALUE_ERROR (next))
|
||||
{
|
||||
ret = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p);
|
||||
break;
|
||||
*done_p = true;
|
||||
return next;
|
||||
}
|
||||
|
||||
/* d. */
|
||||
if (ecma_is_value_false (next))
|
||||
{
|
||||
/* i. */
|
||||
*done_p = true;
|
||||
/* ii. */
|
||||
return ecma_op_object_get_by_magic_id (capability_obj_p, LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
|
||||
}
|
||||
|
||||
/* e. */
|
||||
ecma_value_t array_item = ecma_op_object_get_by_uint32_index (array_p, index);
|
||||
ecma_value_t next_val = ecma_op_iterator_value (next);
|
||||
ecma_free_value (next);
|
||||
|
||||
/* f. */
|
||||
if (ECMA_IS_VALUE_ERROR (array_item))
|
||||
/* f, g. */
|
||||
if (ECMA_IS_VALUE_ERROR (next_val))
|
||||
{
|
||||
ret = array_item;
|
||||
break;
|
||||
*done_p = true;
|
||||
return next_val;
|
||||
}
|
||||
|
||||
/* h. */
|
||||
ecma_value_t next_promise = ecma_builtin_promise_resolve (ctor, array_item);
|
||||
ecma_free_value (array_item);
|
||||
ecma_value_t next_promise = ecma_op_invoke_by_magic_id (ctor, LIT_MAGIC_STRING_RESOLVE, &next_val, 1);
|
||||
ecma_free_value (next_val);
|
||||
|
||||
/* i. */
|
||||
if (ECMA_IS_VALUE_ERROR (next_promise))
|
||||
{
|
||||
ret = next_promise;
|
||||
break;
|
||||
return next_promise;
|
||||
}
|
||||
|
||||
/* j. */
|
||||
ecma_value_t then_result = ecma_promise_then (next_promise, resolve, reject);
|
||||
ecma_value_t args[2];
|
||||
args[0] = ecma_op_object_get_by_magic_id (capability_obj_p, LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
|
||||
args[1] = ecma_op_object_get_by_magic_id (capability_obj_p, LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
|
||||
ecma_value_t result = ecma_op_invoke_by_magic_id (next_promise, LIT_MAGIC_STRING_THEN, args, 2);
|
||||
ecma_free_value (next_promise);
|
||||
|
||||
/* k. */
|
||||
if (ECMA_IS_VALUE_ERROR (then_result))
|
||||
for (uint8_t i = 0; i < 2; i++)
|
||||
{
|
||||
ret = then_result;
|
||||
break;
|
||||
ecma_free_value (args[i]);
|
||||
}
|
||||
|
||||
ecma_free_value (then_result);
|
||||
/* k. */
|
||||
if (ECMA_IS_VALUE_ERROR (result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
ecma_free_value (result);
|
||||
}
|
||||
|
||||
ecma_free_value (reject);
|
||||
ecma_free_value (resolve);
|
||||
|
||||
JERRY_ASSERT (!ecma_is_value_empty (ret));
|
||||
|
||||
return ret;
|
||||
} /* ecma_builtin_promise_do_race */
|
||||
JERRY_UNREACHABLE ();
|
||||
} /* ecma_builtin_promise_perform_race */
|
||||
|
||||
/**
|
||||
* Helper function for increase or decrease the remaining count.
|
||||
@ -226,7 +229,6 @@ ecma_builtin_promise_remaining_inc_or_dec (ecma_value_t remaining, /**< the rema
|
||||
{
|
||||
current--;
|
||||
}
|
||||
|
||||
ext_object_p->u.class_prop.u.value = ecma_make_uint32_value (current);
|
||||
|
||||
return current;
|
||||
@ -249,7 +251,6 @@ ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function
|
||||
JERRY_UNUSED (this);
|
||||
JERRY_UNUSED (argc);
|
||||
|
||||
ecma_value_t ret = ECMA_VALUE_UNDEFINED;
|
||||
/* 1. */
|
||||
ecma_object_t *function_p = ecma_get_object_from_value (function);
|
||||
ecma_string_t *already_called_str_p;
|
||||
@ -261,8 +262,7 @@ ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function
|
||||
/* 2. */
|
||||
if (ecma_is_value_true (already_called))
|
||||
{
|
||||
ecma_fast_free_value (already_called);
|
||||
return ret;
|
||||
return ECMA_VALUE_UNDEFINED;
|
||||
}
|
||||
|
||||
/* 3. */
|
||||
@ -278,37 +278,36 @@ ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function
|
||||
|
||||
/* 4-7. */
|
||||
ecma_value_t index_val = ecma_op_object_get (function_p, str_index_p);
|
||||
ecma_value_t value_array = ecma_op_object_get (function_p, str_value_p);
|
||||
ecma_value_t values_array = ecma_op_object_get (function_p, str_value_p);
|
||||
ecma_value_t capability = ecma_op_object_get (function_p, str_capability_p);
|
||||
ecma_value_t remaining = ecma_op_object_get (function_p, str_remaining_p);
|
||||
|
||||
JERRY_ASSERT (ecma_is_value_integer_number (index_val));
|
||||
|
||||
/* 8. */
|
||||
ecma_op_object_put_by_uint32_index (ecma_get_object_from_value (value_array),
|
||||
ecma_op_object_put_by_uint32_index (ecma_get_object_from_value (values_array),
|
||||
(uint32_t) ecma_get_integer_from_value (index_val),
|
||||
argv[0],
|
||||
false);
|
||||
|
||||
|
||||
/* 9-10. */
|
||||
ecma_value_t ret = ECMA_VALUE_UNDEFINED;
|
||||
if (ecma_builtin_promise_remaining_inc_or_dec (remaining, false) == 0)
|
||||
{
|
||||
ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
|
||||
ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), resolve_str_p);
|
||||
|
||||
ecma_value_t resolve = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (capability),
|
||||
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
|
||||
ret = ecma_op_function_call (ecma_get_object_from_value (resolve),
|
||||
ECMA_VALUE_UNDEFINED,
|
||||
&value_array,
|
||||
&values_array,
|
||||
1);
|
||||
ecma_free_value (resolve);
|
||||
}
|
||||
|
||||
ecma_free_value (remaining);
|
||||
ecma_free_value (capability);
|
||||
ecma_free_value (value_array);
|
||||
ecma_fast_free_value (index_val);
|
||||
ecma_fast_free_value (already_called);
|
||||
ecma_free_value (values_array);
|
||||
ecma_free_value (index_val);
|
||||
|
||||
return ret;
|
||||
} /* ecma_builtin_promise_all_handler */
|
||||
@ -323,25 +322,25 @@ ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
inline static ecma_value_t
|
||||
ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */
|
||||
ecma_value_t capability, /**< PromiseCapability record */
|
||||
ecma_value_t ctor) /**< the caller of Promise.race */
|
||||
ecma_builtin_promise_perform_all (ecma_value_t iterator, /**< iteratorRecord */
|
||||
ecma_value_t ctor, /**< the caller of Promise.race */
|
||||
ecma_value_t capability, /**< PromiseCapability record */
|
||||
bool *done_p) /**< [out] iteratorRecord[[done]] */
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_value_object (capability)
|
||||
&& ecma_is_value_object (array)
|
||||
&& ecma_is_value_object (ctor));
|
||||
JERRY_ASSERT (ecma_get_object_builtin_id (ecma_get_object_from_value (ctor)) == ECMA_BUILTIN_ID_PROMISE);
|
||||
JERRY_ASSERT (ecma_get_object_type (ecma_get_object_from_value (array)) == ECMA_OBJECT_TYPE_ARRAY);
|
||||
/* 1. - 2. */
|
||||
JERRY_ASSERT (ecma_is_value_object (capability) && ecma_is_constructor (ctor));
|
||||
|
||||
ecma_value_t ret = ECMA_VALUE_EMPTY;
|
||||
ecma_object_t *array_p = ecma_get_object_from_value (array);
|
||||
ecma_extended_object_t *ext_array_p = (ecma_extended_object_t *) array_p;
|
||||
/* 3. */
|
||||
ecma_object_t *values_array_obj_p = ecma_op_new_fast_array_object (0);
|
||||
ecma_value_t values_array = ecma_make_object_value (values_array_obj_p);
|
||||
/* 4. */
|
||||
ecma_value_t remaining = ecma_op_create_number_object (ecma_make_integer_value (1));
|
||||
/* 5. */
|
||||
uint32_t idx = 0;
|
||||
|
||||
ecma_length_t len = ext_array_p->u.array.length;
|
||||
ecma_value_t ret_value = ECMA_VALUE_ERROR;
|
||||
ecma_object_t *capability_obj_p = ecma_get_object_from_value (capability);
|
||||
|
||||
ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
|
||||
ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
|
||||
ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
|
||||
ecma_string_t *already_called_str_p;
|
||||
already_called_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_ALREADY_CALLED);
|
||||
ecma_string_t *index_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_INDEX);
|
||||
@ -349,81 +348,75 @@ ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */
|
||||
ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY);
|
||||
ecma_string_t *remaining_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REMAINING_ELEMENT);
|
||||
|
||||
ecma_value_t undefined_val = ECMA_VALUE_UNDEFINED;
|
||||
/* String '1' indicates [[Resolve]] and '2' indicates [[Reject]]. */
|
||||
ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability),
|
||||
resolve_str_p);
|
||||
ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability),
|
||||
reject_str_p);
|
||||
/* 3. */
|
||||
ecma_value_t result_array_length_val = ecma_make_uint32_value (0);
|
||||
ecma_value_t value_array = ecma_op_create_array_object (&result_array_length_val, 1, true);
|
||||
ecma_free_value (result_array_length_val);
|
||||
/* 4. */
|
||||
ecma_value_t remaining = ecma_op_create_number_object (ecma_make_integer_value (1));
|
||||
/* 5. */
|
||||
ecma_length_t index = 0;
|
||||
|
||||
/* 6 */
|
||||
/* 6. */
|
||||
while (true)
|
||||
{
|
||||
JERRY_ASSERT (index <= len);
|
||||
/* d. */
|
||||
if (index == len)
|
||||
/* a. */
|
||||
ecma_value_t next = ecma_op_iterator_step (iterator);
|
||||
/* b. - c. */
|
||||
if (ECMA_IS_VALUE_ERROR (next))
|
||||
{
|
||||
/* ii. */
|
||||
*done_p = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* d. */
|
||||
if (ecma_is_value_false (next))
|
||||
{
|
||||
/* i. */
|
||||
*done_p = true;
|
||||
|
||||
/* ii. - iii. */
|
||||
if (ecma_builtin_promise_remaining_inc_or_dec (remaining, false) == 0)
|
||||
{
|
||||
/* iii. */
|
||||
ecma_value_t resolve_ret = ecma_op_function_call (ecma_get_object_from_value (resolve),
|
||||
ECMA_VALUE_UNDEFINED,
|
||||
&value_array,
|
||||
1);
|
||||
/* 2. */
|
||||
ecma_value_t resolve = ecma_op_object_get_by_magic_id (capability_obj_p,
|
||||
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
|
||||
ecma_value_t resolve_result = ecma_op_function_call (ecma_get_object_from_value (resolve),
|
||||
ECMA_VALUE_UNDEFINED,
|
||||
&values_array,
|
||||
1);
|
||||
ecma_free_value (resolve);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (resolve_ret))
|
||||
/* 3. */
|
||||
if (ECMA_IS_VALUE_ERROR (resolve_result))
|
||||
{
|
||||
ret = resolve_ret;
|
||||
break;
|
||||
}
|
||||
|
||||
ecma_free_value (resolve_result);
|
||||
}
|
||||
|
||||
/* iv. */
|
||||
ret = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p);
|
||||
ret_value = ecma_op_object_get_by_magic_id (capability_obj_p,
|
||||
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* e. h. */
|
||||
ecma_string_t *index_to_str_p = ecma_new_ecma_string_from_uint32 (index);
|
||||
ecma_value_t array_item = ecma_op_object_get (array_p, index_to_str_p);
|
||||
/* e. */
|
||||
ecma_value_t next_value = ecma_op_iterator_value (next);
|
||||
ecma_free_value (next);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (array_item))
|
||||
/* f. - g. */
|
||||
if (ECMA_IS_VALUE_ERROR (next_value))
|
||||
{
|
||||
ecma_deref_ecma_string (index_to_str_p);
|
||||
ret = array_item;
|
||||
*done_p = true;
|
||||
break;
|
||||
}
|
||||
|
||||
ecma_value_t put_ret = ecma_builtin_helper_def_prop (ecma_get_object_from_value (value_array),
|
||||
index_to_str_p,
|
||||
undefined_val,
|
||||
ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
|
||||
ecma_deref_ecma_string (index_to_str_p);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (put_ret))
|
||||
{
|
||||
ecma_free_value (array_item);
|
||||
ret = put_ret;
|
||||
break;
|
||||
}
|
||||
/* h. */
|
||||
ecma_builtin_helper_def_prop_by_index (values_array_obj_p,
|
||||
idx,
|
||||
ECMA_VALUE_UNDEFINED,
|
||||
ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
|
||||
|
||||
/* i. */
|
||||
ecma_value_t next_promise = ecma_builtin_promise_resolve (ctor, array_item);
|
||||
ecma_free_value (array_item);
|
||||
ecma_value_t next_promise = ecma_op_invoke_by_magic_id (ctor, LIT_MAGIC_STRING_RESOLVE, &next_value, 1);
|
||||
ecma_free_value (next_value);
|
||||
|
||||
/* j. */
|
||||
if (ECMA_IS_VALUE_ERROR (next_promise))
|
||||
{
|
||||
ret = next_promise;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -436,15 +429,19 @@ ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */
|
||||
ECMA_VALUE_FALSE,
|
||||
false);
|
||||
/* m. */
|
||||
ecma_value_t idx_value = ecma_make_uint32_value (idx);
|
||||
ecma_op_object_put (res_ele_p,
|
||||
index_str_p,
|
||||
ecma_make_uint32_value (index),
|
||||
idx_value,
|
||||
false);
|
||||
ecma_free_value (idx_value);
|
||||
|
||||
/* n. */
|
||||
ecma_op_object_put (res_ele_p,
|
||||
value_str_p,
|
||||
value_array,
|
||||
values_array,
|
||||
false);
|
||||
|
||||
/* o. */
|
||||
ecma_op_object_put (res_ele_p,
|
||||
capability_str_p,
|
||||
@ -458,33 +455,35 @@ ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */
|
||||
|
||||
/* q. */
|
||||
ecma_builtin_promise_remaining_inc_or_dec (remaining, true);
|
||||
|
||||
/* r. */
|
||||
ecma_value_t then_result = ecma_promise_then (next_promise,
|
||||
ecma_make_object_value (res_ele_p),
|
||||
reject);
|
||||
ecma_deref_object (res_ele_p);
|
||||
ecma_value_t args[2];
|
||||
args[0] = ecma_make_object_value (res_ele_p);
|
||||
args[1] = ecma_op_object_get_by_magic_id (capability_obj_p, LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
|
||||
ecma_value_t result = ecma_op_invoke_by_magic_id (next_promise, LIT_MAGIC_STRING_THEN, args, 2);
|
||||
ecma_free_value (next_promise);
|
||||
|
||||
/* s. */
|
||||
if (ECMA_IS_VALUE_ERROR (then_result))
|
||||
for (uint8_t i = 0; i < 2; i++)
|
||||
{
|
||||
ecma_free_value (args[i]);
|
||||
}
|
||||
|
||||
/* s. */
|
||||
if (ECMA_IS_VALUE_ERROR (result))
|
||||
{
|
||||
ret = then_result;
|
||||
break;
|
||||
}
|
||||
|
||||
ecma_free_value (then_result);
|
||||
index ++;
|
||||
ecma_free_value (result);
|
||||
|
||||
/* t. */
|
||||
idx++;
|
||||
}
|
||||
|
||||
ecma_free_value (reject);
|
||||
ecma_free_value (resolve);
|
||||
ecma_free_value (remaining);
|
||||
ecma_free_value (value_array);
|
||||
|
||||
JERRY_ASSERT (!ecma_is_value_empty (ret));
|
||||
|
||||
return ret;
|
||||
} /* ecma_builtin_promise_do_all */
|
||||
ecma_deref_object (values_array_obj_p);
|
||||
return ret_value;
|
||||
} /* ecma_builtin_promise_perform_all */
|
||||
|
||||
/**
|
||||
* The common function for both Promise.race and Promise.all.
|
||||
@ -494,7 +493,7 @@ ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */
|
||||
*/
|
||||
static ecma_value_t
|
||||
ecma_builtin_promise_race_or_all (ecma_value_t this_arg, /**< 'this' argument */
|
||||
ecma_value_t array, /**< the items to be resolved */
|
||||
ecma_value_t iterable, /**< the items to be resolved */
|
||||
bool is_race) /**< indicates whether it is race function */
|
||||
{
|
||||
if (!ecma_is_value_object (this_arg))
|
||||
@ -530,33 +529,41 @@ ecma_builtin_promise_race_or_all (ecma_value_t this_arg, /**< 'this' argument */
|
||||
return capability;
|
||||
}
|
||||
|
||||
ecma_value_t ret = ECMA_VALUE_EMPTY;
|
||||
ecma_value_t iterator = ecma_builtin_promise_reject_abrupt (ecma_op_get_iterator (iterable, ECMA_VALUE_EMPTY),
|
||||
capability);
|
||||
|
||||
if (!ecma_is_value_object (array)
|
||||
|| ecma_get_object_type (ecma_get_object_from_value (array)) != ECMA_OBJECT_TYPE_ARRAY)
|
||||
if (ECMA_IS_VALUE_ERROR (iterator))
|
||||
{
|
||||
ret = ecma_builtin_promise_reject_abrupt (capability);
|
||||
ecma_free_value (constructor_value);
|
||||
ecma_free_value (capability);
|
||||
return ret;
|
||||
return iterator;
|
||||
}
|
||||
|
||||
ecma_value_t ret = ECMA_VALUE_EMPTY;
|
||||
bool is_done = false;
|
||||
|
||||
if (is_race)
|
||||
{
|
||||
ret = ecma_builtin_promise_do_race (array, capability, constructor_value);
|
||||
ret = ecma_builtin_promise_perform_race (iterator, capability, constructor_value, &is_done);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ecma_builtin_promise_do_all (array, capability, constructor_value);
|
||||
ret = ecma_builtin_promise_perform_all (iterator, constructor_value, capability, &is_done);
|
||||
}
|
||||
|
||||
ecma_free_value (constructor_value);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (ret))
|
||||
{
|
||||
ret = jcontext_take_exception ();
|
||||
if (is_done)
|
||||
{
|
||||
ret = ecma_op_iterator_close (iterator);
|
||||
}
|
||||
|
||||
ret = ecma_builtin_promise_reject_abrupt (ret, capability);
|
||||
}
|
||||
|
||||
ecma_free_value (iterator);
|
||||
ecma_free_value (capability);
|
||||
|
||||
return ret;
|
||||
|
||||
@ -2672,6 +2672,65 @@ ecma_op_species_constructor (ecma_object_t *this_value, /**< This Value */
|
||||
|
||||
#endif /* ENABLED (JERRY_ES2015) */
|
||||
|
||||
/**
|
||||
* 7.3.18 Abstract operation Invoke when property name is a magic string
|
||||
*
|
||||
* @return ecma_value result of the invoked function or raised error
|
||||
* note: returned value must be freed with ecma_free_value
|
||||
*/
|
||||
inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
|
||||
ecma_op_invoke_by_magic_id (ecma_value_t object, /**< Object value */
|
||||
lit_magic_string_id_t magic_string_id, /**< Magic string ID */
|
||||
ecma_value_t *args_p, /**< Argument list */
|
||||
ecma_length_t args_len) /**< Argument list length */
|
||||
{
|
||||
return ecma_op_invoke (object, ecma_get_magic_string (magic_string_id), args_p, args_len);
|
||||
} /* ecma_op_invoke_by_magic_id */
|
||||
|
||||
/**
|
||||
* 7.3.18 Abstract operation Invoke
|
||||
*
|
||||
* @return ecma_value result of the invoked function or raised error
|
||||
* note: returned value must be freed with ecma_free_value
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_op_invoke (ecma_value_t object, /**< Object value */
|
||||
ecma_string_t *property_name_p, /**< Property name */
|
||||
ecma_value_t *args_p, /**< Argument list */
|
||||
ecma_length_t args_len) /**< Argument list length */
|
||||
{
|
||||
/* 3. */
|
||||
ecma_value_t object_value = ecma_op_to_object (object);
|
||||
if (ECMA_IS_VALUE_ERROR (object_value))
|
||||
{
|
||||
return object_value;
|
||||
}
|
||||
|
||||
ecma_object_t *object_p = ecma_get_object_from_value (object_value);
|
||||
ecma_value_t func = ecma_op_object_get (object_p, property_name_p);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (func))
|
||||
{
|
||||
ecma_deref_object (object_p);
|
||||
return func;
|
||||
}
|
||||
|
||||
/* 4. */
|
||||
if (!ecma_op_is_callable (func))
|
||||
{
|
||||
ecma_free_value (func);
|
||||
ecma_deref_object (object_p);
|
||||
return ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not callable"));
|
||||
}
|
||||
|
||||
ecma_object_t *func_obj_p = ecma_get_object_from_value (func);
|
||||
ecma_value_t call_result = ecma_op_function_call (func_obj_p, object, args_p, args_len);
|
||||
ecma_deref_object (object_p);
|
||||
ecma_deref_object (func_obj_p);
|
||||
|
||||
return call_result;
|
||||
} /* ecma_op_invoke */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
|
||||
@ -73,6 +73,10 @@ ecma_value_t ecma_op_is_concat_spreadable (ecma_value_t arg);
|
||||
ecma_value_t ecma_op_is_regexp (ecma_value_t arg);
|
||||
ecma_value_t ecma_op_species_constructor (ecma_object_t *this_value, ecma_builtin_id_t default_constructor_id);
|
||||
#endif /* ENABLED (JERRY_ES2015) */
|
||||
ecma_value_t ecma_op_invoke (ecma_value_t object, ecma_string_t *property_name_p, ecma_value_t *args_p,
|
||||
ecma_length_t args_len);
|
||||
ecma_value_t ecma_op_invoke_by_magic_id (ecma_value_t object, lit_magic_string_id_t magic_string_id,
|
||||
ecma_value_t *args_p, ecma_length_t args_len);
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
||||
@ -249,8 +249,8 @@ ecma_promise_reject_handler (const ecma_value_t function, /**< the function itse
|
||||
/* 4. */
|
||||
if (ecma_get_already_resolved_bool_value (already_resolved))
|
||||
{
|
||||
ecma_free_value (promise);
|
||||
ecma_free_value (already_resolved);
|
||||
ecma_free_value (promise);
|
||||
return ECMA_VALUE_UNDEFINED;
|
||||
}
|
||||
|
||||
@ -325,7 +325,7 @@ ecma_promise_resolve_handler (const ecma_value_t function, /**< the function its
|
||||
|
||||
/* 8. */
|
||||
ecma_value_t then = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (argv[0]),
|
||||
LIT_MAGIC_STRING_THEN);
|
||||
LIT_MAGIC_STRING_THEN);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (then))
|
||||
{
|
||||
@ -409,6 +409,35 @@ ecma_call_builtin_executor (ecma_object_t *executor_p, /**< the executor object
|
||||
return ECMA_VALUE_UNDEFINED;
|
||||
} /* ecma_call_builtin_executor */
|
||||
|
||||
/**
|
||||
* Helper function for PromiseCreateResovingFucntions.
|
||||
*
|
||||
* See also: ES2015 25.4.1.3 2. - 7.
|
||||
*
|
||||
* @return pointer to the resolving function
|
||||
*/
|
||||
static ecma_object_t *
|
||||
ecma_promise_create_resolving_functions_helper (ecma_object_t *obj_p, /**< Promise Object */
|
||||
ecma_value_t already_resolved, /**< AlreadyResolved property */
|
||||
ecma_external_handler_t handler_cb) /**< Callback handler */
|
||||
{
|
||||
ecma_string_t *str_promise_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE);
|
||||
ecma_string_t *str_already_resolved_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED);
|
||||
ecma_object_t *func_obj_p = ecma_op_create_external_function_object (handler_cb);
|
||||
|
||||
ecma_op_object_put (func_obj_p,
|
||||
str_promise_p,
|
||||
ecma_make_object_value (obj_p),
|
||||
false);
|
||||
|
||||
ecma_op_object_put (func_obj_p,
|
||||
str_already_resolved_p,
|
||||
already_resolved,
|
||||
false);
|
||||
|
||||
return func_obj_p;
|
||||
} /* ecma_promise_create_resolving_functions_helper */
|
||||
|
||||
/**
|
||||
* Create a PromiseCreateResovingFucntions.
|
||||
*
|
||||
@ -422,36 +451,15 @@ ecma_promise_create_resolving_functions (ecma_object_t *object_p) /**< the promi
|
||||
/* 1. */
|
||||
ecma_value_t already_resolved = ecma_op_create_boolean_object (ECMA_VALUE_FALSE);
|
||||
|
||||
ecma_string_t *str_promise_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE);
|
||||
ecma_string_t *str_already_resolved_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED);
|
||||
/* 2. - 4. */
|
||||
ecma_object_t *resolve_p = ecma_promise_create_resolving_functions_helper (object_p,
|
||||
already_resolved,
|
||||
ecma_promise_resolve_handler);
|
||||
|
||||
/* 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_p,
|
||||
ecma_make_object_value (object_p),
|
||||
false);
|
||||
/* 4. */
|
||||
ecma_op_object_put (resolve_p,
|
||||
str_already_resolved_p,
|
||||
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_p,
|
||||
ecma_make_object_value (object_p),
|
||||
false);
|
||||
/* 7. */
|
||||
ecma_op_object_put (reject_p,
|
||||
str_already_resolved_p,
|
||||
already_resolved,
|
||||
false);
|
||||
/* 5. - 7. */
|
||||
ecma_object_t *reject_p = ecma_promise_create_resolving_functions_helper (object_p,
|
||||
already_resolved,
|
||||
ecma_promise_reject_handler);
|
||||
|
||||
/* 8. */
|
||||
ecma_promise_resolving_functions_t *funcs = jmem_heap_alloc_block (sizeof (ecma_promise_resolving_functions_t));
|
||||
@ -459,7 +467,6 @@ ecma_promise_create_resolving_functions (ecma_object_t *object_p) /**< the promi
|
||||
funcs->reject = ecma_make_object_value (reject_p);
|
||||
|
||||
ecma_free_value (already_resolved);
|
||||
|
||||
return funcs;
|
||||
} /* ecma_promise_create_resolving_functions */
|
||||
|
||||
|
||||
76
tests/jerry/es2015/promise-all-iterator.js
Normal file
76
tests/jerry/es2015/promise-all-iterator.js
Normal file
@ -0,0 +1,76 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
function createIterable(arr, methods = {}) {
|
||||
let iterable = function *() {
|
||||
let idx = 0;
|
||||
while (idx < arr.length) {
|
||||
yield arr[idx];
|
||||
idx++;
|
||||
}
|
||||
}();
|
||||
iterable['return'] = methods['return'];
|
||||
iterable['throw'] = methods['throw'];
|
||||
|
||||
return iterable;
|
||||
};
|
||||
|
||||
// iterator next
|
||||
Promise.all({[Symbol.iterator]() { return {get next() { throw 5; }}}
|
||||
}).then(onfullfilled => {
|
||||
// If this is not called, the promise has failed, and catch must be called.
|
||||
assert(false);
|
||||
}).catch(err => {
|
||||
assert(err === 5);
|
||||
});
|
||||
|
||||
// iterator value
|
||||
Promise.all({ [Symbol.iterator] () { return { next () { return { get value () { throw 5 }}}}}
|
||||
}).then(onfullfilled => {
|
||||
// If this is not called, the promise has failed, and catch must be called.
|
||||
assert(false);
|
||||
}).catch(err => {
|
||||
assert(err === 5);
|
||||
});
|
||||
|
||||
// iterator done
|
||||
Promise.all({ [Symbol.iterator] () { return { next () { return { get done () { throw 5 }}}}}
|
||||
}).then(onfullfilled => {
|
||||
// If this is not called, the promise has failed, and catch must be called.
|
||||
assert(false);
|
||||
}).catch(err => {
|
||||
assert(err === 5);
|
||||
});
|
||||
|
||||
// iterator get
|
||||
Promise.all({ get [Symbol.iterator] () { throw 5 }
|
||||
}).then(onfullfilled => {
|
||||
// If this is not called, the promise has failed, and catch must be called.
|
||||
assert(false);
|
||||
}).catch(err => {
|
||||
assert(err === 5);
|
||||
});
|
||||
|
||||
var fulfills = Promise.all(createIterable([
|
||||
new Promise(resolve => { resolve("foo"); }),
|
||||
new Promise(resolve => { resolve("bar"); }),
|
||||
]));
|
||||
var rejects = Promise.all(createIterable([
|
||||
new Promise((_, reject) => { reject("baz"); }),
|
||||
new Promise((_, reject) => { reject("qux"); }),
|
||||
]));
|
||||
|
||||
fulfills.then(result => { assert (result + "" === "foo,bar"); });
|
||||
rejects.catch(result => { assert (result === "baz"); });
|
||||
64
tests/jerry/es2015/promise-race-iterator.js
Normal file
64
tests/jerry/es2015/promise-race-iterator.js
Normal file
@ -0,0 +1,64 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
function createIterable(arr, methods = {}) {
|
||||
let iterable = function *() {
|
||||
let idx = 0;
|
||||
while (idx < arr.length) {
|
||||
yield arr[idx];
|
||||
idx++;
|
||||
}
|
||||
}();
|
||||
iterable['return'] = methods['return'];
|
||||
iterable['throw'] = methods['throw'];
|
||||
|
||||
return iterable;
|
||||
};
|
||||
|
||||
// iterator next
|
||||
Promise.race({[Symbol.iterator]() { return {get next() { throw 5; }}}
|
||||
}).catch(err => {
|
||||
assert(err === 5);
|
||||
});
|
||||
|
||||
// iterator value
|
||||
Promise.race({ [Symbol.iterator] () { return { next () { return { get value () { throw 5 }}}}}
|
||||
}).catch(err => {
|
||||
assert(err === 5);
|
||||
});
|
||||
|
||||
// iterator done
|
||||
Promise.race({ [Symbol.iterator] () { return { next () { return { get done () { throw 5 }}}}}
|
||||
}).catch(err => {
|
||||
assert(err === 5);
|
||||
});
|
||||
|
||||
// iterator get
|
||||
Promise.race({ get [Symbol.iterator] () { throw 5 }
|
||||
}).catch(err => {
|
||||
assert(err === 5);
|
||||
});
|
||||
|
||||
var fulfills = Promise.race(createIterable([
|
||||
new Promise(resolve => { resolve("foo"); }),
|
||||
new Promise(resolve => { resolve("bar"); }),
|
||||
]));
|
||||
var rejects = Promise.race(createIterable([
|
||||
new Promise((_, reject) => { reject("baz"); }),
|
||||
new Promise((_, reject) => { reject("qux"); }),
|
||||
]));
|
||||
|
||||
fulfills.then(result => { assert (result + "" === "foo"); });
|
||||
rejects.catch(result => { assert (result === "baz"); });
|
||||
@ -13,4 +13,8 @@
|
||||
// limitations under the License.
|
||||
|
||||
Object.defineProperty(Array.prototype, 0, { get : function () { throw $; } });
|
||||
Promise.race([ , this]).then(Error);
|
||||
var asyncPassed = false;
|
||||
Promise.race([ , this]).then(Error).catch(function(err) { asyncPassed = (err instanceof ReferenceError); });
|
||||
new Promise(function() {
|
||||
throw 5;
|
||||
}).then(Error).catch(function() { assert(asyncPassed); });
|
||||
Loading…
x
Reference in New Issue
Block a user