Add TypedArray C API (#2165)

New API functions added:
 - jerry_value_is_typedarray
 - jerry_create_typedarray
 - jerry_create_typedarray_for_arraybuffer_sz
 - jerry_create_typedarray_for_arraybuffer
 - jerry_get_typedarray_type
 - jerry_get_typedarray_length
 - jerry_get_typedarray_buffer

JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.u-szeged@partner.samsung.com
This commit is contained in:
Péter Gál
2018-02-06 08:01:32 +01:00
committed by László Langó
parent 0cc98340c3
commit 8041953a7a
6 changed files with 1168 additions and 1 deletions
+335
View File
@@ -296,6 +296,26 @@ typedef jerry_value_t (*jerry_vm_exec_stop_callback_t) (void *user_p);
- [jerry_set_vm_exec_stop_callback](#jerry_set_vm_exec_stop_callback)
## jerry_typedarray_type_t
Enum which describes the TypedArray types.
Possible values:
- JERRY_TYPEDARRAY_UINT8 - represents the Uint8Array TypedArray
- JERRY_TYPEDARRAY_UINT8CLAMPED - represents the Uint8ClampedArray TypedArray
- JERRY_TYPEDARRAY_INT8 - represents the Int8Array TypedArray
- JERRY_TYPEDARRAY_UINT16 - represents the Uint16Array TypedArray
- JERRY_TYPEDARRAY_INT16 - represents the Int16Array TypedArray
- JERRY_TYPEDARRAY_UINT32 - represents the Uint32Array TypedArray
- JERRY_TYPEDARRAY_INT32 - represents the Int32Array TypedArray
- JERRY_TYPEDARRAY_FLOAT32 - represents the Float32Array TypedArray
- JERRY_TYPEDARRAY_FLOAT64 - represents the Float64Array TypedArray
- JERRY_TYPEDARRAY_INVALID - represents an invalid TypedArray
API functions can return the `JERRY_TYPEDARRAY_INVALID` value if the
TypedArray support is not in the engine.
# General engine functions
## jerry_init
@@ -1347,6 +1367,45 @@ jerry_value_is_string (const jerry_value_t value)
- [jerry_release_value](#jerry_release_value)
## jerry_value_is_typedarray
**Summary**
Checks whether the given `jerry_value_t` is a TypedArray object or not.
**Prototype**
```c
bool
jerry_value_is_typedarray (const jerry_value_t value)
```
- `value` - object to check
- return value
- true, if the given `jerry_value_t` is a TypedArray object.
- false, otherwise
**Example**
```c
{
jerry_value_t value;
... // create or acquire value
if (jerry_value_is_typedarray (value))
{
...
}
jerry_release_value (value);
}
```
**See also**
- [jerry_create_typedarray](#jerry_create_typedarray)
## jerry_value_is_undefined
**Summary**
@@ -3129,6 +3188,151 @@ jerry_create_string_sz (const jerry_char_t *str_p,
- [jerry_create_string_from_utf8](#jerry_create_string_from_utf8)
## jerry_create_typedarray
**Summary**
Create a jerry_value_t representing an TypedArray object.
For the new object the type of the TypedArray (see: [jerry_typedarray_type_t](#jerry_typedarray_type_t))
and element count can be specified.
**Prototype**
```c
jerry_value_t
jerry_create_typedarray (jerry_typedarray_type_t type_name, jerry_length_t item_count);
```
- `type_name` - type of TypedArray to create
- `item_count` - number of items in the new TypedArray
- return value - the new TypedArray as a `jerry_value_t`
**Example**
```c
{
jerry_value_t array = jerry_create_typedarray (JERRY_TYPEDARRAY_UINT16, 15);
... // use the TypedArray
jerry_release_value (array);
}
```
**See also**
- [jerry_typedarray_type_t](#jerry_typedarray_type_t)
- [jerry_value_is_typedarray](#jerry_value_is_typedarray)
- [jerry_release_value](#jerry_release_value)
## jerry_create_typedarray_for_arraybuffer
**Summary**
Create a jerry_value_t representing an TypedArray object using
an already existing ArrayBuffer object.
For the new object the type of the TypedArray (see: [jerry_typedarray_type_t](#jerry_typedarray_type_t))
and element count can be specified.
The developer must ensure that the ArrayBuffer has the correct length for the given
type of TypedArray otherwise an error is generated.
The JavaScript equivalent of this function is: `new %TypedArray%(arraybuffer)` where `%TypedArray%` is
one of the allowed TypedArray functions.
**Prototype**
```c
jerry_value_t
jerry_create_typedarray_for_arraybuffer (jerry_typedarray_type_t type_name,
const jerry_value_t arraybuffer);
```
- `type_name` - type of TypedArray to create
- `arraybuffer` - the ArrayBuffer to use for the new TypedArray
- return value
- the new TypedArray as a `jerry_value_t`
- Error if the ArrayBuffer does not have enough space for the given type of TypedArray
**Example**
```c
{
jerry_value_t buffer = jerry_create_array_buffer (12 * 2);
jerry_value_t array = jerry_create_typedarray_for_arraybuffer (JERRY_TYPEDARRAY_UINT16, buffer);
jerry_release_value (buffer);
... // use the TypedArray
jerry_release_value (array);
}
```
**See also**
- [jerry_typedarray_type_t](#jerry_typedarray_type_t)
- [jerry_value_is_typedarray](#jerry_value_is_typedarray)
- [jerry_release_value](#jerry_release_value)
## jerry_create_typedarray_for_arraybuffer_sz
**Summary**
Create a jerry_value_t representing an TypedArray object using
an already existing ArrayBuffer object and by specifying the byteOffset, and length properties.
For the new object the type of the TypedArray (see: [jerry_typedarray_type_t](#jerry_typedarray_type_t))
and element count can be specified.
The developer must ensure that the ArrayBuffer has the correct length for the given
type of TypedArray otherwise an error is generated.
The JavaScript equivalent of this function is: `new %TypedArray%(arraybuffer, byteOffset, length)` where `%TypedArray%` is
one of the allowed TypedArray functions.
**Prototype**
```c
jerry_value_t
jerry_create_typedarray_for_arraybuffer_sz (jerry_typedarray_type_t type_name,
const jerry_value_t arraybuffer,
jerry_length_t byte_offset,
jerry_length_t length);
```
- `type_name` - type of TypedArray to create
- `arraybuffer` - the ArrayBuffer to use for the new TypedArray
- `byte_offset` - start offset to use for the ArrayBuffer
- `length` - number of elements to used from the ArrayBuffer (this is not the same as the byteLength)
- return value
- the new TypedArray as a `jerry_value_t`
- Error if the ArrayBuffer does not have enough space for the given type of TypedArray
**Example**
```c
{
jerry_value_t buffer = jerry_create_array_buffer (12 * 2);
jerry_value_t array = jerry_create_typedarray_for_arraybuffer_sz (JERRY_TYPEDARRAY_UINT16, buffer, 4, 10);
jerry_release_value (buffer);
... // use the TypedArray
jerry_release_value (array);
}
```
**See also**
- [jerry_typedarray_type_t](#jerry_typedarray_type_t)
- [jerry_value_is_typedarray](#jerry_value_is_typedarray)
- [jerry_release_value](#jerry_release_value)
## jerry_create_undefined
**Summary**
@@ -5123,3 +5327,134 @@ jerry_get_arraybuffer_pointer (const jerry_value_t value);
**See also**
- [jerry_create_arraybuffer_external](#jerry_create_arraybuffer_external)
## jerry_get_typedarray_type
**Summary**
Get the type of the TypedArray.
The returned type is one of the [jerry_typedarray_type_t](#jerry_typedarray_type_t)
enum value.
**Prototype**
```c
jerry_typedarray_type_t
jerry_get_typedarray_type (jerry_value_t value);
```
- `value` - TypedArray object to query for type.
- return
- the type of the TypedArray
- JERRY_TYPEDARRAY_INVALID if the object was not a TypedArray
**Example**
```c
{
jerry_typedarray_type_t expected_type = JERRY_TYPEDARRAY_UINT32;
jerry_value_t typedarray = jerry_create_typedarray (expected_klass, 25);
jerry_typedarray_type_t type = jerry_get_typedarray_type (typedarray);
// 'type' is now JERRY_TYPEDARRAY_UINT32
jerry_release_value (typedarray);
}
```
**See also**
- [jerry_create_typedarray](#jerry_create_typedarray)
- [jerry_typedarray_type_t](#jerry_typedarray_type_t)
## jerry_get_typedarray_length
**Summary**
Get the element count of the TypedArray as specified during creation.
This is not the same as the byteLength property of a TypedArray object.
**Prototype**
```
jerry_length_t
jerry_get_typedarray_length (jerry_value_t value);
```
- `value` - TypedArray object to query
- return
- length (element count) of the TypedArray object
- 0 if the object is not a TypedArray
**Example**
```c
{
jerry_value_t array = jerry_create_typedarray (JERRY_TYPEDARRAY_INT32, 21);
jerry_length_t element_count = jerry_get_typedarray_length (array);
// element_count is now 21.
jerry_release_value (array);
}
```
**See also**
- [jerry_create_typedarray](#jerry_create_typedarray)
## jerry_get_typedarray_buffer
**Summary**
Get the ArrayBuffer object used by a TypedArray object.
Additionally returns the byteLength and byteOffset properties
of the TypedArray object.
For the returned ArrayBuffer the [jerry_release_value](#jerry_release_value)
must be called.
**Prototype**
```c
jerry_value_t jerry_get_typedarray_buffer (jerry_value_t value,
jerry_length_t *byteOffset,
jerry_length_t *byteLength);
```
- `value` - TypedArray to get the ArrayBuffer from
- `byteOffset` - (Optional) returns the start offset of the ArrayBuffer for the TypedArray
- `byteLength` - (Optional) returns the number of bytes used from the ArrayBuffer for the TypedArray
- return
- TypedArray object's underlying ArrayBuffer object
- TypeError if the `value` is not a TypedArray object
**Example**
```c
{
jerry_value_t array = jerry_create_typedarray (JERRY_TYPEDARRAY_INT16, 11);
jerry_length_t byteLength = 0;
jerry_length_t byteOffset = 0;
jerry_value_t buffer = jerry_get_typedarray_buffer (array, &byteOffset, &byteLength);
// buffer is an ArrayBuffer object and ArrayBuffer operations can be performed on it
// byteLength is 11 * 2 (2 as the TypedArray stores Int16 that is 2 byte elements)
// byteOffset is 0
jerry_release_value (buffer);
jerry_release_value (array);
}
```
**See also**
- [jerry_create_typedarray](#jerry_create_typedarray)
+316
View File
@@ -32,6 +32,7 @@
#include "ecma-objects.h"
#include "ecma-objects-general.h"
#include "ecma-promise-object.h"
#include "ecma-typedarray-object.h"
#include "jcontext.h"
#include "jerryscript.h"
#include "jmem.h"
@@ -2936,6 +2937,321 @@ jerry_get_arraybuffer_pointer (const jerry_value_t value) /**< Array Buffer to u
return NULL;
} /* jerry_get_arraybuffer_pointer */
/**
* TypedArray related functions
*/
/**
* Check if the given value is a TypedArray object.
*
* @return true - if it is a TypedArray object
* false - otherwise
*/
bool
jerry_value_is_typedarray (jerry_value_t value) /**< value to check if it is a TypedArray */
{
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
jerry_value_t array = jerry_get_arg_value (value);
return ecma_is_typedarray (array);
#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
JERRY_UNUSED (value);
return false;
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
} /* jerry_value_is_typedarray */
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
typedef struct
{
jerry_typedarray_type_t api_type;
ecma_builtin_id_t prototype_id;
lit_magic_string_id_t lit_id;
uint8_t element_size_shift;
} jerry_typedarray_mapping_t;
static jerry_typedarray_mapping_t jerry_typedarray_mappings[] =
{
#define TYPEDARRAY_ENTRY(NAME, LIT_NAME, SIZE_SHIFT) \
{ JERRY_TYPEDARRAY_ ## NAME, ECMA_BUILTIN_ID_ ## NAME ## ARRAY_PROTOTYPE, \
LIT_MAGIC_STRING_ ## LIT_NAME ## _ARRAY_UL, SIZE_SHIFT }
TYPEDARRAY_ENTRY (UINT8, UINT8, 0),
TYPEDARRAY_ENTRY (UINT8CLAMPED, UINT8_CLAMPED, 0),
TYPEDARRAY_ENTRY (INT8, INT8, 0),
TYPEDARRAY_ENTRY (UINT16, UINT16, 1),
TYPEDARRAY_ENTRY (INT16, INT16, 1),
TYPEDARRAY_ENTRY (UINT32, UINT32, 2),
TYPEDARRAY_ENTRY (INT32, INT32, 2),
TYPEDARRAY_ENTRY (FLOAT32, FLOAT32, 2),
#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
TYPEDARRAY_ENTRY (FLOAT64, FLOAT64, 3),
#endif
#undef TYPEDARRAY_ENTRY
};
/**
* Helper function to get the TypedArray prototype, literal id, and element size shift
* information.
*
* @return true - if the TypedArray information was found
* false - if there is no such TypedArray type
*/
static bool
jerry_typedarray_find_by_type (jerry_typedarray_type_t type_name, /**< type of the TypedArray */
ecma_builtin_id_t *prototype_id, /**< [out] found prototype object id */
lit_magic_string_id_t *lit_id, /**< [out] found literal id */
uint8_t *element_size_shift) /**< [out] found element size shift value */
{
JERRY_ASSERT (prototype_id != NULL);
JERRY_ASSERT (lit_id != NULL);
JERRY_ASSERT (element_size_shift != NULL);
for (uint32_t i = 0; i < sizeof (jerry_typedarray_mappings) / sizeof (jerry_typedarray_mappings[0]); i++)
{
if (type_name == jerry_typedarray_mappings[i].api_type)
{
*prototype_id = jerry_typedarray_mappings[i].prototype_id;
*lit_id = jerry_typedarray_mappings[i].lit_id;
*element_size_shift = jerry_typedarray_mappings[i].element_size_shift;
return true;
}
}
return false;
} /* jerry_typedarray_find_by_type */
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
/**
* Create a TypedArray object with a given type and length.
*
* Notes:
* * returns TypeError if an incorrect type (type_name) is specified.
* * byteOffset property will be set to 0.
* * byteLength property will be a multiple of the length parameter (based on the type).
*
* @return - new TypedArray object
*/
jerry_value_t
jerry_create_typedarray (jerry_typedarray_type_t type_name, /**< type of TypedArray to create */
jerry_length_t length) /**< element count of the new TypedArray */
{
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
ecma_builtin_id_t prototype_id = 0;
lit_magic_string_id_t lit_id = 0;
uint8_t element_size_shift = 0;
if (!jerry_typedarray_find_by_type (type_name, &prototype_id, &lit_id, &element_size_shift))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("incorrect type for TypedArray.")));
}
ecma_object_t *prototype_obj_p = ecma_builtin_get (prototype_id);
ecma_value_t array_value = ecma_typedarray_create_object_with_length (length,
prototype_obj_p,
element_size_shift,
lit_id);
ecma_deref_object (prototype_obj_p);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (array_value));
return array_value;
#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
JERRY_UNUSED (type_name);
JERRY_UNUSED (length);
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("TypedArray not supported.")));
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
} /* jerry_create_typedarray */
/**
* Create a TypedArray object using the given arraybuffer and size information.
*
* Notes:
* * returns TypeError if an incorrect type (type_name) is specified.
* * this is the 'new %TypedArray%(arraybuffer, byteOffset, length)' equivalent call.
*
* @return - new TypedArray object
*/
jerry_value_t
jerry_create_typedarray_for_arraybuffer_sz (jerry_typedarray_type_t type_name, /**< type of TypedArray to create */
const jerry_value_t arraybuffer, /**< ArrayBuffer to use */
jerry_length_t byte_offset, /**< offset for the ArrayBuffer */
jerry_length_t length) /**< number of elements to use from ArrayBuffer */
{
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
ecma_builtin_id_t prototype_id = 0;
lit_magic_string_id_t lit_id = 0;
uint8_t element_size_shift = 0;
if (!jerry_typedarray_find_by_type (type_name, &prototype_id, &lit_id, &element_size_shift))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("incorrect type for TypedArray.")));
}
jerry_value_t buffer = jerry_get_arg_value (arraybuffer);
if (!ecma_is_arraybuffer (buffer))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an ArrayBuffer")));
}
ecma_object_t *prototype_obj_p = ecma_builtin_get (prototype_id);
ecma_value_t arguments_p[3] =
{
arraybuffer,
ecma_make_uint32_value (byte_offset),
ecma_make_uint32_value (length)
};
ecma_value_t array_value = ecma_op_create_typedarray (arguments_p, 3, prototype_obj_p, element_size_shift, lit_id);
ecma_free_value (arguments_p[1]);
ecma_free_value (arguments_p[2]);
ecma_deref_object (prototype_obj_p);
return jerry_return (array_value);
#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
JERRY_UNUSED (type_name);
JERRY_UNUSED (arraybuffer);
JERRY_UNUSED (byte_offset);
JERRY_UNUSED (length);
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("TypedArray not supported.")));
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
} /* jerry_create_typedarray_for_arraybuffer_sz */
/**
* Create a TypedArray object using the given arraybuffer and size information.
*
* Notes:
* * returns TypeError if an incorrect type (type_name) is specified.
* * this is the 'new %TypedArray%(arraybuffer)' equivalent call.
*
* @return - new TypedArray object
*/
jerry_value_t
jerry_create_typedarray_for_arraybuffer (jerry_typedarray_type_t type_name, /**< type of TypedArray to create */
const jerry_value_t arraybuffer) /**< ArrayBuffer to use */
{
jerry_assert_api_available ();
jerry_length_t byteLength = jerry_get_arraybuffer_byte_length (arraybuffer);
return jerry_create_typedarray_for_arraybuffer_sz (type_name, arraybuffer, 0, byteLength);
} /* jerry_create_typedarray_for_arraybuffer */
/**
* Get the type of the TypedArray.
*
* @return - type of the TypedArray
* - JERRY_TYPEDARRAY_INVALID if the argument is not a TypedArray
*/
jerry_typedarray_type_t
jerry_get_typedarray_type (jerry_value_t value) /**< object to get the TypedArray type */
{
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
jerry_value_t array = jerry_get_arg_value (value);
if (!ecma_is_typedarray (array))
{
return JERRY_TYPEDARRAY_INVALID;
}
ecma_object_t *array_p = ecma_get_object_from_value (array);
lit_magic_string_id_t class_name_id = ecma_object_get_class_name (array_p);
for (uint32_t i = 0; i < sizeof (jerry_typedarray_mappings) / sizeof (jerry_typedarray_mappings[0]); i++)
{
if (class_name_id == jerry_typedarray_mappings[i].lit_id)
{
return jerry_typedarray_mappings[i].api_type;
}
}
#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
JERRY_UNUSED (value);
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
return JERRY_TYPEDARRAY_INVALID;
} /* jerry_get_typedarray_type */
/**
* Get the element count of the TypedArray.
*
* @return length of the TypedArray.
*/
jerry_length_t
jerry_get_typedarray_length (jerry_value_t value) /**< TypedArray to query */
{
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
jerry_value_t array = jerry_get_arg_value (value);
if (ecma_is_typedarray (array))
{
ecma_object_t *array_p = ecma_get_object_from_value (array);
return ecma_typedarray_get_length (array_p);
}
#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
JERRY_UNUSED (value);
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
return 0;
} /* jerry_get_typedarray_length */
/**
* Get the underlying ArrayBuffer from a TypedArray.
*
* Additionally the byteLength and byteOffset properties are also returned
* which were specified when the TypedArray was created.
*
* Note:
* the returned value must be freed with a jerry_release_value call
*
* @return ArrayBuffer of a TypedArray
* TypeError if the object is not a TypedArray.
*/
jerry_value_t
jerry_get_typedarray_buffer (jerry_value_t value, /**< TypedArray to get the arraybuffer from */
jerry_length_t *byte_offset, /**< [out] byteOffset property */
jerry_length_t *byte_length) /**< [out] byteLength property */
{
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
jerry_value_t array = jerry_get_arg_value (value);
if (!ecma_is_typedarray (array))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Object is not a TypedArray.")));
}
ecma_object_t *array_p = ecma_get_object_from_value (array);
uint8_t shift = ecma_typedarray_get_element_size_shift (array_p);
if (byte_length != NULL)
{
*byte_length = (jerry_length_t) (ecma_typedarray_get_length (array_p) << shift);
}
if (byte_offset != NULL)
{
*byte_offset = (jerry_length_t) ecma_typedarray_get_offset (array_p);
}
ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (array_p);
ecma_ref_object (arraybuffer_p);
return jerry_return (ecma_make_object_value (arraybuffer_p));
#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
JERRY_UNUSED (value);
JERRY_UNUSED (byte_length);
JERRY_UNUSED (byte_offset);
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("TypedArray is not supported.")));
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
} /* jerry_get_typedarray_buffer */
/**
* @}
*/
@@ -226,7 +226,7 @@ ecma_set_typedarray_element (lit_utf8_byte_t *dst_p, /**< the location in the in
* @return ecma value of the new typedarray object
* Returned value must be freed with ecma_free_value
*/
static ecma_value_t
ecma_value_t
ecma_typedarray_create_object_with_length (ecma_length_t array_length, /**< length of the typedarray */
ecma_object_t *proto_p, /**< prototype object */
uint8_t element_size_shift, /**< the size shift of the element length */
@@ -57,6 +57,10 @@ bool ecma_op_typedarray_define_index_prop (ecma_object_t *obj_p,
bool ecma_op_typedarray_set_index_prop (ecma_object_t *obj_p, uint32_t index, ecma_value_t value);
ecma_value_t ecma_op_create_typedarray_with_type_and_length (ecma_object_t *obj_p,
ecma_length_t array_length);
ecma_value_t ecma_typedarray_create_object_with_length (ecma_length_t array_length,
ecma_object_t *proto_p,
uint8_t element_size_shift,
lit_magic_string_id_t class_id);
/**
* @}
+37
View File
@@ -462,6 +462,43 @@ jerry_length_t jerry_arraybuffer_read (const jerry_value_t value,
jerry_length_t jerry_get_arraybuffer_byte_length (const jerry_value_t value);
uint8_t *jerry_get_arraybuffer_pointer (const jerry_value_t value);
/**
* TypedArray functions.
*/
/**
* TypedArray types.
*/
typedef enum
{
JERRY_TYPEDARRAY_INVALID = 0,
JERRY_TYPEDARRAY_UINT8,
JERRY_TYPEDARRAY_UINT8CLAMPED,
JERRY_TYPEDARRAY_INT8,
JERRY_TYPEDARRAY_UINT16,
JERRY_TYPEDARRAY_INT16,
JERRY_TYPEDARRAY_UINT32,
JERRY_TYPEDARRAY_INT32,
JERRY_TYPEDARRAY_FLOAT32,
JERRY_TYPEDARRAY_FLOAT64,
} jerry_typedarray_type_t;
bool jerry_value_is_typedarray (jerry_value_t value);
jerry_value_t jerry_create_typedarray (jerry_typedarray_type_t type_name, jerry_length_t length);
jerry_value_t jerry_create_typedarray_for_arraybuffer_sz (jerry_typedarray_type_t type_name,
const jerry_value_t arraybuffer,
jerry_length_t byte_offset,
jerry_length_t length);
jerry_value_t jerry_create_typedarray_for_arraybuffer (jerry_typedarray_type_t type_name,
const jerry_value_t arraybuffer);
jerry_typedarray_type_t jerry_get_typedarray_type (jerry_value_t value);
jerry_length_t jerry_get_typedarray_length (jerry_value_t value);
jerry_value_t jerry_get_typedarray_buffer (jerry_value_t value,
jerry_length_t *byte_offset,
jerry_length_t *byte_length);
/**
* @}
*/
+475
View File
@@ -0,0 +1,475 @@
/* 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.
*/
#include "jerryscript.h"
#include "jerryscript-port.h"
#include "jerryscript-port-default.h"
#include "test-common.h"
#include <stdio.h>
/**
* Type to describe test cases.
*/
typedef struct
{
jerry_typedarray_type_t typedarray_type; /**< what kind of TypedArray */
char *constructor_name; /**< JS constructor name for TypedArray */
uint32_t element_count; /**< number of elements for the TypedArray */
uint32_t bytes_per_element; /**< bytes per elment of the given typedarray_type */
} test_entry_t;
/**
* Register a JavaScript value in the global object.
*/
static void
register_js_value (const char *name_p, /**< name of the function */
jerry_value_t value) /**< function callback */
{
jerry_value_t global_obj_val = jerry_get_global_object ();
jerry_value_t name_val = jerry_create_string ((const jerry_char_t *) name_p);
jerry_value_t result_val = jerry_set_property (global_obj_val, name_val, value);
jerry_release_value (name_val);
jerry_release_value (global_obj_val);
jerry_release_value (result_val);
} /* register_js_value */
static jerry_value_t
assert_handler (const jerry_value_t func_obj_val, /**< function object */
const jerry_value_t this_val, /**< this arg */
const jerry_value_t args_p[], /**< function arguments */
const jerry_length_t args_cnt) /**< number of function arguments */
{
JERRY_UNUSED (func_obj_val);
JERRY_UNUSED (this_val);
if (jerry_value_is_boolean (args_p[0])
&& jerry_get_boolean_value (args_p[0]))
{
return jerry_create_boolean (true);
}
else
{
if (args_cnt > 1
&& jerry_value_is_string (args_p[1]))
{
jerry_length_t utf8_sz = jerry_get_string_size (args_p[1]);
char string_from_utf8[utf8_sz];
string_from_utf8[utf8_sz] = 0;
jerry_string_to_char_buffer (args_p[1], (jerry_char_t *) string_from_utf8, utf8_sz);
printf ("JS assert: %s\n", string_from_utf8);
}
TEST_ASSERT (false);
}
} /* assert_handler */
/**
* Checks whether global object has typedarray.
*/
static bool
typedarray_is_available (void)
{
jerry_value_t global_obj_val = jerry_get_global_object ();
jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "Int8Array");
jerry_value_t prop_value = jerry_has_property (global_obj_val, prop_name);
bool has_prop = jerry_get_boolean_value (prop_value);
jerry_release_value (global_obj_val);
jerry_release_value (prop_name);
jerry_release_value (prop_value);
return has_prop;
} /* typedarray_is_available */
/**
* Do simple TypedArray property validation.
*/
static void
test_typedarray_info (jerry_value_t typedarray, /**< target TypedArray to query */
jerry_typedarray_type_t typedarray_type, /**< expected TypedArray type */
jerry_length_t element_count, /**< expected element count */
jerry_length_t bytes_per_element) /**< bytes per element for the given type */
{
TEST_ASSERT (!jerry_value_has_error_flag (typedarray));
TEST_ASSERT (jerry_value_is_typedarray (typedarray));
TEST_ASSERT (jerry_get_typedarray_type (typedarray) == typedarray_type);
TEST_ASSERT (jerry_get_typedarray_length (typedarray) == element_count);
jerry_length_t byte_length = (uint32_t) -1;
jerry_length_t byte_offset = (uint32_t) -1;
jerry_value_t arraybuffer = jerry_get_typedarray_buffer (typedarray, &byte_offset, &byte_length);
TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer));
TEST_ASSERT (byte_length == element_count * bytes_per_element);
TEST_ASSERT (byte_offset == 0);
jerry_release_value (arraybuffer);
} /* test_typedarray_info */
/**
* Test construction of TypedArrays and validate properties.
*/
static void
test_typedarray_queries (test_entry_t test_entries[]) /**< test cases */
{
jerry_value_t global_obj_val = jerry_get_global_object ();
for (uint32_t i = 0; test_entries[i].constructor_name != NULL; i++)
{
/* Create TypedArray via construct call */
{
jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) test_entries[i].constructor_name);
jerry_value_t prop_value = jerry_get_property (global_obj_val, prop_name);
TEST_ASSERT (!jerry_value_has_error_flag (prop_value));
jerry_value_t length_arg = jerry_create_number (test_entries[i].element_count);
jerry_value_t typedarray = jerry_construct_object (prop_value, &length_arg, 1);
jerry_release_value (prop_name);
jerry_release_value (prop_value);
jerry_release_value (length_arg);
test_typedarray_info (typedarray,
test_entries[i].typedarray_type,
test_entries[i].element_count,
test_entries[i].bytes_per_element);
jerry_release_value (typedarray);
}
/* Create TypedArray via api call */
{
jerry_value_t typedarray = jerry_create_typedarray (test_entries[i].typedarray_type,
test_entries[i].element_count);
test_typedarray_info (typedarray,
test_entries[i].typedarray_type,
test_entries[i].element_count,
test_entries[i].bytes_per_element);
jerry_release_value (typedarray);
}
}
jerry_release_value (global_obj_val);
} /* test_typedarray_queries */
/**
* Test value at given position in the buffer based on TypedArray type.
*/
static
void test_buffer_value (uint64_t value, /**< value to test for */
const uint8_t *buffer, /**< buffer to read value from */
uint32_t start_offset, /**< start offset of the value */
jerry_typedarray_type_t typedarray_type, /**< type of TypedArray */
uint32_t bytes_per_element) /**< bytes per element for the given type */
{
uint32_t offset = start_offset / bytes_per_element;
#define TEST_VALUE_AT(TYPE, BUFFER, OFFSET, VALUE) TEST_ASSERT (((TYPE *) BUFFER)[OFFSET] == (TYPE) (VALUE))
switch (typedarray_type)
{
case JERRY_TYPEDARRAY_UINT8: TEST_VALUE_AT (uint8_t, buffer, offset, value); break;
case JERRY_TYPEDARRAY_INT8: TEST_VALUE_AT (int8_t, buffer, offset, value); break;
case JERRY_TYPEDARRAY_UINT16: TEST_VALUE_AT (uint16_t, buffer, offset, value); break;
case JERRY_TYPEDARRAY_INT16: TEST_VALUE_AT (int16_t, buffer, offset, value); break;
case JERRY_TYPEDARRAY_UINT32: TEST_VALUE_AT (uint32_t, buffer, offset, value); break;
case JERRY_TYPEDARRAY_INT32: TEST_VALUE_AT (int32_t, buffer, offset, value); break;
case JERRY_TYPEDARRAY_FLOAT32: TEST_VALUE_AT (float, buffer, offset, value); break;
case JERRY_TYPEDARRAY_FLOAT64: TEST_VALUE_AT (double, buffer, offset, value); break;
case JERRY_TYPEDARRAY_UINT8CLAMPED:
{
int64_t signed_value = (int64_t) value;
uint8_t expected = (uint8_t) value;
/* clamp the value if required*/
if (signed_value > 0xFF)
{
expected = 0xFF;
}
else if (signed_value < 0)
{
expected = 0;
}
TEST_VALUE_AT (uint8_t, buffer, offset, expected); break;
}
default: TEST_ASSERT (false); break;
}
#undef TEST_VALUE_AT
} /* test_buffer_value */
static void
test_typedarray_complex_creation (test_entry_t test_entries[], /**< test cases */
bool use_external_buffer) /**< run tests using arraybuffer with external memory */
{
const uint32_t arraybuffer_size = 256;
uint8_t buffer_ext[arraybuffer_size];
memset (buffer_ext, 0, arraybuffer_size);
for (uint32_t i = 0; test_entries[i].constructor_name != NULL; i++)
{
const uint32_t offset = 8;
uint32_t element_count = test_entries[i].element_count;
uint32_t bytes_per_element = test_entries[i].bytes_per_element;
/* new %TypedArray% (buffer, offset, length); */
jerry_value_t typedarray;
{
jerry_value_t arraybuffer;
if (use_external_buffer)
{
arraybuffer = jerry_create_arraybuffer_external (arraybuffer_size, buffer_ext, NULL);
}
else
{
arraybuffer = jerry_create_arraybuffer (arraybuffer_size);
}
jerry_value_t js_offset = jerry_create_number (offset);
jerry_value_t js_element_count = jerry_create_number (element_count);
register_js_value ("expected_offset", js_offset);
register_js_value ("expected_length", js_element_count);
typedarray = jerry_create_typedarray_for_arraybuffer_sz (test_entries[i].typedarray_type,
arraybuffer,
offset,
element_count);
TEST_ASSERT (!jerry_value_has_error_flag (typedarray));
jerry_release_value (js_offset);
jerry_release_value (js_element_count);
jerry_release_value (arraybuffer);
}
register_js_value ("array", typedarray);
const char *eval_src_p = (
"assert (array.length == expected_length,"
" 'expected length: ' + expected_length + ' got: ' + array.length);"
"assert (array.byteOffset == expected_offset);"
"array[0] = 0x11223344;");
jerry_value_t result = jerry_eval ((jerry_char_t *) eval_src_p,
strlen (eval_src_p),
true);
TEST_ASSERT (!jerry_value_has_error_flag (result));
jerry_release_value (result);
{
jerry_length_t byte_length = 0;
jerry_length_t byte_offset = 0;
jerry_value_t buffer = jerry_get_typedarray_buffer (typedarray, &byte_offset, &byte_length);
TEST_ASSERT (byte_length == element_count * bytes_per_element);
TEST_ASSERT (byte_offset == offset);
uint8_t test_buffer[arraybuffer_size];
jerry_typedarray_type_t type = jerry_get_typedarray_type (typedarray);
jerry_value_t read_count = jerry_arraybuffer_read (buffer, 0, test_buffer, offset + byte_length);
TEST_ASSERT (read_count == offset + byte_length);
test_buffer_value (0x11223344, test_buffer, offset, type, bytes_per_element);
if (use_external_buffer)
{
test_buffer_value (0x11223344, buffer_ext, offset, type, bytes_per_element);
TEST_ASSERT (memcmp (buffer_ext, test_buffer, offset + byte_length) == 0);
}
jerry_release_value (buffer);
}
jerry_release_value (typedarray);
}
} /* test_typedarray_complex_creation */
int
main (void)
{
jerry_init (JERRY_INIT_EMPTY);
if (!typedarray_is_available ())
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "TypedArray is disabled!\n");
jerry_cleanup ();
return 0;
}
jerry_value_t function_val = jerry_create_external_function (assert_handler);
register_js_value ("assert", function_val);
jerry_release_value (function_val);
test_entry_t test_entries[] =
{
#define TEST_ENTRY(TYPE, CONSTRUCTOR, COUNT, BYTES_PER_ELEMENT) \
{ TYPE, CONSTRUCTOR, COUNT, BYTES_PER_ELEMENT }
TEST_ENTRY (JERRY_TYPEDARRAY_UINT8, "Uint8Array", 12, 1),
TEST_ENTRY (JERRY_TYPEDARRAY_UINT8CLAMPED, "Uint8ClampedArray", 12, 1),
TEST_ENTRY (JERRY_TYPEDARRAY_INT8, "Int8Array", 12, 1),
TEST_ENTRY (JERRY_TYPEDARRAY_UINT16, "Uint16Array", 12, 2),
TEST_ENTRY (JERRY_TYPEDARRAY_INT16, "Int16Array", 12, 2),
TEST_ENTRY (JERRY_TYPEDARRAY_UINT16, "Uint16Array", 12, 2),
TEST_ENTRY (JERRY_TYPEDARRAY_INT32, "Int32Array", 12, 4),
TEST_ENTRY (JERRY_TYPEDARRAY_UINT32, "Uint32Array", 12, 4),
TEST_ENTRY (JERRY_TYPEDARRAY_FLOAT32, "Float32Array", 12, 4),
/* TODO: add check if the float64 is supported */
TEST_ENTRY (JERRY_TYPEDARRAY_FLOAT64, "Float64Array", 12, 8),
TEST_ENTRY (JERRY_TYPEDARRAY_INVALID, NULL, 0, 0)
#undef TEST_ENTRY
};
/* Test TypedArray queries */
test_typedarray_queries (test_entries);
/* Test TypedArray operations in js */
{
const uint32_t element_count = 14;
uint8_t expected_value = 42;
jerry_value_t array = jerry_create_typedarray (JERRY_TYPEDARRAY_UINT8, element_count);
{
uint8_t expected_data[element_count];
memset (expected_data, expected_value, element_count);
jerry_length_t byte_length;
jerry_length_t offset;
jerry_value_t buffer = jerry_get_typedarray_buffer (array, &offset, &byte_length);
TEST_ASSERT (byte_length == element_count);
jerry_length_t written = jerry_arraybuffer_write (buffer, offset, expected_data, element_count);
TEST_ASSERT (written == element_count);
jerry_release_value (buffer);
jerry_value_t js_element_count = jerry_create_number (element_count);
jerry_value_t js_expected_value = jerry_create_number (expected_value);
register_js_value ("array", array);
register_js_value ("expected_length", js_element_count);
register_js_value ("expected_value", js_expected_value);
jerry_release_value (js_element_count);
jerry_release_value (js_expected_value);
}
/* Check read and to write */
const char *eval_src_p = (
"assert (array.length == expected_length, 'expected length: ' + expected_length + ' got: ' + array.length);"
"for (var i = 0; i < array.length; i++)"
"{"
" assert (array[i] == expected_value);"
" array[i] = i;"
"};");
jerry_value_t result = jerry_eval ((jerry_char_t *) eval_src_p,
strlen (eval_src_p),
true);
TEST_ASSERT (!jerry_value_has_error_flag (result));
jerry_release_value (result);
/* Check write results */
{
jerry_length_t byte_length;
jerry_length_t offset;
jerry_value_t buffer = jerry_get_typedarray_buffer (array, &offset, &byte_length);
TEST_ASSERT (byte_length == element_count);
uint8_t result_data[element_count];
jerry_length_t read_count = jerry_arraybuffer_read (buffer, offset, result_data, byte_length);
TEST_ASSERT (read_count == byte_length);
for (uint8_t i = 0; i < read_count; i++)
{
TEST_ASSERT (result_data[i] == i);
}
jerry_release_value (buffer);
}
jerry_release_value (array);
}
test_typedarray_complex_creation (test_entries, false);
test_typedarray_complex_creation (test_entries, true);
/* test invalid things */
{
jerry_value_t values[] =
{
jerry_create_number (11),
jerry_create_boolean (false),
jerry_create_string ((const jerry_char_t *) "test"),
jerry_create_object (),
jerry_create_null (),
jerry_create_arraybuffer (16),
jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t *) "error"),
jerry_create_undefined (),
jerry_create_promise (),
};
for (size_t idx = 0; idx < sizeof (values) / sizeof (values[0]); idx++)
{
/* A non-TypedArray object should not be regarded a TypedArray. */
bool is_typedarray = jerry_value_is_typedarray (values[idx]);
TEST_ASSERT (is_typedarray == false);
/* JERRY_TYPEDARRAY_INVALID should be returned for non-TypedArray objects */
jerry_typedarray_type_t type = jerry_get_typedarray_type (values[idx]);
TEST_ASSERT (type == JERRY_TYPEDARRAY_INVALID);
/* Zero should be returned for non-TypedArray objects */
jerry_length_t length = jerry_get_typedarray_length (values[idx]);
TEST_ASSERT (length == 0);
/**
* Getting the ArrayBuffer from a non-TypedArray object(s) should return an error
* and should not modify the output parameter values.
*/
{
jerry_length_t offset = 22;
jerry_length_t byte_count = 23;
jerry_value_t error = jerry_get_typedarray_buffer (values[idx], &offset, &byte_count);
TEST_ASSERT (jerry_value_has_error_flag (error));
TEST_ASSERT (offset == 22);
TEST_ASSERT (byte_count == 23);
jerry_release_value (error);
}
/**
* Creating a TypedArray from a non-ArrayBuffer should result an error.
*/
if (!jerry_value_is_arraybuffer (values[idx]))
{
jerry_value_t error = jerry_create_typedarray_for_arraybuffer (JERRY_TYPEDARRAY_UINT8, values[idx]);
TEST_ASSERT (jerry_value_has_error_flag (error));
jerry_release_value (error);
}
jerry_release_value (values[idx]);
}
}
jerry_cleanup ();
} /* main */