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:
Daniel Balla
2020-01-10 15:44:52 +01:00
committed by Robert Fancsik
parent c407e8a04c
commit 1725e014b8
7 changed files with 416 additions and 195 deletions
@@ -19,6 +19,7 @@
#include "ecma-function-object.h" #include "ecma-function-object.h"
#include "ecma-gc.h" #include "ecma-gc.h"
#include "ecma-globals.h" #include "ecma-globals.h"
#include "ecma-iterator-object.h"
#include "ecma-number-object.h" #include "ecma-number-object.h"
#include "ecma-promise-object.h" #include "ecma-promise-object.h"
#include "jcontext.h" #include "jcontext.h"
@@ -52,12 +53,17 @@
* Returned value must be freed with ecma_free_value. * Returned value must be freed with ecma_free_value.
*/ */
inline static ecma_value_t 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_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_by_magic_id (ecma_get_object_from_value (capability),
ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), reject_str_p); LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (reject), ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (reject),
ECMA_VALUE_UNDEFINED, ECMA_VALUE_UNDEFINED,
@@ -73,10 +79,8 @@ ecma_builtin_promise_reject_abrupt (ecma_value_t capability) /**< reject descrip
ecma_free_value (call_ret); ecma_free_value (call_ret);
ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); return ecma_op_object_get_by_magic_id (ecma_get_object_from_value (capability),
ecma_value_t promise_new = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p); LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
return promise_new;
} /* ecma_builtin_promise_reject_abrupt */ } /* 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. * Returned value must be freed with ecma_free_value.
*/ */
inline static ecma_value_t inline static ecma_value_t
ecma_builtin_promise_do_race (ecma_value_t array, /**< the array for race */ ecma_builtin_promise_perform_race (ecma_value_t iterator, /**< the iterator for race */
ecma_value_t capability, /**< PromiseCapability record */ ecma_value_t capability, /**< PromiseCapability record */
ecma_value_t ctor) /**< the caller of Promise.race */ ecma_value_t ctor, /**< Constructor value */
bool *done_p) /**< [out] iteratorRecord[[done]] */
{ {
JERRY_ASSERT (ecma_is_value_object (capability) JERRY_ASSERT (ecma_is_value_object (iterator)
&& ecma_is_value_object (array) && ecma_is_value_object (capability));
&& 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);
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_object_t *capability_obj_p = ecma_get_object_from_value (capability);
/* 1. */
ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); while (true)
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++)
{ {
/* b-d. */ /* a. */
if (index == len) 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); *done_p = true;
break; 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. */ /* 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. */ /* f, g. */
if (ECMA_IS_VALUE_ERROR (array_item)) if (ECMA_IS_VALUE_ERROR (next_val))
{ {
ret = array_item; *done_p = true;
break; return next_val;
} }
/* h. */ /* h. */
ecma_value_t next_promise = ecma_builtin_promise_resolve (ctor, array_item); ecma_value_t next_promise = ecma_op_invoke_by_magic_id (ctor, LIT_MAGIC_STRING_RESOLVE, &next_val, 1);
ecma_free_value (array_item); ecma_free_value (next_val);
/* i. */ /* i. */
if (ECMA_IS_VALUE_ERROR (next_promise)) if (ECMA_IS_VALUE_ERROR (next_promise))
{ {
ret = next_promise; return next_promise;
break;
} }
/* j. */ /* 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); ecma_free_value (next_promise);
/* k. */ for (uint8_t i = 0; i < 2; i++)
if (ECMA_IS_VALUE_ERROR (then_result))
{ {
ret = then_result; ecma_free_value (args[i]);
break;
} }
ecma_free_value (then_result); /* k. */
if (ECMA_IS_VALUE_ERROR (result))
{
return result;
}
ecma_free_value (result);
} }
ecma_free_value (reject); JERRY_UNREACHABLE ();
ecma_free_value (resolve); } /* ecma_builtin_promise_perform_race */
JERRY_ASSERT (!ecma_is_value_empty (ret));
return ret;
} /* ecma_builtin_promise_do_race */
/** /**
* Helper function for increase or decrease the remaining count. * 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--; current--;
} }
ext_object_p->u.class_prop.u.value = ecma_make_uint32_value (current); ext_object_p->u.class_prop.u.value = ecma_make_uint32_value (current);
return current; return current;
@@ -249,7 +251,6 @@ ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function
JERRY_UNUSED (this); JERRY_UNUSED (this);
JERRY_UNUSED (argc); JERRY_UNUSED (argc);
ecma_value_t ret = ECMA_VALUE_UNDEFINED;
/* 1. */ /* 1. */
ecma_object_t *function_p = ecma_get_object_from_value (function); ecma_object_t *function_p = ecma_get_object_from_value (function);
ecma_string_t *already_called_str_p; ecma_string_t *already_called_str_p;
@@ -261,8 +262,7 @@ ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function
/* 2. */ /* 2. */
if (ecma_is_value_true (already_called)) if (ecma_is_value_true (already_called))
{ {
ecma_fast_free_value (already_called); return ECMA_VALUE_UNDEFINED;
return ret;
} }
/* 3. */ /* 3. */
@@ -278,37 +278,36 @@ ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function
/* 4-7. */ /* 4-7. */
ecma_value_t index_val = ecma_op_object_get (function_p, str_index_p); 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 capability = ecma_op_object_get (function_p, str_capability_p);
ecma_value_t remaining = ecma_op_object_get (function_p, str_remaining_p); ecma_value_t remaining = ecma_op_object_get (function_p, str_remaining_p);
JERRY_ASSERT (ecma_is_value_integer_number (index_val)); JERRY_ASSERT (ecma_is_value_integer_number (index_val));
/* 8. */ /* 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), (uint32_t) ecma_get_integer_from_value (index_val),
argv[0], argv[0],
false); false);
/* 9-10. */ /* 9-10. */
ecma_value_t ret = ECMA_VALUE_UNDEFINED;
if (ecma_builtin_promise_remaining_inc_or_dec (remaining, false) == 0) 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_by_magic_id (ecma_get_object_from_value (capability),
ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), resolve_str_p); LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
ret = ecma_op_function_call (ecma_get_object_from_value (resolve), ret = ecma_op_function_call (ecma_get_object_from_value (resolve),
ECMA_VALUE_UNDEFINED, ECMA_VALUE_UNDEFINED,
&value_array, &values_array,
1); 1);
ecma_free_value (resolve); ecma_free_value (resolve);
} }
ecma_free_value (remaining); ecma_free_value (remaining);
ecma_free_value (capability); ecma_free_value (capability);
ecma_free_value (value_array); ecma_free_value (values_array);
ecma_fast_free_value (index_val); ecma_free_value (index_val);
ecma_fast_free_value (already_called);
return ret; return ret;
} /* ecma_builtin_promise_all_handler */ } /* 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. * Returned value must be freed with ecma_free_value.
*/ */
inline static ecma_value_t inline static ecma_value_t
ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */ ecma_builtin_promise_perform_all (ecma_value_t iterator, /**< iteratorRecord */
ecma_value_t capability, /**< PromiseCapability record */ ecma_value_t ctor, /**< the caller of Promise.race */
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) /* 1. - 2. */
&& ecma_is_value_object (array) JERRY_ASSERT (ecma_is_value_object (capability) && ecma_is_constructor (ctor));
&& 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);
ecma_value_t ret = ECMA_VALUE_EMPTY; /* 3. */
ecma_object_t *array_p = ecma_get_object_from_value (array); ecma_object_t *values_array_obj_p = ecma_op_new_fast_array_object (0);
ecma_extended_object_t *ext_array_p = (ecma_extended_object_t *) array_p; 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; ecma_string_t *already_called_str_p;
already_called_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_ALREADY_CALLED); 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); 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 *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_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; /* 6. */
/* 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 */
while (true) while (true)
{ {
JERRY_ASSERT (index <= len); /* a. */
/* d. */ ecma_value_t next = ecma_op_iterator_step (iterator);
if (index == len) /* 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) if (ecma_builtin_promise_remaining_inc_or_dec (remaining, false) == 0)
{ {
/* iii. */ /* 2. */
ecma_value_t resolve_ret = ecma_op_function_call (ecma_get_object_from_value (resolve), ecma_value_t resolve = ecma_op_object_get_by_magic_id (capability_obj_p,
ECMA_VALUE_UNDEFINED, LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
&value_array, ecma_value_t resolve_result = ecma_op_function_call (ecma_get_object_from_value (resolve),
1); 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; break;
} }
ecma_free_value (resolve_result);
} }
/* iv. */ /* 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; break;
} }
/* e. h. */ /* e. */
ecma_string_t *index_to_str_p = ecma_new_ecma_string_from_uint32 (index); ecma_value_t next_value = ecma_op_iterator_value (next);
ecma_value_t array_item = ecma_op_object_get (array_p, index_to_str_p); 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); *done_p = true;
ret = array_item;
break; break;
} }
ecma_value_t put_ret = ecma_builtin_helper_def_prop (ecma_get_object_from_value (value_array), /* h. */
index_to_str_p, ecma_builtin_helper_def_prop_by_index (values_array_obj_p,
undefined_val, idx,
ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE); ECMA_VALUE_UNDEFINED,
ecma_deref_ecma_string (index_to_str_p); ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
if (ECMA_IS_VALUE_ERROR (put_ret))
{
ecma_free_value (array_item);
ret = put_ret;
break;
}
/* i. */ /* i. */
ecma_value_t next_promise = ecma_builtin_promise_resolve (ctor, array_item); ecma_value_t next_promise = ecma_op_invoke_by_magic_id (ctor, LIT_MAGIC_STRING_RESOLVE, &next_value, 1);
ecma_free_value (array_item); ecma_free_value (next_value);
/* j. */ /* j. */
if (ECMA_IS_VALUE_ERROR (next_promise)) if (ECMA_IS_VALUE_ERROR (next_promise))
{ {
ret = next_promise;
break; break;
} }
@@ -436,15 +429,19 @@ ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */
ECMA_VALUE_FALSE, ECMA_VALUE_FALSE,
false); false);
/* m. */ /* m. */
ecma_value_t idx_value = ecma_make_uint32_value (idx);
ecma_op_object_put (res_ele_p, ecma_op_object_put (res_ele_p,
index_str_p, index_str_p,
ecma_make_uint32_value (index), idx_value,
false); false);
ecma_free_value (idx_value);
/* n. */ /* n. */
ecma_op_object_put (res_ele_p, ecma_op_object_put (res_ele_p,
value_str_p, value_str_p,
value_array, values_array,
false); false);
/* o. */ /* o. */
ecma_op_object_put (res_ele_p, ecma_op_object_put (res_ele_p,
capability_str_p, capability_str_p,
@@ -458,33 +455,35 @@ ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */
/* q. */ /* q. */
ecma_builtin_promise_remaining_inc_or_dec (remaining, true); ecma_builtin_promise_remaining_inc_or_dec (remaining, true);
/* r. */ /* r. */
ecma_value_t then_result = ecma_promise_then (next_promise, ecma_value_t args[2];
ecma_make_object_value (res_ele_p), args[0] = ecma_make_object_value (res_ele_p);
reject); args[1] = ecma_op_object_get_by_magic_id (capability_obj_p, LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
ecma_deref_object (res_ele_p); ecma_value_t result = ecma_op_invoke_by_magic_id (next_promise, LIT_MAGIC_STRING_THEN, args, 2);
ecma_free_value (next_promise); ecma_free_value (next_promise);
/* s. */ for (uint8_t i = 0; i < 2; i++)
if (ECMA_IS_VALUE_ERROR (then_result)) {
ecma_free_value (args[i]);
}
/* s. */
if (ECMA_IS_VALUE_ERROR (result))
{ {
ret = then_result;
break; break;
} }
ecma_free_value (then_result); ecma_free_value (result);
index ++;
/* t. */
idx++;
} }
ecma_free_value (reject);
ecma_free_value (resolve);
ecma_free_value (remaining); ecma_free_value (remaining);
ecma_free_value (value_array); ecma_deref_object (values_array_obj_p);
return ret_value;
JERRY_ASSERT (!ecma_is_value_empty (ret)); } /* ecma_builtin_promise_perform_all */
return ret;
} /* ecma_builtin_promise_do_all */
/** /**
* The common function for both Promise.race and Promise.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 static ecma_value_t
ecma_builtin_promise_race_or_all (ecma_value_t this_arg, /**< 'this' argument */ 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 */ bool is_race) /**< indicates whether it is race function */
{ {
if (!ecma_is_value_object (this_arg)) 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; 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) if (ECMA_IS_VALUE_ERROR (iterator))
|| ecma_get_object_type (ecma_get_object_from_value (array)) != ECMA_OBJECT_TYPE_ARRAY)
{ {
ret = ecma_builtin_promise_reject_abrupt (capability);
ecma_free_value (constructor_value); ecma_free_value (constructor_value);
ecma_free_value (capability); ecma_free_value (capability);
return ret; return iterator;
} }
ecma_value_t ret = ECMA_VALUE_EMPTY;
bool is_done = false;
if (is_race) 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 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); ecma_free_value (constructor_value);
if (ECMA_IS_VALUE_ERROR (ret)) 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); ecma_free_value (capability);
return ret; return ret;
+59
View File
@@ -2672,6 +2672,65 @@ ecma_op_species_constructor (ecma_object_t *this_value, /**< This Value */
#endif /* ENABLED (JERRY_ES2015) */ #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_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); ecma_value_t ecma_op_species_constructor (ecma_object_t *this_value, ecma_builtin_id_t default_constructor_id);
#endif /* ENABLED (JERRY_ES2015) */ #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. */ /* 4. */
if (ecma_get_already_resolved_bool_value (already_resolved)) if (ecma_get_already_resolved_bool_value (already_resolved))
{ {
ecma_free_value (promise);
ecma_free_value (already_resolved); ecma_free_value (already_resolved);
ecma_free_value (promise);
return ECMA_VALUE_UNDEFINED; return ECMA_VALUE_UNDEFINED;
} }
@@ -325,7 +325,7 @@ ecma_promise_resolve_handler (const ecma_value_t function, /**< the function its
/* 8. */ /* 8. */
ecma_value_t then = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (argv[0]), 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)) 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; return ECMA_VALUE_UNDEFINED;
} /* ecma_call_builtin_executor */ } /* 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. * Create a PromiseCreateResovingFucntions.
* *
@@ -422,36 +451,15 @@ ecma_promise_create_resolving_functions (ecma_object_t *object_p) /**< the promi
/* 1. */ /* 1. */
ecma_value_t already_resolved = ecma_op_create_boolean_object (ECMA_VALUE_FALSE); 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); /* 2. - 4. */
ecma_string_t *str_already_resolved_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); ecma_object_t *resolve_p = ecma_promise_create_resolving_functions_helper (object_p,
already_resolved,
ecma_promise_resolve_handler);
/* 2. */ /* 5. - 7. */
ecma_object_t *resolve_p; ecma_object_t *reject_p = ecma_promise_create_resolving_functions_helper (object_p,
resolve_p = ecma_op_create_external_function_object (ecma_promise_resolve_handler); already_resolved,
ecma_promise_reject_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);
/* 8. */ /* 8. */
ecma_promise_resolving_functions_t *funcs = jmem_heap_alloc_block (sizeof (ecma_promise_resolving_functions_t)); 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); funcs->reject = ecma_make_object_value (reject_p);
ecma_free_value (already_resolved); ecma_free_value (already_resolved);
return funcs; return funcs;
} /* ecma_promise_create_resolving_functions */ } /* ecma_promise_create_resolving_functions */
@@ -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"); });
@@ -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. // limitations under the License.
Object.defineProperty(Array.prototype, 0, { get : function () { throw $; } }); 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); });