aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Balla <dballa@inf.u-szeged.hu>2019-12-16 11:44:15 +0100
committerRobert Fancsik <frobert@inf.u-szeged.hu>2019-12-16 11:44:15 +0100
commite0d8c4ca103384a046bc90bb68a45e7d99d91b7b (patch)
treeb6a813aa966611df037d495617c6ff309aa314b9
parent40d930d62c518361218e232d8600a9960472776b (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
-rw-r--r--jerry-core/api/jerry.c1
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c89
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-array.c12
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-array.inc.h5
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.c12
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer.inc.h5
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-map.c12
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-map.inc.h5
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-promise.c65
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h5
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-regexp.c14
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-regexp.inc.h7
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-set.c12
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-set.inc.h5
-rw-r--r--jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c11
-rw-r--r--jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.c13
-rw-r--r--jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray.inc.h5
-rw-r--r--jerry-core/ecma/operations/ecma-array-object.c79
-rw-r--r--jerry-core/ecma/operations/ecma-array-object.h4
-rw-r--r--jerry-core/ecma/operations/ecma-objects.c56
-rw-r--r--jerry-core/ecma/operations/ecma-objects.h4
-rw-r--r--jerry-core/ecma/operations/ecma-promise-object.c106
-rw-r--r--jerry-core/ecma/operations/ecma-promise-object.h2
-rw-r--r--jerry-core/ecma/operations/ecma-typedarray-object.c82
-rw-r--r--jerry-core/ecma/operations/ecma-typedarray-object.h4
-rw-r--r--jerry-core/lit/lit-magic-strings.inc.h3
-rw-r--r--tests/jerry/es2015/array-species.js184
-rw-r--r--tests/jerry/es2015/promise-species.js53
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);