From b06bd842604fb424c974985a69b9d84e2f5a6a38 Mon Sep 17 00:00:00 2001 From: Anthony Calandra Date: Tue, 19 Jun 2018 17:08:13 -0400 Subject: [PATCH] Add %TypedArray%.prototype.subarray([ begin [, end ] ]) support. JerryScript-DCO-1.0-Signed-off-by: Anthony Calandra anthony@anthony-calandra.com --- .../ecma-builtin-typedarray-helpers.c | 36 ++++++++ .../ecma-builtin-typedarray-helpers.h | 1 + .../ecma-builtin-typedarray-prototype.c | 92 +++++++++++++++++++ .../ecma-builtin-typedarray-prototype.inc.h | 1 + jerry-core/lit/lit-magic-strings.inc.h | 3 + jerry-core/lit/lit-magic-strings.ini | 1 + tests/jerry/es2015/typedArray-subarray.js | 48 ++++++++++ 7 files changed, 182 insertions(+) create mode 100644 tests/jerry/es2015/typedArray-subarray.js diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-helpers.c b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-helpers.c index 8aff794f31..e6660ba5e6 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-helpers.c +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-helpers.c @@ -19,6 +19,7 @@ #include "ecma-builtins.h" #include "ecma-gc.h" +#include "ecma-objects.h" #include "ecma-typedarray-object.h" #define ECMA_BUILTINS_INTERNAL @@ -95,6 +96,41 @@ ecma_typedarray_helper_get_shift_size (uint8_t builtin_id) /**< the builtin id o } } /* ecma_typedarray_helper_get_shift_size */ +/** + * Get the built-in TypedArray type from a magic string. + * + * @return uint8_t + */ +uint8_t +ecma_typedarray_helper_get_builtin_id (ecma_object_t *obj_p) /**< typedarray object **/ +{ +#define TYPEDARRAY_ID_CASE(magic_id, builtin_id) \ + case magic_id: \ + { \ + return builtin_id; \ + } + + switch (ecma_object_get_class_name (obj_p)) + { + TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_INT8_ARRAY_UL, ECMA_BUILTIN_ID_INT8ARRAY) + TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_UINT8_ARRAY_UL, ECMA_BUILTIN_ID_UINT8ARRAY) + TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_UINT8_CLAMPED_ARRAY_UL, ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY) + TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_INT16_ARRAY_UL, ECMA_BUILTIN_ID_INT16ARRAY) + TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_UINT16_ARRAY_UL, ECMA_BUILTIN_ID_UINT16ARRAY) + TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_INT32_ARRAY_UL, ECMA_BUILTIN_ID_INT32ARRAY) + TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_UINT32_ARRAY_UL, ECMA_BUILTIN_ID_UINT32ARRAY) + TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_FLOAT32_ARRAY_UL, ECMA_BUILTIN_ID_FLOAT32ARRAY) +#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 + TYPEDARRAY_ID_CASE (LIT_MAGIC_STRING_FLOAT64_ARRAY_UL, ECMA_BUILTIN_ID_FLOAT64ARRAY) +#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */ + default: + { + JERRY_UNREACHABLE (); + } + } +#undef TYPEDARRAY_ID_CASE +} /* ecma_typedarray_helper_get_builtin_id */ + /** * Get the magic string of a TypedArray type. * diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-helpers.h b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-helpers.h index bb9478a7a7..db98ddbf1f 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-helpers.h +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-helpers.h @@ -28,6 +28,7 @@ bool ecma_typedarray_helper_is_typedarray (uint8_t builtin_id); uint8_t ecma_typedarray_helper_get_shift_size (uint8_t builtin_id); +uint8_t ecma_typedarray_helper_get_builtin_id (ecma_object_t *obj_p); uint8_t ecma_typedarray_helper_get_magic_string (uint8_t builtin_id); uint8_t ecma_typedarray_helper_get_prototype_id (uint8_t builtin_id); 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 69fa50fb6f..f29a615eb9 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 @@ -14,6 +14,7 @@ */ #include "ecma-builtin-helpers.h" +#include "ecma-builtin-typedarray-helpers.h" #include "ecma-builtins.h" #include "ecma-exceptions.h" #include "ecma-globals.h" @@ -988,6 +989,97 @@ ecma_builtin_typedarray_prototype_object_to_string (ecma_value_t this_arg) /**< return ret_value; } /* ecma_builtin_typedarray_prototype_object_to_string */ +/** + * The %TypedArray%.prototype object's 'subarray' routine. + * + * See also: + * ES2015, 22.2.3.26 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_typedarray_prototype_subarray (ecma_value_t this_arg, /**< this argument */ + ecma_value_t begin, /**< begin */ + ecma_value_t end) /**< end */ +{ + ecma_value_t ret_value = ECMA_VALUE_EMPTY; + + /* 2.~ 4. */ + if (!ecma_is_typedarray (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray.")); + } + + ecma_object_t *src_typedarray_p = ecma_get_object_from_value (this_arg); + + /* 5. buffer */ + ecma_object_t *src_typedarray_arraybuffer_p = ecma_typedarray_get_arraybuffer (src_typedarray_p); + + /* 6. srcLength */ + ecma_length_t src_length = ecma_typedarray_get_length (src_typedarray_p); + + /* 9. beginIndex, 12. endIndex */ + uint32_t begin_index_uint32 = 0, end_index_uint32 = 0; + + /* 7. relativeBegin */ + ECMA_OP_TO_NUMBER_TRY_CATCH (relative_begin, begin, ret_value); + begin_index_uint32 = ecma_builtin_helper_array_index_normalize (relative_begin, src_length); + + if (ecma_is_value_undefined (end)) + { + end_index_uint32 = (uint32_t) src_length; + } + else + { + /* 10. relativeEnd */ + ECMA_OP_TO_NUMBER_TRY_CATCH (relative_end, end, ret_value); + + end_index_uint32 = ecma_builtin_helper_array_index_normalize (relative_end, src_length); + + ECMA_OP_TO_NUMBER_FINALIZE (relative_end); + } + + ECMA_OP_TO_NUMBER_FINALIZE (relative_begin); + + if (!ecma_is_value_empty (ret_value)) + { + return ret_value; + } + + /* 13. newLength */ + ecma_length_t subarray_length = 0; + + if (end_index_uint32 > begin_index_uint32) + { + subarray_length = end_index_uint32 - begin_index_uint32; + } + + /* 15. elementSize */ + uint8_t shift = ecma_typedarray_get_element_size_shift (src_typedarray_p); + uint8_t element_size = (uint8_t) (1 << shift); + + /* 16. srcByteOffset */ + ecma_length_t src_byte_offset = ecma_typedarray_get_offset (src_typedarray_p); + + /* 17. beginByteOffset */ + ecma_length_t begin_byte_offset = src_byte_offset + begin_index_uint32 * element_size; + + uint8_t src_builtin_id = ecma_typedarray_helper_get_builtin_id (src_typedarray_p); + ecma_value_t arguments_p[3] = + { + ecma_make_object_value (src_typedarray_arraybuffer_p), + ecma_make_uint32_value (begin_byte_offset), + ecma_make_uint32_value (subarray_length) + }; + + ret_value = ecma_typedarray_helper_dispatch_construct (arguments_p, 3, src_builtin_id); + + ecma_free_value (arguments_p[1]); + ecma_free_value (arguments_p[2]); + return ret_value; +} /* ecma_builtin_typedarray_prototype_subarray */ + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h index 88844322b4..02634ddf09 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.inc.h @@ -58,6 +58,7 @@ ROUTINE (LIT_MAGIC_STRING_REDUCE_RIGHT_UL, ecma_builtin_typedarray_prototype_red ROUTINE (LIT_MAGIC_STRING_FILTER, ecma_builtin_typedarray_prototype_filter, 2, 1) ROUTINE (LIT_MAGIC_STRING_REVERSE, ecma_builtin_typedarray_prototype_reverse, 0, 0) ROUTINE (LIT_MAGIC_STRING_SET, ecma_builtin_typedarray_prototype_set, 2, 1) +ROUTINE (LIT_MAGIC_STRING_SUBARRAY, ecma_builtin_typedarray_prototype_subarray, 2, 2) #endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index 850d202013..874b5cf5d9 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -334,6 +334,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PARSE_INT, "parseInt") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_HOURS_UL, "setHours") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_MONTH_UL, "setMonth") #endif +#if !defined (CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SUBARRAY, "subarray") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_STRING_UL, "toString") #if !defined (CONFIG_DISABLE_ANNEXB_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UNESCAPE, "unescape") diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index 905dade696..acaa707dcd 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -162,6 +162,7 @@ LIT_MAGIC_STRING_IS_SEALED_UL = "isSealed" LIT_MAGIC_STRING_PARSE_INT = "parseInt" LIT_MAGIC_STRING_SET_HOURS_UL = "setHours" LIT_MAGIC_STRING_SET_MONTH_UL = "setMonth" +LIT_MAGIC_STRING_SUBARRAY = "subarray" LIT_MAGIC_STRING_TO_STRING_UL = "toString" LIT_MAGIC_STRING_UNESCAPE = "unescape" LIT_MAGIC_STRING_WRITABLE = "writable" diff --git a/tests/jerry/es2015/typedArray-subarray.js b/tests/jerry/es2015/typedArray-subarray.js new file mode 100644 index 0000000000..57bf771887 --- /dev/null +++ b/tests/jerry/es2015/typedArray-subarray.js @@ -0,0 +1,48 @@ +/* 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. + */ + +var a = new Int32Array([1, 2, 3, 4, 5]); +assert(a.subarray().toString() === '1,2,3,4,5'); +assert(a.subarray(3).toString() === '4,5'); +assert(a.subarray(1, 3).toString() === '2,3'); +assert(a.subarray(-3).toString() === '3,4,5'); +assert(a.subarray(-3, -1).toString() === '3,4'); +assert(a.subarray(3, 2).toString() === ''); +assert(a.subarray(-2, -3).toString() === ''); +assert(a.subarray(4, 1).toString() === ''); +assert(a.subarray(-1, -4).toString() === ''); +assert(a.subarray(1).subarray(1).toString() === '3,4,5'); +assert(a.subarray(1, 4).subarray(1, 2).toString() === '3'); + +var b = new Uint8Array([]); +assert(b.subarray(123456, -123456).toString() === ''); +assert(b.subarray().subarray().toString() === ''); + +var ab = new ArrayBuffer(28); +var tmp = new Int32Array(ab); +tmp.set([0, 1, 2, 3, 4, 5, 0]); +var c = new Int32Array(ab, 4, 5); +assert(c.toString() === '1,2,3,4,5'); +assert(c.subarray().toString() === '1,2,3,4,5'); +assert(c.subarray(3).toString() === '4,5'); +assert(c.subarray(1, 3).toString() === '2,3'); +assert(c.subarray(-3).toString() === '3,4,5'); +assert(c.subarray(-3, -1).toString() === '3,4'); +assert(c.subarray(3, 2).toString() === ''); +assert(c.subarray(-2, -3).toString() === ''); +assert(c.subarray(4, 1).toString() === ''); +assert(c.subarray(-1, -4).toString() === ''); +assert(c.subarray(1).subarray(1).toString() === '3,4,5'); +assert(c.subarray(1, 4).subarray(1, 2).toString() === '3');