diff options
author | Daniel Balla <dballa@inf.u-szeged.hu> | 2019-12-16 11:44:15 +0100 |
---|---|---|
committer | Robert Fancsik <frobert@inf.u-szeged.hu> | 2019-12-16 11:44:15 +0100 |
commit | e0d8c4ca103384a046bc90bb68a45e7d99d91b7b (patch) | |
tree | b6a813aa966611df037d495617c6ff309aa314b9 | |
parent | 40d930d62c518361218e232d8600a9960472776b (diff) |
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
28 files changed, 741 insertions, 114 deletions
diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 49bd4a64..a08bcc18 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -3925,6 +3925,7 @@ jerry_create_typedarray (jerry_typedarray_type_t type_name, /**< type of TypedAr ecma_object_t *prototype_obj_p = ecma_builtin_get (prototype_id); ecma_value_t array_value = ecma_typedarray_create_object_with_length (length, + NULL, prototype_obj_p, element_size_shift, id); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c index 3e5685e1..417cf0fc 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c @@ -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++; } diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array.c b/jerry-core/ecma/builtin-objects/ecma-builtin-array.c index 9f7504ea..ee2d95c4 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array.c @@ -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) */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-array.inc.h index 013aa683..43ff947b 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array.inc.h @@ -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)) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.c b/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.c index 1cc71718..460e410d 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.c @@ -94,6 +94,18 @@ ecma_builtin_arraybuffer_dispatch_construct (const ecma_value_t *arguments_list_ } /* 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 */ + +/** * @} * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.inc.h index 2ed9fa4a..c2c7e26b 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.inc.h @@ -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" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-map.c b/jerry-core/ecma/builtin-objects/ecma-builtin-map.c index 644753c8..33b5fb57 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-map.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-map.c @@ -66,6 +66,18 @@ ecma_builtin_map_dispatch_construct (const ecma_value_t *arguments_list_p, /**< } /* 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 */ + +/** * @} * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-map.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-map.inc.h index 2c4ca3d2..da6951fc 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-map.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-map.inc.h @@ -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" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c index 5e1f0937..ae3381fc 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c @@ -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 (); @@ -687,6 +710,18 @@ ecma_builtin_promise_dispatch_construct (const ecma_value_t *arguments_list_p, / } /* 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 */ + +/** * @} * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h index 3135ac70..9eebf799 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h @@ -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" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.c b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.c index c91fa3fc..1de7784c 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.c @@ -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) */ + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.inc.h index 135427af..2001f1c1 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp.inc.h @@ -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" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-set.c b/jerry-core/ecma/builtin-objects/ecma-builtin-set.c index e6f6187a..e6f9f9df 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-set.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-set.c @@ -66,6 +66,18 @@ ecma_builtin_set_dispatch_construct (const ecma_value_t *arguments_list_p, /**< } /* 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 */ + +/** * @} * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-set.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-set.inc.h index c2847bbc..227bb344 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-set.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-set.inc.h @@ -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" diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c index a222f8dc..ed08b94b 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c @@ -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)) { diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.c b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.c index afb9f6f3..d30c0104 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.c +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.c @@ -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); @@ -216,6 +217,18 @@ ecma_builtin_typedarray_dispatch_construct (const ecma_value_t *arguments_list_p } /* 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 */ + +/** * @} * @} * @} diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.inc.h b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.inc.h index 36cf1eaf..6a05ba53 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.inc.h +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.inc.h @@ -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" diff --git a/jerry-core/ecma/operations/ecma-array-object.c b/jerry-core/ecma/operations/ecma-array-object.c index 8c01c664..d9101d43 100644 --- a/jerry-core/ecma/operations/ecma-array-object.c +++ b/jerry-core/ecma/operations/ecma-array-object.c @@ -663,27 +663,68 @@ ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of * Returned value must be freed with ecma_free_value */ ecma_value_t -ecma_op_create_array_object_by_constructor (const ecma_value_t *arguments_list_p, /**< list of arguments that - * are passed to - * Array constructor */ - ecma_length_t arguments_list_len, /**< length of the arguments' list */ - bool is_treat_single_arg_as_length, /**< if the value is true, - * arguments_list_len is 1 - * and single argument is Number, - * then treat the single argument - * as new Array's length rather - * than as single item of the - * Array */ - ecma_object_t *object_p) /**< The object from whom the new array object - * is being created */ +ecma_op_array_species_create (ecma_object_t *original_array_p, /**< The object from whom the new array object + * is being created */ + ecma_length_t length) /**< length of the array */ { - /* TODO: Use @@species after Symbol has been implemented */ - JERRY_UNUSED (object_p); + ecma_value_t constructor = ECMA_VALUE_UNDEFINED; + ecma_value_t original_array = ecma_make_object_value (original_array_p); - return ecma_op_create_array_object (arguments_list_p, - arguments_list_len, - is_treat_single_arg_as_length); -} /* ecma_op_create_array_object_by_constructor */ + if (ecma_is_value_array (original_array)) + { + constructor = ecma_op_object_get_by_magic_id (original_array_p, LIT_MAGIC_STRING_CONSTRUCTOR); + if (ECMA_IS_VALUE_ERROR (constructor)) + { + return constructor; + } + + if (ecma_is_constructor (constructor) + && ecma_get_object_from_value (constructor) == ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY)) + { + ecma_free_value (constructor); + constructor = ECMA_VALUE_UNDEFINED; + } + else if (ecma_is_value_object (constructor)) + { + ecma_object_t *ctor_object_p = ecma_get_object_from_value (constructor); + constructor = ecma_op_object_get_by_symbol_id (ctor_object_p, LIT_MAGIC_STRING_SPECIES); + ecma_deref_object (ctor_object_p); + + if (ECMA_IS_VALUE_ERROR (constructor)) + { + return constructor; + } + + if (ecma_is_value_null (constructor)) + { + constructor = ECMA_VALUE_UNDEFINED; + } + } + } + + if (ecma_is_value_undefined (constructor)) + { + return ecma_make_object_value (ecma_op_new_fast_array_object (length)); + } + + if (!ecma_is_constructor (constructor)) + { + ecma_free_value (constructor); + return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid species constructor")); + } + + ecma_value_t len_val = ecma_make_uint32_value (length); + ecma_object_t *ctor_object_p = ecma_get_object_from_value (constructor); + ecma_value_t ret_val = ecma_op_function_construct (ctor_object_p, + ECMA_VALUE_UNDEFINED, + &len_val, + 1); + + + ecma_deref_object (ctor_object_p); + ecma_free_value (len_val); + return ret_val; +} /* ecma_op_array_species_create */ #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/jerry-core/ecma/operations/ecma-array-object.h b/jerry-core/ecma/operations/ecma-array-object.h index 0204e81c..3e1e35a5 100644 --- a/jerry-core/ecma/operations/ecma-array-object.h +++ b/jerry-core/ecma/operations/ecma-array-object.h @@ -99,8 +99,8 @@ ecma_op_create_array_object (const ecma_value_t *arguments_list_p, ecma_length_t #if ENABLED (JERRY_ES2015) ecma_value_t -ecma_op_create_array_object_by_constructor (const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len, - bool is_treat_single_arg_as_length, ecma_object_t *object_p); +ecma_op_array_species_create (ecma_object_t *original_array_p, + ecma_length_t length); #endif /* ENABLED (JERRY_ES2015) */ ecma_value_t diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 1103ba10..be91449f 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -2614,6 +2614,62 @@ ecma_op_is_regexp (ecma_value_t arg) /**< argument */ return ecma_make_boolean_value (ecma_object_is_regexp_object (arg)); } /* ecma_op_is_regexp */ + +/** + * SpeciesConstructor operation + * See also: + * ECMA-262 v6, 7.3.20; + * + * @return ecma_value + * returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_op_species_constructor (ecma_object_t *this_value, /**< This Value */ + ecma_builtin_id_t default_constructor_id) /**< Builtin ID of default constructor */ +{ + ecma_object_t *default_constructor_p = ecma_builtin_get (default_constructor_id); + ecma_value_t constructor = ecma_op_object_get_by_magic_id (this_value, LIT_MAGIC_STRING_CONSTRUCTOR); + if (ECMA_IS_VALUE_ERROR (constructor)) + { + return constructor; + } + + if (ecma_is_value_undefined (constructor)) + { + ecma_ref_object (default_constructor_p); + return ecma_make_object_value (default_constructor_p); + } + + if (!ecma_is_value_object (constructor)) + { + ecma_free_value (constructor); + return ecma_raise_type_error (ECMA_ERR_MSG ("Constructor must be an Object")); + } + + ecma_object_t *ctor_object_p = ecma_get_object_from_value (constructor); + ecma_value_t species = ecma_op_object_get_by_symbol_id (ctor_object_p, LIT_MAGIC_STRING_SPECIES); + ecma_deref_object (ctor_object_p); + + if (ECMA_IS_VALUE_ERROR (species)) + { + return species; + } + + if (ecma_is_value_undefined (species) || ecma_is_value_null (species)) + { + ecma_ref_object (default_constructor_p); + return ecma_make_object_value (default_constructor_p); + } + + if (!ecma_is_constructor (species)) + { + ecma_free_value (species); + return ecma_raise_type_error (ECMA_ERR_MSG ("Species must be a Constructor")); + } + + return species; +} /* ecma_op_species_constructor */ + #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/jerry-core/ecma/operations/ecma-objects.h b/jerry-core/ecma/operations/ecma-objects.h index c5d56114..03e32404 100644 --- a/jerry-core/ecma/operations/ecma-objects.h +++ b/jerry-core/ecma/operations/ecma-objects.h @@ -16,6 +16,7 @@ #ifndef ECMA_OBJECTS_H #define ECMA_OBJECTS_H +#include "ecma-builtins.h" #include "ecma-conversion.h" #include "ecma-globals.h" @@ -70,7 +71,8 @@ bool ecma_object_is_regexp_object (ecma_value_t arg); #if ENABLED (JERRY_ES2015) ecma_value_t ecma_op_is_concat_spreadable (ecma_value_t arg); ecma_value_t ecma_op_is_regexp (ecma_value_t arg); -#endif /* !ENABLED (JERRY_ES2015) */ +ecma_value_t ecma_op_species_constructor (ecma_object_t *this_value, ecma_builtin_id_t default_constructor_id); +#endif /* ENABLED (JERRY_ES2015) */ /** * @} diff --git a/jerry-core/ecma/operations/ecma-promise-object.c b/jerry-core/ecma/operations/ecma-promise-object.c index 88258efc..1f5c8652 100644 --- a/jerry-core/ecma/operations/ecma-promise-object.c +++ b/jerry-core/ecma/operations/ecma-promise-object.c @@ -574,6 +574,71 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function } /* ecma_op_create_promise_object */ /** + * 25.4.1.5.1 GetCapabilitiesExecutor Functions + * + * Checks and sets a promiseCapability's resolve and reject properties. + * + * @return ECMA_VALUE_UNDEFINED or TypeError + * returned value must be freed with ecma_free_value + */ +static ecma_value_t +ecma_op_get_capabilities_executor_cb (const ecma_value_t function_obj, /**< the function itself */ + const ecma_value_t this_val, /**< this_arg of the function */ + const ecma_value_t args_p[], /**< argument list */ + const ecma_length_t args_count) /**< argument number */ +{ + JERRY_UNUSED (this_val); + /* 1. */ + ecma_value_t capability = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (function_obj), + LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY); + JERRY_ASSERT (ecma_is_value_object (capability)); + + /* 2. */ + ecma_object_t *capability_obj_p = ecma_get_object_from_value (capability); + + /* 3. */ + ecma_value_t resolve = ecma_op_object_get_by_magic_id (capability_obj_p, + LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); + + if (!ecma_is_value_undefined (resolve)) + { + ecma_free_value (resolve); + ecma_deref_object (capability_obj_p); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Resolve must be undefined")); + } + + /* 4. */ + ecma_value_t reject = ecma_op_object_get_by_magic_id (capability_obj_p, + LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); + + if (!ecma_is_value_undefined (reject)) + { + ecma_free_value (reject); + ecma_deref_object (capability_obj_p); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Reject must be undefined")); + } + + /* 5. */ + ecma_op_object_put (capability_obj_p, + ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE), + args_count > 0 ? args_p[0] : ECMA_VALUE_UNDEFINED, + false); + + /* 6. */ + ecma_op_object_put (capability_obj_p, + ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT), + args_count > 1 ? args_p[1] : ECMA_VALUE_UNDEFINED, + false); + + ecma_deref_object (capability_obj_p); + + /* 7. */ + return ECMA_VALUE_UNDEFINED; +} /* ecma_op_get_capabilities_executor_cb */ + +/** * Create a new PromiseCapability. * * See also: ES2015 25.4.1.5 @@ -582,16 +647,22 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function * Returned value must be freed with ecma_free_value */ ecma_value_t -ecma_promise_new_capability (void) +ecma_promise_new_capability (ecma_value_t constructor) { + /* 1. */ + if (!ecma_is_constructor (constructor)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid capability")); + } + + ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor); /* 3. */ ecma_object_t *capability_p = ecma_op_create_object_object_noarg (); ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY); ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); /* 4. */ - ecma_object_t *executor_p; - executor_p = ecma_op_create_object_object_noarg (); + ecma_object_t *executor_p = ecma_op_create_external_function_object (ecma_op_get_capabilities_executor_cb); ecma_value_t executor = ecma_make_object_value (executor_p); /* 5. */ ecma_op_object_put (executor_p, @@ -600,25 +671,27 @@ ecma_promise_new_capability (void) false); /* 6. */ - ecma_value_t promise = ecma_op_create_promise_object (executor, ECMA_PROMISE_EXECUTOR_OBJECT); - - /* 10. */ - ecma_op_object_put (capability_p, - promise_str_p, - promise, - false); - + ecma_value_t promise = ecma_op_function_construct (constructor_obj_p, + ECMA_VALUE_UNDEFINED, + &executor, + 1); ecma_deref_object (executor_p); /* 7. */ if (ECMA_IS_VALUE_ERROR (promise)) { - ecma_free_value (promise); ecma_deref_object (capability_p); return promise; } + /* 10. */ + ecma_op_object_put (capability_p, + promise_str_p, + promise, + false); + ecma_free_value (promise); + /* 8. */ 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 (capability_p, resolve_str_p); @@ -755,7 +828,14 @@ ecma_promise_then (ecma_value_t promise, /**< the promise which call 'then' */ return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a Promise.")); } - ecma_value_t result_capability = ecma_promise_new_capability (); + ecma_value_t species = ecma_op_species_constructor (obj, ECMA_BUILTIN_ID_PROMISE); + if (ECMA_IS_VALUE_ERROR (species)) + { + return species; + } + + ecma_value_t result_capability = ecma_promise_new_capability (species); + ecma_free_value (species); if (ECMA_IS_VALUE_ERROR (result_capability)) { diff --git a/jerry-core/ecma/operations/ecma-promise-object.h b/jerry-core/ecma/operations/ecma-promise-object.h index ad019f33..d39cdce7 100644 --- a/jerry-core/ecma/operations/ecma-promise-object.h +++ b/jerry-core/ecma/operations/ecma-promise-object.h @@ -73,7 +73,7 @@ ecma_value_t ecma_op_create_promise_object (ecma_value_t executor, ecma_promise_executor_type_t type); uint8_t ecma_promise_get_state (ecma_object_t *promise_p); ecma_value_t ecma_promise_get_result (ecma_object_t *promise_p); -ecma_value_t ecma_promise_new_capability (void); +ecma_value_t ecma_promise_new_capability (ecma_value_t constructor); ecma_value_t ecma_promise_then (ecma_value_t promise, ecma_value_t on_fulfilled, diff --git a/jerry-core/ecma/operations/ecma-typedarray-object.c b/jerry-core/ecma/operations/ecma-typedarray-object.c index 71566328..c09d38e3 100644 --- a/jerry-core/ecma/operations/ecma-typedarray-object.c +++ b/jerry-core/ecma/operations/ecma-typedarray-object.c @@ -459,6 +459,17 @@ ecma_typedarray_helper_get_prototype_id (ecma_typedarray_type_t typedarray_id) / } /* ecma_typedarray_helper_get_prototype_id */ /** + * Get the constructor ID of a TypedArray type. + * + * @return ecma_builtin_id_t + */ +ecma_builtin_id_t +ecma_typedarray_helper_get_constructor_id (ecma_typedarray_type_t typedarray_id) /**< the id of the typedarray **/ +{ + return (ecma_builtin_id_t) (ECMA_FIRST_TYPEDARRAY_BUILTIN_ROUTINE_ID + typedarray_id); +} /* ecma_typedarray_helper_get_constructor_id */ + +/** * Get the built-in TypedArray type of the given object. * * @return ecma_typedarray_type_t @@ -496,6 +507,7 @@ ecma_typedarray_helper_builtin_to_typedarray_id (ecma_builtin_id_t builtin_id) */ ecma_value_t ecma_typedarray_create_object_with_length (ecma_length_t array_length, /**< length of the typedarray */ + ecma_object_t *src_buffer_p, /**< source buffer */ ecma_object_t *proto_p, /**< prototype object */ uint8_t element_size_shift, /**< the size shift of the element length */ ecma_typedarray_type_t typedarray_id) /**< id of the typedarray */ @@ -512,7 +524,32 @@ ecma_typedarray_create_object_with_length (ecma_length_t array_length, /**< leng return ecma_raise_range_error (ECMA_ERR_MSG ("Maximum typedarray size is reached.")); } - ecma_object_t *new_arraybuffer_p = ecma_arraybuffer_new_object (byte_length); + ecma_object_t *new_arraybuffer_p = NULL; + if (src_buffer_p == NULL) + { + new_arraybuffer_p = ecma_arraybuffer_new_object (byte_length); + } + else + { + ecma_value_t ctor_proto = ecma_op_species_constructor (src_buffer_p, ECMA_BUILTIN_ID_ARRAYBUFFER); + if (ECMA_IS_VALUE_ERROR (ctor_proto)) + { + return ctor_proto; + } + + ecma_object_t *ctor_proto_p = ecma_get_object_from_value (ctor_proto); + + ecma_value_t byte_length_val = ecma_make_uint32_value (byte_length); + ecma_value_t new_arraybuffer = ecma_op_function_construct (ctor_proto_p, + ECMA_VALUE_UNDEFINED, + &byte_length_val, + 1); + ecma_deref_object (ctor_proto_p); + ecma_free_value (byte_length_val); + + new_arraybuffer_p = ecma_get_object_from_value (new_arraybuffer); + } + ecma_object_t *object_p = ecma_create_object (proto_p, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_PSEUDO_ARRAY); @@ -597,6 +634,7 @@ ecma_typedarray_create_object_with_typedarray (ecma_object_t *typedarray_p, /**< } ecma_value_t new_typedarray = ecma_typedarray_create_object_with_length (array_length, + src_arraybuffer_p, proto_p, element_size_shift, typedarray_id); @@ -691,6 +729,7 @@ ecma_op_typedarray_from (ecma_value_t items_val, /**< the source array-like obje /* 14 */ ecma_value_t new_typedarray = ecma_typedarray_create_object_with_length (len, + NULL, proto_p, element_size_shift, typedarray_id); @@ -899,7 +938,7 @@ ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg li if (arguments_list_len == 0) { /* 22.2.1.1 */ - ret = ecma_typedarray_create_object_with_length (0, proto_p, element_size_shift, typedarray_id); + ret = ecma_typedarray_create_object_with_length (0, NULL, proto_p, element_size_shift, typedarray_id); } else if (!ecma_is_value_object (arguments_list_p[0])) { @@ -920,6 +959,7 @@ ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg li else { ret = ecma_typedarray_create_object_with_length (length, + NULL, proto_p, element_size_shift, typedarray_id); @@ -1154,51 +1194,19 @@ ecma_op_typedarray_define_index_prop (ecma_object_t *obj_p, /**< a TypedArray ob * @return ecma_value_t */ ecma_value_t -ecma_op_create_typedarray_with_type_and_length (ecma_object_t *obj_p, /**< TypedArray object - * indicates the type */ +ecma_op_create_typedarray_with_type_and_length (ecma_typedarray_type_t typedarray_id, /** TypedArray id */ ecma_length_t array_length) /**< length of the typedarray */ { - JERRY_ASSERT (ecma_object_is_typedarray (obj_p)); - -#if ENABLED (JERRY_ES2015) - ecma_value_t constructor_value = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_CONSTRUCTOR); - - if (ECMA_IS_VALUE_ERROR (constructor_value) - || !ecma_is_constructor (constructor_value)) - { - ecma_free_value (constructor_value); - return ecma_raise_type_error (ECMA_ERR_MSG ("object.constructor is not a constructor.")); - } - - ecma_object_t *constructor_object_p = ecma_get_object_from_value (constructor_value); - ecma_value_t constructor_prototype = ecma_op_object_get_by_magic_id (constructor_object_p, - LIT_MAGIC_STRING_PROTOTYPE); - - ecma_deref_object (constructor_object_p); - - if (ECMA_IS_VALUE_ERROR (constructor_prototype)) - { - return constructor_prototype; - } -#endif /* ENABLED (JERRY_ES2015) */ - - ecma_typedarray_type_t typedarray_id = ecma_get_typedarray_id (obj_p); + // TODO: assert validate typedarray_id ecma_object_t *proto_p = ecma_builtin_get (ecma_typedarray_helper_get_prototype_id (typedarray_id)); uint8_t element_size_shift = ecma_typedarray_helper_get_shift_size (typedarray_id); ecma_value_t new_obj = ecma_typedarray_create_object_with_length (array_length, + NULL, proto_p, element_size_shift, typedarray_id); -#if ENABLED (JERRY_ES2015) - ecma_object_t *constructor_prototype_object_p = ecma_get_object_from_value (constructor_prototype); - ecma_object_t *new_obj_p = ecma_get_object_from_value (new_obj); - ECMA_SET_NON_NULL_POINTER (new_obj_p->u2.prototype_cp, constructor_prototype_object_p); - - ecma_deref_object (constructor_prototype_object_p); -#endif /* ENABLED (JERRY_ES2015) */ - return new_obj; } /* ecma_op_create_typedarray_with_type_and_length */ diff --git a/jerry-core/ecma/operations/ecma-typedarray-object.h b/jerry-core/ecma/operations/ecma-typedarray-object.h index 770423f1..52821fa7 100644 --- a/jerry-core/ecma/operations/ecma-typedarray-object.h +++ b/jerry-core/ecma/operations/ecma-typedarray-object.h @@ -39,6 +39,7 @@ void ecma_set_typedarray_element (lit_utf8_byte_t *dst_p, bool ecma_typedarray_helper_is_typedarray (ecma_builtin_id_t builtin_id); ecma_typedarray_type_t ecma_get_typedarray_id (ecma_object_t *obj_p); ecma_builtin_id_t ecma_typedarray_helper_get_prototype_id (ecma_typedarray_type_t typedarray_id); +ecma_builtin_id_t ecma_typedarray_helper_get_constructor_id (ecma_typedarray_type_t typedarray_id); ecma_typedarray_type_t ecma_typedarray_helper_builtin_to_typedarray_id (ecma_builtin_id_t builtin_id); ecma_value_t ecma_op_typedarray_from (ecma_value_t items_val, @@ -64,10 +65,11 @@ void ecma_op_typedarray_list_lazy_property_names (ecma_object_t *obj_p, bool ecma_op_typedarray_define_index_prop (ecma_object_t *obj_p, uint32_t index, const ecma_property_descriptor_t *property_desc_p); -ecma_value_t ecma_op_create_typedarray_with_type_and_length (ecma_object_t *obj_p, +ecma_value_t ecma_op_create_typedarray_with_type_and_length (ecma_typedarray_type_t typedarray_id, ecma_length_t array_length); ecma_typedarray_info_t ecma_typedarray_get_info (ecma_object_t *typedarray_p); ecma_value_t ecma_typedarray_create_object_with_length (ecma_length_t array_length, + ecma_object_t *src_arraybuffer_p, ecma_object_t *proto_p, uint8_t element_size_shift, ecma_typedarray_type_t typedarray_id); diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index 6891e722..265f9b8b 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -345,7 +345,8 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_STRING, "string") #if ENABLED (JERRY_BUILTIN_ANNEXB) && ENABLED (JERRY_BUILTIN_STRING) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SUBSTR, "substr") #endif -#if ENABLED (JERRY_ES2015) +#if ENABLED (JERRY_ES2015) \ +|| ENABLED (JERRY_ES2015_BUILTIN_PROMISE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SYMBOL, "symbol") #endif #if ENABLED (JERRY_BUILTIN_DATE) \ diff --git a/tests/jerry/es2015/array-species.js b/tests/jerry/es2015/array-species.js new file mode 100644 index 00000000..05b36ece --- /dev/null +++ b/tests/jerry/es2015/array-species.js @@ -0,0 +1,184 @@ +/* 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. + */ + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test the ES2015 @@species feature + +'use strict'; + +// Subclasses of Array construct themselves under map, etc + +class MyArray extends Array { } + +function assertEquals(a, b) { + assert(a === b); +} + +assertEquals(MyArray, new MyArray().map(()=>{}).constructor); +assertEquals(MyArray, new MyArray().filter(()=>{}).constructor); +assertEquals(MyArray, new MyArray().slice().constructor); +assertEquals(MyArray, new MyArray().splice().constructor); +assertEquals(MyArray, new MyArray().concat([1]).constructor); +assertEquals(1, new MyArray().concat([1])[0]); + +// Subclasses can override @@species to return the another class + +class MyOtherArray extends Array { + static get [Symbol.species]() { return MyArray; } +} + +assertEquals(MyArray, new MyOtherArray().map(()=>{}).constructor); +assertEquals(MyArray, new MyOtherArray().filter(()=>{}).constructor); +assertEquals(MyArray, new MyOtherArray().slice().constructor); +assertEquals(MyArray, new MyOtherArray().splice().constructor); +assertEquals(MyArray, new MyOtherArray().concat().constructor); + +// Array methods on non-arrays return arrays + +class MyNonArray extends Array { + static get [Symbol.species]() { return MyObject; } +} + +class MyObject { } + +assertEquals(MyObject, + Array.prototype.map.call(new MyNonArray(), ()=>{}).constructor); +assertEquals(MyObject, + Array.prototype.filter.call(new MyNonArray(), ()=>{}).constructor); +assertEquals(MyObject, + Array.prototype.slice.call(new MyNonArray()).constructor); +assertEquals(MyObject, + Array.prototype.splice.call(new MyNonArray()).constructor); +assertEquals(MyObject, + Array.prototype.concat.call(new MyNonArray()).constructor); + +assertEquals(undefined, + Array.prototype.map.call(new MyNonArray(), ()=>{}).length); +assertEquals(undefined, + Array.prototype.filter.call(new MyNonArray(), ()=>{}).length); +// slice, splice, and concat actually do explicitly define the length. +assertEquals(0, Array.prototype.slice.call(new MyNonArray()).length); +assertEquals(0, Array.prototype.splice.call(new MyNonArray()).length); +assertEquals(1, Array.prototype.concat.call(new MyNonArray(), ()=>{}).length); + +// Defaults when constructor or @@species is missing or non-constructor + +class MyDefaultArray extends Array { + static get [Symbol.species]() { return undefined; } +} +assertEquals(Array, new MyDefaultArray().map(()=>{}).constructor); + +class MyOtherDefaultArray extends Array { } +assertEquals(MyOtherDefaultArray, + new MyOtherDefaultArray().map(()=>{}).constructor); +MyOtherDefaultArray.prototype.constructor = undefined; +assertEquals(Array, new MyOtherDefaultArray().map(()=>{}).constructor); +assertEquals(Array, new MyOtherDefaultArray().concat().constructor); + +// Exceptions propagated when getting constructor @@species throws + +class SpeciesError extends Error { } +class ConstructorError extends Error { } +class MyThrowingArray extends Array { + static get [Symbol.species]() { throw new SpeciesError; } +} + +function assertThrows (a, b) { + try { + a(); + } catch (e) { + assert(e instanceof b); + } +} + +assertThrows(() => new MyThrowingArray().map(()=>{}), SpeciesError); +Object.defineProperty(MyThrowingArray.prototype, 'constructor', { + get() { throw new ConstructorError; } +}); +assertThrows(() => new MyThrowingArray().map(()=>{}), ConstructorError); + +// Previously unexpected errors from setting properties in arrays throw + +class FrozenArray extends Array { + constructor(...args) { + super(...args); + Object.freeze(this); + } +} +assertThrows(() => new FrozenArray([1]).map(()=>0), TypeError); +assertThrows(() => new FrozenArray([1]).filter(()=>true), TypeError); +assertThrows(() => new FrozenArray([1]).slice(0, 1), TypeError); +assertThrows(() => new FrozenArray([1]).splice(0, 1), TypeError); +assertThrows(() => new FrozenArray([]).concat([1]), TypeError); + +// Verify call counts and constructor parameters + +var count; +var params; +class MyObservedArray extends Array { + constructor(...args) { + super(...args); + params = args; + } + static get [Symbol.species]() { + count++ + return this; + } +} + +function assertArrayEquals(value, expected, type) { + assert(expected.length === value.length); + for (var i=0; i<value.length; ++i) { + assertEquals(expected[i], value[i]); + } +} + +count = 0; +params = undefined; +assertEquals(MyObservedArray, + new MyObservedArray().map(()=>{}).constructor); +assertEquals(1, count); +assertArrayEquals([0], params); + +count = 0; +params = undefined; +assertEquals(MyObservedArray, + new MyObservedArray().filter(()=>{}).constructor); +assertEquals(1, count); +assertArrayEquals([0], params); + +count = 0; +params = undefined; +assertEquals(MyObservedArray, + new MyObservedArray().concat().constructor); +assertEquals(1, count); +assertArrayEquals([0], params); + +count = 0; +params = undefined; +assertEquals(MyObservedArray, + new MyObservedArray().slice().constructor); +assertEquals(1, count); +assertArrayEquals([0], params); + +count = 0; +params = undefined; +assertEquals(MyObservedArray, + new MyObservedArray().splice().constructor); +assertEquals(1, count); +assertArrayEquals([0], params); diff --git a/tests/jerry/es2015/promise-species.js b/tests/jerry/es2015/promise-species.js new file mode 100644 index 00000000..6773bfcc --- /dev/null +++ b/tests/jerry/es2015/promise-species.js @@ -0,0 +1,53 @@ +/* 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. + */ + +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test that Promises use @@species appropriately + +// Another constructor with no species will not be instantiated + +var test = new Promise(function(){}); +var bogoCount = 0; +function bogusConstructor() { bogoCount++; } +test.constructor = bogusConstructor; +assert(Promise.resolve(test) instanceof Promise); +assert(!(Promise.resolve(test) instanceof bogusConstructor)); + +// If there is a species, it will be instantiated +// @@species will be read exactly once, and the constructor is called with a +// function +var count = 0; +var params; + +class MyPromise extends Promise { + constructor(...args) { + super(...args); + params = args; + } + static get [Symbol.species]() { + count++ + return this; + } +} + +var myPromise = MyPromise.resolve().then(); +assert(1 === count); +assert(1 === params.length); +assert('function' === typeof(params[0])); +assert(myPromise instanceof MyPromise); +assert(myPromise instanceof Promise); |