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

View File

@ -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;

View File

@ -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 */
/**
* @}
* @}

View File

@ -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);
/**
* @}

View File

@ -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 */

View 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"); });

View 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"); });

View File

@ -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); });