1/* Copyright JS Foundation and other contributors, http://js.foundation 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecma-arraybuffer-object.h" 17#include "ecma-try-catch-macro.h" 18#include "ecma-typedarray-object.h" 19#include "ecma-objects.h" 20#include "ecma-builtins.h" 21#include "ecma-exceptions.h" 22#include "ecma-gc.h" 23#include "ecma-globals.h" 24#include "ecma-helpers.h" 25#include "jmem.h" 26 27#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) 28 29/** \addtogroup ecma ECMA 30 * @{ 31 * 32 * \addtogroup ecmaarraybufferobject ECMA ArrayBuffer object related routines 33 * @{ 34 */ 35 36/** 37 * Helper function: create arraybuffer object based on the array length 38 * 39 * The struct of arraybuffer object: 40 * ecma_object_t 41 * extend_part 42 * data buffer 43 * 44 * @return ecma_object_t * 45 */ 46ecma_object_t * 47ecma_arraybuffer_new_object (ecma_length_t length) /**< length of the arraybuffer */ 48{ 49 ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAYBUFFER_PROTOTYPE); 50 ecma_object_t *object_p = ecma_create_object (prototype_obj_p, 51 sizeof (ecma_extended_object_t) + length, 52 ECMA_OBJECT_TYPE_CLASS); 53 54 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 55 ext_object_p->u.class_prop.extra_info = ECMA_ARRAYBUFFER_INTERNAL_MEMORY; 56 ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_ARRAY_BUFFER_UL; 57 ext_object_p->u.class_prop.u.length = length; 58 59 lit_utf8_byte_t *buf = (lit_utf8_byte_t *) (ext_object_p + 1); 60 memset (buf, 0, length); 61 62 return object_p; 63} /* ecma_arraybuffer_new_object */ 64 65/** 66 * Helper function: create arraybuffer object with external buffer backing. 67 * 68 * The struct of external arraybuffer object: 69 * ecma_object_t 70 * extend_part 71 * arraybuffer external info part 72 * 73 * @return ecma_object_t *, pointer to the created ArrayBuffer object 74 */ 75ecma_object_t * 76ecma_arraybuffer_new_object_external (ecma_length_t length, /**< length of the buffer_p to use */ 77 void *buffer_p, /**< pointer for ArrayBuffer's buffer backing */ 78 ecma_object_native_free_callback_t free_cb) /**< buffer free callback */ 79{ 80 ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAYBUFFER_PROTOTYPE); 81 ecma_object_t *object_p = ecma_create_object (prototype_obj_p, 82 sizeof (ecma_arraybuffer_external_info), 83 ECMA_OBJECT_TYPE_CLASS); 84 85 ecma_arraybuffer_external_info *array_object_p = (ecma_arraybuffer_external_info *) object_p; 86 array_object_p->extended_object.u.class_prop.extra_info = ECMA_ARRAYBUFFER_EXTERNAL_MEMORY; 87 array_object_p->extended_object.u.class_prop.class_id = LIT_MAGIC_STRING_ARRAY_BUFFER_UL; 88 array_object_p->extended_object.u.class_prop.u.length = length; 89 90 array_object_p->buffer_p = buffer_p; 91 array_object_p->free_cb = free_cb; 92 93 return object_p; 94} /* ecma_arraybuffer_new_object_external */ 95 96/** 97 * ArrayBuffer object creation operation. 98 * 99 * See also: ES2015 24.1.1.1 100 * 101 * @return ecma value 102 * Returned value must be freed with ecma_free_value 103 */ 104ecma_value_t 105ecma_op_create_arraybuffer_object (const ecma_value_t *arguments_list_p, /**< list of arguments that 106 * are passed to String constructor */ 107 ecma_length_t arguments_list_len) /**< length of the arguments' list */ 108{ 109 JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); 110 111 ecma_number_t length_num = 0; 112 113 if (arguments_list_len > 0) 114 { 115 116 if (ecma_is_value_number (arguments_list_p[0])) 117 { 118 length_num = ecma_get_number_from_value (arguments_list_p[0]); 119 } 120 else 121 { 122 ecma_value_t to_number_value = ecma_op_to_number (arguments_list_p[0]); 123 124 if (ECMA_IS_VALUE_ERROR (to_number_value)) 125 { 126 return to_number_value; 127 } 128 129 length_num = ecma_get_number_from_value (to_number_value); 130 131 ecma_free_value (to_number_value); 132 } 133 134 if (ecma_number_is_nan (length_num)) 135 { 136 length_num = 0; 137 } 138 139 const uint32_t maximum_size_in_byte = UINT32_MAX - sizeof (ecma_extended_object_t) - JMEM_ALIGNMENT + 1; 140 141 if (length_num <= -1.0 || length_num > (ecma_number_t) maximum_size_in_byte + 0.5) 142 { 143 return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid ArrayBuffer length.")); 144 } 145 } 146 147 uint32_t length_uint32 = ecma_number_to_uint32 (length_num); 148 149 return ecma_make_object_value (ecma_arraybuffer_new_object (length_uint32)); 150} /* ecma_op_create_arraybuffer_object */ 151 152/** 153 * Helper function: check if the target is ArrayBuffer 154 * 155 * 156 * See also: ES2015 24.1.1.4 157 * 158 * @return true - if value is an ArrayBuffer object 159 * false - otherwise 160 */ 161bool 162ecma_is_arraybuffer (ecma_value_t target) /**< the target value */ 163{ 164 return (ecma_is_value_object (target) 165 && ecma_object_class_is (ecma_get_object_from_value (target), 166 LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); 167} /* ecma_is_arraybuffer */ 168 169/** 170 * Helper function: return the length of the buffer inside the arraybuffer object 171 * 172 * @return ecma_length_t, the length of the arraybuffer 173 */ 174ecma_length_t JERRY_ATTR_PURE 175ecma_arraybuffer_get_length (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ 176{ 177 JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); 178 179 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 180 return ext_object_p->u.class_prop.u.length; 181} /* ecma_arraybuffer_get_length */ 182 183/** 184 * Helper function: return the pointer to the data buffer inside the arraybuffer object 185 * 186 * @return pointer to the data buffer 187 */ 188inline lit_utf8_byte_t * JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE 189ecma_arraybuffer_get_buffer (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ 190{ 191 JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); 192 193 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 194 195 if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p)) 196 { 197 ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p; 198 return (lit_utf8_byte_t *) array_p->buffer_p; 199 } 200 else 201 { 202 return (lit_utf8_byte_t *) (ext_object_p + 1); 203 } 204} /* ecma_arraybuffer_get_buffer */ 205 206/** 207 * Helper function: check if the target ArrayBuffer is detached 208 * 209 * @return true - if value is an detached ArrayBuffer object 210 * false - otherwise 211 */ 212inline bool JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE 213ecma_arraybuffer_is_detached (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ 214{ 215 JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); 216 217 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 218 219 if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p)) 220 { 221 ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p; 222 /* in case the arraybuffer has been detached */ 223 return array_p->buffer_p == NULL; 224 } 225 226 return false; 227} /* ecma_arraybuffer_is_detached */ 228 229/** 230 * Helper function: check if the target ArrayBuffer is detachable 231 * 232 * @return true - if value is an detachable ArrayBuffer object 233 * false - otherwise 234 */ 235inline bool JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE 236ecma_arraybuffer_is_detachable (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ 237{ 238 JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); 239 240 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 241 242 if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p)) 243 { 244 ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p; 245 /* in case the arraybuffer has been detached */ 246 return array_p->buffer_p != NULL; 247 } 248 249 return false; 250} /* ecma_arraybuffer_is_detachable */ 251 252/** 253 * ArrayBuffer object detaching operation 254 * 255 * See also: ES2015 24.1.1.3 256 * 257 * @return true - if detach op succeeded 258 * false - otherwise 259 */ 260inline bool JERRY_ATTR_ALWAYS_INLINE 261ecma_arraybuffer_detach (ecma_object_t *object_p) /**< pointer to the ArrayBuffer object */ 262{ 263 JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); 264 265 if (!ecma_arraybuffer_is_detachable (object_p)) 266 { 267 return false; 268 } 269 270 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; 271 272 ecma_arraybuffer_external_info *array_object_p = (ecma_arraybuffer_external_info *) ext_object_p; 273 array_object_p->buffer_p = NULL; 274 array_object_p->extended_object.u.class_prop.u.length = 0; 275 276 return true; 277} /* ecma_arraybuffer_detach */ 278 279/** 280 * @} 281 * @} 282 */ 283#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ 284