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 <math.h>
17
18 #include "ecma-iterator-object.h"
19 #include "ecma-typedarray-object.h"
20 #include "ecma-arraybuffer-object.h"
21 #include "ecma-function-object.h"
22 #include "ecma-builtin-helpers.h"
23 #include "ecma-try-catch-macro.h"
24 #include "ecma-objects.h"
25 #include "ecma-builtins.h"
26 #include "ecma-exceptions.h"
27 #include "ecma-gc.h"
28 #include "ecma-globals.h"
29 #include "ecma-helpers.h"
30 #include "jcontext.h"
31
32 #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY)
33
34 /** \addtogroup ecma ECMA
35 * @{
36 *
37 * \addtogroup ecmatypedarrayobject ECMA TypedArray object related routines
38 * @{
39 */
40
41 /**
42 * Read an int8_t value from the given arraybuffer
43 */
44 static ecma_number_t
ecma_typedarray_get_int8_element(lit_utf8_byte_t * src)45 ecma_typedarray_get_int8_element (lit_utf8_byte_t *src) /**< the location in the internal arraybuffer */
46 {
47 int8_t num = (int8_t) *src;
48 return (ecma_number_t) num;
49 } /* ecma_typedarray_get_int8_element */
50
51 /**
52 * Read an uint8_t value from the given arraybuffer
53 */
54 static ecma_number_t
ecma_typedarray_get_uint8_element(lit_utf8_byte_t * src)55 ecma_typedarray_get_uint8_element (lit_utf8_byte_t *src) /**< the location in the internal arraybuffer */
56 {
57 uint8_t num = (uint8_t) *src;
58 return (ecma_number_t) num;
59 } /* ecma_typedarray_get_uint8_element */
60
61 /**
62 * Read an int16_t value from the given arraybuffer
63 */
64 static ecma_number_t
ecma_typedarray_get_int16_element(lit_utf8_byte_t * src)65 ecma_typedarray_get_int16_element (lit_utf8_byte_t *src) /**< the location in the internal arraybuffer */
66 {
67 int16_t num;
68 memcpy (&num, src, sizeof (int16_t));
69 return (ecma_number_t) num;
70 } /* ecma_typedarray_get_int16_element */
71
72 /**
73 * Read an uint16_t value from the given arraybuffer
74 */
75 static ecma_number_t
ecma_typedarray_get_uint16_element(lit_utf8_byte_t * src)76 ecma_typedarray_get_uint16_element (lit_utf8_byte_t *src) /**< the location in the internal arraybuffer */
77 {
78 uint16_t num;
79 memcpy (&num, src, sizeof (uint16_t));
80 return (ecma_number_t) num;
81 } /* ecma_typedarray_get_uint16_element */
82
83 /**
84 * Read an int32_t value from the given arraybuffer
85 */
86 static ecma_number_t
ecma_typedarray_get_int32_element(lit_utf8_byte_t * src)87 ecma_typedarray_get_int32_element (lit_utf8_byte_t *src) /**< the location in the internal arraybuffer */
88 {
89 int32_t num;
90 memcpy (&num, src, sizeof (int32_t));
91 return (ecma_number_t) num;
92 } /* ecma_typedarray_get_int32_element */
93
94 /**
95 * Read an uint32_t value from the given arraybuffer
96 */
97 static ecma_number_t
ecma_typedarray_get_uint32_element(lit_utf8_byte_t * src)98 ecma_typedarray_get_uint32_element (lit_utf8_byte_t *src) /**< the location in the internal arraybuffer */
99 {
100 uint32_t num;
101 memcpy (&num, src, sizeof (uint32_t));
102 return (ecma_number_t) num;
103 } /* ecma_typedarray_get_uint32_element */
104
105 /**
106 * Read a float value from the given arraybuffer
107 */
108 static ecma_number_t
ecma_typedarray_get_float_element(lit_utf8_byte_t * src)109 ecma_typedarray_get_float_element (lit_utf8_byte_t *src) /**< the location in the internal arraybuffer */
110 {
111 float num;
112 memcpy (&num, src, sizeof (float));
113 return (ecma_number_t) num;
114 } /* ecma_typedarray_get_float_element */
115
116 /**
117 * Read a double value from the given arraybuffer
118 */
119 static ecma_number_t
ecma_typedarray_get_double_element(lit_utf8_byte_t * src)120 ecma_typedarray_get_double_element (lit_utf8_byte_t *src) /**< the location in the internal arraybuffer */
121 {
122 double num;
123 memcpy (&num, src, sizeof (double));
124 return (ecma_number_t) num;
125 } /* ecma_typedarray_get_double_element */
126
127 /**
128 * Normalize the given ecma_number_t to an uint32_t value
129 */
130 static uint32_t
ecma_typedarray_setter_number_to_uint32(ecma_number_t value)131 ecma_typedarray_setter_number_to_uint32 (ecma_number_t value) /**< the number value to normalize */
132 {
133 uint32_t uint32_value = 0;
134
135 if (!ecma_number_is_nan (value) && !ecma_number_is_infinity (value))
136 {
137 bool is_negative = false;
138
139 if (value < 0)
140 {
141 is_negative = true;
142 value = -value;
143 }
144
145 if (value > ((ecma_number_t) 0xffffffff))
146 {
147 value = (ecma_number_t) (fmod (value, (ecma_number_t) 0x100000000));
148 }
149
150 uint32_value = (uint32_t) value;
151
152 if (is_negative)
153 {
154 uint32_value = (uint32_t) (-(int32_t) uint32_value);
155 }
156 }
157
158 return uint32_value;
159 } /* ecma_typedarray_setter_number_to_uint32 */
160
161 /**
162 * Write an int8_t value into the given arraybuffer
163 */
164 static void
ecma_typedarray_set_int8_element(lit_utf8_byte_t * dst_p,ecma_number_t value)165 ecma_typedarray_set_int8_element (lit_utf8_byte_t *dst_p, /**< the location in the internal arraybuffer */
166 ecma_number_t value) /**< the number value to set */
167 {
168 int8_t num = (int8_t) ecma_typedarray_setter_number_to_uint32 (value);
169 *dst_p = (lit_utf8_byte_t) num;
170 } /* ecma_typedarray_set_int8_element */
171
172 /**
173 * Write an uint8_t value into the given arraybuffer
174 */
175 static void
ecma_typedarray_set_uint8_element(lit_utf8_byte_t * dst_p,ecma_number_t value)176 ecma_typedarray_set_uint8_element (lit_utf8_byte_t *dst_p, /**< the location in the internal arraybuffer */
177 ecma_number_t value) /**< the number value to set */
178 {
179 uint8_t num = (uint8_t) ecma_typedarray_setter_number_to_uint32 (value);
180 *dst_p = (lit_utf8_byte_t) num;
181 } /* ecma_typedarray_set_uint8_element */
182
183 /**
184 * Write an uint8_t clamped value into the given arraybuffer
185 */
186 static void
ecma_typedarray_set_uint8_clamped_element(lit_utf8_byte_t * dst_p,ecma_number_t value)187 ecma_typedarray_set_uint8_clamped_element (lit_utf8_byte_t *dst_p, /**< the location in the internal arraybuffer */
188 ecma_number_t value) /**< the number value to set */
189 {
190 uint8_t clamped;
191
192 if (value > 255)
193 {
194 clamped = 255;
195 }
196 else if (value <= 0)
197 {
198 clamped = 0;
199 }
200 else
201 {
202 clamped = (uint8_t) value;
203
204 if (clamped + 0.5 < value
205 || (clamped + 0.5 == value && (clamped % 2) == 1))
206 {
207 clamped ++;
208 }
209 }
210
211 *dst_p = (lit_utf8_byte_t) clamped;
212 } /* ecma_typedarray_set_uint8_clamped_element */
213
214 /**
215 * Write an int16_t value into the given arraybuffer
216 */
217 static void
ecma_typedarray_set_int16_element(lit_utf8_byte_t * dst_p,ecma_number_t value)218 ecma_typedarray_set_int16_element (lit_utf8_byte_t *dst_p, /**< the location in the internal arraybuffer */
219 ecma_number_t value) /**< the number value to set */
220 {
221 int16_t num = (int16_t) ecma_typedarray_setter_number_to_uint32 (value);
222 memcpy (dst_p, &num, sizeof (int16_t));
223 } /* ecma_typedarray_set_int16_element */
224
225 /**
226 * Write an uint8_t value into the given arraybuffer
227 */
228 static void
ecma_typedarray_set_uint16_element(lit_utf8_byte_t * dst_p,ecma_number_t value)229 ecma_typedarray_set_uint16_element (lit_utf8_byte_t *dst_p, /**< the location in the internal arraybuffer */
230 ecma_number_t value) /**< the number value to set */
231 {
232 uint16_t num = (uint16_t) ecma_typedarray_setter_number_to_uint32 (value);
233 memcpy (dst_p, &num, sizeof (uint16_t));
234 } /* ecma_typedarray_set_uint16_element */
235
236 /**
237 * Write an int32_t value into the given arraybuffer
238 */
239 static void
ecma_typedarray_set_int32_element(lit_utf8_byte_t * dst_p,ecma_number_t value)240 ecma_typedarray_set_int32_element (lit_utf8_byte_t *dst_p, /**< the location in the internal arraybuffer */
241 ecma_number_t value) /**< the number value to set */
242 {
243 int32_t num = (int32_t) ecma_typedarray_setter_number_to_uint32 (value);
244 memcpy (dst_p, &num, sizeof (int32_t));
245 } /* ecma_typedarray_set_int32_element */
246
247 /**
248 * Write an uint32_t value into the given arraybuffer
249 */
250 static void
ecma_typedarray_set_uint32_element(lit_utf8_byte_t * dst_p,ecma_number_t value)251 ecma_typedarray_set_uint32_element (lit_utf8_byte_t *dst_p, /**< the location in the internal arraybuffer */
252 ecma_number_t value) /**< the number value to set */
253 {
254 uint32_t num = (uint32_t) ecma_typedarray_setter_number_to_uint32 (value);
255 memcpy (dst_p, &num, sizeof (uint32_t));
256 } /* ecma_typedarray_set_uint32_element */
257
258 /**
259 * Write a float value into the given arraybuffer
260 */
261 static void
ecma_typedarray_set_float_element(lit_utf8_byte_t * dst_p,ecma_number_t value)262 ecma_typedarray_set_float_element (lit_utf8_byte_t *dst_p, /**< the location in the internal arraybuffer */
263 ecma_number_t value) /**< the number value to set */
264 {
265 float num = (float) value;
266 memcpy (dst_p, &num, sizeof (float));
267 } /* ecma_typedarray_set_float_element */
268
269 #if ENABLED (JERRY_NUMBER_TYPE_FLOAT64)
270 /**
271 * Write a double value into the given arraybuffer
272 */
273 static void
ecma_typedarray_set_double_element(lit_utf8_byte_t * dst_p,ecma_number_t value)274 ecma_typedarray_set_double_element (lit_utf8_byte_t *dst_p, /**< the location in the internal arraybuffer */
275 ecma_number_t value) /**< the number value to set */
276 {
277 double num = (double) value;
278 memcpy (dst_p, &num, sizeof (double));
279 } /* ecma_typedarray_set_double_element */
280 #endif /* ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
281
282 /**
283 * Builtin id of the first %TypedArray% builtin routine intrinsic object
284 */
285 #define ECMA_FIRST_TYPEDARRAY_BUILTIN_ROUTINE_ID ECMA_BUILTIN_ID_INT8ARRAY
286
287 #if ENABLED (JERRY_NUMBER_TYPE_FLOAT64)
288 /**
289 * Builtin id of the last %TypedArray% builtin routine intrinsic object
290 */
291 #define ECMA_LAST_TYPEDARRAY_BUILTIN_ROUTINE_ID ECMA_BUILTIN_ID_FLOAT64ARRAY
292 #else /* !ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
293 /**
294 * Builtin id of the last %TypedArray% builtin routine intrinsic object
295 */
296 #define ECMA_LAST_TYPEDARRAY_BUILTIN_ROUTINE_ID ECMA_BUILTIN_ID_FLOAT32ARRAY
297 #endif /* ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
298
299 /**
300 * Builtin id of the first %TypedArray% builtin prototype intrinsic object
301 */
302 #define ECMA_FIRST_TYPEDARRAY_BUILTIN_PROTOTYPE_ID ECMA_BUILTIN_ID_INT8ARRAY_PROTOTYPE
303
304 /**
305 * List of typedarray getters based on their builtin id
306 */
307 static const ecma_typedarray_getter_fn_t ecma_typedarray_getters[] =
308 {
309 ecma_typedarray_get_int8_element, /**< Int8Array */
310 ecma_typedarray_get_uint8_element, /**< Uint8Array */
311 ecma_typedarray_get_uint8_element, /**< Uint8ClampedArray */
312 ecma_typedarray_get_int16_element, /**< Int16Array */
313 ecma_typedarray_get_uint16_element, /**< Int32Array */
314 ecma_typedarray_get_int32_element, /**< Uint32Array */
315 ecma_typedarray_get_uint32_element, /**< Uint32Array */
316 ecma_typedarray_get_float_element, /**< Float32Array */
317 #if ENABLED (JERRY_NUMBER_TYPE_FLOAT64)
318 ecma_typedarray_get_double_element, /**< Float64Array */
319 #endif /* ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
320 };
321
322 /**
323 * List of typedarray setters based on their builtin id
324 */
325 static const ecma_typedarray_setter_fn_t ecma_typedarray_setters[] =
326 {
327 ecma_typedarray_set_int8_element, /**< Int8Array */
328 ecma_typedarray_set_uint8_element, /**< Uint8Array */
329 ecma_typedarray_set_uint8_clamped_element, /**< Uint8ClampedArray */
330 ecma_typedarray_set_int16_element, /**< Int16Array */
331 ecma_typedarray_set_uint16_element, /**< Int32Array */
332 ecma_typedarray_set_int32_element, /**< Uint32Array */
333 ecma_typedarray_set_uint32_element, /**< Uint32Array */
334 ecma_typedarray_set_float_element, /**< Float32Array */
335 #if ENABLED (JERRY_NUMBER_TYPE_FLOAT64)
336 ecma_typedarray_set_double_element, /**< Float64Array */
337 #endif /* ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
338 };
339
340 /**
341 * List of typedarray element shift sizes based on their builtin id
342 */
343 static const uint8_t ecma_typedarray_element_shift_sizes[] =
344 {
345 0, /**< Int8Array */
346 0, /**< Uint8Array */
347 0, /**< Uint8ClampedArray */
348 1, /**< Int16Array */
349 1, /**< Uint16Array */
350 2, /**< Int32Array */
351 2, /**< Uint32Array */
352 2, /**< Float32Array */
353 #if ENABLED (JERRY_NUMBER_TYPE_FLOAT64)
354 3, /**< Float64Array */
355 #endif /* ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
356 };
357
358 /**
359 * List of typedarray class magic strings based on their builtin id
360 */
361 static const uint16_t ecma_typedarray_magic_string_list[] =
362 {
363 (uint16_t) LIT_MAGIC_STRING_INT8_ARRAY_UL, /**< Int8Array */
364 (uint16_t) LIT_MAGIC_STRING_UINT8_ARRAY_UL, /**< Uint8Array */
365 (uint16_t) LIT_MAGIC_STRING_UINT8_CLAMPED_ARRAY_UL, /**< Uint8ClampedArray */
366 (uint16_t) LIT_MAGIC_STRING_INT16_ARRAY_UL, /**< Int16Array */
367 (uint16_t) LIT_MAGIC_STRING_UINT16_ARRAY_UL, /**< Uint16Array */
368 (uint16_t) LIT_MAGIC_STRING_INT32_ARRAY_UL, /**< Int32Array */
369 (uint16_t) LIT_MAGIC_STRING_UINT32_ARRAY_UL, /**< Uint32Array */
370 (uint16_t) LIT_MAGIC_STRING_FLOAT32_ARRAY_UL, /**< Float32Array */
371 #if ENABLED (JERRY_NUMBER_TYPE_FLOAT64)
372 (uint16_t) LIT_MAGIC_STRING_FLOAT64_ARRAY_UL, /**< Float64Array */
373 #endif /* ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
374 };
375
376 /**
377 * Get typedarray's getter function callback
378 *
379 * @return ecma_typedarray_getter_fn_t: the getter function for the given builtin TypedArray id
380 */
381 inline ecma_typedarray_getter_fn_t JERRY_ATTR_ALWAYS_INLINE
ecma_get_typedarray_getter_fn(ecma_typedarray_type_t typedarray_id)382 ecma_get_typedarray_getter_fn (ecma_typedarray_type_t typedarray_id)
383 {
384 return ecma_typedarray_getters[typedarray_id];
385 } /* ecma_get_typedarray_getter_fn */
386
387 /**
388 * get typedarray's element value
389 *
390 * @return ecma_number_t: the value of the element
391 */
392 inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_get_typedarray_element(lit_utf8_byte_t * src_p,ecma_typedarray_type_t typedarray_id)393 ecma_get_typedarray_element (lit_utf8_byte_t *src_p,
394 ecma_typedarray_type_t typedarray_id)
395 {
396 return ecma_typedarray_getters[typedarray_id](src_p);
397 } /* ecma_get_typedarray_element */
398
399 /**
400 * Get typedarray's setter function callback
401 *
402 * @return ecma_typedarray_setter_fn_t: the setter function for the given builtin TypedArray id
403 */
404 inline ecma_typedarray_setter_fn_t JERRY_ATTR_ALWAYS_INLINE
ecma_get_typedarray_setter_fn(ecma_typedarray_type_t typedarray_id)405 ecma_get_typedarray_setter_fn (ecma_typedarray_type_t typedarray_id)
406 {
407 return ecma_typedarray_setters[typedarray_id];
408 } /* ecma_get_typedarray_setter_fn */
409
410 /**
411 * set typedarray's element value
412 */
413 inline void JERRY_ATTR_ALWAYS_INLINE
ecma_set_typedarray_element(lit_utf8_byte_t * dst_p,ecma_number_t value,ecma_typedarray_type_t typedarray_id)414 ecma_set_typedarray_element (lit_utf8_byte_t *dst_p,
415 ecma_number_t value,
416 ecma_typedarray_type_t typedarray_id)
417 {
418 ecma_typedarray_setters[typedarray_id](dst_p, value);
419 } /* ecma_set_typedarray_element */
420
421 /**
422 * Get the element shift size of a TypedArray type.
423 *
424 * @return uint8_t
425 */
426 inline uint8_t JERRY_ATTR_ALWAYS_INLINE
ecma_typedarray_helper_get_shift_size(ecma_typedarray_type_t typedarray_id)427 ecma_typedarray_helper_get_shift_size (ecma_typedarray_type_t typedarray_id)
428 {
429 return ecma_typedarray_element_shift_sizes[typedarray_id];
430 } /* ecma_typedarray_helper_get_shift_size */
431
432 /**
433 * Check if the builtin is a TypedArray type.
434 *
435 * @return bool: - true if based on the given id it is a TypedArray
436 * - false if based on the given id it is not a TypedArray
437 */
438 bool
ecma_typedarray_helper_is_typedarray(ecma_builtin_id_t builtin_id)439 ecma_typedarray_helper_is_typedarray (ecma_builtin_id_t builtin_id) /**< the builtin id of a type **/
440 {
441 return ((builtin_id >= ECMA_FIRST_TYPEDARRAY_BUILTIN_ROUTINE_ID)
442 && (builtin_id <= ECMA_LAST_TYPEDARRAY_BUILTIN_ROUTINE_ID));
443 } /* ecma_typedarray_helper_is_typedarray */
444
445 /**
446 * Get the prototype ID of a TypedArray type.
447 *
448 * @return ecma_builtin_id_t
449 */
450 ecma_builtin_id_t
ecma_typedarray_helper_get_prototype_id(ecma_typedarray_type_t typedarray_id)451 ecma_typedarray_helper_get_prototype_id (ecma_typedarray_type_t typedarray_id) /**< the id of the typedarray **/
452 {
453 return (ecma_builtin_id_t) (ECMA_FIRST_TYPEDARRAY_BUILTIN_PROTOTYPE_ID + typedarray_id);
454 } /* ecma_typedarray_helper_get_prototype_id */
455
456 /**
457 * Get the constructor ID of a TypedArray type.
458 *
459 * @return ecma_builtin_id_t
460 */
461 ecma_builtin_id_t
ecma_typedarray_helper_get_constructor_id(ecma_typedarray_type_t typedarray_id)462 ecma_typedarray_helper_get_constructor_id (ecma_typedarray_type_t typedarray_id) /**< the id of the typedarray **/
463 {
464 return (ecma_builtin_id_t) (ECMA_FIRST_TYPEDARRAY_BUILTIN_ROUTINE_ID + typedarray_id);
465 } /* ecma_typedarray_helper_get_constructor_id */
466
467 /**
468 * Get the built-in TypedArray type of the given object.
469 *
470 * @return ecma_typedarray_type_t
471 */
472 ecma_typedarray_type_t
ecma_get_typedarray_id(ecma_object_t * obj_p)473 ecma_get_typedarray_id (ecma_object_t *obj_p) /**< typedarray object **/
474 {
475 JERRY_ASSERT (ecma_object_is_typedarray (obj_p));
476
477 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
478
479 return (ecma_typedarray_type_t) ext_object_p->u.pseudo_array.extra_info;
480 } /* ecma_get_typedarray_id */
481
482 /**
483 * Get the built-in TypedArray type of the given object.
484 *
485 * @return ecma_typedarray_type_t
486 */
487 ecma_typedarray_type_t
ecma_typedarray_helper_builtin_to_typedarray_id(ecma_builtin_id_t builtin_id)488 ecma_typedarray_helper_builtin_to_typedarray_id (ecma_builtin_id_t builtin_id)
489 {
490 JERRY_ASSERT (ecma_typedarray_helper_is_typedarray (builtin_id));
491
492 return (ecma_typedarray_type_t) (builtin_id - ECMA_FIRST_TYPEDARRAY_BUILTIN_ROUTINE_ID);
493 } /* ecma_typedarray_helper_builtin_to_typedarray_id */
494
495 /**
496 * Create a TypedArray object by given array_length
497 *
498 * See also: ES2015 22.2.1.2.1
499 *
500 * @return ecma value of the new typedarray object
501 * Returned value must be freed with ecma_free_value
502 */
503 ecma_value_t
ecma_typedarray_create_object_with_length(ecma_length_t array_length,ecma_object_t * src_buffer_p,ecma_object_t * proto_p,uint8_t element_size_shift,ecma_typedarray_type_t typedarray_id)504 ecma_typedarray_create_object_with_length (ecma_length_t array_length, /**< length of the typedarray */
505 ecma_object_t *src_buffer_p, /**< source buffer */
506 ecma_object_t *proto_p, /**< prototype object */
507 uint8_t element_size_shift, /**< the size shift of the element length */
508 ecma_typedarray_type_t typedarray_id) /**< id of the typedarray */
509 {
510 if (array_length > (UINT32_MAX >> element_size_shift))
511 {
512 return ecma_raise_range_error (ECMA_ERR_MSG ("Maximum typedarray size is reached."));
513 }
514
515 ecma_length_t byte_length = array_length << element_size_shift;
516
517 if (byte_length > UINT32_MAX - sizeof (ecma_extended_object_t) - JMEM_ALIGNMENT + 1)
518 {
519 return ecma_raise_range_error (ECMA_ERR_MSG ("Maximum typedarray size is reached."));
520 }
521
522 ecma_object_t *new_arraybuffer_p = NULL;
523 if (src_buffer_p == NULL)
524 {
525 new_arraybuffer_p = ecma_arraybuffer_new_object (byte_length);
526 }
527 else
528 {
529 #if ENABLED (JERRY_ES2015)
530 ecma_value_t ctor_proto = ecma_op_species_constructor (src_buffer_p, ECMA_BUILTIN_ID_ARRAYBUFFER);
531 #else
532 ecma_value_t ctor_proto = ECMA_VALUE_ERROR;
533 #endif /* ENABLED (JERRY_ES2015) */
534 if (ECMA_IS_VALUE_ERROR (ctor_proto))
535 {
536 return ctor_proto;
537 }
538
539 ecma_object_t *ctor_proto_p = ecma_get_object_from_value (ctor_proto);
540
541 ecma_object_t *prototype_p = ecma_op_get_prototype_from_constructor (ctor_proto_p,
542 ECMA_BUILTIN_ID_ARRAYBUFFER_PROTOTYPE);
543
544 ecma_deref_object (ctor_proto_p);
545
546 if (JERRY_UNLIKELY (prototype_p == NULL))
547 {
548 return ECMA_VALUE_ERROR;
549 }
550
551 new_arraybuffer_p = ecma_arraybuffer_new_object (byte_length);
552
553 ECMA_SET_NON_NULL_POINTER (new_arraybuffer_p->u2.prototype_cp, prototype_p);
554
555 ecma_deref_object (prototype_p);
556 }
557
558 ecma_object_t *object_p = ecma_create_object (proto_p,
559 sizeof (ecma_extended_object_t),
560 ECMA_OBJECT_TYPE_PSEUDO_ARRAY);
561
562 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
563 ext_object_p->u.pseudo_array.u1.class_id = ecma_typedarray_magic_string_list[typedarray_id];
564 ext_object_p->u.pseudo_array.type = ECMA_PSEUDO_ARRAY_TYPEDARRAY;
565 ext_object_p->u.pseudo_array.extra_info = (uint8_t) typedarray_id;
566 ext_object_p->u.pseudo_array.u2.arraybuffer = ecma_make_object_value (new_arraybuffer_p);
567
568 ecma_deref_object (new_arraybuffer_p);
569
570 return ecma_make_object_value (object_p);
571 } /* ecma_typedarray_create_object_with_length */
572
573 /**
574 * Create a TypedArray object by given buffer, offset, and array_length
575 *
576 * See also: ES2015 22.2.1.5
577 *
578 * @return ecma value of the new typedarray object
579 * Returned value must be freed with ecma_free_value
580 */
581 static ecma_value_t
ecma_typedarray_create_object_with_buffer(ecma_object_t * arraybuffer_p,ecma_length_t byte_offset,ecma_length_t array_length,ecma_object_t * proto_p,uint8_t element_size_shift,ecma_typedarray_type_t typedarray_id)582 ecma_typedarray_create_object_with_buffer (ecma_object_t *arraybuffer_p, /**< the arraybuffer inside */
583 ecma_length_t byte_offset, /**< the byte offset of the arraybuffer */
584 ecma_length_t array_length, /**< length of the typedarray */
585 ecma_object_t *proto_p, /**< prototype object */
586 uint8_t element_size_shift, /**< the size shift of the element length */
587 ecma_typedarray_type_t typedarray_id) /**< id of the typedarray */
588 {
589 if (ecma_arraybuffer_is_detached (arraybuffer_p))
590 {
591 return ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer has been detached."));
592 }
593 ecma_length_t expected_length = (ecma_arraybuffer_get_length (arraybuffer_p) >> element_size_shift);
594
595 bool needs_ext_typedarray_obj = (byte_offset != 0 || array_length != expected_length);
596
597 size_t object_size = (needs_ext_typedarray_obj ? sizeof (ecma_extended_typedarray_object_t)
598 : sizeof (ecma_extended_object_t));
599
600 ecma_object_t *object_p = ecma_create_object (proto_p, object_size, ECMA_OBJECT_TYPE_PSEUDO_ARRAY);
601
602 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
603 ext_object_p->u.pseudo_array.u1.class_id = ecma_typedarray_magic_string_list[typedarray_id];
604 ext_object_p->u.pseudo_array.type = ECMA_PSEUDO_ARRAY_TYPEDARRAY;
605 ext_object_p->u.pseudo_array.extra_info = (uint8_t) typedarray_id;
606 ext_object_p->u.pseudo_array.u2.arraybuffer = ecma_make_object_value (arraybuffer_p);
607
608 if (needs_ext_typedarray_obj)
609 {
610 ext_object_p->u.pseudo_array.type = ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO;
611
612 ecma_extended_typedarray_object_t *typedarray_info_p = (ecma_extended_typedarray_object_t *) object_p;
613 typedarray_info_p->array_length = array_length;
614 typedarray_info_p->byte_offset = byte_offset;
615 }
616
617 return ecma_make_object_value (object_p);
618 } /* ecma_typedarray_create_object_with_buffer */
619
620 /**
621 * Create a TypedArray object by given another TypedArray object
622 *
623 * See also: ES2015 22.2.1.3
624 *
625 * @return ecma value of the new typedarray object
626 * Returned value must be freed with ecma_free_value
627 */
628 static ecma_value_t
ecma_typedarray_create_object_with_typedarray(ecma_object_t * typedarray_p,ecma_object_t * proto_p,uint8_t element_size_shift,ecma_typedarray_type_t typedarray_id)629 ecma_typedarray_create_object_with_typedarray (ecma_object_t *typedarray_p, /**< a typedarray object */
630 ecma_object_t *proto_p, /**< prototype object */
631 uint8_t element_size_shift, /**< the size shift of the element length */
632 ecma_typedarray_type_t typedarray_id) /**< id of the typedarray */
633 {
634 ecma_length_t array_length = ecma_typedarray_get_length (typedarray_p);
635 ecma_object_t *src_arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p);
636 if (ecma_arraybuffer_is_detached (src_arraybuffer_p))
637 {
638 return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid detached ArrayBuffer."));
639 }
640
641 ecma_value_t new_typedarray = ecma_typedarray_create_object_with_length (array_length,
642 src_arraybuffer_p,
643 proto_p,
644 element_size_shift,
645 typedarray_id);
646
647 if (ECMA_IS_VALUE_ERROR (new_typedarray))
648 {
649 return new_typedarray;
650 }
651
652 ecma_object_t *new_typedarray_p = ecma_get_object_from_value (new_typedarray);
653
654 lit_utf8_byte_t *src_buf_p = ecma_arraybuffer_get_buffer (src_arraybuffer_p);
655
656 ecma_object_t *dst_arraybuffer_p = ecma_typedarray_get_arraybuffer (new_typedarray_p);
657 lit_utf8_byte_t *dst_buf_p = ecma_arraybuffer_get_buffer (dst_arraybuffer_p);
658
659 src_buf_p += ecma_typedarray_get_offset (typedarray_p);
660
661 ecma_typedarray_type_t src_id = ecma_get_typedarray_id (typedarray_p);
662
663 if (src_id == typedarray_id)
664 {
665 memcpy (dst_buf_p, src_buf_p, array_length << element_size_shift);
666 }
667 else
668 {
669 uint32_t src_element_size = 1u << ecma_typedarray_get_element_size_shift (typedarray_p);
670 uint32_t dst_element_size = 1u << element_size_shift;
671 ecma_typedarray_getter_fn_t src_typedarray_getter_cb = ecma_get_typedarray_getter_fn (src_id);
672 ecma_typedarray_setter_fn_t target_typedarray_setter_cb = ecma_get_typedarray_setter_fn (typedarray_id);
673
674 for (uint32_t i = 0; i < array_length; i++)
675 {
676 /* Convert values from source to destination format. */
677 ecma_number_t tmp = src_typedarray_getter_cb (src_buf_p);
678 target_typedarray_setter_cb (dst_buf_p, tmp);
679
680 src_buf_p += src_element_size;
681 dst_buf_p += dst_element_size;
682 }
683 }
684
685 return new_typedarray;
686 } /* ecma_typedarray_create_object_with_typedarray */
687
688 /**
689 * Helper method for ecma_op_typedarray_from
690 *
691 * @return ECMA_VALUE_TRUE - if setting the given value to the new typedarray was successful
692 * ECMA_VALUE_ERROR - otherwise
693 */
694 static ecma_value_t
ecma_op_typedarray_from_helper(ecma_value_t this_val,ecma_value_t current_value,uint32_t index,ecma_object_t * func_object_p,ecma_typedarray_info_t * info_p,ecma_typedarray_setter_fn_t setter_cb)695 ecma_op_typedarray_from_helper (ecma_value_t this_val, /**< this_arg for the above from function */
696 ecma_value_t current_value, /**< given value to set */
697 uint32_t index, /**< currrent index */
698 ecma_object_t *func_object_p, /**< map function object */
699 ecma_typedarray_info_t *info_p, /**< typedarray info */
700 ecma_typedarray_setter_fn_t setter_cb) /**< setter callback function */
701 {
702 ecma_value_t mapped_value;
703 if (func_object_p != NULL)
704 {
705 /* 17.d 17.f */
706 ecma_value_t current_index = ecma_make_uint32_value (index);
707 ecma_value_t call_args[] = { current_value, current_index };
708
709 ecma_value_t cb_value = ecma_op_function_call (func_object_p, this_val, call_args, 2);
710
711 ecma_free_value (current_index);
712 ecma_free_value (current_value);
713
714 if (ECMA_IS_VALUE_ERROR (cb_value))
715 {
716 return cb_value;
717 }
718
719 mapped_value = cb_value;
720 }
721 else
722 {
723 mapped_value = current_value;
724 }
725
726 ecma_number_t num_var;
727 ecma_value_t mapped_number = ecma_get_number (mapped_value, &num_var);
728 ecma_free_value (mapped_value);
729
730 if (ECMA_IS_VALUE_ERROR (mapped_number))
731 {
732 return mapped_number;
733 }
734
735 if (index >= info_p->length)
736 {
737 return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument type."));
738 }
739
740 setter_cb (info_p->buffer_p + (index << info_p->shift), num_var);
741
742 return ECMA_VALUE_TRUE;
743 } /* ecma_op_typedarray_from_helper */
744
745 /**
746 * Create a TypedArray object by transforming from an array-like object or iterable object
747 *
748 * See also: ES2015 22.2.2.1
749 *
750 * @return ecma value of the new typedarray object
751 * Returned value must be freed with ecma_free_value
752 */
753 ecma_value_t
ecma_op_typedarray_from(ecma_value_t items_val,ecma_value_t map_fn_val,ecma_value_t this_val,ecma_object_t * proto_p,uint8_t element_size_shift,ecma_typedarray_type_t typedarray_id)754 ecma_op_typedarray_from (ecma_value_t items_val, /**< the source array-like object */
755 ecma_value_t map_fn_val, /**< map function */
756 ecma_value_t this_val, /**< this_arg for the above map function */
757 ecma_object_t *proto_p, /**< prototype object */
758 uint8_t element_size_shift, /**< the size shift of the element length */
759 ecma_typedarray_type_t typedarray_id) /**< id of the typedarray */
760 {
761 /* 3 */
762 JERRY_ASSERT (ecma_op_is_callable (map_fn_val) || ecma_is_value_undefined (map_fn_val));
763
764 /* 4-5 */
765 ecma_object_t *func_object_p = NULL;
766 if (!ecma_is_value_undefined (map_fn_val))
767 {
768 func_object_p = ecma_get_object_from_value (map_fn_val);
769 }
770
771 #if ENABLED (JERRY_ES2015)
772 /* 6 */
773 ecma_value_t using_iterator = ecma_op_get_method_by_symbol_id (items_val, LIT_GLOBAL_SYMBOL_ITERATOR);
774
775 /* 7 */
776 if (ECMA_IS_VALUE_ERROR (using_iterator))
777 {
778 return using_iterator;
779 }
780
781 /* 8 */
782 if (!ecma_is_value_undefined (using_iterator))
783 {
784 /* 8.a */
785 ecma_value_t iterator = ecma_op_get_iterator (items_val, using_iterator);
786 ecma_free_value (using_iterator);
787
788 /* 8.b */
789 if (ECMA_IS_VALUE_ERROR (iterator))
790 {
791 return iterator;
792 }
793
794 /* 8.c */
795 ecma_collection_t *values_p = ecma_new_collection ();
796 ecma_value_t ret_value = ECMA_VALUE_EMPTY;
797
798 /* 8.e */
799 while (true)
800 {
801 /* 8.e.i */
802 ecma_value_t next = ecma_op_iterator_step (iterator);
803
804 /* 8.e.ii */
805 if (ECMA_IS_VALUE_ERROR (next))
806 {
807 ret_value = next;
808 break;
809 }
810
811 if (next == ECMA_VALUE_FALSE)
812 {
813 break;
814 }
815
816 /* 8.e.iii */
817 ecma_value_t next_value = ecma_op_iterator_value (next);
818 ecma_free_value (next);
819
820 if (ECMA_IS_VALUE_ERROR (next_value))
821 {
822 ret_value = next_value;
823 break;
824 }
825
826 ecma_collection_push_back (values_p, next_value);
827 }
828
829 ecma_free_value (iterator);
830
831 if (ECMA_IS_VALUE_ERROR (ret_value))
832 {
833 ecma_collection_free (values_p);
834 return ret_value;
835 }
836
837 /* 8.g */
838 ecma_value_t new_typedarray = ecma_typedarray_create_object_with_length (values_p->item_count,
839 NULL,
840 proto_p,
841 element_size_shift,
842 typedarray_id);
843
844 /* 8.h */
845 if (ECMA_IS_VALUE_ERROR (new_typedarray))
846 {
847 ecma_collection_free (values_p);
848 return new_typedarray;
849 }
850
851 ecma_object_t *new_typedarray_p = ecma_get_object_from_value (new_typedarray);
852 ecma_typedarray_info_t info = ecma_typedarray_get_info (new_typedarray_p);
853 ecma_typedarray_setter_fn_t setter_cb = ecma_get_typedarray_setter_fn (info.id);
854
855 ret_value = ecma_make_object_value (new_typedarray_p);
856
857 /* 8.j */
858 for (uint32_t index = 0; index < values_p->item_count; index++)
859 {
860 ecma_value_t set_value = ecma_op_typedarray_from_helper (this_val,
861 values_p->buffer_p[index],
862 index,
863 func_object_p,
864 &info,
865 setter_cb);
866
867 if (ECMA_IS_VALUE_ERROR (set_value))
868 {
869 for (uint32_t j = index + 1; j < values_p->item_count; j++)
870 {
871 ecma_free_value (values_p->buffer_p[j]);
872 }
873
874 ret_value = set_value;
875 break;
876 }
877 }
878
879 ecma_collection_destroy (values_p);
880
881 if (ECMA_IS_VALUE_ERROR (ret_value))
882 {
883 ecma_deref_object (new_typedarray_p);
884 }
885
886 return ret_value;
887 }
888 #endif /* ENABLED (JERRY_ES2015) */
889
890 /* 10 */
891 ecma_value_t arraylike_object_val = ecma_op_to_object (items_val);
892
893 if (ECMA_IS_VALUE_ERROR (arraylike_object_val))
894 {
895 return arraylike_object_val;
896 }
897
898 ecma_object_t *arraylike_object_p = ecma_get_object_from_value (arraylike_object_val);
899
900 /* 12 */
901 uint32_t len;
902 ecma_value_t len_value = ecma_op_object_get_length (arraylike_object_p, &len);
903
904 if (ECMA_IS_VALUE_ERROR (len_value))
905 {
906 ecma_deref_object (arraylike_object_p);
907 return len_value;
908 }
909
910 /* 14 */
911 ecma_value_t new_typedarray = ecma_typedarray_create_object_with_length (len,
912 NULL,
913 proto_p,
914 element_size_shift,
915 typedarray_id);
916
917 if (ECMA_IS_VALUE_ERROR (new_typedarray))
918 {
919 ecma_deref_object (arraylike_object_p);
920 return new_typedarray;
921 }
922
923 ecma_object_t *new_typedarray_p = ecma_get_object_from_value (new_typedarray);
924 ecma_typedarray_info_t info = ecma_typedarray_get_info (new_typedarray_p);
925 ecma_typedarray_setter_fn_t setter_cb = ecma_get_typedarray_setter_fn (info.id);
926 ecma_value_t ret_value = ecma_make_object_value (new_typedarray_p);
927
928 /* 17 */
929 for (uint32_t index = 0; index < len; index++)
930 {
931 ecma_value_t current_value = ecma_op_object_find_by_uint32_index (arraylike_object_p, index);
932
933 if (ECMA_IS_VALUE_ERROR (current_value))
934 {
935 ret_value = current_value;
936 break;
937 }
938
939 if (ecma_is_value_found (current_value))
940 {
941 ecma_value_t set_value = ecma_op_typedarray_from_helper (this_val,
942 current_value,
943 index,
944 func_object_p,
945 &info,
946 setter_cb);
947
948 if (ECMA_IS_VALUE_ERROR (set_value))
949 {
950 ret_value = set_value;
951 break;
952 }
953 }
954 }
955
956 ecma_deref_object (arraylike_object_p);
957
958 if (ECMA_IS_VALUE_ERROR (ret_value))
959 {
960 ecma_deref_object (new_typedarray_p);
961 }
962
963 return ret_value;
964 } /* ecma_op_typedarray_from */
965
966 /**
967 * Get the arraybuffer of the typedarray object
968 *
969 * @return the pointer to the internal arraybuffer
970 */
971 inline ecma_object_t * JERRY_ATTR_ALWAYS_INLINE
ecma_typedarray_get_arraybuffer(ecma_object_t * typedarray_p)972 ecma_typedarray_get_arraybuffer (ecma_object_t *typedarray_p) /**< the pointer to the typedarray object */
973 {
974 JERRY_ASSERT (ecma_object_is_typedarray (typedarray_p));
975
976 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) typedarray_p;
977
978 return ecma_get_object_from_value (ext_object_p->u.pseudo_array.u2.arraybuffer);
979 } /* ecma_typedarray_get_arraybuffer */
980
981 /**
982 * Get the element size shift in the typedarray object
983 *
984 * @return the size shift of the element, size is 1 << shift
985 */
986 uint8_t
ecma_typedarray_get_element_size_shift(ecma_object_t * typedarray_p)987 ecma_typedarray_get_element_size_shift (ecma_object_t *typedarray_p) /**< the pointer to the typedarray object */
988 {
989 JERRY_ASSERT (ecma_object_is_typedarray (typedarray_p));
990
991 return ecma_typedarray_helper_get_shift_size (ecma_get_typedarray_id (typedarray_p));
992 } /* ecma_typedarray_get_element_size_shift */
993
994 /**
995 * Get the array length of the typedarray object
996 *
997 * @return the array length
998 */
999 ecma_length_t
ecma_typedarray_get_length(ecma_object_t * typedarray_p)1000 ecma_typedarray_get_length (ecma_object_t *typedarray_p) /**< the pointer to the typedarray object */
1001 {
1002 JERRY_ASSERT (ecma_object_is_typedarray (typedarray_p));
1003
1004 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) typedarray_p;
1005
1006 if (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_TYPEDARRAY)
1007 {
1008 ecma_object_t *arraybuffer_p = ecma_get_object_from_value (ext_object_p->u.pseudo_array.u2.arraybuffer);
1009 ecma_length_t buffer_length = ecma_arraybuffer_get_length (arraybuffer_p);
1010 uint8_t shift = ecma_typedarray_get_element_size_shift (typedarray_p);
1011
1012 return buffer_length >> shift;
1013 }
1014
1015 ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p);
1016 if (ecma_arraybuffer_is_detached (arraybuffer_p))
1017 {
1018 return 0;
1019 }
1020
1021 ecma_extended_typedarray_object_t *info_p = (ecma_extended_typedarray_object_t *) ext_object_p;
1022
1023 return info_p->array_length;
1024 } /* ecma_typedarray_get_length */
1025
1026 /**
1027 * Get the offset of the internal arraybuffer
1028 *
1029 * @return the offset
1030 */
1031 ecma_length_t
ecma_typedarray_get_offset(ecma_object_t * typedarray_p)1032 ecma_typedarray_get_offset (ecma_object_t *typedarray_p) /**< the pointer to the typedarray object */
1033 {
1034 JERRY_ASSERT (ecma_object_is_typedarray (typedarray_p));
1035
1036 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) typedarray_p;
1037
1038 if (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_TYPEDARRAY)
1039 {
1040 return 0;
1041 }
1042
1043 ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p);
1044 if (ecma_arraybuffer_is_detached (arraybuffer_p))
1045 {
1046 return 0;
1047 }
1048
1049 ecma_extended_typedarray_object_t *info_p = (ecma_extended_typedarray_object_t *) ext_object_p;
1050
1051 return info_p->byte_offset;
1052 } /* ecma_typedarray_get_offset */
1053
1054 /**
1055 * Utility function: return the pointer of the data buffer referenced by the typed array
1056 *
1057 * @return pointer to the data buffer
1058 */
1059 lit_utf8_byte_t *
ecma_typedarray_get_buffer(ecma_object_t * typedarray_p)1060 ecma_typedarray_get_buffer (ecma_object_t *typedarray_p) /**< the pointer to the typed array object */
1061 {
1062 ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (typedarray_p);
1063
1064 return ecma_arraybuffer_get_buffer (arraybuffer_p) + ecma_typedarray_get_offset (typedarray_p);
1065 } /* ecma_typedarray_get_buffer */
1066
1067 /**
1068 * Create a new typedarray object.
1069 *
1070 * The struct of the typedarray object
1071 * ecma_object_t
1072 * extend_part
1073 * typedarray_info
1074 *
1075 * @return ecma value of the new typedarray object
1076 * Returned value must be freed with ecma_free_value
1077 */
1078 ecma_value_t
ecma_op_create_typedarray(const ecma_value_t * arguments_list_p,ecma_length_t arguments_list_len,ecma_object_t * proto_p,uint8_t element_size_shift,ecma_typedarray_type_t typedarray_id)1079 ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg list passed to typedarray construct */
1080 ecma_length_t arguments_list_len, /**< the length of the arguments_list_p */
1081 ecma_object_t *proto_p, /**< prototype object */
1082 uint8_t element_size_shift, /**< the size shift of the element length */
1083 ecma_typedarray_type_t typedarray_id) /**< id of the typedarray */
1084 {
1085 JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
1086
1087 ecma_value_t ret = ECMA_VALUE_EMPTY;
1088
1089 if (arguments_list_len == 0)
1090 {
1091 /* 22.2.1.1 */
1092 ret = ecma_typedarray_create_object_with_length (0, NULL, proto_p, element_size_shift, typedarray_id);
1093 }
1094 else if (!ecma_is_value_object (arguments_list_p[0]))
1095 {
1096 /* 22.2.1.2 */
1097 if (ecma_is_value_undefined (arguments_list_p[0]))
1098 {
1099 return ecma_raise_type_error (ECMA_ERR_MSG ("length argument is undefined"));
1100 }
1101
1102 ECMA_OP_TO_NUMBER_TRY_CATCH (num, arguments_list_p[0], ret);
1103
1104 uint32_t length = ecma_number_to_uint32 (num);
1105
1106 if (num != ((ecma_number_t) length))
1107 {
1108 ret = ecma_raise_range_error (ECMA_ERR_MSG ("Invalid typedarray length."));
1109 }
1110 else
1111 {
1112 ret = ecma_typedarray_create_object_with_length (length,
1113 NULL,
1114 proto_p,
1115 element_size_shift,
1116 typedarray_id);
1117 }
1118
1119 ECMA_OP_TO_NUMBER_FINALIZE (num);
1120 }
1121 else if (ecma_is_value_object (arguments_list_p[0]))
1122 {
1123 ecma_object_t *obj_p = ecma_get_object_from_value (arguments_list_p[0]);
1124 if (ecma_object_is_typedarray (obj_p))
1125 {
1126 /* 22.2.1.3 */
1127 ecma_object_t *typedarray_p = obj_p;
1128 ret = ecma_typedarray_create_object_with_typedarray (typedarray_p,
1129 proto_p,
1130 element_size_shift,
1131 typedarray_id);
1132 }
1133 else if (ecma_object_class_is (obj_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL))
1134 {
1135 /* 22.2.1.5 */
1136 ecma_object_t *arraybuffer_p = obj_p;
1137 ecma_value_t arg2 = ((arguments_list_len > 1) ? arguments_list_p[1]
1138 : ECMA_VALUE_UNDEFINED);
1139
1140 ecma_value_t arg3 = ((arguments_list_len > 2) ? arguments_list_p[2]
1141 : ECMA_VALUE_UNDEFINED);
1142
1143 ecma_number_t offset;
1144 if (ECMA_IS_VALUE_ERROR (ecma_op_to_integer (arg2, &offset)))
1145 {
1146 return ECMA_VALUE_ERROR;
1147 }
1148
1149 if (ecma_number_is_negative (offset))
1150 {
1151 ret = ecma_raise_range_error (ECMA_ERR_MSG ("Invalid offset."));
1152 }
1153 else if (ecma_arraybuffer_is_detached (arraybuffer_p))
1154 {
1155 ret = ecma_raise_type_error (ECMA_ERR_MSG ("Invalid detached ArrayBuffer."));
1156 }
1157 else
1158 {
1159 ecma_length_t buf_byte_length = ecma_arraybuffer_get_length (arraybuffer_p);
1160 ecma_length_t new_byte_length = 0;
1161
1162 if (ecma_is_value_undefined (arg3))
1163 {
1164 if (buf_byte_length % (uint32_t) (1 << element_size_shift) != 0)
1165 {
1166 ret = ecma_raise_range_error (ECMA_ERR_MSG ("Invalid length."));
1167 }
1168 else if (buf_byte_length < offset)
1169 {
1170 ret = ecma_raise_range_error (ECMA_ERR_MSG ("Invalid length."));
1171 }
1172 else
1173 {
1174 new_byte_length = (ecma_length_t) (buf_byte_length - offset);
1175 }
1176 }
1177 else
1178 {
1179 uint32_t new_length;
1180 if (ECMA_IS_VALUE_ERROR (ecma_op_to_length (arg3, &new_length)))
1181 {
1182 return ECMA_VALUE_ERROR;
1183 }
1184
1185 if (new_length > (UINT32_MAX >> element_size_shift))
1186 {
1187 ret = ecma_raise_range_error (ECMA_ERR_MSG ("Maximum typedarray size is reached."));
1188 }
1189 else
1190 {
1191 new_byte_length = (ecma_length_t) new_length << element_size_shift;
1192
1193 if (((ecma_number_t) new_byte_length + offset) > buf_byte_length)
1194 {
1195 ret = ecma_raise_range_error (ECMA_ERR_MSG ("Invalid length."));
1196 }
1197 }
1198 }
1199
1200 if (ecma_is_value_empty (ret))
1201 {
1202 ecma_length_t array_length = new_byte_length >> element_size_shift;
1203 ret = ecma_typedarray_create_object_with_buffer (arraybuffer_p,
1204 (ecma_length_t) offset,
1205 array_length,
1206 proto_p,
1207 element_size_shift,
1208 typedarray_id);
1209 }
1210 }
1211 }
1212 else
1213 {
1214 /* 22.2.1.4 */
1215 ecma_value_t undef = ECMA_VALUE_UNDEFINED;
1216 ret = ecma_op_typedarray_from (arguments_list_p[0],
1217 undef,
1218 undef,
1219 proto_p,
1220 element_size_shift,
1221 typedarray_id);
1222 }
1223 }
1224
1225 return ret;
1226 } /* ecma_op_create_typedarray */
1227
1228 /**
1229 * Check if the object is typedarray
1230 *
1231 * @return true - if object is a TypedArray object
1232 * false - otherwise
1233 */
1234 bool
ecma_object_is_typedarray(ecma_object_t * obj_p)1235 ecma_object_is_typedarray (ecma_object_t *obj_p) /**< the target object need to be checked */
1236 {
1237 JERRY_ASSERT (!ecma_is_lexical_environment (obj_p));
1238
1239 if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_PSEUDO_ARRAY)
1240 {
1241 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
1242
1243 return ((ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_TYPEDARRAY)
1244 || (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO));
1245 }
1246
1247 return false;
1248 } /* ecma_object_is_typedarray */
1249
1250 /**
1251 * Check if the value is typedarray
1252 *
1253 * @return true - if value is a TypedArray object
1254 * false - otherwise
1255 */
1256 bool
ecma_is_typedarray(ecma_value_t value)1257 ecma_is_typedarray (ecma_value_t value) /**< the target need to be checked */
1258 {
1259 if (!ecma_is_value_object (value))
1260 {
1261 return false;
1262 }
1263
1264 return ecma_object_is_typedarray (ecma_get_object_from_value (value));
1265 } /* ecma_is_typedarray */
1266
1267 /**
1268 * List names of a TypedArray object's integer indexed properties
1269 *
1270 * @return void
1271 */
1272 void
ecma_op_typedarray_list_lazy_property_names(ecma_object_t * obj_p,ecma_collection_t * main_collection_p)1273 ecma_op_typedarray_list_lazy_property_names (ecma_object_t *obj_p, /**< a TypedArray object */
1274 ecma_collection_t *main_collection_p) /**< 'main' collection */
1275 {
1276 JERRY_ASSERT (ecma_object_is_typedarray (obj_p));
1277
1278 ecma_length_t array_length = ecma_typedarray_get_length (obj_p);
1279
1280 for (ecma_length_t i = 0; i < array_length; i++)
1281 {
1282 ecma_string_t *name_p = ecma_new_ecma_string_from_uint32 (i);
1283
1284 ecma_collection_push_back (main_collection_p, ecma_make_string_value (name_p));
1285 }
1286 } /* ecma_op_typedarray_list_lazy_property_names */
1287
1288 /**
1289 * Define the integer number property value of the typedarray
1290 *
1291 * See also: ES2015 9.4.5.3: 3.c
1292 *
1293 * @return boolean, false if failed
1294 */
1295 bool
ecma_op_typedarray_define_index_prop(ecma_object_t * obj_p,uint32_t index,const ecma_property_descriptor_t * property_desc_p)1296 ecma_op_typedarray_define_index_prop (ecma_object_t *obj_p, /**< a TypedArray object */
1297 uint32_t index, /**< the index number */
1298 const ecma_property_descriptor_t *property_desc_p) /**< the description of
1299 the prop */
1300 {
1301 JERRY_ASSERT (ecma_object_is_typedarray (obj_p));
1302
1303 ecma_length_t array_length = ecma_typedarray_get_length (obj_p);
1304
1305 if ((index >= array_length)
1306 || (property_desc_p->flags & (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED))
1307 || ((property_desc_p->flags & (ECMA_PROP_IS_CONFIGURABLE_DEFINED | ECMA_PROP_IS_CONFIGURABLE))
1308 == (ECMA_PROP_IS_CONFIGURABLE_DEFINED | ECMA_PROP_IS_CONFIGURABLE))
1309 || ((property_desc_p->flags & ECMA_PROP_IS_ENUMERABLE_DEFINED)
1310 && !(property_desc_p->flags & ECMA_PROP_IS_ENUMERABLE))
1311 || ((property_desc_p->flags & ECMA_PROP_IS_WRITABLE_DEFINED)
1312 && !(property_desc_p->flags & ECMA_PROP_IS_WRITABLE)))
1313 {
1314 return false;
1315 }
1316
1317 if (property_desc_p->flags & ECMA_PROP_IS_VALUE_DEFINED)
1318 {
1319 ecma_number_t num_var;
1320 ecma_value_t error = ecma_get_number (property_desc_p->value, &num_var);
1321
1322 if (ECMA_IS_VALUE_ERROR (error))
1323 {
1324 jcontext_release_exception ();
1325 return false;
1326 }
1327 ecma_typedarray_info_t info = ecma_typedarray_get_info (obj_p);
1328
1329 if (index >= info.length)
1330 {
1331 return false;
1332 }
1333
1334 lit_utf8_byte_t *src_buffer = info.buffer_p + (index << info.shift);
1335 ecma_set_typedarray_element (src_buffer, num_var, info.id);
1336 }
1337
1338 return true;
1339 } /* ecma_op_typedarray_define_index_prop */
1340
1341 /**
1342 * Create a typedarray object based on the "type" and arraylength
1343 * The "type" is same with arg1
1344 *
1345 * @return ecma_value_t
1346 */
1347 ecma_value_t
ecma_op_create_typedarray_with_type_and_length(ecma_typedarray_type_t typedarray_id,ecma_length_t array_length)1348 ecma_op_create_typedarray_with_type_and_length (ecma_typedarray_type_t typedarray_id, /** TypedArray id */
1349 ecma_length_t array_length) /**< length of the typedarray */
1350 {
1351 // TODO: assert validate typedarray_id
1352 ecma_object_t *proto_p = ecma_builtin_get (ecma_typedarray_helper_get_prototype_id (typedarray_id));
1353 uint8_t element_size_shift = ecma_typedarray_helper_get_shift_size (typedarray_id);
1354
1355 ecma_value_t new_obj = ecma_typedarray_create_object_with_length (array_length,
1356 NULL,
1357 proto_p,
1358 element_size_shift,
1359 typedarray_id);
1360
1361 return new_obj;
1362 } /* ecma_op_create_typedarray_with_type_and_length */
1363
1364 /**
1365 * Method for getting the additional typedArray informations.
1366 */
1367 ecma_typedarray_info_t
ecma_typedarray_get_info(ecma_object_t * typedarray_p)1368 ecma_typedarray_get_info (ecma_object_t *typedarray_p)
1369 {
1370 ecma_typedarray_info_t info;
1371
1372 info.id = ecma_get_typedarray_id (typedarray_p);
1373 info.length = ecma_typedarray_get_length (typedarray_p);
1374 info.shift = ecma_typedarray_get_element_size_shift (typedarray_p);
1375 info.element_size = (uint8_t) (1 << info.shift);
1376 info.offset = ecma_typedarray_get_offset (typedarray_p);
1377 info.array_buffer_p = ecma_typedarray_get_arraybuffer (typedarray_p);
1378 info.buffer_p = ecma_arraybuffer_get_buffer (info.array_buffer_p) + info.offset;
1379
1380 return info;
1381 } /* ecma_typedarray_get_info */
1382
1383 /**
1384 * @}
1385 * @}
1386 */
1387 #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */
1388