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 b285d3a869..562817d0d5 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 @@ -1797,6 +1797,187 @@ ecma_builtin_typedarray_prototype_last_index_of (ecma_value_t this_arg, /**< thi return ecma_builtin_typedarray_prototype_index_helper (this_arg, args, args_number, true); } /* ecma_builtin_typedarray_prototype_last_index_of */ +/** + * Helper function to get the uint32_t value from an argument. + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_get_uint32_value_from_argument (ecma_value_t arg_value, /**< this argument */ + uint32_t length, /**< length of the TypedArray */ + uint32_t *index, /**< [out] pointer to the given index */ + bool is_end_index) /**< true - normalize the end index */ +{ + ecma_number_t num_var; + ecma_value_t ret_value = ecma_get_number (arg_value, &num_var); + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + return ret_value; + } + + if (is_end_index && ecma_number_is_nan (num_var)) + { + *index = length; + } + else + { + *index = ecma_builtin_helper_array_index_normalize (num_var, length, false); + } + + return ECMA_VALUE_EMPTY; +} /* ecma_builtin_get_uint32_value_from_argument */ + +/** + * The %TypedArray%.prototype object's 'copyWithin' routine + * + * See also: + * ECMA-262 v6, 22.2.3.5 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_typedarray_prototype_copy_within (ecma_value_t this_arg, /**< this argument */ + const ecma_value_t args[], /**< arguments list */ + ecma_length_t args_number) /**< number of arguments */ +{ + if (!ecma_is_typedarray (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray.")); + } + + ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); + lit_utf8_byte_t *typedarray_buffer_p = ecma_typedarray_get_buffer (typedarray_p); + uint32_t length = ecma_typedarray_get_length (typedarray_p); + uint8_t shift = ecma_typedarray_get_element_size_shift (typedarray_p); + uint8_t element_size = (uint8_t) (1 << shift); + uint32_t target = 0; + uint32_t start = 0; + uint32_t end = length; + + if (args_number > 0) + { + ecma_value_t target_value = ecma_builtin_get_uint32_value_from_argument (args[0], length, &target, false); + + if (ECMA_IS_VALUE_ERROR (target_value)) + { + return target_value; + } + + if (args_number > 1) + { + ecma_value_t start_value = ecma_builtin_get_uint32_value_from_argument (args[1], length, &start, false); + + if (ECMA_IS_VALUE_ERROR (start_value)) + { + return start_value; + } + + if (args_number > 2) + { + ecma_value_t end_value = ecma_builtin_get_uint32_value_from_argument (args[2], length, &end, true); + + if (ECMA_IS_VALUE_ERROR (end_value)) + { + return end_value; + } + } + } + } + + int32_t distance = (int32_t) (end - start); + int32_t offset = (int32_t) (length - target); + int32_t count = JERRY_MIN (distance, offset); + + if (target >= length || start >= length || end == 0) + { + return ecma_copy_value (this_arg); + } + else + { + memmove (typedarray_buffer_p + (target * element_size), + typedarray_buffer_p + (start * element_size), + (size_t) (count * element_size)); + } + + return ecma_copy_value (this_arg); +} /* ecma_builtin_typedarray_prototype_copy_within */ + +/** + * The %TypedArray%.prototype object's 'slice' routine + * + * See also: + * ECMA-262 v6, 22.2.3.23 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_typedarray_prototype_slice (ecma_value_t this_arg, /**< this argument */ + const ecma_value_t args[], /**< arguments list */ + ecma_length_t args_number) /**< number of arguments */ +{ + if (!ecma_is_typedarray (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray.")); + } + + ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); + uint32_t length = ecma_typedarray_get_length (typedarray_p); + uint32_t start = 0; + uint32_t end = length; + + if (args_number > 0) + { + ecma_value_t start_value = ecma_builtin_get_uint32_value_from_argument (args[0], length, &start, false); + + if (ECMA_IS_VALUE_ERROR (start_value)) + { + return start_value; + } + + if (args_number > 1) + { + ecma_value_t end_value = ecma_builtin_get_uint32_value_from_argument (args[1], length, &end, true); + + if (ECMA_IS_VALUE_ERROR (end_value)) + { + return end_value; + } + } + } + + int32_t distance = (int32_t) (end - 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); + + if (ECMA_IS_VALUE_ERROR (new_typedarray)) + { + return new_typedarray; + } + + if (count > 0) + { + lit_utf8_byte_t *typedarray_buffer_p = ecma_typedarray_get_buffer (typedarray_p); + uint8_t shift = ecma_typedarray_get_element_size_shift (typedarray_p); + uint8_t element_size = (uint8_t) (1 << shift); + + ecma_object_t *new_typedarray_p = ecma_get_object_from_value (new_typedarray); + lit_utf8_byte_t *new_typedarray_buffer_p = ecma_typedarray_get_buffer (new_typedarray_p); + ecma_length_t src_byte_offset = ecma_typedarray_get_offset (typedarray_p); + uint32_t src_byte_index = (start * element_size) + src_byte_offset; + + memcpy (new_typedarray_buffer_p, + typedarray_buffer_p + src_byte_index, + count * element_size); + } + + return new_typedarray; +} /* ecma_builtin_typedarray_prototype_slice */ + /** * @} * @} 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 909b14da25..342178a8e4 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 @@ -72,6 +72,8 @@ ROUTINE (LIT_MAGIC_STRING_FIND, ecma_builtin_typedarray_prototype_find, 2, 1) ROUTINE (LIT_MAGIC_STRING_FIND_INDEX, ecma_builtin_typedarray_prototype_find_index, 2, 1) ROUTINE (LIT_MAGIC_STRING_INDEX_OF_UL, ecma_builtin_typedarray_prototype_index_of, NON_FIXED, 1) ROUTINE (LIT_MAGIC_STRING_LAST_INDEX_OF_UL, ecma_builtin_typedarray_prototype_last_index_of, NON_FIXED, 1) +ROUTINE (LIT_MAGIC_STRING_COPY_WITHIN, ecma_builtin_typedarray_prototype_copy_within, NON_FIXED, 2) +ROUTINE (LIT_MAGIC_STRING_SLICE, ecma_builtin_typedarray_prototype_slice, NON_FIXED, 2) #if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index 1e492045db..64c341de87 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -551,6 +551,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BYTE_OFFSET_UL, "byteOffset") #if ENABLED (JERRY_BUILTIN_STRING) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CHAR_CODE_AT_UL, "charCodeAt") #endif +#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COPY_WITHIN, "copyWithin") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ENUMERABLE, "enumerable") #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_FLOAT_32_UL, "getFloat32") @@ -804,6 +807,8 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_TYPED_ARRAY_UL) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_BYTE_LENGTH_UL) #elif ENABLED (JERRY_BUILTIN_STRING) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_CHAR_CODE_AT_UL) +#elif ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) +LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_COPY_WITHIN) #else LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (10, LIT_MAGIC_STRING_ENUMERABLE) #endif diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index 7ae4b1a0f5..ec1f5e7397 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -237,6 +237,7 @@ LIT_MAGIC_STRING_UINT8_ARRAY_UL = "Uint8Array" LIT_MAGIC_STRING_BYTE_LENGTH_UL = "byteLength" LIT_MAGIC_STRING_BYTE_OFFSET_UL = "byteOffset" LIT_MAGIC_STRING_CHAR_CODE_AT_UL = "charCodeAt" +LIT_MAGIC_STRING_COPY_WITHIN = "copyWithin" LIT_MAGIC_STRING_ENUMERABLE = "enumerable" LIT_MAGIC_STRING_GET_FLOAT_32_UL = "getFloat32" LIT_MAGIC_STRING_GET_FLOAT_64_UL = "getFloat64" diff --git a/tests/jerry/es2015/typedarray-prototype-copy-within.js b/tests/jerry/es2015/typedarray-prototype-copy-within.js new file mode 100644 index 0000000000..cee467245f --- /dev/null +++ b/tests/jerry/es2015/typedarray-prototype-copy-within.js @@ -0,0 +1,74 @@ +/* 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 typedarrays = [ + new Uint8ClampedArray ([0, 1, 2, 3, 4, 5]), + new Uint8Array([0, 1, 2, 3, 4, 5]), + new Uint16Array([0, 1, 2, 3, 4, 5]), + new Uint32Array([0, 1, 2, 3, 4, 5]), + new Float32Array([0, 1, 2, 3, 4, 5]), + new Float64Array([0, 1, 2, 3, 4, 5]), + new Int8Array([0, 1, 2, 3, 4, 5]), + new Int16Array([0, 1, 2, 3, 4, 5]), + new Int32Array([0, 1, 2, 3, 4, 5]) + ]; + +typedarrays.forEach(function(e){ + try { + e.prototype.copyWithin.call (undefined); + assert (false); + } catch (err) { + assert (err instanceof TypeError); + } + + // Test with normal inputs + assert(e.copyWithin(2, 1 ,4).toString() === '0,1,1,2,3,5'); + assert(e.copyWithin(3, 4, 6).toString() === '0,1,1,3,5,5'); + assert(e.copyWithin(4, 1, 3).toString() === '0,1,1,3,1,1'); + + e.set([5, 2, 1, 3, 4, 4]); + + // Test with negative inputs + assert(e.copyWithin(2, -10, 3).toString() === '5,2,5,2,1,4'); + assert(e.copyWithin(-3, 1, 6).toString() === '5,2,5,2,5,2'); + assert(e.copyWithin(2, 0, -3).toString() === '5,2,5,2,5,2'); + + e.set([9, 3, 4, 5, 1, 7]); + + // Test with default inputs + assert(e.copyWithin().toString() === '9,3,4,5,1,7'); + assert(e.copyWithin(3).toString() === '9,3,4,9,3,4'); + assert(e.copyWithin(1, 5).toString() === '9,4,4,9,3,4'); + + e.set([12, 3, 1, 43, 2, 9]); + + // Test with too big inputs + assert(e.copyWithin(2, 12, 21).toString() === '12,3,1,43,2,9'); + assert(e.copyWithin(4, 5, 13).toString() === '12,3,1,43,9,9'); + + e.set([1, 2, 3, 1, 2, 1]); + + // Test with undefined inputs + assert(e.copyWithin(undefined, 2, 4).toString() === '3,1,3,1,2,1'); + assert(e.copyWithin(undefined, undefined, 2).toString() === '3,1,3,1,2,1'); + assert(e.copyWithin(3, undefined, 5).toString() === '3,1,3,3,1,3'); + + e.set([0, 2, 4, 2, 1, 5]); + + // Test with NaN/+-Infinity + assert(e.copyWithin(NaN, 3, 5).toString() === '2,1,4,2,1,5'); + assert(e.copyWithin(3, Infinity, 5).toString() === '2,1,4,2,1,5'); + assert(e.copyWithin(1, 3, -Infinity).toString() === '2,1,4,2,1,5'); +}); diff --git a/tests/jerry/es2015/typedarray-prototype-slice.js b/tests/jerry/es2015/typedarray-prototype-slice.js new file mode 100644 index 0000000000..a27749a040 --- /dev/null +++ b/tests/jerry/es2015/typedarray-prototype-slice.js @@ -0,0 +1,63 @@ +/* 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 typedarrays = [ + new Uint8ClampedArray([0, 1, 2, 3, 4, 5]), + new Uint8Array([0, 1, 2, 3, 4, 5]), + new Uint16Array([0, 1, 2, 3, 4, 5]), + new Uint32Array([0, 1, 2, 3, 4, 5]), + new Float32Array([0, 1, 2, 3, 4, 5]), + new Float64Array([0, 1, 2, 3, 4, 5]), + new Int8Array([0, 1, 2, 3, 4, 5]), + new Int16Array([0, 1, 2, 3, 4, 5]), + new Int32Array([0, 1, 2, 3, 4, 5]) + ]; + +typedarrays.forEach(function(e){ + try { + e.prototype.slice.call (undefined); + assert (false); + } catch (err) { + assert (err instanceof TypeError); + } + + // Test with normal inputs + assert(e.slice(1, 3).toString() === "1,2"); + assert(e.slice(2, 5).toString() === "2,3,4"); + assert(e.slice(0, 6).toString() === "0,1,2,3,4,5"); + + // Test witn negative inputs + assert(e.slice(-2, 5).toString() === "4"); + assert(e.slice(0, -3).toString() === "0,1,2"); + assert(e.slice(-1, -4).toString() === ""); + + // Test with bigger inputs then length + assert(e.slice(7, 1).toString() === ""); + assert(e.slice(2, 9).toString() === "2,3,4,5"); + + // Test with undefined + assert(e.slice(undefined, 4).toString() === "0,1,2,3"); + assert(e.slice(0, undefined).toString() === "0,1,2,3,4,5"); + assert(e.slice(undefined, undefined).toString() === "0,1,2,3,4,5"); + + // Test with NaN and +/-Infinity + assert(e.slice(NaN, 3).toString() === "0,1,2"); + assert(e.slice(2, Infinity).toString() === "2,3,4,5"); + assert(e.slice(-Infinity, Infinity).toString() === "0,1,2,3,4,5"); + + // Test with default inputs + assert(e.slice().toString() === "0,1,2,3,4,5"); + assert(e.slice(4).toString() === "4,5"); +});