Add @@species accessor to Array and Promise builtin objects (#3440)

Fully support @@species and SpeciesConstructor in Array and Promise builtins.
Also added partial support to TypedArrays, but a rework is needed in %TypedArray%.prototype functions' typedarray constructor, which is out of this patch's scope.

JerryScript-DCO-1.0-Signed-off-by: Daniel Balla dballa@inf.u-szeged.hu
This commit is contained in:
Daniel Balla
2019-12-16 11:44:15 +01:00
committed by Robert Fancsik
parent 40d930d62c
commit e0d8c4ca10
28 changed files with 743 additions and 116 deletions
@@ -224,7 +224,7 @@ ecma_builtin_array_prototype_object_concat (const ecma_value_t args[], /**< argu
{
/* 2. */
#if ENABLED (JERRY_ES2015)
ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p);
ecma_value_t new_array = ecma_op_array_species_create (obj_p, 0);
if (ECMA_IS_VALUE_ERROR (new_array))
{
@@ -828,7 +828,7 @@ ecma_builtin_array_prototype_object_slice (ecma_value_t arg1, /**< start */
JERRY_ASSERT (start <= len && end <= len);
#if ENABLED (JERRY_ES2015)
ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p);
ecma_value_t new_array = ecma_op_array_species_create (obj_p, 0);
if (ECMA_IS_VALUE_ERROR (new_array))
{
@@ -887,11 +887,30 @@ ecma_builtin_array_prototype_object_slice (ecma_value_t arg1, /**< start */
n,
get_value,
ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
JERRY_ASSERT (ecma_is_value_true (put_comp));
ecma_free_value (get_value);
#if ENABLED (JERRY_ES2015)
if (ECMA_IS_VALUE_ERROR (put_comp))
{
ecma_deref_object (new_array_p);
return put_comp;
}
#else /* !ENABLED (JERRY_ES2015) */
JERRY_ASSERT (ecma_is_value_true (put_comp));
#endif /* ENABLED (JERRY_ES2015) */
}
}
#if ENABLED (JERRY_ES2015)
ecma_value_t set_length_value = ecma_builtin_array_prototype_helper_set_length (new_array_p, ((ecma_number_t) n));
if (ECMA_IS_VALUE_ERROR (set_length_value))
{
ecma_deref_object (new_array_p);
return set_length_value;
}
#endif /* ENABLED (JERRY_ES2015) */
return new_array;
} /* ecma_builtin_array_prototype_object_slice */
@@ -1167,7 +1186,7 @@ ecma_builtin_array_prototype_object_splice (const ecma_value_t args[], /**< argu
uint32_t len) /**< array object's length */
{
#if ENABLED (JERRY_ES2015)
ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p);
ecma_value_t new_array = ecma_op_array_species_create (obj_p, 0);
if (ECMA_IS_VALUE_ERROR (new_array))
{
@@ -1259,12 +1278,30 @@ ecma_builtin_array_prototype_object_splice (const ecma_value_t args[], /**< argu
k,
get_value,
ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
JERRY_ASSERT (ecma_is_value_true (put_comp));
ecma_free_value (get_value);
#if ENABLED (JERRY_ES2015)
if (ECMA_IS_VALUE_ERROR (put_comp))
{
ecma_deref_object (new_array_p);
return put_comp;
}
#else /* !ENABLED (JERRY_ES2015) */
JERRY_ASSERT (ecma_is_value_true (put_comp));
#endif /* ENABLED (JERRY_ES2015) */
}
}
#if ENABLED (JERRY_ES2015)
ecma_value_t new_set_length_value = ecma_builtin_array_prototype_helper_set_length (new_array_p,
((ecma_number_t) delete_count));
if (ECMA_IS_VALUE_ERROR (new_set_length_value))
{
ecma_deref_object (new_array_p);
return new_set_length_value;
}
#endif /* ENABLED (JERRY_ES2015) */
/* 11. */
ecma_length_t item_count;
@@ -1832,14 +1869,16 @@ ecma_builtin_array_prototype_object_map (ecma_value_t arg1, /**< callbackfn */
/* 6. */
#if ENABLED (JERRY_ES2015)
ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p);
ecma_value_t new_array = ecma_op_array_species_create (obj_p, len);
if (ECMA_IS_VALUE_ERROR (new_array))
{
return new_array;
}
#else /* !ENABLED (JERRY_ES2015) */
ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false);
ecma_value_t length_value = ecma_make_number_value (len);
ecma_value_t new_array = ecma_op_create_array_object (&length_value, 1, true);
ecma_free_value (length_value);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array));
#endif /* ENABLED (JERRY_ES2015) */
@@ -1883,23 +1922,22 @@ ecma_builtin_array_prototype_object_map (ecma_value_t arg1, /**< callbackfn */
mapped_value,
ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
JERRY_ASSERT (ecma_is_value_true (put_comp));
ecma_free_value (mapped_value);
ecma_free_value (current_value);
#if ENABLED (JERRY_ES2015)
if (ECMA_IS_VALUE_ERROR (put_comp))
{
ecma_deref_object (new_array_p);
return put_comp;
}
#else /* !ENABLED (JERRY_ES2015) */
JERRY_ASSERT (ecma_is_value_true (put_comp));
#endif /* ENABLED (JERRY_ES2015) */
}
}
ecma_value_t set_length_value = ecma_builtin_array_prototype_helper_set_length (new_array_p, ((ecma_number_t) len));
if (ECMA_IS_VALUE_ERROR (set_length_value))
{
ecma_deref_object (new_array_p);
return set_length_value;
}
return new_array;
return ecma_make_object_value (new_array_p);
} /* ecma_builtin_array_prototype_object_map */
/**
@@ -1925,7 +1963,7 @@ ecma_builtin_array_prototype_object_filter (ecma_value_t arg1, /**< callbackfn *
/* 6. */
#if ENABLED (JERRY_ES2015)
ecma_value_t new_array = ecma_op_create_array_object_by_constructor (NULL, 0, false, obj_p);
ecma_value_t new_array = ecma_op_array_species_create (obj_p, 0);
if (ECMA_IS_VALUE_ERROR (new_array))
{
@@ -1981,7 +2019,18 @@ ecma_builtin_array_prototype_object_filter (ecma_value_t arg1, /**< callbackfn *
new_array_index,
get_value,
ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
#if ENABLED (JERRY_ES2015)
if (ECMA_IS_VALUE_ERROR (put_comp))
{
ecma_free_value (call_value);
ecma_free_value (get_value);
ecma_deref_object (new_array_p);
return put_comp;
}
#else /* !ENABLED (JERRY_ES2015) */
JERRY_ASSERT (ecma_is_value_true (put_comp));
#endif /* ENABLED (JERRY_ES2015) */
new_array_index++;
}
@@ -460,6 +460,18 @@ ecma_builtin_array_object_of (ecma_value_t this_arg, /**< 'this' argument */
return ecma_make_object_value (obj_p);
} /* ecma_builtin_array_object_of */
/**
* 22.1.2.5 get Array [ @@species ] accessor
*
* @return ecma_value
* returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_builtin_array_species_get (ecma_value_t this_value) /**< This Value */
{
return ecma_copy_value (this_value);
} /* ecma_builtin_array_species_get */
#endif /* ENABLED (JERRY_ES2015) */
/**
@@ -43,6 +43,11 @@ ROUTINE (LIT_MAGIC_STRING_IS_ARRAY_UL, ecma_builtin_array_object_is_array, 1, 1)
#if ENABLED (JERRY_ES2015)
ROUTINE (LIT_MAGIC_STRING_FROM, ecma_builtin_array_object_from, NON_FIXED, 1)
ROUTINE (LIT_MAGIC_STRING_OF, ecma_builtin_array_object_of, NON_FIXED, 0)
/* ECMA-262 v6, 22.1.2.5 */
ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_SPECIES,
ecma_builtin_array_species_get,
ECMA_PROPERTY_FLAG_CONFIGURABLE)
#endif /* ENABLED (JERRY_ES2015) */
#endif /* !(ENABLED (JERRY_BUILTIN_ARRAY)) */
@@ -93,6 +93,18 @@ ecma_builtin_arraybuffer_dispatch_construct (const ecma_value_t *arguments_list_
return ecma_op_create_arraybuffer_object (arguments_list_p, arguments_list_len);
} /* ecma_builtin_arraybuffer_dispatch_construct */
/**
* 24.1.3.3 get ArrayBuffer [ @@species ] accessor
*
* @return ecma_value
* returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_builtin_arraybuffer_species_get (ecma_value_t this_value) /**< This Value */
{
return ecma_copy_value (this_value);
} /* ecma_builtin_arraybuffer_species_get */
/**
* @}
* @}
@@ -41,6 +41,11 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
/* ES2015 24.1.3.1 */
ROUTINE (LIT_MAGIC_STRING_IS_VIEW_UL, ecma_builtin_arraybuffer_object_is_view, 1, 1)
/* ES2015 24.1.3.3 */
ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_SPECIES,
ecma_builtin_arraybuffer_species_get,
ECMA_PROPERTY_FLAG_CONFIGURABLE)
#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */
#include "ecma-builtin-helpers-macro-undefs.inc.h"
@@ -65,6 +65,18 @@ ecma_builtin_map_dispatch_construct (const ecma_value_t *arguments_list_p, /**<
ECMA_BUILTIN_ID_MAP_PROTOTYPE);
} /* ecma_builtin_map_dispatch_construct */
/**
* 23.1.2.2 get Map [ @@species ] accessor
*
* @return ecma_value
* returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_builtin_map_species_get (ecma_value_t this_value) /**< This Value */
{
return ecma_copy_value (this_value);
} /* ecma_builtin_map_species_get */
/**
* @}
* @}
@@ -42,6 +42,11 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
ECMA_BUILTIN_ID_MAP_PROTOTYPE,
ECMA_PROPERTY_FIXED)
/* ECMA-262 v6, 23.1.2.2 */
ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_SPECIES,
ecma_builtin_map_species_get,
ECMA_PROPERTY_FLAG_CONFIGURABLE)
#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */
#include "ecma-builtin-helpers-macro-undefs.inc.h"
@@ -58,22 +58,27 @@ ecma_builtin_promise_reject_or_resolve (ecma_value_t this_arg, /**< "this" argum
return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object."));
}
uint8_t builtin_id = ecma_get_object_builtin_id (ecma_get_object_from_value (this_arg));
if (builtin_id != ECMA_BUILTIN_ID_PROMISE)
{
return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not the Promise constructor."));
}
if (is_resolve
&& ecma_is_value_object (argument)
&& ecma_is_promise (ecma_get_object_from_value (argument)))
{
return ecma_copy_value (argument);
ecma_object_t *ctor_obj_p = ecma_get_object_from_value (argument);
ecma_value_t x_ctor = ecma_op_object_get_by_magic_id (ctor_obj_p, LIT_MAGIC_STRING_CONSTRUCTOR);
if (ECMA_IS_VALUE_ERROR (x_ctor))
{
return x_ctor;
}
bool is_same_value = ecma_op_same_value (x_ctor, this_arg);
ecma_free_value (x_ctor);
if (is_same_value)
{
return ecma_copy_value (argument);
}
}
ecma_value_t capability = ecma_promise_new_capability ();
ecma_value_t capability = ecma_promise_new_capability (this_arg);
if (ECMA_IS_VALUE_ERROR (capability))
{
@@ -574,17 +579,32 @@ ecma_builtin_promise_race_or_all (ecma_value_t this_arg, /**< 'this' argument */
return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object."));
}
uint8_t builtin_id = ecma_get_object_builtin_id (ecma_get_object_from_value (this_arg));
ecma_object_t *this_obj_p = ecma_get_object_from_value (this_arg);
ecma_value_t species_symbol = ecma_op_object_get_by_magic_id (this_obj_p,
LIT_MAGIC_STRING_SYMBOL);
if (builtin_id != ECMA_BUILTIN_ID_PROMISE)
if (ECMA_IS_VALUE_ERROR (species_symbol))
{
return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not the Promise constructor."));
return species_symbol;
}
ecma_value_t capability = ecma_promise_new_capability ();
ecma_value_t constructor_value = this_arg;
if (!ecma_is_value_null (species_symbol) && !ecma_is_value_undefined (species_symbol))
{
ecma_free_value (constructor_value);
constructor_value = species_symbol;
}
else
{
ecma_ref_object (this_obj_p);
}
ecma_value_t capability = ecma_promise_new_capability (constructor_value);
if (ECMA_IS_VALUE_ERROR (capability))
{
ecma_free_value (constructor_value);
return capability;
}
@@ -594,19 +614,22 @@ ecma_builtin_promise_race_or_all (ecma_value_t this_arg, /**< 'this' argument */
|| 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 (capability);
return ret;
}
if (is_race)
{
ret = ecma_builtin_promise_do_race (array, capability, this_arg);
ret = ecma_builtin_promise_do_race (array, capability, constructor_value);
}
else
{
ret = ecma_builtin_promise_do_all (array, capability, this_arg);
ret = ecma_builtin_promise_do_all (array, capability, constructor_value);
}
ecma_free_value (constructor_value);
if (ECMA_IS_VALUE_ERROR (ret))
{
ret = jcontext_take_exception ();
@@ -686,6 +709,18 @@ ecma_builtin_promise_dispatch_construct (const ecma_value_t *arguments_list_p, /
return ecma_op_create_promise_object (arguments_list_p[0], ECMA_PROMISE_EXECUTOR_FUNCTION);
} /* ecma_builtin_promise_dispatch_construct */
/**
* 25.4.4.6 get Promise [ @@species ] accessor
*
* @return ecma_value
* returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_builtin_promise_species_get (ecma_value_t this_value) /**< This Value */
{
return ecma_copy_value (this_value);
} /* ecma_builtin_promise_species_get */
/**
* @}
* @}
@@ -42,6 +42,11 @@ ROUTINE (LIT_MAGIC_STRING_RESOLVE, ecma_builtin_promise_resolve, 1, 1)
ROUTINE (LIT_MAGIC_STRING_RACE, ecma_builtin_promise_race, 1, 1)
ROUTINE (LIT_MAGIC_STRING_ALL, ecma_builtin_promise_all, 1, 1)
/* ES2015 25.4.4.6 */
ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_SPECIES,
ecma_builtin_promise_species_get,
ECMA_PROPERTY_FLAG_CONFIGURABLE)
#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */
#include "ecma-builtin-helpers-macro-undefs.inc.h"
@@ -174,6 +174,20 @@ cleanup:
return ret_value;
} /* ecma_builtin_regexp_dispatch_construct */
#if ENABLED (JERRY_ES2015)
/**
* 21.2.4.2 get RegExp [ @@species ] accessor
*
* @return ecma_value
* returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_builtin_regexp_species_get (ecma_value_t this_value) /**< This Value */
{
return ecma_copy_value (this_value);
} /* ecma_builtin_regexp_species_get */
#endif /* ENABLED (JERRY_ES2015) */
/**
* @}
* @}
@@ -31,6 +31,13 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
ECMA_BUILTIN_ID_REGEXP_PROTOTYPE,
ECMA_PROPERTY_FIXED)
#if ENABLED (JERRY_ES2015)
/* ECMA-262 v6, 21.2.4.2 */
ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_SPECIES,
ecma_builtin_regexp_species_get,
ECMA_PROPERTY_FLAG_CONFIGURABLE)
#endif /* ENABLED (JERRY_ES2015) */
#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
#include "ecma-builtin-helpers-macro-undefs.inc.h"
@@ -65,6 +65,18 @@ ecma_builtin_set_dispatch_construct (const ecma_value_t *arguments_list_p, /**<
ECMA_BUILTIN_ID_SET_PROTOTYPE);
} /* ecma_builtin_set_dispatch_construct */
/**
* 23.2.2.2 get Set [ @@species ] accessor
*
* @return ecma_value
* returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_builtin_set_species_get (ecma_value_t this_value) /**< This Value */
{
return ecma_copy_value (this_value);
} /* ecma_builtin_set_species_get */
/**
* @}
* @}
@@ -42,6 +42,11 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
ECMA_BUILTIN_ID_SET_PROTOTYPE,
ECMA_PROPERTY_FIXED)
/* ECMA-262 v6, 23.2.2.2 */
ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_SPECIES,
ecma_builtin_set_species_get,
ECMA_PROPERTY_FLAG_CONFIGURABLE)
#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */
#include "ecma-builtin-helpers-macro-undefs.inc.h"
@@ -453,7 +453,8 @@ ecma_builtin_typedarray_prototype_map (ecma_value_t this_arg, /**< this argument
ecma_object_t *func_object_p = ecma_get_object_from_value (cb_func_val);
ecma_value_t new_typedarray = ecma_op_create_typedarray_with_type_and_length (src_obj_p, src_info.length);
// TODO: 22.2.3.18, 7-8.
ecma_value_t new_typedarray = ecma_op_create_typedarray_with_type_and_length (src_info.id, src_info.length);
if (ECMA_IS_VALUE_ERROR (new_typedarray))
{
@@ -713,9 +714,10 @@ ecma_builtin_typedarray_prototype_filter (ecma_value_t this_arg, /**< this argum
ecma_object_t *func_object_p = ecma_get_object_from_value (cb_func_val);
ecma_value_t ret_value = ECMA_VALUE_ERROR;
// TODO: 22.2.3.9, 7-8.
if (info.length == 0)
{
return ecma_op_create_typedarray_with_type_and_length (obj_p, 0);
return ecma_op_create_typedarray_with_type_and_length (info.id, 0);
}
JMEM_DEFINE_LOCAL_ARRAY (pass_value_list_p, info.length * info.element_size, lit_utf8_byte_t);
@@ -756,7 +758,7 @@ ecma_builtin_typedarray_prototype_filter (ecma_value_t this_arg, /**< this argum
uint32_t pass_num = (uint32_t) ((pass_value_p - pass_value_list_p) >> info.shift);
ret_value = ecma_op_create_typedarray_with_type_and_length (obj_p, pass_num);
ret_value = ecma_op_create_typedarray_with_type_and_length (info.id, pass_num);
if (!ECMA_IS_VALUE_ERROR (ret_value))
{
@@ -1967,7 +1969,8 @@ ecma_builtin_typedarray_prototype_slice (ecma_value_t this_arg, /**< this argume
int32_t distance = (int32_t) (relative_end - relative_start);
uint32_t count = distance > 0 ? (uint32_t) distance : 0;
ecma_value_t new_typedarray = ecma_op_create_typedarray_with_type_and_length (typedarray_p, count);
// TODO: 22.2.3.23, 12-13.
ecma_value_t new_typedarray = ecma_op_create_typedarray_with_type_and_length (info.id, count);
if (ECMA_IS_VALUE_ERROR (new_typedarray))
{
@@ -147,6 +147,7 @@ ecma_builtin_typedarray_of (ecma_value_t this_arg, /**< 'this' argument */
const uint8_t element_size_shift = ecma_typedarray_helper_get_shift_size (typedarray_id);
ecma_value_t ret_val = ecma_typedarray_create_object_with_length (arguments_list_len,
NULL,
proto_p,
element_size_shift,
typedarray_id);
@@ -215,6 +216,18 @@ ecma_builtin_typedarray_dispatch_construct (const ecma_value_t *arguments_list_p
return ecma_raise_type_error (ECMA_ERR_MSG ("TypedArray intrinstic cannot be called by a 'new' expression"));
} /* ecma_builtin_typedarray_dispatch_construct */
/**
* 22.2.2.4 get %TypedArray% [ @@species ] accessor
*
* @return ecma_value
* returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_builtin_typedarray_species_get (ecma_value_t this_value) /**< This Value */
{
return ecma_copy_value (this_value);
} /* ecma_builtin_typedarray_species_get */
/**
* @}
* @}
@@ -45,6 +45,11 @@ ROUTINE (LIT_MAGIC_STRING_FROM, ecma_builtin_typedarray_from, NON_FIXED, 1)
/* ES2015 22.2.2.2 */
ROUTINE (LIT_MAGIC_STRING_OF, ecma_builtin_typedarray_of, NON_FIXED, 0)
/* ES2015 22.2.2.4 */
ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_SPECIES,
ecma_builtin_typedarray_species_get,
ECMA_PROPERTY_FLAG_CONFIGURABLE)
#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */
#include "ecma-builtin-helpers-macro-undefs.inc.h"