Skip to content

Add %TypedArray%.prototype.subarray([ begin [, end ] ]) support. #2410

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should return here if ret_value contains an error. The ECMA_OP_TO_NUMBER_TRY_CATCH might fail, so it can fill the ret_value with an error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

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 */

/**
* @}
* @}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down
3 changes: 3 additions & 0 deletions jerry-core/lit/lit-magic-strings.inc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
1 change: 1 addition & 0 deletions jerry-core/lit/lit-magic-strings.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
48 changes: 48 additions & 0 deletions tests/jerry/es2015/typedArray-subarray.js
Original file line number Diff line number Diff line change
@@ -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]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the original Int32Array is mapped only to a subarray of the arraybuffer? I would like a test case for that as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. If the new tests aren't what you requested please put your request into pseudocode.

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');