Add allocate/free callbacks to ArrayBuffers (#4801)

Larger buffer allocations will throw error instead of calling jerry_fatal.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2021-10-28 13:51:34 +02:00
committed by GitHub
parent d2388e907f
commit a024eb2118
19 changed files with 1365 additions and 716 deletions
+333 -23
View File
@@ -1457,6 +1457,86 @@ typedef struct
- [jerry_source_info_enabled_fields_t](#jerry_source_info_enabled_fields_t)
- [jerry_get_source_info](#jerry_get_source_info)
## jerry_arraybuffer_type_t
**Summary**
Enum that contains the JerryScript type of an array buffer:
- JERRY_ARRAYBUFFER_TYPE_ARRAYBUFFER - the object is an array buffer object
- JERRY_ARRAYBUFFER_TYPE_SHARED_ARRAYBUFFER - the object is a shared array buffer object
*New in version [[NEXT_RELEASE]]*.
**See also**
- [jerry_arraybuffer_allocate_t](#jerry_arraybuffer_allocate_t)
- [jerry_arraybuffer_free_t](#jerry_arraybuffer_free_t)
## jerry_arraybuffer_allocate_t
**Summary**
Callback for allocating the backing store of array buffer or shared array buffer objects.
*Note*:
- The value referenced by `arraybuffer_user_p` is always NULL unless the buffer is created by
[jerry_create_arraybuffer_external](#jerry_create_arraybuffer_external) or
[jerry_create_shared_arraybuffer_external](#jerry_create_shared_arraybuffer_external).
The value referenced by `arraybuffer_user_p` can be changed, and the new value is passed to
[jerry_arraybuffer_free_t](#jerry_arraybuffer_free_t).
**Prototype**
```c
typedef uint8_t *(*jerry_arraybuffer_allocate_t) (jerry_arraybuffer_type_t buffer_type, uint32_t buffer_size,
void **arraybuffer_user_p, void *user_p);
```
- `buffer_type` - type of the array buffer object, see: [jerry_arraybuffer_type_t](#jerry_arraybuffer_type_t).
- `buffer_size` - size of the requested buffer.
- `arraybuffer_user_p` - [in/out] user pointer assigned to the array buffer or shared array buffer object.
- `user_p` - user pointer passed to [jerry_arraybuffer_set_allocator_callbacks](#jerry_arraybuffer_set_allocator_callbacks)
- return value
- Pointer to the buffer, if the allocation is successful, NULL otherwise.
*New in version [[NEXT_RELEASE]]*.
**See also**
- [jerry_arraybuffer_set_allocator_callbacks](#jerry_arraybuffer_set_allocator_callbacks)
## jerry_arraybuffer_free_t
**Summary**
Callback for freeing the backing store of array buffer or shared array buffer objects.
*Note*:
- The value passed to `arraybuffer_user_p` is always NULL unless the buffer is created by
[jerry_create_arraybuffer_external](#jerry_create_arraybuffer_external) or
[jerry_create_shared_arraybuffer_external](#jerry_create_shared_arraybuffer_external),
or the value is modified by [jerry_arraybuffer_allocate_t](#jerry_arraybuffer_allocate_t).
**Prototype**
```c
typedef void (*jerry_arraybuffer_free_t) (jerry_arraybuffer_type_t buffer_type, uint8_t *buffer_p,
uint32_t buffer_size, void *arraybuffer_user_p, void *user_p);
```
- `buffer_type` - type of the array buffer object, see: [jerry_arraybuffer_type_t](#jerry_arraybuffer_type_t).
- `buffer_p` - pointer to the allocated buffer.
- `buffer_size` - size of the allocated buffer.
- `arraybuffer_user_p` - [in/out] user pointer assigned to the array buffer or shared array buffer object.
- `user_p` - user pointer passed to [jerry_arraybuffer_set_allocator_callbacks](#jerry_arraybuffer_set_allocator_callbacks)
*New in version [[NEXT_RELEASE]]*.
**See also**
- [jerry_arraybuffer_set_allocator_callbacks](#jerry_arraybuffer_set_allocator_callbacks)
# General engine functions
@@ -6893,9 +6973,11 @@ jerry_create_array (uint32_t size);
Create a jerry_value_t representing an ArrayBuffer object.
*Note*:
- This API depends on the es.next profile.
- Returned value must be freed with [jerry_release_value](#jerry_release_value)
when it is no longer needed.
- This API depends on a build option (`JERRY_BUILTIN_TYPEDARRAY`) and can be checked
in runtime with the `JERRY_FEATURE_TYPEDARRAY` feature enum value,
see: [jerry_is_feature_enabled](#jerry_is_feature_enabled).
- Returned value must be freed with [jerry_release_value](#jerry_release_value)
when it is no longer needed.
**Prototype**
@@ -6904,7 +6986,7 @@ jerry_value_t
jerry_create_arraybuffer (jerry_length_t size);
```
- `size` - size of the ArrayBuffer to create **in bytes**
- `size` - size of the backing store allocated for the array buffer **in bytes**.
- return value - the new ArrayBuffer as a `jerry_value_t`
*New in version 2.0*.
@@ -6941,29 +7023,31 @@ After the object is not needed the GC will call the `free_cb`
so the user can release the buffer which was provided.
*Note*:
- This API depends on the es.next profile.
- Returned value must be freed with [jerry_release_value](#jerry_release_value)
when it is no longer needed.
- This API depends on a build option (`JERRY_BUILTIN_TYPEDARRAY`) and can be checked
in runtime with the `JERRY_FEATURE_TYPEDARRAY` feature enum value,
see: [jerry_is_feature_enabled](#jerry_is_feature_enabled).
- If `buffer_p` is NULL, the buffer is allocated by the allocator callback passed to
[jerry_arraybuffer_set_allocator_callbacks](#jerry_arraybuffer_set_allocator_callbacks)
- Returned value must be freed with [jerry_release_value](#jerry_release_value)
when it is no longer needed.
**Prototype**
```c
jerry_value_t
jerry_create_arraybuffer_external (const jerry_length_t size
uint8_t *buffer_p,
jerry_value_free_callback_t free_cb);
uint8_t *buffer_p, void *arraybuffer_user_p);
```
- `size` - size of the buffer to use **in bytes** (should not be 0)
- `buffer_p` - the buffer used for the Array Buffer object (should not be a null pointer)
- `free_cb` - the callback function called when the object is released
- `size` - size of the buffer **in bytes**.
- `buffer_p` - the backing store used by the array buffer object.
- `arraybuffer_user_p` - user pointer assigned to the array buffer object.
- return value
- the new ArrayBuffer as a `jerry_value_t`
- if the `size` is zero or `buffer_p` is a null pointer this will return an empty ArrayBuffer.
- value of the newly construced array buffer object.
*New in version 2.0*.
*Changed in version [[NEXT_RELEASE]]*: type of `free_cb` has been changed.
*Changed in version [[NEXT_RELEASE]]*: `free_cb` has been replaced by `arraybuffer_user_p`.
**Example**
@@ -6995,7 +7079,7 @@ jerry_create_arraybuffer_external (const jerry_length_t size
Create a jerry_value_t representing a SharedArrayBuffer object.
*Note*:
- This API depends on the es.next profile.
- This API depends on a build option (`JERRY_BUILTIN_SHAREDARRAYBUFFER`).
- Returned value must be freed with [jerry_release_value](#jerry_release_value)
when it is no longer needed.
@@ -7006,7 +7090,7 @@ jerry_value_t
jerry_create_shared_arraybuffer (jerry_length_t size);
```
- `size` - size of the SharedArrayBuffer to create **in bytes**
- `size` - size of the backing store allocated for the shared array buffer **in bytes**.
- return value - the new SharedArrayBuffer as a `jerry_value_t`
*New in version [[NEXT_RELEASE]]*.
@@ -7043,7 +7127,9 @@ After the object is not needed the GC will call the `free_cb`
so the user can release the buffer which was provided.
*Note*:
- This API depends on the es.next profile.
- This API depends on a build option (`JERRY_BUILTIN_SHAREDARRAYBUFFER`).
- If `buffer_p` is NULL, the buffer is allocated by the allocator callback passed to
[jerry_arraybuffer_set_allocator_callbacks](#jerry_arraybuffer_set_allocator_callbacks)
- Returned value must be freed with [jerry_release_value](#jerry_release_value)
when it is no longer needed.
@@ -7056,12 +7142,11 @@ jerry_create_shared_arraybuffer_external (const jerry_length_t size
jerry_value_free_callback_t free_cb);
```
- `size` - size of the buffer to use **in bytes** (should not be 0)
- `buffer_p` - the buffer used for the Shared Array Buffer object (should not be a null pointer)
- `free_cb` - the callback function called when the object is released
- `size` - size of the buffer **in bytes**.
- `buffer_p` - the backing store used by the shared array buffer object.
- `arraybuffer_user_p` - user pointer assigned to the shared array buffer object.
- return value
- the new SharedArrayBuffer as a `jerry_value_t`
- if the `size` is zero or `buffer_p` is a null pointer this will return an empty SharedArrayBuffer.
- value of the newly construced shared array buffer object.
*New in version [[NEXT_RELEASE]]*.
@@ -12702,6 +12787,231 @@ jerry_detach_arraybuffer (const jerry_value_t value);
- [jerry_is_arraybuffer_detachable](#jerry_is_arraybuffer_detachable)
## jerry_arraybuffer_has_buffer
**Summary**
Checks whether a buffer is currently allocated for an array buffer or typed array.
*Notes*:
- This API depends on a build option (`JERRY_BUILTIN_TYPEDARRAY`) and can be checked
in runtime with the `JERRY_FEATURE_TYPEDARRAY` feature enum value,
see: [jerry_is_feature_enabled](#jerry_is_feature_enabled).
**Prototype**
```c
bool
jerry_arraybuffer_has_buffer (const jerry_value_t value);
```
- `value` - array buffer or typed array value.
- return
- true, if a buffer is allocated for an array buffer or typed array
- false, otherwise
*New in version [[NEXT_RELEASE]]*.
**Example**
[doctest]: # (test="compile")
```c
#include "jerryscript.h"
int
main (void)
{
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t array_buffer_value = jerry_create_arraybuffer (1024 * 1024);
/* By default, the backing store of large array buffers
* is allocated when it is used the first time. */
if (!jerry_arraybuffer_has_buffer (array_buffer_value))
{
/* Code enters here in this case. */
}
jerry_release_value (array_buffer_value);
jerry_cleanup ();
return 0;
}
```
**See also**
- [jerry_create_arraybuffer_external](#jerry_create_arraybuffer_external)
- [jerry_create_shared_arraybuffer_external](#jerry_create_shared_arraybuffer_external)
- [jerry_arraybuffer_set_compact_allocation_limit](#jerry_arraybuffer_set_compact_allocation_limit)
- [jerry_arraybuffer_set_allocator_callbacks](#jerry_arraybuffer_set_allocator_callbacks)
## jerry_arraybuffer_set_compact_allocation_limit
**Summary**
Array buffers which size is less or equal than the limit passed to this
function are allocated in a single memory block. The allocator callbacks set by
[jerry_arraybuffer_set_allocation_callbacks](#jerry_arraybuffer_set_allocation_callbacks)
are not called for these array buffers.
*Notes*:
- This API depends on a build option (`JERRY_BUILTIN_TYPEDARRAY`) and can be checked
in runtime with the `JERRY_FEATURE_TYPEDARRAY` feature enum value,
see: [jerry_is_feature_enabled](#jerry_is_feature_enabled).
- The default limit is 256 bytes.
- When an array buffer is allocated in a single memory block, its
backing store is not freed when the array buffer is detached.
- This limit does not affect shared array buffers, their backing store is always
allocated by the allocator callback.
**Prototype**
```c
void
jerry_arraybuffer_set_compact_allocation_limit (const jerry_length_t allocation_limit);
```
- `allocation_limit` - maximum size of compact allocation.
*New in version [[NEXT_RELEASE]]*.
**Example**
[doctest]: # (test="compile")
```c
#include "jerryscript.h"
int
main (void)
{
jerry_init (JERRY_INIT_EMPTY);
jerry_arraybuffer_set_compact_allocation_limit (1);
jerry_value_t array_buffer_value = jerry_create_arraybuffer (1);
if (jerry_arraybuffer_has_buffer (array_buffer_value))
{
/* Code enters here because the backing store
* is allocated during buffer creation. */
}
jerry_release_value (array_buffer_value);
array_buffer_value = jerry_create_arraybuffer (2);
if (jerry_arraybuffer_has_buffer (array_buffer_value))
{
/* Code does not enter here because the backing store
* is allocated when it is used the first time. */
}
jerry_release_value (array_buffer_value);
jerry_cleanup ();
return 0;
}
```
**See also**
- [jerry_arraybuffer_has_buffer](#jerry_arraybuffer_has_buffer)
- [jerry_arraybuffer_set_allocator_callbacks](#jerry_arraybuffer_set_allocator_callbacks)
## jerry_arraybuffer_set_allocator_callbacks
**Summary**
Set callbacks for allocating and freeing backing stores for array buffer objects.
*Notes*:
- This API depends on a build option (`JERRY_BUILTIN_TYPEDARRAY`) and can be checked
in runtime with the `JERRY_FEATURE_TYPEDARRAY` feature enum value,
see: [jerry_is_feature_enabled](#jerry_is_feature_enabled).
- This function is recommended to be called after [jerry_init](#jerry_init) before
any array buffer is allocated.
- The callbacks can be NULL to use the default callbacks. The default `allocate_callback`
allocates memory using [jerry_heap_alloc](#jerry_heap_alloc) and the default
`free_callback` frees memory using [jerry_heap_free](#jerry_heap_free).
**Prototype**
```c
void
jerry_arraybuffer_set_allocator_callbacks (jerry_arraybuffer_allocate_t allocate_callback,
jerry_arraybuffer_free_t free_callback,
void *user_p)
```
- `allocate_callback` - callback for allocating array buffer memory.
- `free_callback` - callback for freeing array buffer memory.
- `user_p` - user pointer passed to the callbacks.
*New in version [[NEXT_RELEASE]]*.
**Example**
[doctest]: # (test="compile")
```c
#include "jerryscript.h"
static uint8_t global_buffer[64];
static void
array_buffer_free_cb (jerry_arraybuffer_type_t buffer_type, /**< type of the array buffer object */
uint8_t *buffer_p, /**< pointer to the allocated buffer */
uint32_t buffer_size, /**< size of the allocated buffer */
void *arraybuffer_user_p, /**< user pointer assigned to the array buffer object */
void *user_p) /**< user pointer passed to jerry_arraybuffer_set_allocation_callbacks */
{
(void) buffer_type;
(void) user_p;
/* As for this example, only the free callback is redirected. This callback
* function does not free the memory if the arraybuffer_user_p is non-NULL. */
if (arraybuffer_user_p == NULL)
{
jerry_heap_free (buffer_p, buffer_size);
}
} /* array_buffer_free_cb */
int
main (void)
{
jerry_init (JERRY_INIT_EMPTY);
jerry_arraybuffer_set_allocator_callbacks (NULL, array_buffer_free_cb, NULL);
/* The buffer of the array buffer object is allocated by the default
* allocator using jerry_heap_alloc and freed by array_buffer_free_cb. */
const jerry_char_t script[] = "var result = new uint32Array(1024); result[0] = 1; result";
jerry_value_t array_buffer_value = jerry_eval (script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
jerry_release_value (array_buffer_value);
/* The buffer of the array buffer object has a non-NULL
* arraybuffer_user_p value, so it is not freed by array_buffer_free_cb. */
array_buffer_value = jerry_create_arraybuffer_external (sizeof (global_buffer), global_buffer, global_buffer);
jerry_release_value (array_buffer_value);
jerry_cleanup ();
return 0;
}
```
**See also**
- [jerry_arraybuffer_has_buffer](#jerry_arraybuffer_has_buffer)
- [jerry_arraybuffer_set_allocator_callbacks](#jerry_arraybuffer_set_allocator_callbacks)
## jerry_get_dataview_buffer
**Summary**