1425bb815Sopenharmony_ci/* Copyright JS Foundation and other contributors, http://js.foundation 2425bb815Sopenharmony_ci * 3425bb815Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4425bb815Sopenharmony_ci * you may not use this file except in compliance with the License. 5425bb815Sopenharmony_ci * You may obtain a copy of the License at 6425bb815Sopenharmony_ci * 7425bb815Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8425bb815Sopenharmony_ci * 9425bb815Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10425bb815Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS 11425bb815Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12425bb815Sopenharmony_ci * See the License for the specific language governing permissions and 13425bb815Sopenharmony_ci * limitations under the License. 14425bb815Sopenharmony_ci */ 15425bb815Sopenharmony_ci 16425bb815Sopenharmony_ci#include "ecma-arraybuffer-object.h" 17425bb815Sopenharmony_ci#include "ecma-try-catch-macro.h" 18425bb815Sopenharmony_ci#include "ecma-typedarray-object.h" 19425bb815Sopenharmony_ci#include "ecma-objects.h" 20425bb815Sopenharmony_ci#include "ecma-builtins.h" 21425bb815Sopenharmony_ci#include "ecma-exceptions.h" 22425bb815Sopenharmony_ci#include "ecma-gc.h" 23425bb815Sopenharmony_ci#include "ecma-globals.h" 24425bb815Sopenharmony_ci#include "ecma-helpers.h" 25425bb815Sopenharmony_ci#include "jmem.h" 26425bb815Sopenharmony_ci 27425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) 28425bb815Sopenharmony_ci 29425bb815Sopenharmony_ci/** \addtogroup ecma ECMA 30425bb815Sopenharmony_ci * @{ 31425bb815Sopenharmony_ci * 32425bb815Sopenharmony_ci * \addtogroup ecmaarraybufferobject ECMA ArrayBuffer object related routines 33425bb815Sopenharmony_ci * @{ 34425bb815Sopenharmony_ci */ 35425bb815Sopenharmony_ci 36425bb815Sopenharmony_ci/** 37425bb815Sopenharmony_ci * Helper function: create arraybuffer object based on the array length 38425bb815Sopenharmony_ci * 39425bb815Sopenharmony_ci * The struct of arraybuffer object: 40425bb815Sopenharmony_ci * ecma_object_t 41425bb815Sopenharmony_ci * extend_part 42425bb815Sopenharmony_ci * data buffer 43425bb815Sopenharmony_ci * 44425bb815Sopenharmony_ci * @return ecma_object_t * 45425bb815Sopenharmony_ci */ 46425bb815Sopenharmony_ciecma_object_t * 47425bb815Sopenharmony_ciecma_arraybuffer_new_object (ecma_length_t length) /**< length of the arraybuffer */ 48425bb815Sopenharmony_ci{ 49425bb815Sopenharmony_ci ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAYBUFFER_PROTOTYPE); 50425bb815Sopenharmony_ci ecma_object_t *object_p = ecma_create_object (prototype_obj_p, 51425bb815Sopenharmony_ci sizeof (ecma_extended_object_t) + length, 52425bb815Sopenharmony_ci ECMA_OBJECT_TYPE_CLASS); 53425bb815Sopenharmony_ci 54425bb815Sopenharmony_ci ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 55425bb815Sopenharmony_ci ext_object_p->u.class_prop.extra_info = ECMA_ARRAYBUFFER_INTERNAL_MEMORY; 56425bb815Sopenharmony_ci ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_ARRAY_BUFFER_UL; 57425bb815Sopenharmony_ci ext_object_p->u.class_prop.u.length = length; 58425bb815Sopenharmony_ci 59425bb815Sopenharmony_ci lit_utf8_byte_t *buf = (lit_utf8_byte_t *) (ext_object_p + 1); 60425bb815Sopenharmony_ci memset (buf, 0, length); 61425bb815Sopenharmony_ci 62425bb815Sopenharmony_ci return object_p; 63425bb815Sopenharmony_ci} /* ecma_arraybuffer_new_object */ 64425bb815Sopenharmony_ci 65425bb815Sopenharmony_ci/** 66425bb815Sopenharmony_ci * Helper function: create arraybuffer object with external buffer backing. 67425bb815Sopenharmony_ci * 68425bb815Sopenharmony_ci * The struct of external arraybuffer object: 69425bb815Sopenharmony_ci * ecma_object_t 70425bb815Sopenharmony_ci * extend_part 71425bb815Sopenharmony_ci * arraybuffer external info part 72425bb815Sopenharmony_ci * 73425bb815Sopenharmony_ci * @return ecma_object_t *, pointer to the created ArrayBuffer object 74425bb815Sopenharmony_ci */ 75425bb815Sopenharmony_ciecma_object_t * 76425bb815Sopenharmony_ciecma_arraybuffer_new_object_external (ecma_length_t length, /**< length of the buffer_p to use */ 77425bb815Sopenharmony_ci void *buffer_p, /**< pointer for ArrayBuffer's buffer backing */ 78425bb815Sopenharmony_ci ecma_object_native_free_callback_t free_cb) /**< buffer free callback */ 79425bb815Sopenharmony_ci{ 80425bb815Sopenharmony_ci ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAYBUFFER_PROTOTYPE); 81425bb815Sopenharmony_ci ecma_object_t *object_p = ecma_create_object (prototype_obj_p, 82425bb815Sopenharmony_ci sizeof (ecma_arraybuffer_external_info), 83425bb815Sopenharmony_ci ECMA_OBJECT_TYPE_CLASS); 84425bb815Sopenharmony_ci 85425bb815Sopenharmony_ci ecma_arraybuffer_external_info *array_object_p = (ecma_arraybuffer_external_info *) object_p; 86425bb815Sopenharmony_ci array_object_p->extended_object.u.class_prop.extra_info = ECMA_ARRAYBUFFER_EXTERNAL_MEMORY; 87425bb815Sopenharmony_ci array_object_p->extended_object.u.class_prop.class_id = LIT_MAGIC_STRING_ARRAY_BUFFER_UL; 88425bb815Sopenharmony_ci array_object_p->extended_object.u.class_prop.u.length = length; 89425bb815Sopenharmony_ci 90425bb815Sopenharmony_ci array_object_p->buffer_p = buffer_p; 91425bb815Sopenharmony_ci array_object_p->free_cb = free_cb; 92425bb815Sopenharmony_ci 93425bb815Sopenharmony_ci return object_p; 94425bb815Sopenharmony_ci} /* ecma_arraybuffer_new_object_external */ 95425bb815Sopenharmony_ci 96425bb815Sopenharmony_ci/** 97425bb815Sopenharmony_ci * ArrayBuffer object creation operation. 98425bb815Sopenharmony_ci * 99425bb815Sopenharmony_ci * See also: ES2015 24.1.1.1 100425bb815Sopenharmony_ci * 101425bb815Sopenharmony_ci * @return ecma value 102425bb815Sopenharmony_ci * Returned value must be freed with ecma_free_value 103425bb815Sopenharmony_ci */ 104425bb815Sopenharmony_ciecma_value_t 105425bb815Sopenharmony_ciecma_op_create_arraybuffer_object (const ecma_value_t *arguments_list_p, /**< list of arguments that 106425bb815Sopenharmony_ci * are passed to String constructor */ 107425bb815Sopenharmony_ci ecma_length_t arguments_list_len) /**< length of the arguments' list */ 108425bb815Sopenharmony_ci{ 109425bb815Sopenharmony_ci JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); 110425bb815Sopenharmony_ci 111425bb815Sopenharmony_ci ecma_number_t length_num = 0; 112425bb815Sopenharmony_ci 113425bb815Sopenharmony_ci if (arguments_list_len > 0) 114425bb815Sopenharmony_ci { 115425bb815Sopenharmony_ci 116425bb815Sopenharmony_ci if (ecma_is_value_number (arguments_list_p[0])) 117425bb815Sopenharmony_ci { 118425bb815Sopenharmony_ci length_num = ecma_get_number_from_value (arguments_list_p[0]); 119425bb815Sopenharmony_ci } 120425bb815Sopenharmony_ci else 121425bb815Sopenharmony_ci { 122425bb815Sopenharmony_ci ecma_value_t to_number_value = ecma_op_to_number (arguments_list_p[0]); 123425bb815Sopenharmony_ci 124425bb815Sopenharmony_ci if (ECMA_IS_VALUE_ERROR (to_number_value)) 125425bb815Sopenharmony_ci { 126425bb815Sopenharmony_ci return to_number_value; 127425bb815Sopenharmony_ci } 128425bb815Sopenharmony_ci 129425bb815Sopenharmony_ci length_num = ecma_get_number_from_value (to_number_value); 130425bb815Sopenharmony_ci 131425bb815Sopenharmony_ci ecma_free_value (to_number_value); 132425bb815Sopenharmony_ci } 133425bb815Sopenharmony_ci 134425bb815Sopenharmony_ci if (ecma_number_is_nan (length_num)) 135425bb815Sopenharmony_ci { 136425bb815Sopenharmony_ci length_num = 0; 137425bb815Sopenharmony_ci } 138425bb815Sopenharmony_ci 139425bb815Sopenharmony_ci const uint32_t maximum_size_in_byte = UINT32_MAX - sizeof (ecma_extended_object_t) - JMEM_ALIGNMENT + 1; 140425bb815Sopenharmony_ci 141425bb815Sopenharmony_ci if (length_num <= -1.0 || length_num > (ecma_number_t) maximum_size_in_byte + 0.5) 142425bb815Sopenharmony_ci { 143425bb815Sopenharmony_ci return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid ArrayBuffer length.")); 144425bb815Sopenharmony_ci } 145425bb815Sopenharmony_ci } 146425bb815Sopenharmony_ci 147425bb815Sopenharmony_ci uint32_t length_uint32 = ecma_number_to_uint32 (length_num); 148425bb815Sopenharmony_ci 149425bb815Sopenharmony_ci return ecma_make_object_value (ecma_arraybuffer_new_object (length_uint32)); 150425bb815Sopenharmony_ci} /* ecma_op_create_arraybuffer_object */ 151425bb815Sopenharmony_ci 152425bb815Sopenharmony_ci/** 153425bb815Sopenharmony_ci * Helper function: check if the target is ArrayBuffer 154425bb815Sopenharmony_ci * 155425bb815Sopenharmony_ci * 156425bb815Sopenharmony_ci * See also: ES2015 24.1.1.4 157425bb815Sopenharmony_ci * 158425bb815Sopenharmony_ci * @return true - if value is an ArrayBuffer object 159425bb815Sopenharmony_ci * false - otherwise 160425bb815Sopenharmony_ci */ 161425bb815Sopenharmony_cibool 162425bb815Sopenharmony_ciecma_is_arraybuffer (ecma_value_t target) /**< the target value */ 163425bb815Sopenharmony_ci{ 164425bb815Sopenharmony_ci return (ecma_is_value_object (target) 165425bb815Sopenharmony_ci && ecma_object_class_is (ecma_get_object_from_value (target), 166425bb815Sopenharmony_ci LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); 167425bb815Sopenharmony_ci} /* ecma_is_arraybuffer */ 168425bb815Sopenharmony_ci 169425bb815Sopenharmony_ci/** 170425bb815Sopenharmony_ci * Helper function: return the length of the buffer inside the arraybuffer object 171425bb815Sopenharmony_ci * 172425bb815Sopenharmony_ci * @return ecma_length_t, the length of the arraybuffer 173425bb815Sopenharmony_ci */ 174425bb815Sopenharmony_ciecma_length_t JERRY_ATTR_PURE 175425bb815Sopenharmony_ciecma_arraybuffer_get_length (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ 176425bb815Sopenharmony_ci{ 177425bb815Sopenharmony_ci JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); 178425bb815Sopenharmony_ci 179425bb815Sopenharmony_ci ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 180425bb815Sopenharmony_ci return ext_object_p->u.class_prop.u.length; 181425bb815Sopenharmony_ci} /* ecma_arraybuffer_get_length */ 182425bb815Sopenharmony_ci 183425bb815Sopenharmony_ci/** 184425bb815Sopenharmony_ci * Helper function: return the pointer to the data buffer inside the arraybuffer object 185425bb815Sopenharmony_ci * 186425bb815Sopenharmony_ci * @return pointer to the data buffer 187425bb815Sopenharmony_ci */ 188425bb815Sopenharmony_ciinline lit_utf8_byte_t * JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE 189425bb815Sopenharmony_ciecma_arraybuffer_get_buffer (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ 190425bb815Sopenharmony_ci{ 191425bb815Sopenharmony_ci JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); 192425bb815Sopenharmony_ci 193425bb815Sopenharmony_ci ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 194425bb815Sopenharmony_ci 195425bb815Sopenharmony_ci if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p)) 196425bb815Sopenharmony_ci { 197425bb815Sopenharmony_ci ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p; 198425bb815Sopenharmony_ci return (lit_utf8_byte_t *) array_p->buffer_p; 199425bb815Sopenharmony_ci } 200425bb815Sopenharmony_ci else 201425bb815Sopenharmony_ci { 202425bb815Sopenharmony_ci return (lit_utf8_byte_t *) (ext_object_p + 1); 203425bb815Sopenharmony_ci } 204425bb815Sopenharmony_ci} /* ecma_arraybuffer_get_buffer */ 205425bb815Sopenharmony_ci 206425bb815Sopenharmony_ci/** 207425bb815Sopenharmony_ci * Helper function: check if the target ArrayBuffer is detached 208425bb815Sopenharmony_ci * 209425bb815Sopenharmony_ci * @return true - if value is an detached ArrayBuffer object 210425bb815Sopenharmony_ci * false - otherwise 211425bb815Sopenharmony_ci */ 212425bb815Sopenharmony_ciinline bool JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE 213425bb815Sopenharmony_ciecma_arraybuffer_is_detached (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ 214425bb815Sopenharmony_ci{ 215425bb815Sopenharmony_ci JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); 216425bb815Sopenharmony_ci 217425bb815Sopenharmony_ci ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 218425bb815Sopenharmony_ci 219425bb815Sopenharmony_ci if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p)) 220425bb815Sopenharmony_ci { 221425bb815Sopenharmony_ci ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p; 222425bb815Sopenharmony_ci /* in case the arraybuffer has been detached */ 223425bb815Sopenharmony_ci return array_p->buffer_p == NULL; 224425bb815Sopenharmony_ci } 225425bb815Sopenharmony_ci 226425bb815Sopenharmony_ci return false; 227425bb815Sopenharmony_ci} /* ecma_arraybuffer_is_detached */ 228425bb815Sopenharmony_ci 229425bb815Sopenharmony_ci/** 230425bb815Sopenharmony_ci * Helper function: check if the target ArrayBuffer is detachable 231425bb815Sopenharmony_ci * 232425bb815Sopenharmony_ci * @return true - if value is an detachable ArrayBuffer object 233425bb815Sopenharmony_ci * false - otherwise 234425bb815Sopenharmony_ci */ 235425bb815Sopenharmony_ciinline bool JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE 236425bb815Sopenharmony_ciecma_arraybuffer_is_detachable (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ 237425bb815Sopenharmony_ci{ 238425bb815Sopenharmony_ci JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); 239425bb815Sopenharmony_ci 240425bb815Sopenharmony_ci ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 241425bb815Sopenharmony_ci 242425bb815Sopenharmony_ci if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p)) 243425bb815Sopenharmony_ci { 244425bb815Sopenharmony_ci ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p; 245425bb815Sopenharmony_ci /* in case the arraybuffer has been detached */ 246425bb815Sopenharmony_ci return array_p->buffer_p != NULL; 247425bb815Sopenharmony_ci } 248425bb815Sopenharmony_ci 249425bb815Sopenharmony_ci return false; 250425bb815Sopenharmony_ci} /* ecma_arraybuffer_is_detachable */ 251425bb815Sopenharmony_ci 252425bb815Sopenharmony_ci/** 253425bb815Sopenharmony_ci * ArrayBuffer object detaching operation 254425bb815Sopenharmony_ci * 255425bb815Sopenharmony_ci * See also: ES2015 24.1.1.3 256425bb815Sopenharmony_ci * 257425bb815Sopenharmony_ci * @return true - if detach op succeeded 258425bb815Sopenharmony_ci * false - otherwise 259425bb815Sopenharmony_ci */ 260425bb815Sopenharmony_ciinline bool JERRY_ATTR_ALWAYS_INLINE 261425bb815Sopenharmony_ciecma_arraybuffer_detach (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ 262425bb815Sopenharmony_ci{ 263425bb815Sopenharmony_ci JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); 264425bb815Sopenharmony_ci 265425bb815Sopenharmony_ci if (!ecma_arraybuffer_is_detachable (object_p)) 266425bb815Sopenharmony_ci { 267425bb815Sopenharmony_ci return false; 268425bb815Sopenharmony_ci } 269425bb815Sopenharmony_ci 270425bb815Sopenharmony_ci ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 271425bb815Sopenharmony_ci 272425bb815Sopenharmony_ci ecma_arraybuffer_external_info *array_object_p = (ecma_arraybuffer_external_info *) ext_object_p; 273425bb815Sopenharmony_ci array_object_p->buffer_p = NULL; 274425bb815Sopenharmony_ci array_object_p->extended_object.u.class_prop.u.length = 0; 275425bb815Sopenharmony_ci 276425bb815Sopenharmony_ci return true; 277425bb815Sopenharmony_ci} /* ecma_arraybuffer_detach */ 278425bb815Sopenharmony_ci 279425bb815Sopenharmony_ci/** 280425bb815Sopenharmony_ci * @} 281425bb815Sopenharmony_ci * @} 282425bb815Sopenharmony_ci */ 283425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ 284