diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index 927da6600e..61b021af66 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -7397,6 +7397,85 @@ jerry_get_arraybuffer_pointer (const jerry_value_t value); - [jerry_create_arraybuffer_external](#jerry_create_arraybuffer_external) +## jerry_is_arraybuffer_detachable + +**Summary** + +Get if the ArrayBuffer is detachable. + +**Prototype** + +```c +jerry_value_t +jerry_is_arraybuffer_detachable (const jerry_value_t value); +``` + +- `value` - ArrayBuffer to be detached +- return + - boolean value if success + - Error otherwise + +**Example** + +```c +{ + // create the ArrayBuffer + jerry_value_t buffer = jerry_create_arraybuffer (16); + + jerry_value_t res = jerry_is_arraybuffer_detachable (buffer); + bool is_detachable = jerry_get_boolean_value (res); + + // release buffer as it is not needed after this point + jerry_release_value (res); + jerry_release_value (buffer); +} +``` + +**See also** + +- [jerry_detach_arraybuffer](#jerry_detach_arraybuffer) + +## jerry_detach_arraybuffer + +**Summary** + +Detach the underlying data block from ArrayBuffer and set its bytelength to 0. + +This operation requires the ArrayBuffer to be external that created by +`jerry_create_arraybuffer_external`. + +**Prototype** + +```c +jerry_value_t +jerry_detach_arraybuffer (const jerry_value_t value); +``` + +- `value` - ArrayBuffer to be detached +- return + - null value if success + - Error otherwise + +**Example** + +```c +{ + uint8_t buf[1]; + jerry_size_t length = 1; + // create the ArrayBuffer + jerry_value_t buffer = jerry_create_arraybuffer (length, buf, NULL); + + jerry_value_t res = jerry_detach_arraybuffer (buffer); + + // release buffer as it is not needed after this point + jerry_release_value (res); + jerry_release_value (buffer); +} +``` + +**See also** + +- [jerry_is_arraybuffer_detachable](#jerry_is_arraybuffer_detachable) ## jerry_get_dataview_buffer diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index c1776a5c60..44a94ce1c4 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -3271,6 +3271,59 @@ jerry_get_arraybuffer_pointer (const jerry_value_t array_buffer) /**< Array Buff return NULL; } /* jerry_get_arraybuffer_pointer */ +/** + * Get if the ArrayBuffer is detachable. + * + * @return boolean value - if success + * value marked with error flag - otherwise + */ +jerry_value_t +jerry_is_arraybuffer_detachable (const jerry_value_t value) /**< ArrayBuffer */ +{ + jerry_assert_api_available (); + +#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) + if (ecma_is_arraybuffer (value)) + { + ecma_object_t *buffer_p = ecma_get_object_from_value (value); + return ecma_arraybuffer_is_detachable (buffer_p) ? ECMA_VALUE_TRUE : ECMA_VALUE_FALSE; + } +#else /* !ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ + JERRY_UNUSED (value); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Expects an ArrayBuffer"))); +} /* jerry_is_arraybuffer_detachable */ + +/** + * Detach the underlying data block from ArrayBuffer and set its bytelength to 0. + * This operation requires the ArrayBuffer to be external that created by + * `jerry_create_arraybuffer_external`. + * + * @return null value - if success + * value marked with error flag - otherwise + */ +jerry_value_t +jerry_detach_arraybuffer (const jerry_value_t value) /**< ArrayBuffer */ +{ + jerry_assert_api_available (); + +#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) + if (ecma_is_arraybuffer (value)) + { + ecma_object_t *buffer_p = ecma_get_object_from_value (value); + bool detached = ecma_arraybuffer_detach (buffer_p); + if (!detached) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Expects a detachable ArrayBuffer."))); + } + return ECMA_VALUE_NULL; + } +#else /* !ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ + JERRY_UNUSED (value); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Expects an ArrayBuffer"))); +} /* jerry_detach_arraybuffer */ + /** * DataView related functions */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.c index e393912f4d..f870a245ba 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.c @@ -61,6 +61,10 @@ ecma_builtin_arraybuffer_prototype_bytelength_getter (ecma_value_t this_arg) /** if (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)) { + if (ecma_arraybuffer_is_detached (object_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } ecma_length_t len = ecma_arraybuffer_get_length (object_p); return ecma_make_uint32_value (len); @@ -96,6 +100,11 @@ ecma_builtin_arraybuffer_prototype_object_slice (ecma_value_t this_arg, /**< thi return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not an ArrayBuffer object.")); } + if (ecma_arraybuffer_is_detached (object_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_length_t len = ecma_arraybuffer_get_length (object_p); ecma_length_t start = 0, end = len; diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-dataview-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-dataview-prototype.c index fc443f95dd..8f2240e0c4 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-dataview-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-dataview-prototype.c @@ -13,6 +13,8 @@ * limitations under the License. */ +#include "ecma-arraybuffer-object.h" +#include "ecma-exceptions.h" #include "ecma-dataview-object.h" #include "ecma-gc.h" @@ -110,11 +112,20 @@ ecma_builtin_dataview_prototype_object_getters (ecma_value_t this_arg, /**< this } case ECMA_DATAVIEW_PROTOTYPE_BYTE_LENGTH_GETTER: { + if (ecma_arraybuffer_is_detached (obj_p->buffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } return ecma_make_uint32_value (obj_p->header.u.class_prop.u.length); } default: { JERRY_ASSERT (builtin_routine_id == ECMA_DATAVIEW_PROTOTYPE_BYTE_OFFSET_GETTER); + + if (ecma_arraybuffer_is_detached (obj_p->buffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } return ecma_make_uint32_value (obj_p->byte_offset); } } 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 da9cd4ee8b..7f2ecf238f 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 @@ -206,6 +206,11 @@ ecma_builtin_typedarray_prototype_exec_routine (ecma_value_t this_arg, /**< this ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); ecma_typedarray_info_t info = ecma_typedarray_get_info (obj_p); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (obj_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } ecma_typedarray_getter_fn_t typedarray_getter_cb = ecma_get_typedarray_getter_fn (info.id); @@ -435,6 +440,12 @@ ecma_builtin_typedarray_prototype_map (ecma_value_t this_arg, /**< this argument } ecma_object_t *src_obj_p = ecma_get_object_from_value (this_arg); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (src_obj_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_typedarray_info_t src_info = ecma_typedarray_get_info (src_obj_p); ecma_object_t *func_object_p = ecma_get_object_from_value (cb_func_val); @@ -517,6 +528,12 @@ ecma_builtin_typedarray_prototype_reduce_with_direction (ecma_value_t this_arg, } ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (obj_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_typedarray_info_t info = ecma_typedarray_get_info (obj_p); ecma_typedarray_getter_fn_t getter_cb = ecma_get_typedarray_getter_fn (info.id); @@ -770,6 +787,12 @@ ecma_builtin_typedarray_prototype_reverse (ecma_value_t this_arg) /**< this argu } ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (obj_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_typedarray_info_t info = ecma_typedarray_get_info (obj_p); uint32_t middle = (info.length / 2) << info.shift; @@ -822,9 +845,21 @@ ecma_op_typedarray_set_with_typedarray (ecma_value_t this_arg, /**< this argumen } ecma_object_t *target_typedarray_p = ecma_get_object_from_value (this_arg); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (target_typedarray_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_typedarray_info_t target_info = ecma_typedarray_get_info (target_typedarray_p); ecma_object_t *src_typedarray_p = ecma_get_object_from_value (arr_val); + ecma_object_t *src_arraybuffer_p = ecma_typedarray_get_arraybuffer (src_typedarray_p); + if (ecma_arraybuffer_is_detached (src_arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_typedarray_info_t src_info = ecma_typedarray_get_info (src_typedarray_p); uint32_t target_offset_uint32 = ecma_number_to_uint32 (target_offset_num); @@ -911,6 +946,12 @@ ecma_builtin_typedarray_prototype_set (ecma_value_t this_arg, /**< this argument /* 11. ~ 15. */ ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_typedarray_info_t target_info = ecma_typedarray_get_info (typedarray_p); /* 16.~ 17. */ @@ -1476,6 +1517,11 @@ ecma_builtin_typedarray_prototype_sort (ecma_value_t this_arg, /**< this argumen } ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } ecma_typedarray_info_t info = ecma_typedarray_get_info (typedarray_p); if (!info.length) @@ -1577,6 +1623,11 @@ ecma_builtin_typedarray_prototype_find_helper (ecma_value_t this_arg, /**< this ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); ecma_typedarray_info_t info = ecma_typedarray_get_info (typedarray_p); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } uint32_t buffer_index = 0; uint32_t limit = info.length * info.element_size; @@ -1678,6 +1729,11 @@ ecma_builtin_typedarray_prototype_index_helper (ecma_value_t this_arg, /**< this ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); ecma_typedarray_info_t info = ecma_typedarray_get_info (typedarray_p); + if (ecma_arraybuffer_is_detached (info.array_buffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + uint32_t limit = info.length * info.element_size; uint32_t from_index; @@ -1901,6 +1957,12 @@ ecma_builtin_typedarray_prototype_slice (ecma_value_t this_arg, /**< this argume } ecma_object_t *typedarray_p = ecma_get_object_from_value (this_arg); + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } + ecma_typedarray_info_t info = ecma_typedarray_get_info (typedarray_p); uint32_t start = 0; uint32_t end = info.length; @@ -1944,6 +2006,7 @@ ecma_builtin_typedarray_prototype_slice (ecma_value_t this_arg, /**< this argume if (count > 0) { 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); uint32_t src_byte_index = (start * info.element_size); diff --git a/jerry-core/ecma/operations/ecma-arraybuffer-object.c b/jerry-core/ecma/operations/ecma-arraybuffer-object.c index 08f61554ac..61d058fa54 100644 --- a/jerry-core/ecma/operations/ecma-arraybuffer-object.c +++ b/jerry-core/ecma/operations/ecma-arraybuffer-object.c @@ -203,6 +203,79 @@ ecma_arraybuffer_get_buffer (ecma_object_t *object_p) /**< pointer to the ArrayB } } /* ecma_arraybuffer_get_buffer */ +/** + * Helper function: check if the target ArrayBuffer is detached + * + * @return true - if value is an detached ArrayBuffer object + * false - otherwise + */ +inline bool JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE +ecma_arraybuffer_is_detached (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ +{ + JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); + + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + + if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p)) + { + ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p; + /* in case the arraybuffer has been detached */ + return array_p->buffer_p == NULL; + } + + return false; +} /* ecma_arraybuffer_is_detached */ + +/** + * Helper function: check if the target ArrayBuffer is detachable + * + * @return true - if value is an detachable ArrayBuffer object + * false - otherwise + */ +inline bool JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE +ecma_arraybuffer_is_detachable (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ +{ + JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); + + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + + if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p)) + { + ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p; + /* in case the arraybuffer has been detached */ + return array_p->buffer_p != NULL; + } + + return false; +} /* ecma_arraybuffer_is_detachable */ + +/** + * ArrayBuffer object detaching operation + * + * See also: ES2015 24.1.1.3 + * + * @return true - if detach op succeeded + * false - otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +ecma_arraybuffer_detach (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ +{ + JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); + + if (!ecma_arraybuffer_is_detachable (object_p)) + { + return false; + } + + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + + ecma_arraybuffer_external_info *array_object_p = (ecma_arraybuffer_external_info *) ext_object_p; + array_object_p->buffer_p = NULL; + array_object_p->extended_object.u.class_prop.u.length = 0; + + return true; +} /* ecma_arraybuffer_detach */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-arraybuffer-object.h b/jerry-core/ecma/operations/ecma-arraybuffer-object.h index a77deb5005..c654b7b6f9 100644 --- a/jerry-core/ecma/operations/ecma-arraybuffer-object.h +++ b/jerry-core/ecma/operations/ecma-arraybuffer-object.h @@ -43,6 +43,12 @@ lit_utf8_byte_t * JERRY_ATTR_PURE ecma_arraybuffer_get_buffer (ecma_object_t *obj_p); ecma_length_t JERRY_ATTR_PURE ecma_arraybuffer_get_length (ecma_object_t *obj_p); +bool JERRY_ATTR_PURE +ecma_arraybuffer_is_detached (ecma_object_t *obj_p); +bool JERRY_ATTR_PURE +ecma_arraybuffer_is_detachable (ecma_object_t *obj_p); +bool +ecma_arraybuffer_detach (ecma_object_t *obj_p); bool ecma_is_arraybuffer (ecma_value_t val); diff --git a/jerry-core/ecma/operations/ecma-dataview-object.c b/jerry-core/ecma/operations/ecma-dataview-object.c index 6c4ae23f99..e6b0b0bffe 100644 --- a/jerry-core/ecma/operations/ecma-dataview-object.c +++ b/jerry-core/ecma/operations/ecma-dataview-object.c @@ -84,7 +84,11 @@ ecma_op_dataview_create (const ecma_value_t *arguments_list_p, /**< arguments li } } - /* 8. TODO: Throw TypeError, when Detached ArrayBuffer will be supported. */ + /* 8. */ + if (ecma_arraybuffer_is_detached (buffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } /* 9. */ ecma_length_t buffer_byte_length = ecma_arraybuffer_get_length (buffer_p); @@ -284,6 +288,10 @@ ecma_op_dataview_get_set_view_value (ecma_value_t view, /**< the operation's 'vi /* 9. */ ecma_object_t *buffer_p = view_p->buffer_p; JERRY_ASSERT (ecma_object_class_is (buffer_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); + if (ecma_arraybuffer_is_detached (buffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } /* 10. */ uint32_t view_offset = view_p->byte_offset; diff --git a/jerry-core/ecma/operations/ecma-typedarray-object.c b/jerry-core/ecma/operations/ecma-typedarray-object.c index 5899795576..3160a1cde2 100644 --- a/jerry-core/ecma/operations/ecma-typedarray-object.c +++ b/jerry-core/ecma/operations/ecma-typedarray-object.c @@ -544,6 +544,10 @@ ecma_typedarray_create_object_with_buffer (ecma_object_t *arraybuffer_p, /**< th uint8_t element_size_shift, /**< the size shift of the element length */ ecma_typedarray_type_t typedarray_id) /**< id of the typedarray */ { + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); + } ecma_length_t expected_length = (ecma_arraybuffer_get_length (arraybuffer_p) >> element_size_shift); bool needs_ext_typedarray_obj = (byte_offset != 0 || array_length != expected_length); @@ -586,6 +590,11 @@ ecma_typedarray_create_object_with_typedarray (ecma_object_t *typedarray_p, /**< ecma_typedarray_type_t typedarray_id) /**< id of the typedarray */ { ecma_length_t array_length = ecma_typedarray_get_length (typedarray_p); + ecma_object_t *src_arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p); + if (ecma_arraybuffer_is_detached (src_arraybuffer_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid detached ArrayBuffer.")); + } ecma_value_t new_typedarray = ecma_typedarray_create_object_with_length (array_length, proto_p, @@ -599,7 +608,6 @@ ecma_typedarray_create_object_with_typedarray (ecma_object_t *typedarray_p, /**< 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); @@ -825,6 +833,12 @@ ecma_typedarray_get_length (ecma_object_t *typedarray_p) /**< the pointer to the return buffer_length >> shift; } + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return 0; + } + ecma_extended_typedarray_object_t *info_p = (ecma_extended_typedarray_object_t *) ext_object_p; return info_p->array_length; @@ -847,6 +861,12 @@ ecma_typedarray_get_offset (ecma_object_t *typedarray_p) /**< the pointer to the return 0; } + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p); + if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + return 0; + } + ecma_extended_typedarray_object_t *info_p = (ecma_extended_typedarray_object_t *) ext_object_p; return info_p->byte_offset; @@ -947,6 +967,10 @@ ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg li { ret = ecma_raise_range_error (ECMA_ERR_MSG ("Invalid offset.")); } + else if (ecma_arraybuffer_is_detached (arraybuffer_p)) + { + ret = ecma_raise_range_error (ECMA_ERR_MSG ("Invalid detached ArrayBuffer.")); + } else { ecma_length_t buf_byte_length = ecma_arraybuffer_get_length (arraybuffer_p); diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index 16b4b5c6b1..151b655ec4 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -595,6 +595,8 @@ jerry_length_t jerry_arraybuffer_read (const jerry_value_t value, jerry_length_t buf_size); jerry_length_t jerry_get_arraybuffer_byte_length (const jerry_value_t value); uint8_t *jerry_get_arraybuffer_pointer (const jerry_value_t value); +jerry_value_t jerry_is_arraybuffer_detachable (const jerry_value_t value); +jerry_value_t jerry_detach_arraybuffer (const jerry_value_t value); /** * DataView functions. diff --git a/tests/unit-core/test-arraybuffer.c b/tests/unit-core/test-arraybuffer.c index 46dffc237c..6cda688d55 100644 --- a/tests/unit-core/test-arraybuffer.c +++ b/tests/unit-core/test-arraybuffer.c @@ -354,6 +354,51 @@ main (void) jerry_release_value (input_buffer); } + /* Test ArrayBuffer detach */ + { + const uint32_t length = 1; + jerry_value_t arraybuffer = jerry_create_arraybuffer (length); + TEST_ASSERT (!jerry_value_is_error (arraybuffer)); + TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer)); + TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length); + + jerry_value_t is_detachable = jerry_is_arraybuffer_detachable (arraybuffer); + TEST_ASSERT (!jerry_value_is_error (is_detachable)); + TEST_ASSERT (!jerry_get_boolean_value (is_detachable)); + + jerry_value_t res = jerry_detach_arraybuffer (arraybuffer); + TEST_ASSERT (jerry_value_is_error (res)); + + jerry_release_value (res); + jerry_release_value (arraybuffer); + } + + /* Test external ArrayBuffer detach */ + { + uint8_t buf[1]; + const uint32_t length = 1; + jerry_value_t arraybuffer = jerry_create_arraybuffer_external (length, buf, NULL); + TEST_ASSERT (!jerry_value_is_error (arraybuffer)); + TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer)); + TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length); + + jerry_value_t is_detachable = jerry_is_arraybuffer_detachable (arraybuffer); + TEST_ASSERT (!jerry_value_is_error (is_detachable)); + TEST_ASSERT (jerry_get_boolean_value (is_detachable)); + jerry_release_value (is_detachable); + + jerry_value_t res = jerry_detach_arraybuffer (arraybuffer); + TEST_ASSERT (!jerry_value_is_error (res)); + + is_detachable = jerry_is_arraybuffer_detachable (arraybuffer); + TEST_ASSERT (!jerry_value_is_error (is_detachable)); + TEST_ASSERT (!jerry_get_boolean_value (is_detachable)); + jerry_release_value (is_detachable); + + jerry_release_value (res); + jerry_release_value (arraybuffer); + } + jerry_cleanup (); TEST_ASSERT (callback_called == true);