diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 737d9add0..7beeb79bb 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -6072,6 +6072,29 @@ jerry_create_shared_arraybuffer_external (const jerry_length_t size, /**< size o #endif /* JERRY_BUILTIN_SHAREDARRAYBUFFER */ } /* jerry_create_shared_arraybuffer_external */ +#if JERRY_BUILTIN_TYPEDARRAY + +/** + * Allocate a backing store for an array buffer, ignores allocation fails. + * + * @return true on success, + * false otherwise + */ +static bool +jerry_arraybuffer_allocate_buffer_no_throw (ecma_object_t *arraybuffer_p) /**< ArrayBuffer object */ +{ + JERRY_ASSERT (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_ALLOCATED)); + + if (ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_DETACHED) + { + return false; + } + + return ecma_arraybuffer_allocate_buffer (arraybuffer_p) != NULL; +} /* jerry_arraybuffer_allocate_buffer_no_throw */ + +#endif /* JERRY_BUILTIN_TYPEDARRAY */ + /** * Copy bytes into the ArrayBuffer or SharedArrayBuffer from a buffer. * @@ -6094,15 +6117,15 @@ jerry_arraybuffer_write (const jerry_value_t value, /**< target ArrayBuffer or S return 0; } - ecma_object_t *buffer_p = ecma_get_object_from_value (value); + ecma_object_t *arraybuffer_p = ecma_get_object_from_value (value); - if (ECMA_ARRAYBUFFER_CHECK_BUFFER_ERROR (buffer_p)) + if (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_ALLOCATED) + && !jerry_arraybuffer_allocate_buffer_no_throw (arraybuffer_p)) { - jerry_release_value (jcontext_take_exception ()); return 0; } - jerry_length_t length = ecma_arraybuffer_get_length (buffer_p); + jerry_length_t length = ecma_arraybuffer_get_length (arraybuffer_p); if (offset >= length) { @@ -6113,9 +6136,9 @@ jerry_arraybuffer_write (const jerry_value_t value, /**< target ArrayBuffer or S if (copy_count > 0) { - lit_utf8_byte_t *mem_buffer_p = ecma_arraybuffer_get_buffer (buffer_p); + lit_utf8_byte_t *buffer_p = ecma_arraybuffer_get_buffer (arraybuffer_p); - memcpy ((void *) (mem_buffer_p + offset), (void *) buf_p, copy_count); + memcpy ((void *) (buffer_p + offset), (void *) buf_p, copy_count); } return copy_count; @@ -6150,15 +6173,15 @@ jerry_arraybuffer_read (const jerry_value_t value, /**< ArrayBuffer or SharedArr return 0; } - ecma_object_t *buffer_p = ecma_get_object_from_value (value); + ecma_object_t *arraybuffer_p = ecma_get_object_from_value (value); - if (ECMA_ARRAYBUFFER_CHECK_BUFFER_ERROR (buffer_p)) + if (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_ALLOCATED) + && !jerry_arraybuffer_allocate_buffer_no_throw (arraybuffer_p)) { - jerry_release_value (jcontext_take_exception ()); return 0; } - jerry_length_t length = ecma_arraybuffer_get_length (buffer_p); + jerry_length_t length = ecma_arraybuffer_get_length (arraybuffer_p); if (offset >= length) { @@ -6169,9 +6192,9 @@ jerry_arraybuffer_read (const jerry_value_t value, /**< ArrayBuffer or SharedArr if (copy_count > 0) { - lit_utf8_byte_t *mem_buffer_p = ecma_arraybuffer_get_buffer (buffer_p); + lit_utf8_byte_t *buffer_p = ecma_arraybuffer_get_buffer (arraybuffer_p); - memcpy ((void *) buf_p, (void *) (mem_buffer_p + offset), copy_count); + memcpy ((void *) buf_p, (void *) (buffer_p + offset), copy_count); } return copy_count; @@ -6200,8 +6223,8 @@ jerry_get_arraybuffer_byte_length (const jerry_value_t value) /**< ArrayBuffer o #if JERRY_BUILTIN_TYPEDARRAY if (ecma_is_arraybuffer (value) || ecma_is_shared_arraybuffer (value)) { - ecma_object_t *buffer_p = ecma_get_object_from_value (value); - return ecma_arraybuffer_get_length (buffer_p); + ecma_object_t *arraybuffer_p = ecma_get_object_from_value (value); + return ecma_arraybuffer_get_length (arraybuffer_p); } #else /* !JERRY_BUILTIN_TYPEDARRAY */ JERRY_UNUSED (value); @@ -6232,14 +6255,15 @@ jerry_get_arraybuffer_pointer (const jerry_value_t array_buffer) /**< Array Buff return NULL; } - ecma_object_t *buffer_p = ecma_get_object_from_value (array_buffer); + ecma_object_t *arraybuffer_p = ecma_get_object_from_value (array_buffer); - if (!(ECMA_ARRAYBUFFER_GET_FLAGS (buffer_p) & ECMA_ARRAYBUFFER_ALLOCATED)) + if (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_ALLOCATED) + && !jerry_arraybuffer_allocate_buffer_no_throw (arraybuffer_p)) { return NULL; } - return (uint8_t *) ecma_arraybuffer_get_buffer (buffer_p); + return (uint8_t *) ecma_arraybuffer_get_buffer (arraybuffer_p); #else /* !JERRY_BUILTIN_TYPEDARRAY */ JERRY_UNUSED (array_buffer); #endif /* JERRY_BUILTIN_TYPEDARRAY */ diff --git a/jerry-core/ecma/operations/ecma-arraybuffer-object.c b/jerry-core/ecma/operations/ecma-arraybuffer-object.c index 99749921e..eebf31f37 100644 --- a/jerry-core/ecma/operations/ecma-arraybuffer-object.c +++ b/jerry-core/ecma/operations/ecma-arraybuffer-object.c @@ -128,26 +128,21 @@ ecma_arraybuffer_new_object (uint32_t length) /**< length of the arraybuffer */ /** * Allocate a backing store for an array buffer. * - * @return ECMA_VALUE_UNDEFINED on success, - * ECMA_VALUE_ERROR otherwise + * @return buffer pointer on success, + * NULL otherwise */ -ecma_value_t -ecma_arraybuffer_allocate_buffer (ecma_object_t *object_p) /**< ArrayBuffer object */ +uint8_t * +ecma_arraybuffer_allocate_buffer (ecma_object_t *arraybuffer_p) /**< ArrayBuffer object */ { - JERRY_ASSERT (!(ECMA_ARRAYBUFFER_GET_FLAGS (object_p) & ECMA_ARRAYBUFFER_ALLOCATED)); + JERRY_ASSERT (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_ALLOCATED)); + JERRY_ASSERT (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_DETACHED)); + JERRY_ASSERT (ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_HAS_POINTER); - if (ECMA_ARRAYBUFFER_GET_FLAGS (object_p) & ECMA_ARRAYBUFFER_DETACHED) - { - return ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_arraybuffer_is_detached)); - } - - JERRY_ASSERT (ECMA_ARRAYBUFFER_GET_FLAGS (object_p) & ECMA_ARRAYBUFFER_HAS_POINTER); - - ecma_extended_object_t *extended_object_p = (ecma_extended_object_t *) object_p; + ecma_extended_object_t *extended_object_p = (ecma_extended_object_t *) arraybuffer_p; uint32_t arraybuffer_length = extended_object_p->u.cls.u3.length; - ecma_arraybuffer_pointer_t *arraybuffer_pointer_p = (ecma_arraybuffer_pointer_t *) object_p; + ecma_arraybuffer_pointer_t *arraybuffer_pointer_p = (ecma_arraybuffer_pointer_t *) arraybuffer_p; jerry_arraybuffer_allocate_t arraybuffer_allocate_callback = JERRY_CONTEXT (arraybuffer_allocate_callback); - void *buffer_p; + uint8_t *buffer_p; if (arraybuffer_allocate_callback != NULL) { @@ -167,33 +162,59 @@ ecma_arraybuffer_allocate_buffer (ecma_object_t *object_p) /**< ArrayBuffer obje } else { - buffer_p = jmem_heap_alloc_block_null_on_error (arraybuffer_length); + buffer_p = (uint8_t *) jmem_heap_alloc_block_null_on_error (arraybuffer_length); } if (buffer_p == NULL) { extended_object_p->u.cls.u1.array_buffer_flags |= ECMA_ARRAYBUFFER_DETACHED; - return ecma_raise_range_error (ECMA_ERR_MSG ("Cannot allocate memory for ArrayBuffer")); + return NULL; } arraybuffer_pointer_p->buffer_p = buffer_p; extended_object_p->u.cls.u1.array_buffer_flags |= ECMA_ARRAYBUFFER_ALLOCATED; memset (buffer_p, 0, arraybuffer_length); - return ECMA_VALUE_UNDEFINED; + return buffer_p; } /* ecma_arraybuffer_allocate_buffer */ +/** + * Allocate a backing store for an array buffer, throws an error if the allocation fails. + * + * @return ECMA_VALUE_UNDEFINED on success, + * ECMA_VALUE_ERROR otherwise + */ +ecma_value_t +ecma_arraybuffer_allocate_buffer_throw (ecma_object_t *arraybuffer_p) +{ + JERRY_ASSERT (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_ALLOCATED)); + + if (ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_DETACHED) + { + return ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_arraybuffer_is_detached)); + } + + uint8_t *buffer_p = ecma_arraybuffer_allocate_buffer (arraybuffer_p); + + if (buffer_p == NULL) + { + return ecma_raise_range_error (ECMA_ERR_MSG ("Cannot allocate memory for ArrayBuffer")); + } + + return ECMA_VALUE_UNDEFINED; +} /* ecma_arraybuffer_allocate_buffer_throw */ + /** * Release the backing store allocated by an array buffer. */ void -ecma_arraybuffer_release_buffer (ecma_object_t *object_p) /**< ArrayBuffer object */ +ecma_arraybuffer_release_buffer (ecma_object_t *arraybuffer_p) /**< ArrayBuffer object */ { - JERRY_ASSERT (ecma_object_class_is (object_p, ECMA_OBJECT_CLASS_ARRAY_BUFFER) - || ecma_object_is_shared_arraybuffer (object_p)); + JERRY_ASSERT (ecma_object_class_is (arraybuffer_p, ECMA_OBJECT_CLASS_ARRAY_BUFFER) + || ecma_object_is_shared_arraybuffer (arraybuffer_p)); jerry_arraybuffer_free_t free_callback = JERRY_CONTEXT (arraybuffer_free_callback); - ecma_arraybuffer_pointer_t *arraybuffer_pointer_p = (ecma_arraybuffer_pointer_t *) object_p; + ecma_arraybuffer_pointer_t *arraybuffer_pointer_p = (ecma_arraybuffer_pointer_t *) arraybuffer_p; uint32_t arraybuffer_length = arraybuffer_pointer_p->extended_object.u.cls.u3.length; if (free_callback == NULL) diff --git a/jerry-core/ecma/operations/ecma-arraybuffer-object.h b/jerry-core/ecma/operations/ecma-arraybuffer-object.h index be53a944f..f904c1aef 100644 --- a/jerry-core/ecma/operations/ecma-arraybuffer-object.h +++ b/jerry-core/ecma/operations/ecma-arraybuffer-object.h @@ -38,7 +38,7 @@ */ #define ECMA_ARRAYBUFFER_CHECK_BUFFER_ERROR(arraybuffer_p) \ (JERRY_UNLIKELY (!(ECMA_ARRAYBUFFER_GET_FLAGS (arraybuffer_p) & ECMA_ARRAYBUFFER_ALLOCATED)) \ - && ecma_arraybuffer_allocate_buffer (arraybuffer_p) == ECMA_VALUE_ERROR) + && ecma_arraybuffer_allocate_buffer_throw (arraybuffer_p) == ECMA_VALUE_ERROR) ecma_value_t ecma_op_create_arraybuffer_object (const ecma_value_t *, uint32_t); @@ -52,10 +52,12 @@ ecma_object_t * ecma_arraybuffer_create_object_with_buffer (uint8_t type, uint32_t length); ecma_object_t * ecma_arraybuffer_new_object (uint32_t length); +uint8_t * +ecma_arraybuffer_allocate_buffer (ecma_object_t *arraybuffer_p); ecma_value_t -ecma_arraybuffer_allocate_buffer (ecma_object_t *object_p); +ecma_arraybuffer_allocate_buffer_throw (ecma_object_t *arraybuffer_p); void -ecma_arraybuffer_release_buffer (ecma_object_t *object_p); +ecma_arraybuffer_release_buffer (ecma_object_t *arraybuffer_p); uint8_t * JERRY_ATTR_PURE ecma_arraybuffer_get_buffer (ecma_object_t *obj_p); uint32_t JERRY_ATTR_PURE diff --git a/tests/unit-core/test-arraybuffer.c b/tests/unit-core/test-arraybuffer.c index 687625f47..f5668607d 100644 --- a/tests/unit-core/test-arraybuffer.c +++ b/tests/unit-core/test-arraybuffer.c @@ -376,6 +376,8 @@ main (void) uint8_t *const data = jerry_get_arraybuffer_pointer (buffer); + TEST_ASSERT (data != NULL); + /* test memory read */ for (int i = 0; i < 20; i++) { @@ -472,6 +474,7 @@ main (void) } /* Test ArrayBuffer created in ECMAScript */ + for (int i = 0; i < 3; i++) { const jerry_char_t source[] = TEST_STRING_LITERAL ("new ArrayBuffer(64)"); jerry_value_t arraybuffer = jerry_eval (source, sizeof (source) - 1, JERRY_PARSE_NO_OPTS); @@ -479,8 +482,23 @@ main (void) TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer)); TEST_ASSERT (!jerry_arraybuffer_has_buffer (arraybuffer)); - uint8_t buf[2] = { 2, 3 }; - TEST_ASSERT (jerry_arraybuffer_write (arraybuffer, 63, buf, 2) == 1); + if (i == 0) + { + uint8_t buf[2] = { 2, 3 }; + TEST_ASSERT (jerry_arraybuffer_write (arraybuffer, 63, buf, 2) == 1); + } + else if (i == 1) + { + uint8_t buf[2] = { 1, 1 }; + TEST_ASSERT (jerry_arraybuffer_read (arraybuffer, 63, buf, 2) == 1); + TEST_ASSERT (buf[0] == 0 && buf[1] == 1); + } + else + { + uint8_t *buffer_p = jerry_get_arraybuffer_pointer (arraybuffer); + TEST_ASSERT (buffer_p != NULL); + } + TEST_ASSERT (jerry_arraybuffer_has_buffer (arraybuffer)); jerry_release_value (arraybuffer);