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-builtins.h" 18#include "ecma-exceptions.h" 19#include "ecma-gc.h" 20#include "ecma-helpers.h" 21#include "ecma-dataview-object.h" 22#include "ecma-typedarray-object.h" 23#include "ecma-objects.h" 24#if defined(JERRY_FOR_IAR_CONFIG) 25#include "jerryscript-core.h" 26#endif 27 28#if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) 29 30/** \addtogroup ecma ECMA 31 * @{ 32 * 33 * \addtogroup ecmadataviewobject ECMA builtin DataView helper functions 34 * @{ 35 */ 36 37/** 38 * Handle calling [[Construct]] of built-in DataView like objects 39 * 40 * See also: 41 * ECMA-262 v6, 24.2.2.1 42 * 43 * @return created DataView object as an ecma-value - if success 44 * raised error - otherwise 45 */ 46ecma_value_t 47ecma_op_dataview_create (const ecma_value_t *arguments_list_p, /**< arguments list */ 48 ecma_length_t arguments_list_len) /**< number of arguments */ 49{ 50 JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); 51 52 ecma_value_t buffer = arguments_list_len > 0 ? arguments_list_p[0] : ECMA_VALUE_UNDEFINED; 53 54 /* 2. */ 55 if (!ecma_is_value_object (buffer)) 56 { 57 return ecma_raise_type_error (ECMA_ERR_MSG ("Argument buffer is not an object.")); 58 } 59 60 ecma_object_t *buffer_p = ecma_get_object_from_value (buffer); 61 62 /* 3. */ 63 if (!ecma_object_class_is (buffer_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)) 64 { 65 return ecma_raise_type_error (ECMA_ERR_MSG ("Argument buffer is not an arraybuffer.")); 66 } 67 68 /* 4 - 6. */ 69 uint32_t offset = 0; 70 71 if (arguments_list_len > 1) 72 { 73 ecma_number_t number_offset, offset_num; 74 if (ECMA_IS_VALUE_ERROR (ecma_get_number (arguments_list_p[1], &number_offset))) 75 { 76 return ECMA_VALUE_ERROR; 77 } 78 if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (arguments_list_p[1], &offset_num))) 79 { 80 return ECMA_VALUE_ERROR; 81 } 82 83 /* 7. */ 84 if (number_offset != offset_num || offset_num < 0) 85 { 86 return ecma_raise_range_error (ECMA_ERR_MSG ("Start offset is outside the bounds of the buffer.")); 87 } 88 89 offset = (uint32_t) offset_num; 90 } 91 92 /* 8. */ 93 if (ecma_arraybuffer_is_detached (buffer_p)) 94 { 95 return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); 96 } 97 98 /* 9. */ 99 ecma_length_t buffer_byte_length = ecma_arraybuffer_get_length (buffer_p); 100 101 /* 10. */ 102 if ((ecma_length_t) offset > buffer_byte_length) 103 { 104 return ecma_raise_range_error (ECMA_ERR_MSG ("Start offset is outside the bounds of the buffer.")); 105 } 106 107 /* 11 - 12. */ 108 uint32_t viewByteLength; 109 if (arguments_list_len > 2) 110 { 111 /* 12.a */ 112 ecma_value_t byte_length_value = ecma_op_to_length (arguments_list_p[2], &viewByteLength); 113 114 /* 12.b */ 115 if (ECMA_IS_VALUE_ERROR (byte_length_value)) 116 { 117 return byte_length_value; 118 } 119 120 /* 12.c */ 121 if ((ecma_number_t) offset + viewByteLength > buffer_byte_length) 122 { 123 return ecma_raise_range_error (ECMA_ERR_MSG ("Start offset is outside the bounds of the buffer.")); 124 } 125 } 126 else 127 { 128 /* 11.a */ 129 viewByteLength = (uint32_t) (buffer_byte_length - (ecma_length_t) offset); 130 } 131 132 /* 13. */ 133 ecma_object_t *object_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_DATAVIEW_PROTOTYPE), 134 sizeof (ecma_dataview_object_t), 135 ECMA_OBJECT_TYPE_CLASS); 136 137 ecma_dataview_object_t *dataview_obj_p = (ecma_dataview_object_t *) object_p; 138 dataview_obj_p->header.u.class_prop.class_id = LIT_MAGIC_STRING_DATAVIEW_UL; 139 dataview_obj_p->header.u.class_prop.u.length = viewByteLength; 140 dataview_obj_p->buffer_p = buffer_p; 141 dataview_obj_p->byte_offset = (uint32_t) offset; 142 143 return ecma_make_object_value (object_p); 144} /* ecma_op_dataview_create */ 145 146/** 147 * Get the DataView object pointer 148 * 149 * Note: 150 * If the function returns with NULL, the error object has 151 * already set, and the caller must return with ECMA_VALUE_ERROR 152 * 153 * @return pointer to the dataView if this_arg is a valid dataView object 154 * NULL otherwise 155 */ 156ecma_dataview_object_t * 157ecma_op_dataview_get_object (ecma_value_t this_arg) /**< this argument */ 158{ 159 if (ecma_is_value_object (this_arg)) 160 { 161 ecma_dataview_object_t *dataview_object_p = (ecma_dataview_object_t *) ecma_get_object_from_value (this_arg); 162 163 if (ecma_get_object_type (&dataview_object_p->header.object) == ECMA_OBJECT_TYPE_CLASS 164 && dataview_object_p->header.u.class_prop.class_id == LIT_MAGIC_STRING_DATAVIEW_UL) 165 { 166 return dataview_object_p; 167 } 168 } 169 170 ecma_raise_type_error (ECMA_ERR_MSG ("Expected a DataView object.")); 171 return NULL; 172} /* ecma_op_dataview_get_object */ 173 174/** 175 * Helper union to specify the system's endiannes 176 */ 177typedef union 178{ 179 uint32_t number; /**< for write numeric data */ 180 char data[sizeof (uint32_t)]; /**< for read numeric data */ 181} ecma_dataview_endiannes_check_t; 182 183/** 184 * Helper function to check the current system endiannes 185 * 186 * @return true - if the current system has little endian byteorder 187 * false - otherwise 188 */ 189static bool 190ecma_dataview_check_little_endian (void) 191{ 192 ecma_dataview_endiannes_check_t checker; 193 checker.number = 0x01; 194 195 return checker.data[0] == 0x01; 196} /* ecma_dataview_check_little_endian */ 197 198/** 199 * Helper function for swap bytes if the system's endiannes 200 * does not match with the requested endiannes. 201 */ 202static void 203ecma_dataview_swap_order (bool system_is_little_endian, /**< true - if the system has little endian byteorder 204 * false - otherwise */ 205 bool is_little_endian, /**< true - if little endian byteorder is requested 206 * false - otherwise */ 207 uint32_t element_size, /**< element size byte according to the Table 49.*/ 208 lit_utf8_byte_t *block_p) /**< data block */ 209{ 210 if (system_is_little_endian ^ is_little_endian) 211 { 212 for (uint32_t i = 0; i < element_size / 2; i++) 213 { 214 lit_utf8_byte_t tmp = block_p[i]; 215 block_p[i] = block_p[element_size - i - 1]; 216 block_p[element_size - i - 1] = tmp; 217 } 218 } 219} /* ecma_dataview_swap_order */ 220 221/** 222 * GetViewValue and SetViewValue abstact operation 223 * 224 * See also: 225 * ECMA-262 v6, 24.2.1.1 226 * ECMA-262 v6, 24.2.1.2 227 * 228 * @return ecma value 229 */ 230ecma_value_t 231ecma_op_dataview_get_set_view_value (ecma_value_t view, /**< the operation's 'view' argument */ 232 ecma_value_t request_index, /**< the operation's 'requestIndex' argument */ 233 ecma_value_t is_little_endian_value, /**< the operation's 234 * 'isLittleEndian' argument */ 235 ecma_value_t value_to_set, /**< the operation's 'value' argument */ 236 ecma_typedarray_type_t id) /**< the operation's 'type' argument */ 237{ 238 /* 1 - 2. */ 239 ecma_dataview_object_t *view_p = ecma_op_dataview_get_object (view); 240#if defined(JERRY_FOR_IAR_CONFIG) 241 lit_utf8_byte_t* swap_block_p; 242 ecma_value_t ret; 243#endif 244 245 if (JERRY_UNLIKELY (view_p == NULL)) 246 { 247 return ECMA_VALUE_ERROR; 248 } 249 250 /* 3 - 5. */ 251 ecma_number_t number_index; 252 ecma_value_t number_index_value = ecma_op_to_integer (request_index, &number_index); 253 254 if (ECMA_IS_VALUE_ERROR (number_index_value)) 255 { 256 return number_index_value; 257 } 258 259 int32_t get_index = ecma_number_to_int32 (number_index); 260 261 /* 6. */ 262 if (number_index != get_index || get_index < 0) 263 { 264 return ecma_raise_range_error (ECMA_ERR_MSG ("Start offset is outside the bounds of the buffer.")); 265 } 266 267 /* 7. */ 268 bool is_little_endian = ecma_op_to_boolean (is_little_endian_value); 269 270 /* 8. TODO: Throw TypeError, when Detached ArrayBuffer will be supported. */ 271 272 /* 9. */ 273 ecma_object_t *buffer_p = view_p->buffer_p; 274 JERRY_ASSERT (ecma_object_class_is (buffer_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); 275 if (ecma_arraybuffer_is_detached (buffer_p)) 276 { 277 return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached.")); 278 } 279 280 /* 10. */ 281 uint32_t view_offset = view_p->byte_offset; 282 283 /* 11. */ 284 uint32_t view_size = view_p->header.u.class_prop.u.length; 285 286 /* 12. */ 287 uint8_t element_size = (uint8_t) (1 << (ecma_typedarray_helper_get_shift_size (id))); 288 289 /* 13. */ 290 if ((uint32_t) get_index + element_size > view_size) 291 { 292 return ecma_raise_range_error (ECMA_ERR_MSG ("Start offset is outside the bounds of the buffer.")); 293 } 294 295 /* 14. */ 296 uint32_t buffer_index = (uint32_t) get_index + view_offset; 297 lit_utf8_byte_t *block_p = ecma_arraybuffer_get_buffer (buffer_p) + buffer_index; 298 299 bool system_is_little_endian = ecma_dataview_check_little_endian (); 300 301 if (ecma_is_value_empty (value_to_set)) 302 { 303#if defined(JERRY_FOR_IAR_CONFIG) 304 swap_block_p = jerry_vla_malloc (sizeof(lit_utf8_byte_t) * element_size); 305 if (!swap_block_p) 306 { 307 return ecma_raise_common_error (ECMA_ERR_MSG ("malloc swap_block_p failed.")); 308 } 309#else 310 JERRY_VLA (lit_utf8_byte_t, swap_block_p, element_size); 311#endif 312 memcpy (swap_block_p, block_p, element_size * sizeof (lit_utf8_byte_t)); 313 ecma_dataview_swap_order (system_is_little_endian, is_little_endian, element_size, swap_block_p); 314#if defined(JERRY_FOR_IAR_CONFIG) 315 ret = ecma_make_number_value (ecma_get_typedarray_element (swap_block_p, id)); 316 jerry_vla_free (swap_block_p); 317 return ret; 318#else 319 return ecma_make_number_value (ecma_get_typedarray_element (swap_block_p, id)); 320#endif 321 } 322 323 if (ecma_is_value_number (value_to_set)) 324 { 325 ecma_set_typedarray_element (block_p, ecma_get_number_from_value (value_to_set), id); 326 ecma_dataview_swap_order (system_is_little_endian, is_little_endian, element_size, block_p); 327 } 328 329 return ECMA_VALUE_UNDEFINED; 330} /* ecma_op_dataview_get_set_view_value */ 331 332/** 333 * Check if the value is dataview 334 * 335 * @return true - if value is a DataView object 336 * false - otherwise 337 */ 338bool 339ecma_is_dataview (ecma_value_t value) /**< the target need to be checked */ 340{ 341 if (!ecma_is_value_object (value)) 342 { 343 return false; 344 } 345 346 ecma_dataview_object_t *dataview_object_p = (ecma_dataview_object_t *) ecma_get_object_from_value (value); 347 348 return (ecma_get_object_type (&dataview_object_p->header.object) == ECMA_OBJECT_TYPE_CLASS 349 && dataview_object_p->header.u.class_prop.class_id == LIT_MAGIC_STRING_DATAVIEW_UL); 350} /* ecma_is_dataview */ 351 352/** 353 * @} 354 * @} 355 */ 356 357#endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW */ 358