Refactoring several array buffer and typed array functions. (#1715)

The ecma_typedarray_create_object_with_typedarray function is fully rewritten.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg 2017-04-07 11:20:03 +02:00 committed by GitHub
parent 1886d54474
commit 13b305f716
4 changed files with 195 additions and 209 deletions

View File

@ -32,53 +32,6 @@
* @{
*/
/**
* ArrayBuffer object creation operation.
*
* See also: ES2015 24.1.1.1
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_create_arraybuffer_object (const ecma_value_t *arguments_list_p, /**< list of arguments that
* are passed to String constructor */
ecma_length_t arguments_list_len) /**< length of the arguments' list */
{
JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
uint32_t length = 0;
if (arguments_list_len > 0)
{
ecma_value_t ret = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);
ECMA_OP_TO_NUMBER_TRY_CATCH (num, arguments_list_p[0], ret);
length = ecma_number_to_uint32 (num);
if (num != ((ecma_number_t) length))
{
return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid ArrayBuffer length."));
}
ECMA_OP_TO_NUMBER_FINALIZE (num);
if (!ecma_is_value_empty (ret))
{
return ret;
}
}
if (length > UINT32_MAX - sizeof (ecma_extended_object_t) - JMEM_ALIGNMENT + 1)
{
return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid ArrayBuffer length."));
}
ecma_object_t *object_p = ecma_arraybuffer_new_object (length);
return ecma_make_object_value (object_p);
} /* ecma_op_create_arraybuffer_object */
/**
* Helper function: create arraybuffer object based on the array length
*
@ -108,27 +61,55 @@ ecma_arraybuffer_new_object (ecma_length_t length) /**< length of the arraybuffe
} /* ecma_arraybuffer_new_object */
/**
* Helper function: create arraybuffer object by cloning another arraybuffer
* ArrayBuffer object creation operation.
*
* See also: ES2015 24.1.1.4
* See also: ES2015 24.1.1.1
*
* @return cloned array buffer
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_object_t *
ecma_arraybuffer_clone_arraybuffer (ecma_object_t *array_buf_p, /**< the cloned array buffer */
ecma_length_t offset) /**< start offset */
ecma_value_t
ecma_op_create_arraybuffer_object (const ecma_value_t *arguments_list_p, /**< list of arguments that
* are passed to String constructor */
ecma_length_t arguments_list_len) /**< length of the arguments' list */
{
JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
JERRY_ASSERT (offset <= ecma_arraybuffer_get_length (array_buf_p));
uint32_t length = 0;
ecma_length_t length = ecma_arraybuffer_get_length (array_buf_p) - offset;
ecma_object_t *new_array_buf_p = ecma_arraybuffer_new_object (length);
lit_utf8_byte_t *src_buf_p = ecma_arraybuffer_get_buffer (array_buf_p);
lit_utf8_byte_t *dst_buf_p = ecma_arraybuffer_get_buffer (new_array_buf_p);
memcpy (dst_buf_p, src_buf_p + offset, length);
if (arguments_list_len > 0)
{
ecma_number_t num;
return new_array_buf_p;
} /* ecma_arraybuffer_clone_arraybuffer */
if (ecma_is_value_number (arguments_list_p[0]))
{
num = ecma_get_number_from_value (arguments_list_p[0]);
}
else
{
ecma_value_t to_number_value = ecma_op_to_number (arguments_list_p[0]);
if (ECMA_IS_VALUE_ERROR (to_number_value))
{
return to_number_value;
}
num = ecma_get_number_from_value (to_number_value);
ecma_free_value (to_number_value);
}
length = ecma_number_to_uint32 (num);
if (num != ((ecma_number_t) length)
|| length > (UINT32_MAX - sizeof (ecma_extended_object_t) - JMEM_ALIGNMENT + 1))
{
return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid ArrayBuffer length."));
}
}
return ecma_make_object_value (ecma_arraybuffer_new_object (length));
} /* ecma_op_create_arraybuffer_object */
/**
* Helper function: check if the target is ArrayBuffer
@ -142,15 +123,9 @@ ecma_arraybuffer_clone_arraybuffer (ecma_object_t *array_buf_p, /**< the cloned
bool
ecma_is_arraybuffer (ecma_value_t target) /**< the target value */
{
if (!ecma_is_value_object (target))
{
return false;
}
ecma_object_t *obj_p = ecma_get_object_from_value (target);
lit_magic_string_id_t class_id = ecma_object_get_class_name (obj_p);
return class_id == LIT_MAGIC_STRING_ARRAY_BUFFER_UL;
return (ecma_is_value_object (target)
&& ecma_object_class_is (ecma_get_object_from_value (target),
LIT_MAGIC_STRING_ARRAY_BUFFER_UL));
} /* ecma_is_arraybuffer */
/**

View File

@ -34,8 +34,6 @@ ecma_op_create_arraybuffer_object (const ecma_value_t *, ecma_length_t);
*/
ecma_object_t *
ecma_arraybuffer_new_object (ecma_length_t lengh);
ecma_object_t *
ecma_arraybuffer_clone_arraybuffer (ecma_object_t *src_p, ecma_length_t offset);
lit_utf8_byte_t *
ecma_arraybuffer_get_buffer (ecma_object_t *obj_p) __attr_pure___;
ecma_length_t

View File

@ -13,6 +13,8 @@
* limitations under the License.
*/
#include <math.h>
#include "ecma-typedarray-object.h"
#include "ecma-arraybuffer-object.h"
#include "ecma-function-object.h"
@ -39,17 +41,8 @@
* cast it from type to ecma_number_t
* then assign to variale number
*/
#define GET_ELEMENT(type, location, number) \
type v = *((type *) location); \
number = (ecma_number_t) v;
/**
* Cast the number from ecma_numbet_t into type,
* and store the number in the location
*/
#define SET_ELEMENT(type, location, number) \
int64_t v = (int64_t) number; \
*((type *) location) = (type) v;
#define GET_ELEMENT(type, location) \
((ecma_number_t) (*((type *) location)));
/**
* set typedarray's element value
@ -60,82 +53,63 @@ static ecma_number_t
get_typedarray_element (lit_utf8_byte_t *src, /**< the location in the internal arraybuffer */
lit_magic_string_id_t class_id) /**< class name of the typedarray */
{
ecma_number_t ret_num;
switch (class_id)
{
case LIT_MAGIC_STRING_INT8_ARRAY_UL:
{
GET_ELEMENT (int8_t, src, ret_num);
break;
return GET_ELEMENT (int8_t, src);
}
case LIT_MAGIC_STRING_UINT8_ARRAY_UL:
case LIT_MAGIC_STRING_UINT8_CLAMPED_ARRAY_UL:
{
GET_ELEMENT (uint8_t, src, ret_num);
break;
return GET_ELEMENT (uint8_t, src);
}
case LIT_MAGIC_STRING_INT16_ARRAY_UL:
{
GET_ELEMENT (int16_t, src, ret_num);
break;
return GET_ELEMENT (int16_t, src);
}
case LIT_MAGIC_STRING_UINT16_ARRAY_UL:
{
GET_ELEMENT (uint16_t, src, ret_num);
break;
return GET_ELEMENT (uint16_t, src);
}
case LIT_MAGIC_STRING_INT32_ARRAY_UL:
{
GET_ELEMENT (int32_t, src, ret_num);
break;
return GET_ELEMENT (int32_t, src);
}
case LIT_MAGIC_STRING_UINT32_ARRAY_UL:
{
GET_ELEMENT (uint32_t, src, ret_num);
break;
return GET_ELEMENT (uint32_t, src);
}
case LIT_MAGIC_STRING_FLOAT32_ARRAY_UL:
{
GET_ELEMENT (float, src, ret_num);
break;
return GET_ELEMENT (float, src);
}
#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
case LIT_MAGIC_STRING_FLOAT64_ARRAY_UL:
{
GET_ELEMENT (double, src, ret_num);
break;
return GET_ELEMENT (double, src);
}
#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */
default:
{
JERRY_UNREACHABLE ();
return 0;
}
}
return ret_num;
} /* get_typedarray_element */
#undef GET_ELEMENT
/**
* set typedarray's element value
*/
static void
set_typedarray_element (lit_utf8_byte_t *dst, /**< the location in the internal arraybuffer */
set_typedarray_element (lit_utf8_byte_t *dst_p, /**< the location in the internal arraybuffer */
ecma_number_t value, /**< the number value to set */
lit_magic_string_id_t class_id) /**< class name of the typedarray */
{
switch (class_id)
{
case LIT_MAGIC_STRING_INT8_ARRAY_UL:
{
SET_ELEMENT (int8_t, dst, value);
break;
}
case LIT_MAGIC_STRING_UINT8_ARRAY_UL:
{
SET_ELEMENT (uint8_t, dst, value);
break;
}
case LIT_MAGIC_STRING_UINT8_CLAMPED_ARRAY_UL:
{
uint8_t clamped;
@ -144,7 +118,7 @@ set_typedarray_element (lit_utf8_byte_t *dst, /**< the location in the internal
{
clamped = 255;
}
else if (value < 0)
else if (value <= 0)
{
clamped = 0;
}
@ -153,46 +127,89 @@ set_typedarray_element (lit_utf8_byte_t *dst, /**< the location in the internal
clamped = (uint8_t) value;
if (clamped + 0.5 < value
|| (clamped + 0.5 == value && clamped % 2 == 1))
|| (clamped + 0.5 == value && (clamped % 2) == 1))
{
clamped ++;
}
}
*((uint8_t *) dst) = clamped;
break;
}
case LIT_MAGIC_STRING_INT16_ARRAY_UL:
{
SET_ELEMENT (int16_t, dst, value);
break;
}
case LIT_MAGIC_STRING_UINT16_ARRAY_UL:
{
SET_ELEMENT (uint16_t, dst, value);
break;
}
case LIT_MAGIC_STRING_INT32_ARRAY_UL:
{
SET_ELEMENT (int32_t, dst, value);
break;
}
case LIT_MAGIC_STRING_UINT32_ARRAY_UL:
{
SET_ELEMENT (uint32_t, dst, value);
break;
*((uint8_t *) dst_p) = clamped;
return;
}
case LIT_MAGIC_STRING_FLOAT32_ARRAY_UL:
{
*((float *) dst) = (float) value;
break;
*((float *) dst_p) = (float) value;
return;
}
#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
case LIT_MAGIC_STRING_FLOAT64_ARRAY_UL:
{
*((double *) dst) = (double) value;
break;
*((double *) dst_p) = (double) value;
return;
}
#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */
default:
{
break;
}
}
uint32_t uint32_value = 0;
if (!ecma_number_is_nan (value) && !ecma_number_is_infinity (value))
{
bool is_negative = false;
if (value < 0)
{
is_negative = true;
value = -value;
}
if (value > ((ecma_number_t) 0xffffffff))
{
value = (ecma_number_t) (fmod (value, (ecma_number_t) 0x100000000));
}
uint32_value = (uint32_t) value;
if (is_negative)
{
uint32_value = (uint32_t) (-(int32_t) uint32_value);
}
}
switch (class_id)
{
case LIT_MAGIC_STRING_INT8_ARRAY_UL:
{
*((int8_t *) dst_p) = (int8_t) uint32_value;
break;
}
case LIT_MAGIC_STRING_UINT8_ARRAY_UL:
{
*((uint8_t *) dst_p) = (uint8_t) uint32_value;
break;
}
case LIT_MAGIC_STRING_INT16_ARRAY_UL:
{
*((int16_t *) dst_p) = (int16_t) uint32_value;
break;
}
case LIT_MAGIC_STRING_UINT16_ARRAY_UL:
{
*((uint16_t *) dst_p) = (uint16_t) uint32_value;
break;
}
case LIT_MAGIC_STRING_INT32_ARRAY_UL:
{
*((int32_t *) dst_p) = (int32_t) uint32_value;
break;
}
case LIT_MAGIC_STRING_UINT32_ARRAY_UL:
{
*((uint32_t *) dst_p) = uint32_value;
break;
}
default:
{
JERRY_UNREACHABLE ();
@ -258,36 +275,29 @@ ecma_typedarray_create_object_with_buffer (ecma_object_t *arraybuffer_p, /**< th
uint8_t element_size_shift, /**< the size shift of the element length */
lit_magic_string_id_t class_id) /**< class name of the typedarray */
{
ecma_object_t *object_p;
ecma_length_t expected_length = (ecma_arraybuffer_get_length (arraybuffer_p) >> element_size_shift);
if (byte_offset == 0 && array_length == ecma_arraybuffer_get_length (arraybuffer_p) >> element_size_shift)
{
object_p = ecma_create_object (proto_p,
sizeof (ecma_extended_object_t),
ECMA_OBJECT_TYPE_PSEUDO_ARRAY);
bool needs_ext_typedarray_obj = (byte_offset != 0 || array_length != expected_length);
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
ext_object_p->u.pseudo_array.u1.class_id = class_id;
ext_object_p->u.pseudo_array.type = ECMA_PSEUDO_ARRAY_TYPEDARRAY;
ext_object_p->u.pseudo_array.extra_info = element_size_shift;
ext_object_p->u.pseudo_array.u2.arraybuffer = ecma_make_object_value (arraybuffer_p);
size_t object_size = (needs_ext_typedarray_obj ? sizeof (ecma_extended_typedarray_object_t)
: sizeof (ecma_extended_object_t));
return ecma_make_object_value (object_p);
}
object_p = ecma_create_object (proto_p,
sizeof (ecma_extended_typedarray_object_t),
ECMA_OBJECT_TYPE_PSEUDO_ARRAY);
ecma_object_t *object_p = ecma_create_object (proto_p, object_size, ECMA_OBJECT_TYPE_PSEUDO_ARRAY);
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
ext_object_p->u.pseudo_array.u1.class_id = class_id;
ext_object_p->u.pseudo_array.type = ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO;
ext_object_p->u.pseudo_array.type = ECMA_PSEUDO_ARRAY_TYPEDARRAY;
ext_object_p->u.pseudo_array.extra_info = element_size_shift;
ext_object_p->u.pseudo_array.u2.arraybuffer = ecma_make_object_value (arraybuffer_p);
ecma_extended_typedarray_object_t *typedarray_info_p = (ecma_extended_typedarray_object_t *) ext_object_p;
typedarray_info_p->array_length = array_length;
typedarray_info_p->byte_offset = byte_offset;
if (needs_ext_typedarray_obj)
{
ext_object_p->u.pseudo_array.type = ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO;
ecma_extended_typedarray_object_t *typedarray_info_p = (ecma_extended_typedarray_object_t *) object_p;
typedarray_info_p->array_length = array_length;
typedarray_info_p->byte_offset = byte_offset;
}
return ecma_make_object_value (object_p);
} /* ecma_typedarray_create_object_with_buffer */
@ -307,57 +317,50 @@ ecma_typedarray_create_object_with_typedarray (ecma_object_t *typedarray_p, /**<
lit_magic_string_id_t class_id) /**< class name of the typedarray */
{
ecma_length_t array_length = ecma_typedarray_get_length (typedarray_p);
ecma_length_t byte_offset = ecma_typedarray_get_offset (typedarray_p);
ecma_value_t new_typedarray = ecma_typedarray_create_object_with_length (array_length,
proto_p,
element_size_shift,
class_id);
if (ECMA_IS_VALUE_ERROR (new_typedarray))
{
return new_typedarray;
}
ecma_object_t *new_typedarray_p = ecma_get_object_from_value (new_typedarray);
ecma_object_t *src_arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p);
lit_utf8_byte_t *src_buf_p = ecma_arraybuffer_get_buffer (src_arraybuffer_p);
ecma_object_t *dst_arraybuffer_p = ecma_typedarray_get_arraybuffer (new_typedarray_p);
lit_utf8_byte_t *dst_buf_p = ecma_arraybuffer_get_buffer (dst_arraybuffer_p);
src_buf_p += ecma_typedarray_get_offset (typedarray_p);
lit_magic_string_id_t src_class_id = ecma_object_get_class_name (typedarray_p);
ecma_object_t *arraybuffer_p = NULL;
if (src_class_id == class_id)
{
arraybuffer_p = ecma_arraybuffer_clone_arraybuffer (src_arraybuffer_p,
byte_offset);
memcpy (dst_buf_p, src_buf_p, array_length << element_size_shift);
}
else
{
if (array_length > (UINT32_MAX >> element_size_shift))
{
return ecma_raise_range_error (ECMA_ERR_MSG ("Maximum typedarray size is reached."));
}
ecma_length_t byte_length = array_length << element_size_shift;
if (byte_length > UINT32_MAX - sizeof (ecma_extended_object_t) - JMEM_ALIGNMENT + 1)
{
return ecma_raise_range_error (ECMA_ERR_MSG ("Maximum typedarray size is reached."));
}
arraybuffer_p = ecma_arraybuffer_new_object (byte_length);
lit_utf8_byte_t *src_buf = ecma_arraybuffer_get_buffer (src_arraybuffer_p);
lit_utf8_byte_t *dst_buf = ecma_arraybuffer_get_buffer (arraybuffer_p);
uint8_t src_element_size_shift = ecma_typedarray_get_element_size_shift (typedarray_p);
uint32_t src_element_size = 1u << ecma_typedarray_get_element_size_shift (typedarray_p);
uint32_t dst_element_size = 1u << element_size_shift;
for (uint32_t i = 0; i < array_length; i++)
{
ecma_number_t tmp = get_typedarray_element (src_buf,
ecma_object_get_class_name (typedarray_p));
/** check dst type and set value to dst typedarray */
set_typedarray_element (dst_buf, tmp, class_id);
/* Convert values from source to destination format. */
ecma_number_t tmp = get_typedarray_element (src_buf_p, src_class_id);
set_typedarray_element (dst_buf_p, tmp, class_id);
src_buf = src_buf + (1 << src_element_size_shift);
dst_buf = dst_buf + (1 << element_size_shift);
src_buf_p += src_element_size;
dst_buf_p += dst_element_size;
}
}
ecma_value_t obj = ecma_typedarray_create_object_with_buffer (arraybuffer_p,
0,
array_length,
proto_p,
element_size_shift,
class_id);
ecma_deref_object (arraybuffer_p);
return obj;
return new_typedarray;
} /* ecma_typedarray_create_object_with_typedarray */
/**
@ -388,17 +391,18 @@ ecma_op_typedarray_from (ecma_value_t items_val, /**< the source array-like obje
}
/* 10 */
ECMA_TRY_CATCH (arraylike,
ECMA_TRY_CATCH (arraylike_object_val,
ecma_op_to_object (items_val),
ret_value);
ecma_object_t *arraylike_p = ecma_get_object_from_value (arraylike);
ecma_object_t *arraylike_object_p = ecma_get_object_from_value (arraylike_object_val);
/* 12 */
ecma_string_t *magic_string_length_p = ecma_new_ecma_length_string ();
ecma_string_t magic_string_length;
ecma_init_ecma_length_string (&magic_string_length);
ECMA_TRY_CATCH (len_value,
ecma_op_object_get (arraylike_p, magic_string_length_p),
ecma_op_object_get (arraylike_object_p, &magic_string_length),
ret_value);
ECMA_OP_TO_NUMBER_TRY_CATCH (len_number, len_value, ret_value);
@ -427,7 +431,7 @@ ecma_op_typedarray_from (ecma_value_t items_val, /**< the source array-like obje
ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index);
/* 17.b */
ECMA_TRY_CATCH (current_value, ecma_op_object_find (arraylike_p, index_str_p), ret_value);
ECMA_TRY_CATCH (current_value, ecma_op_object_find (arraylike_object_p, index_str_p), ret_value);
if (ecma_is_value_found (current_value))
{
@ -476,8 +480,7 @@ ecma_op_typedarray_from (ecma_value_t items_val, /**< the source array-like obje
ECMA_OP_TO_NUMBER_FINALIZE (len_number);
ECMA_FINALIZE (len_value);
ecma_deref_ecma_string (magic_string_length_p);
ECMA_FINALIZE (arraylike);
ECMA_FINALIZE (arraylike_object_val);
return ret_value;
} /* ecma_op_typedarray_from */

View File

@ -13,12 +13,22 @@
* limitations under the License.
*/
var a = new Int32Array(3);
var a = new Int32Array(8);
a[0] = 0xffffffff;
a[1] = 0xff00000001;
a[2] = -2.3;
a[2] = 0xff80000001;
a[3] = -2.3;
a[4] = Number.NEGATIVE_INFINITY;
a[5] = NaN;
a[6] = 10e17;
a[7] = -10e17;
assert(a[0] === -1);
assert(a[1] === 1);
assert(a[2] === -2);
assert(a[2] === -2147483647);
assert(a[3] === -2);
assert(a[4] === 0);
assert(a[5] === 0);
assert(a[6] === -1486618624);
assert(a[7] === 1486618624);