• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-alloc.h"
17 #include "ecma-array-object.h"
18 #include "ecma-iterator-object.h"
19 #include "ecma-builtin-helpers.h"
20 #include "ecma-builtins.h"
21 #include "ecma-exceptions.h"
22 #include "ecma-gc.h"
23 #include "ecma-globals.h"
24 #include "ecma-property-hashmap.h"
25 #include "ecma-helpers.h"
26 #include "ecma-number-arithmetic.h"
27 #include "ecma-objects.h"
28 #include "ecma-objects-general.h"
29 #include "ecma-function-object.h"
30 
31 /** \addtogroup ecma ECMA
32  * @{
33  *
34  * \addtogroup ecmaarrayobject ECMA Array object related routines
35  * @{
36  */
37 
38 #if ENABLED (JERRY_CPOINTER_32_BIT)
39 /**
40  * Maximum length of the array length to allocate fast mode access for it
41  * e.g. new Array(5000) is constructed as fast mode access array,
42  * but new Array(50000000) is consturcted as normal property list based array
43  */
44 #define ECMA_FAST_ARRAY_MAX_INITIAL_LENGTH (1 << 17)
45 #else /* ENABLED (JERRY_CPOINTER_32_BIT) */
46 /**
47  * Maximum length of the array length to allocate fast mode access for it
48  * e.g. new Array(5000) is constructed as fast mode access array,
49  * but new Array(50000000) is consturcted as normal property list based array
50  */
51 #define ECMA_FAST_ARRAY_MAX_INITIAL_LENGTH (1 << 13)
52 #endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
53 
54 /**
55  * Property name type flag for array indices.
56  */
57 #define ECMA_FAST_ARRAY_UINT32_DIRECT_STRING_PROP_TYPE 0x80
58 
59 /**
60  * Property attribute for the array 'length' virtual property to indicate fast access mode array
61  */
62 #define ECMA_FAST_ARRAY_FLAG (ECMA_DIRECT_STRING_MAGIC << ECMA_PROPERTY_NAME_TYPE_SHIFT)
63 
64 /**
65  * Allocate a new array object with the given length
66  *
67  * @return pointer to the constructed array object
68  */
69 ecma_object_t *
ecma_op_new_array_object(ecma_length_t length)70 ecma_op_new_array_object (ecma_length_t length) /**< length of the new array */
71 {
72 #if ENABLED (JERRY_BUILTIN_ARRAY)
73   ecma_object_t *array_prototype_object_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY_PROTOTYPE);
74 #else /* !ENABLED (JERRY_BUILTIN_ARRAY) */
75   ecma_object_t *array_prototype_object_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
76 #endif /* ENABLED (JERRY_BUILTIN_ARRAY) */
77 
78   ecma_object_t *object_p = ecma_create_object (array_prototype_object_p,
79                                                 sizeof (ecma_extended_object_t),
80                                                 ECMA_OBJECT_TYPE_ARRAY);
81 
82   /*
83    * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_ARRAY type.
84    *
85    * See also: ecma_object_get_class_name
86    */
87 
88   ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
89   ext_obj_p->u.array.length = length;
90   ext_obj_p->u.array.u.hole_count = 0;
91   ext_obj_p->u.array.u.length_prop = ECMA_PROPERTY_FLAG_WRITABLE | ECMA_PROPERTY_TYPE_VIRTUAL;
92 
93   return object_p;
94 } /* ecma_op_new_array_object */
95 
96 /**
97  * Check whether the given object is fast-access mode array
98  *
99  * @return true - if the object is fast-access mode array
100  *         false, otherwise
101  */
102 inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_op_object_is_fast_array(ecma_object_t * object_p)103 ecma_op_object_is_fast_array (ecma_object_t *object_p) /**< ecma-object */
104 {
105   return (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY &&
106           ecma_op_array_is_fast_array ((ecma_extended_object_t *) object_p));
107 } /* ecma_op_object_is_fast_array */
108 
109 /**
110  * Check whether the given array object is fast-access mode array
111  *
112  * @return true - if the array object is fast-access mode array
113  *         false, otherwise
114  */
115 inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_op_array_is_fast_array(ecma_extended_object_t * array_p)116 ecma_op_array_is_fast_array (ecma_extended_object_t *array_p) /**< ecma-array-object */
117 {
118   JERRY_ASSERT (ecma_get_object_type ((ecma_object_t *) array_p) == ECMA_OBJECT_TYPE_ARRAY);
119 
120   return array_p->u.array.u.length_prop & ECMA_FAST_ARRAY_FLAG;
121 } /* ecma_op_array_is_fast_array */
122 
123 /**
124  * Allocate a new fast access mode array object with the given length
125  *
126  * @return NULL - if the allocation of the underlying buffer failed
127  *         pointer to the constructed fast access mode array object otherwise
128  */
129 ecma_object_t *
ecma_op_new_fast_array_object(ecma_length_t length)130 ecma_op_new_fast_array_object (ecma_length_t length) /**< length of the new fast access mode array */
131 {
132   const uint32_t aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (length);
133   ecma_value_t *values_p = NULL;
134 
135   if (length != 0)
136   {
137     values_p = (ecma_value_t *) jmem_heap_alloc_block_null_on_error (aligned_length * sizeof (ecma_value_t));
138 
139     if (JERRY_UNLIKELY (values_p == NULL))
140     {
141       return NULL;
142     }
143   }
144 
145   ecma_object_t *object_p = ecma_op_new_array_object (length);
146   ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
147 
148   ext_obj_p->u.array.u.length_prop = (uint8_t) (ext_obj_p->u.array.u.length_prop | ECMA_FAST_ARRAY_FLAG);
149   ext_obj_p->u.array.u.hole_count += length * ECMA_FAST_ARRAY_HOLE_ONE;
150 
151   JERRY_ASSERT (object_p->u1.property_list_cp == JMEM_CP_NULL);
152 
153   for (uint32_t i = 0; i < aligned_length; i++)
154   {
155     values_p[i] = ECMA_VALUE_ARRAY_HOLE;
156   }
157 
158   ECMA_SET_POINTER (object_p->u1.property_list_cp, values_p);
159   return object_p;
160 } /* ecma_op_new_fast_array_object */
161 
162 /**
163  * Converts a fast access mode array back to a normal property list based array
164  */
165 void
ecma_fast_array_convert_to_normal(ecma_object_t * object_p)166 ecma_fast_array_convert_to_normal (ecma_object_t *object_p) /**< fast access mode array object */
167 {
168   JERRY_ASSERT (ecma_op_object_is_fast_array (object_p));
169 
170   ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
171 
172   if (object_p->u1.property_list_cp == JMEM_CP_NULL)
173   {
174     ext_obj_p->u.array.u.length_prop = (uint8_t) (ext_obj_p->u.array.u.length_prop & ~ECMA_FAST_ARRAY_FLAG);
175     return;
176   }
177 
178   uint32_t length = ext_obj_p->u.array.length;
179   const uint32_t aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (length);
180   ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp);
181 
182   ecma_ref_object (object_p);
183 
184   ecma_property_pair_t *property_pair_p = NULL;
185   jmem_cpointer_t next_property_pair_cp = JMEM_CP_NULL;
186 
187   uint32_t prop_index = 1;
188   int32_t index = (int32_t) (length - 1);
189 
190   while (index >= 0)
191   {
192     if (ecma_is_value_array_hole (values_p[index]))
193     {
194       index--;
195       continue;
196     }
197 
198     if (prop_index == 1)
199     {
200       property_pair_p = ecma_alloc_property_pair ();
201       property_pair_p->header.next_property_cp = next_property_pair_cp;
202       property_pair_p->names_cp[0] = LIT_INTERNAL_MAGIC_STRING_DELETED;
203       property_pair_p->header.types[0] = ECMA_PROPERTY_TYPE_DELETED;
204       ECMA_SET_NON_NULL_POINTER (next_property_pair_cp, property_pair_p);
205     }
206 
207     JERRY_ASSERT (index <= ECMA_DIRECT_STRING_MAX_IMM);
208 
209     property_pair_p->names_cp[prop_index] = (jmem_cpointer_t) index;
210     property_pair_p->header.types[prop_index] = (ecma_property_t) (ECMA_PROPERTY_TYPE_NAMEDDATA
211                                                                    | ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE
212                                                                    | ECMA_FAST_ARRAY_UINT32_DIRECT_STRING_PROP_TYPE);
213 
214     property_pair_p->values[prop_index].value = values_p[index];
215 
216     index--;
217     prop_index = !prop_index;
218   }
219 
220   ext_obj_p->u.array.u.length_prop = (uint8_t) (ext_obj_p->u.array.u.length_prop & ~ECMA_FAST_ARRAY_FLAG);
221   jmem_heap_free_block (values_p, aligned_length * sizeof (ecma_value_t));
222   ECMA_SET_POINTER (object_p->u1.property_list_cp, property_pair_p);
223 
224   ecma_deref_object (object_p);
225 } /* ecma_fast_array_convert_to_normal */
226 
227 /**
228  * [[Put]] operation for a fast access mode array
229  *
230  * @return false - If the property name is not array index, or the requested index to be set
231  *                 would result too much array hole in the underlying buffer. The these cases
232  *                 the array is converted back to normal property list based array.
233  *         true - If the indexed property can be set with/without resizing the underlying buffer.
234  */
235 bool
ecma_fast_array_set_property(ecma_object_t * object_p,uint32_t index,ecma_value_t value)236 ecma_fast_array_set_property (ecma_object_t *object_p, /**< fast access mode array object */
237                               uint32_t index, /**< property name index */
238                               ecma_value_t value) /**< value to be set */
239 {
240   JERRY_ASSERT (ecma_op_object_is_fast_array (object_p));
241   ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
242   uint32_t old_length = ext_obj_p->u.array.length;
243 
244   ecma_value_t *values_p;
245 
246   if (JERRY_LIKELY (index < old_length))
247   {
248     JERRY_ASSERT (object_p->u1.property_list_cp != JMEM_CP_NULL);
249 
250     values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp);
251 
252     if (ecma_is_value_array_hole (values_p[index]))
253     {
254       ext_obj_p->u.array.u.hole_count -= ECMA_FAST_ARRAY_HOLE_ONE;
255     }
256     else
257     {
258       ecma_free_value_if_not_object (values_p[index]);
259     }
260 
261     values_p[index] = ecma_copy_value_if_not_object (value);
262 
263     return true;
264   }
265 
266   uint32_t old_holes = ext_obj_p->u.array.u.hole_count;
267   uint32_t new_holes = index - old_length;
268 
269   if (JERRY_UNLIKELY (new_holes > ECMA_FAST_ARRAY_MAX_NEW_HOLES_COUNT
270                       || ((old_holes >> ECMA_FAST_ARRAY_HOLE_SHIFT) + new_holes) > ECMA_FAST_ARRAY_MAX_HOLE_COUNT))
271   {
272     ecma_fast_array_convert_to_normal (object_p);
273 
274     return false;
275   }
276 
277   uint32_t new_length = index + 1;
278 
279   JERRY_ASSERT (new_length < UINT32_MAX);
280 
281   const uint32_t aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (old_length);
282 
283   if (JERRY_LIKELY (index < aligned_length))
284   {
285     JERRY_ASSERT (object_p->u1.property_list_cp != JMEM_CP_NULL);
286 
287     values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp);
288     /* This area is filled with ECMA_VALUE_ARRAY_HOLE, but not counted in u.array.u.hole_count */
289     JERRY_ASSERT (ecma_is_value_array_hole (values_p[index]));
290     ext_obj_p->u.array.u.hole_count += new_holes * ECMA_FAST_ARRAY_HOLE_ONE;
291     ext_obj_p->u.array.length = new_length;
292   }
293   else
294   {
295     values_p = ecma_fast_array_extend (object_p, new_length);
296     ext_obj_p->u.array.u.hole_count -= ECMA_FAST_ARRAY_HOLE_ONE;
297   }
298 
299   values_p[index] = ecma_copy_value_if_not_object (value);
300 
301   return true;
302 } /* ecma_fast_array_set_property */
303 
304 /**
305  * Get the number of array holes in a fast access array object
306  *
307  * @return number of array holes in a fast access array object
308  */
309 inline uint32_t JERRY_ATTR_ALWAYS_INLINE
ecma_fast_array_get_hole_count(ecma_object_t * obj_p)310 ecma_fast_array_get_hole_count (ecma_object_t *obj_p) /**< fast access mode array object */
311 {
312   JERRY_ASSERT (ecma_op_object_is_fast_array (obj_p));
313 
314   return ((ecma_extended_object_t *) obj_p)->u.array.u.hole_count >> ECMA_FAST_ARRAY_HOLE_SHIFT;
315 } /* ecma_fast_array_get_hole_count */
316 
317 /**
318  * Extend the underlying buffer of a fast mode access array for the given new length
319  *
320  * @return pointer to the extended underlying buffer
321  */
322 ecma_value_t *
ecma_fast_array_extend(ecma_object_t * object_p,uint32_t new_length)323 ecma_fast_array_extend (ecma_object_t *object_p, /**< fast access mode array object */
324                         uint32_t new_length) /**< new length of the fast access mode array */
325 {
326   JERRY_ASSERT (ecma_op_object_is_fast_array (object_p));
327   ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
328   uint32_t old_length = ext_obj_p->u.array.length;
329 
330   JERRY_ASSERT (old_length < new_length);
331 
332   ecma_ref_object (object_p);
333 
334   ecma_value_t *new_values_p;
335   const uint32_t old_length_aligned = ECMA_FAST_ARRAY_ALIGN_LENGTH (old_length);
336   const uint32_t new_length_aligned = ECMA_FAST_ARRAY_ALIGN_LENGTH (new_length);
337 
338   if (object_p->u1.property_list_cp == JMEM_CP_NULL)
339   {
340     new_values_p = jmem_heap_alloc_block (new_length_aligned * sizeof (ecma_value_t));
341   }
342   else
343   {
344     ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp);
345     new_values_p = (ecma_value_t *) jmem_heap_realloc_block (values_p,
346                                                              old_length_aligned * sizeof (ecma_value_t),
347                                                              new_length_aligned * sizeof (ecma_value_t));
348   }
349 
350   for (uint32_t i = old_length; i < new_length_aligned; i++)
351   {
352     new_values_p[i] = ECMA_VALUE_ARRAY_HOLE;
353   }
354 
355   ext_obj_p->u.array.u.hole_count += (new_length - old_length) * ECMA_FAST_ARRAY_HOLE_ONE;
356   ext_obj_p->u.array.length = new_length;
357 
358   ECMA_SET_NON_NULL_POINTER (object_p->u1.property_list_cp, new_values_p);
359 
360   ecma_deref_object (object_p);
361   return new_values_p;
362 } /* ecma_fast_array_extend */
363 
364 /**
365  * Delete the array object's property referenced by its value pointer.
366  *
367  * Note: specified property must be owned by specified object.
368  */
369 void
ecma_array_object_delete_property(ecma_object_t * object_p,ecma_string_t * property_name_p,ecma_property_value_t * prop_value_p)370 ecma_array_object_delete_property (ecma_object_t *object_p, /**< object */
371                                    ecma_string_t *property_name_p, /**< property name */
372                                    ecma_property_value_t *prop_value_p) /**< property value reference */
373 {
374   JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY);
375   ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
376 
377   if (!ecma_op_object_is_fast_array (object_p))
378   {
379     ecma_delete_property (object_p, prop_value_p);
380     return;
381   }
382 
383   JERRY_ASSERT (object_p->u1.property_list_cp != JMEM_CP_NULL);
384 
385   uint32_t index = ecma_string_get_array_index (property_name_p);
386 
387   JERRY_ASSERT (index != ECMA_STRING_NOT_ARRAY_INDEX);
388   JERRY_ASSERT (index < ext_obj_p->u.array.length);
389 
390   ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp);
391 
392   if (ecma_is_value_array_hole (values_p[index]))
393   {
394     return;
395   }
396 
397   ecma_free_value_if_not_object (values_p[index]);
398 
399   values_p[index] = ECMA_VALUE_ARRAY_HOLE;
400   ext_obj_p->u.array.u.hole_count += ECMA_FAST_ARRAY_HOLE_ONE;
401 } /* ecma_array_object_delete_property */
402 
403 /**
404  * Low level delete of fast access mode array items
405  *
406  * @return the updated value of new_length
407  */
408 uint32_t
ecma_delete_fast_array_properties(ecma_object_t * object_p,uint32_t new_length)409 ecma_delete_fast_array_properties (ecma_object_t *object_p, /**< fast access mode array */
410                                    uint32_t new_length) /**< new length of the fast access mode array */
411 {
412   JERRY_ASSERT (ecma_op_object_is_fast_array (object_p));
413 
414   ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
415 
416   ecma_ref_object (object_p);
417   ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp);
418 
419   uint32_t old_length = ext_obj_p->u.array.length;
420   const uint32_t old_aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (old_length);
421   JERRY_ASSERT (new_length < old_length);
422 
423   for (uint32_t i = new_length; i < old_length; i++)
424   {
425     if (ecma_is_value_array_hole (values_p[i]))
426     {
427       ext_obj_p->u.array.u.hole_count -= ECMA_FAST_ARRAY_HOLE_ONE;
428     }
429     else
430     {
431       ecma_free_value_if_not_object (values_p[i]);
432     }
433   }
434 
435   jmem_cpointer_t new_property_list_cp;
436 
437   if (new_length == 0)
438   {
439     jmem_heap_free_block (values_p, old_aligned_length * sizeof (ecma_value_t));
440     new_property_list_cp = JMEM_CP_NULL;
441   }
442   else
443   {
444     const uint32_t new_aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (new_length);
445 
446     ecma_value_t *new_values_p;
447     new_values_p = (ecma_value_t *) jmem_heap_realloc_block (values_p,
448                                                              old_aligned_length * sizeof (ecma_value_t),
449                                                              new_aligned_length * sizeof (ecma_value_t));
450 
451     for (uint32_t i = new_length; i < new_aligned_length; i++)
452     {
453       new_values_p[i] = ECMA_VALUE_ARRAY_HOLE;
454     }
455 
456     ECMA_SET_NON_NULL_POINTER (new_property_list_cp, new_values_p);
457   }
458 
459   ext_obj_p->u.array.length = new_length;
460   object_p->u1.property_list_cp = new_property_list_cp;
461 
462   ecma_deref_object (object_p);
463 
464   return new_length;
465 } /* ecma_delete_fast_array_properties */
466 
467 /**
468  * Update the length of a fast access mode array to a new length
469  *
470  * Note: if the new length would result too much array hole in the underlying arraybuffer
471  *       the array is converted back to normal property list based array
472  */
473 static void
ecma_fast_array_set_length(ecma_object_t * object_p,uint32_t new_length)474 ecma_fast_array_set_length (ecma_object_t *object_p, /**< fast access mode array object */
475                             uint32_t new_length) /**< new length of the fast access mode array object*/
476 {
477   JERRY_ASSERT (ecma_op_object_is_fast_array (object_p));
478 
479   ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
480   uint32_t old_length = ext_obj_p->u.array.length;
481 
482   JERRY_ASSERT (new_length >= old_length);
483 
484   if (new_length == old_length)
485   {
486     return;
487   }
488 
489   uint32_t old_holes = ext_obj_p->u.array.u.hole_count;
490   uint32_t new_holes = new_length - old_length;
491 
492   if (JERRY_UNLIKELY (new_holes > ECMA_FAST_ARRAY_MAX_NEW_HOLES_COUNT
493                       || ((old_holes >> ECMA_FAST_ARRAY_HOLE_SHIFT) + new_holes) > ECMA_FAST_ARRAY_MAX_HOLE_COUNT))
494   {
495     ecma_fast_array_convert_to_normal (object_p);
496   }
497   else
498   {
499     ecma_fast_array_extend (object_p, new_length);
500   }
501 
502   return;
503 } /* ecma_fast_array_set_length */
504 
505 /**
506  * Get collection of property names of a fast access mode array object
507  *
508  * Note: Since the fast array object only contains indexed, enumerable, writable, configurable properties
509  *       we can return a collection of non-array hole array indices
510  *
511  * @return collection of strings - property names
512  */
513 ecma_collection_t *
ecma_fast_array_get_property_names(ecma_object_t * object_p,uint32_t opts)514 ecma_fast_array_get_property_names (ecma_object_t *object_p, /**< fast access mode array object */
515                                     uint32_t opts) /**< any combination of ecma_list_properties_options_t values */
516 {
517   JERRY_ASSERT (ecma_op_object_is_fast_array (object_p));
518 
519   ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
520   ecma_collection_t *ret_p = ecma_new_collection ();
521 
522 #if ENABLED (JERRY_ES2015)
523   if (opts & ECMA_LIST_SYMBOLS_ONLY)
524   {
525     return ret_p;
526   }
527 #endif /* ENABLED (JERRY_ES2015) */
528 
529   uint32_t length = ext_obj_p->u.array.length;
530 
531   bool append_length = (!(opts & ECMA_LIST_ENUMERABLE) && !(opts & ECMA_LIST_ARRAY_INDICES));
532 
533   if (length == 0)
534   {
535     if (append_length)
536     {
537       ecma_collection_push_back (ret_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH));
538     }
539 
540     return ret_p;
541   }
542 
543   ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp);
544 
545   for (uint32_t i = 0; i < length; i++)
546   {
547     if (ecma_is_value_array_hole (values_p[i]))
548     {
549       continue;
550     }
551 
552     ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (i);
553 
554     ecma_collection_push_back (ret_p, ecma_make_string_value (index_str_p));
555   }
556 
557   if (append_length)
558   {
559     ecma_collection_push_back (ret_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH));
560   }
561 
562   if (opts & ECMA_LIST_CONVERT_FAST_ARRAYS)
563   {
564     ecma_fast_array_convert_to_normal (object_p);
565   }
566 
567   return ret_p;
568 } /* ecma_fast_array_get_property_names */
569 
570 /**
571  * Array object creation operation.
572  *
573  * See also: ECMA-262 v5, 15.4.2.1
574  *           ECMA-262 v5, 15.4.2.2
575  *
576  * @return ecma value
577  *         Returned value must be freed with ecma_free_value
578  */
579 ecma_value_t
ecma_op_create_array_object(const ecma_value_t * arguments_list_p,ecma_length_t arguments_list_len,bool is_treat_single_arg_as_length)580 ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of arguments that
581                                                                     *   are passed to Array constructor */
582                              ecma_length_t arguments_list_len, /**< length of the arguments' list */
583                              bool is_treat_single_arg_as_length) /**< if the value is true,
584                                                                   *   arguments_list_len is 1
585                                                                   *   and single argument is Number,
586                                                                   *   then treat the single argument
587                                                                   *   as new Array's length rather
588                                                                   *   than as single item of the Array */
589 {
590   JERRY_ASSERT (arguments_list_len == 0
591                 || arguments_list_p != NULL);
592 
593   uint32_t length;
594   const ecma_value_t *array_items_p;
595   ecma_length_t array_items_count;
596 
597   if (is_treat_single_arg_as_length
598       && arguments_list_len == 1
599       && ecma_is_value_number (arguments_list_p[0]))
600   {
601     ecma_number_t num = ecma_get_number_from_value (arguments_list_p[0]);
602     uint32_t num_uint32 = ecma_number_to_uint32 (num);
603 
604     if (num != ((ecma_number_t) num_uint32))
605     {
606       return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid array length."));
607     }
608     else
609     {
610       length = num_uint32;
611       array_items_p = NULL;
612       array_items_count = 0;
613     }
614 
615     if (length > ECMA_FAST_ARRAY_MAX_INITIAL_LENGTH)
616     {
617       return ecma_make_object_value (ecma_op_new_array_object (length));
618     }
619 
620     ecma_object_t *object_p = ecma_op_new_fast_array_object (length);
621 
622     if (object_p == NULL)
623     {
624       return ecma_make_object_value (ecma_op_new_array_object (length));
625     }
626 
627     JERRY_ASSERT (ecma_op_object_is_fast_array (object_p));
628 
629     return ecma_make_object_value (object_p);
630   }
631   else
632   {
633     length = arguments_list_len;
634     array_items_p = arguments_list_p;
635     array_items_count = arguments_list_len;
636   }
637 
638   ecma_object_t *object_p = ecma_op_new_fast_array_object (length);
639 
640   /* At this point we were not able to allocate a length * sizeof (ecma_value_t) amount of memory,
641      so we can terminate the engine since converting it into normal property list based array
642      would consume more memory. */
643   if (object_p == NULL)
644   {
645     jerry_fatal (ERR_OUT_OF_MEMORY);
646   }
647 
648   if (length == 0)
649   {
650     return ecma_make_object_value (object_p);
651   }
652 
653   ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp);
654   ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
655 
656   for (uint32_t index = 0;
657        index < array_items_count;
658        index++)
659   {
660     JERRY_ASSERT (!ecma_is_value_array_hole (array_items_p[index]));
661     values_p[index] = ecma_copy_value_if_not_object (array_items_p[index]);
662   }
663 
664   ext_obj_p->u.array.u.hole_count -= ECMA_FAST_ARRAY_HOLE_ONE * array_items_count;
665 
666   return ecma_make_object_value (object_p);
667 } /* ecma_op_create_array_object */
668 
669 #if ENABLED (JERRY_ES2015)
670 /**
671  * Array object creation with custom prototype.
672  *
673  * See also: ECMA-262 v6, 9.4.2.3
674  *
675  * @return ecma value
676  *         Returned value must be freed with ecma_free_value
677  */
678 ecma_value_t
ecma_op_array_species_create(ecma_object_t * original_array_p,ecma_length_t length)679 ecma_op_array_species_create (ecma_object_t *original_array_p, /**< The object from whom the new array object
680                                                                 *   is being created */
681                               ecma_length_t length) /**< length of the array */
682 {
683   ecma_value_t constructor = ECMA_VALUE_UNDEFINED;
684   ecma_value_t original_array = ecma_make_object_value (original_array_p);
685 
686   ecma_value_t is_array = ecma_is_value_array (original_array);
687 
688   if (ECMA_IS_VALUE_ERROR (is_array))
689   {
690     return is_array;
691   }
692 
693   if (ecma_is_value_true (is_array))
694   {
695     constructor = ecma_op_object_get_by_magic_id (original_array_p, LIT_MAGIC_STRING_CONSTRUCTOR);
696     if (ECMA_IS_VALUE_ERROR (constructor))
697     {
698       return constructor;
699     }
700 
701     if (ecma_is_constructor (constructor)
702         && ecma_get_object_from_value (constructor) == ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY))
703     {
704       ecma_free_value (constructor);
705       constructor = ECMA_VALUE_UNDEFINED;
706     }
707     else if (ecma_is_value_object (constructor))
708     {
709       ecma_object_t *ctor_object_p = ecma_get_object_from_value (constructor);
710       constructor = ecma_op_object_get_by_symbol_id (ctor_object_p, LIT_GLOBAL_SYMBOL_SPECIES);
711       ecma_deref_object (ctor_object_p);
712 
713       if (ECMA_IS_VALUE_ERROR (constructor))
714       {
715         return constructor;
716       }
717 
718       if (ecma_is_value_null (constructor))
719       {
720         constructor = ECMA_VALUE_UNDEFINED;
721       }
722     }
723   }
724 
725   if (ecma_is_value_undefined (constructor))
726   {
727     ecma_value_t length_val = ecma_make_uint32_value (length);
728     ecma_value_t new_array = ecma_op_create_array_object (&length_val, 1, true);
729     ecma_free_value (length_val);
730 
731     return new_array;
732   }
733 
734   if (!ecma_is_constructor (constructor))
735   {
736     ecma_free_value (constructor);
737     return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid species constructor"));
738   }
739 
740   ecma_value_t len_val = ecma_make_uint32_value (length);
741   ecma_object_t *ctor_object_p = ecma_get_object_from_value (constructor);
742   ecma_value_t ret_val = ecma_op_function_construct (ctor_object_p,
743                                                      ctor_object_p,
744                                                      &len_val,
745                                                      1);
746 
747   ecma_deref_object (ctor_object_p);
748   ecma_free_value (len_val);
749   return ret_val;
750 } /* ecma_op_array_species_create */
751 
752 /**
753  * CreateArrayIterator Abstract Operation
754  *
755  * See also:
756  *          ECMA-262 v6, 22.1.5.1
757  *
758  * Referenced by:
759  *          ECMA-262 v6, 22.1.3.4
760  *          ECMA-262 v6, 22.1.3.13
761  *          ECMA-262 v6, 22.1.3.29
762  *          ECMA-262 v6, 22.1.3.30
763  *
764  * Note:
765  *      Returned value must be freed with ecma_free_value.
766  *
767  * @return array iterator object
768  */
769 ecma_value_t
ecma_op_create_array_iterator(ecma_object_t * obj_p,ecma_array_iterator_type_t type)770 ecma_op_create_array_iterator (ecma_object_t *obj_p, /**< array object */
771                                ecma_array_iterator_type_t type) /**< array iterator type */
772 {
773   ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY_ITERATOR_PROTOTYPE);
774 
775   return ecma_op_create_iterator_object (ecma_make_object_value (obj_p),
776                                          prototype_obj_p,
777                                          ECMA_PSEUDO_ARRAY_ITERATOR,
778                                          (uint8_t) type);
779 } /* ecma_op_create_array_iterator */
780 #endif /* ENABLED (JERRY_ES2015) */
781 
782 /**
783  * Low level delete of array items from new_length to old_length
784  *
785  * Note: new_length must be less than old_length
786  *
787  * @return the updated value of new_length
788  */
789 static uint32_t
ecma_delete_array_properties(ecma_object_t * object_p,uint32_t new_length,uint32_t old_length)790 ecma_delete_array_properties (ecma_object_t *object_p, /**< object */
791                               uint32_t new_length, /**< new length */
792                               uint32_t old_length) /**< old length */
793 {
794   JERRY_ASSERT (new_length < old_length);
795   JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY);
796 
797   if (ecma_op_object_is_fast_array (object_p))
798   {
799     return ecma_delete_fast_array_properties (object_p, new_length);
800   }
801 
802   /* First the minimum value of new_length is updated. */
803   jmem_cpointer_t current_prop_cp = object_p->u1.property_list_cp;
804 
805   if (current_prop_cp == JMEM_CP_NULL)
806   {
807     return new_length;
808   }
809 
810   ecma_property_header_t *current_prop_p;
811 
812 #if ENABLED (JERRY_PROPRETY_HASHMAP)
813   current_prop_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, current_prop_cp);
814 
815   if (current_prop_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP)
816   {
817     current_prop_cp = current_prop_p->next_property_cp;
818   }
819 #endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
820 
821   while (current_prop_cp != JMEM_CP_NULL)
822   {
823     current_prop_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, current_prop_cp);
824     JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (current_prop_p));
825 
826     ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) current_prop_p;
827 
828     for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
829     {
830       if (ECMA_PROPERTY_IS_NAMED_PROPERTY (current_prop_p->types[i])
831           && !ecma_is_property_configurable (current_prop_p->types[i]))
832       {
833         uint32_t index = ecma_string_get_property_index (current_prop_p->types[i],
834                                                          prop_pair_p->names_cp[i]);
835 
836         if (index < old_length && index >= new_length)
837         {
838           JERRY_ASSERT (index != ECMA_STRING_NOT_ARRAY_INDEX);
839 
840           new_length = index + 1;
841 
842           if (new_length == old_length)
843           {
844             /* Early return. */
845             return new_length;
846           }
847         }
848       }
849     }
850 
851     current_prop_cp = current_prop_p->next_property_cp;
852   }
853 
854   /* Second all properties between new_length and old_length are deleted. */
855   current_prop_cp = object_p->u1.property_list_cp;
856   ecma_property_header_t *prev_prop_p = NULL;
857 
858 #if ENABLED (JERRY_PROPRETY_HASHMAP)
859   JERRY_ASSERT (current_prop_cp != JMEM_CP_NULL);
860 
861   ecma_property_hashmap_delete_status hashmap_status = ECMA_PROPERTY_HASHMAP_DELETE_NO_HASHMAP;
862   current_prop_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, current_prop_cp);
863 
864   if (current_prop_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP)
865   {
866     prev_prop_p = current_prop_p;
867     current_prop_cp = current_prop_p->next_property_cp;
868     hashmap_status = ECMA_PROPERTY_HASHMAP_DELETE_HAS_HASHMAP;
869   }
870 #endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
871 
872   while (current_prop_cp != JMEM_CP_NULL)
873   {
874     current_prop_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, current_prop_cp);
875 
876     JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (current_prop_p));
877     ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) current_prop_p;
878 
879     for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
880     {
881       if (ECMA_PROPERTY_IS_NAMED_PROPERTY (current_prop_p->types[i])
882           && ecma_is_property_configurable (current_prop_p->types[i]))
883       {
884         uint32_t index = ecma_string_get_property_index (current_prop_p->types[i],
885                                                          prop_pair_p->names_cp[i]);
886 
887         if (index < old_length && index >= new_length)
888         {
889           JERRY_ASSERT (index != ECMA_STRING_NOT_ARRAY_INDEX);
890 
891 #if ENABLED (JERRY_PROPRETY_HASHMAP)
892           if (hashmap_status == ECMA_PROPERTY_HASHMAP_DELETE_HAS_HASHMAP)
893           {
894             hashmap_status = ecma_property_hashmap_delete (object_p,
895                                                            prop_pair_p->names_cp[i],
896                                                            current_prop_p->types + i);
897           }
898 #endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
899 
900           ecma_free_property (object_p, prop_pair_p->names_cp[i], current_prop_p->types + i);
901           current_prop_p->types[i] = ECMA_PROPERTY_TYPE_DELETED;
902           prop_pair_p->names_cp[i] = LIT_INTERNAL_MAGIC_STRING_DELETED;
903         }
904       }
905     }
906 
907     if (current_prop_p->types[0] == ECMA_PROPERTY_TYPE_DELETED
908         && current_prop_p->types[1] == ECMA_PROPERTY_TYPE_DELETED)
909     {
910       if (prev_prop_p == NULL)
911       {
912         object_p->u1.property_list_cp = current_prop_p->next_property_cp;
913       }
914       else
915       {
916         prev_prop_p->next_property_cp = current_prop_p->next_property_cp;
917       }
918 
919       jmem_cpointer_t next_prop_cp = current_prop_p->next_property_cp;
920       ecma_dealloc_property_pair ((ecma_property_pair_t *) current_prop_p);
921       current_prop_cp = next_prop_cp;
922     }
923     else
924     {
925       prev_prop_p = current_prop_p;
926       current_prop_cp = current_prop_p->next_property_cp;
927     }
928   }
929 
930 #if ENABLED (JERRY_PROPRETY_HASHMAP)
931   if (hashmap_status == ECMA_PROPERTY_HASHMAP_DELETE_RECREATE_HASHMAP)
932   {
933     ecma_property_hashmap_free (object_p);
934     ecma_property_hashmap_create (object_p);
935   }
936 #endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
937 
938   return new_length;
939 } /* ecma_delete_array_properties */
940 
941 /**
942  * Update the length of an array to a new length
943  *
944  * @return ecma value
945  *         Returned value must be freed with ecma_free_value
946  */
947 ecma_value_t
ecma_op_array_object_set_length(ecma_object_t * object_p,ecma_value_t new_value,uint32_t flags)948 ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object */
949                                  ecma_value_t new_value, /**< new length value */
950                                  uint32_t flags) /**< configuration options */
951 {
952   bool is_throw = (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_IS_THROW);
953 
954   ecma_value_t completion = ecma_op_to_number (new_value);
955 
956   if (ECMA_IS_VALUE_ERROR (completion))
957   {
958     return completion;
959   }
960 
961   JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (completion)
962                 && ecma_is_value_number (completion));
963 
964   ecma_number_t new_len_num = ecma_get_number_from_value (completion);
965 
966   ecma_free_value (completion);
967 
968   if (ecma_is_value_object (new_value))
969   {
970     ecma_value_t compared_num_val = ecma_op_to_number (new_value);
971 
972     if (ECMA_IS_VALUE_ERROR (compared_num_val))
973     {
974       return compared_num_val;
975     }
976 
977     new_len_num = ecma_get_number_from_value (compared_num_val);
978     ecma_free_value (compared_num_val);
979   }
980 
981   uint32_t new_len_uint32 = ecma_number_to_uint32 (new_len_num);
982 
983   if (((ecma_number_t) new_len_uint32) != new_len_num)
984   {
985     return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid array length."));
986   }
987 
988   if (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_REJECT)
989   {
990     return ecma_reject (is_throw);
991   }
992 
993   ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
994 
995   uint32_t old_len_uint32 = ext_object_p->u.array.length;
996 
997   if (new_len_num == old_len_uint32)
998   {
999     /* Only the writable flag must be updated. */
1000     if (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED)
1001     {
1002       if (!(flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE))
1003       {
1004         uint8_t new_prop_value = (uint8_t) (ext_object_p->u.array.u.length_prop & ~ECMA_PROPERTY_FLAG_WRITABLE);
1005         ext_object_p->u.array.u.length_prop = new_prop_value;
1006       }
1007       else if (!ecma_is_property_writable (ext_object_p->u.array.u.length_prop))
1008       {
1009         return ecma_reject (is_throw);
1010       }
1011     }
1012     return ECMA_VALUE_TRUE;
1013   }
1014   else if (!ecma_is_property_writable (ext_object_p->u.array.u.length_prop))
1015   {
1016     return ecma_reject (is_throw);
1017   }
1018 
1019   uint32_t current_len_uint32 = new_len_uint32;
1020 
1021   if (new_len_uint32 < old_len_uint32)
1022   {
1023     current_len_uint32 = ecma_delete_array_properties (object_p, new_len_uint32, old_len_uint32);
1024   }
1025   else if (ecma_op_object_is_fast_array (object_p))
1026   {
1027     ecma_fast_array_set_length (object_p, new_len_uint32);
1028   }
1029 
1030   ext_object_p->u.array.length = current_len_uint32;
1031 
1032   if ((flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED)
1033       && !(flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE))
1034   {
1035     uint8_t new_prop_value = (uint8_t) (ext_object_p->u.array.u.length_prop & ~ECMA_PROPERTY_FLAG_WRITABLE);
1036     ext_object_p->u.array.u.length_prop = new_prop_value;
1037   }
1038 
1039   if (current_len_uint32 == new_len_uint32)
1040   {
1041     return ECMA_VALUE_TRUE;
1042   }
1043   return ecma_reject (is_throw);
1044 } /* ecma_op_array_object_set_length */
1045 
1046 /**
1047  * Property descriptor bitset for fast array data properties.
1048  * If the property desciptor fields contains all the flags below
1049  * attempt to stay fast access array during [[DefineOwnProperty]] operation.
1050  */
1051 #define ECMA_FAST_ARRAY_DATA_PROP_FLAGS (ECMA_PROP_IS_VALUE_DEFINED \
1052                                          | ECMA_PROP_IS_ENUMERABLE_DEFINED \
1053                                          | ECMA_PROP_IS_ENUMERABLE \
1054                                          | ECMA_PROP_IS_CONFIGURABLE_DEFINED \
1055                                          | ECMA_PROP_IS_CONFIGURABLE \
1056                                          | ECMA_PROP_IS_WRITABLE_DEFINED \
1057                                          | ECMA_PROP_IS_WRITABLE)
1058 
1059 /**
1060  * [[DefineOwnProperty]] ecma array object's operation
1061  *
1062  * See also:
1063  *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
1064  *          ECMA-262 v5, 15.4.5.1
1065  *
1066  * @return ecma value
1067  *         Returned value must be freed with ecma_free_value
1068  */
1069 ecma_value_t
ecma_op_array_object_define_own_property(ecma_object_t * object_p,ecma_string_t * property_name_p,const ecma_property_descriptor_t * property_desc_p)1070 ecma_op_array_object_define_own_property (ecma_object_t *object_p, /**< the array object */
1071                                           ecma_string_t *property_name_p, /**< property name */
1072                                           const ecma_property_descriptor_t *property_desc_p) /**< property descriptor */
1073 {
1074   if (ecma_string_is_length (property_name_p))
1075   {
1076     JERRY_ASSERT ((property_desc_p->flags & ECMA_PROP_IS_CONFIGURABLE_DEFINED)
1077                   || !(property_desc_p->flags & ECMA_PROP_IS_CONFIGURABLE));
1078     JERRY_ASSERT ((property_desc_p->flags & ECMA_PROP_IS_ENUMERABLE_DEFINED)
1079                   || !(property_desc_p->flags & ECMA_PROP_IS_ENUMERABLE));
1080     JERRY_ASSERT ((property_desc_p->flags & ECMA_PROP_IS_WRITABLE_DEFINED)
1081                   || !(property_desc_p->flags & ECMA_PROP_IS_WRITABLE));
1082 
1083     uint32_t flags = 0;
1084 
1085     if (property_desc_p->flags & ECMA_PROP_IS_THROW)
1086     {
1087       flags |= ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_IS_THROW;
1088     }
1089 
1090     /* Only the writable and data properties can be modified. */
1091     if (property_desc_p->flags & (ECMA_PROP_IS_CONFIGURABLE
1092                                   | ECMA_PROP_IS_ENUMERABLE
1093                                   | ECMA_PROP_IS_GET_DEFINED
1094                                   | ECMA_PROP_IS_SET_DEFINED))
1095     {
1096       flags |= ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_REJECT;
1097     }
1098 
1099     if (property_desc_p->flags & ECMA_PROP_IS_WRITABLE_DEFINED)
1100     {
1101       flags |= ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED;
1102     }
1103 
1104     if (property_desc_p->flags & ECMA_PROP_IS_WRITABLE)
1105     {
1106       flags |= ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE;
1107     }
1108 
1109     if (property_desc_p->flags & ECMA_PROP_IS_VALUE_DEFINED)
1110     {
1111       return ecma_op_array_object_set_length (object_p, property_desc_p->value, flags);
1112     }
1113 
1114     ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
1115     ecma_value_t length_value = ecma_make_uint32_value (ext_object_p->u.array.length);
1116 
1117     ecma_value_t result = ecma_op_array_object_set_length (object_p, length_value, flags);
1118 
1119     ecma_fast_free_value (length_value);
1120     return result;
1121   }
1122 
1123   ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
1124 
1125   if (ecma_op_object_is_fast_array (object_p))
1126   {
1127     if ((property_desc_p->flags & ECMA_FAST_ARRAY_DATA_PROP_FLAGS) == ECMA_FAST_ARRAY_DATA_PROP_FLAGS)
1128     {
1129       uint32_t index = ecma_string_get_array_index (property_name_p);
1130 
1131       if (JERRY_UNLIKELY (index == ECMA_STRING_NOT_ARRAY_INDEX))
1132       {
1133         ecma_fast_array_convert_to_normal (object_p);
1134       }
1135       else if (ecma_fast_array_set_property (object_p, index, property_desc_p->value))
1136       {
1137         return ECMA_VALUE_TRUE;
1138       }
1139 
1140       JERRY_ASSERT (!ecma_op_array_is_fast_array (ext_object_p));
1141     }
1142     else
1143     {
1144       ecma_fast_array_convert_to_normal (object_p);
1145     }
1146   }
1147 
1148   JERRY_ASSERT (!ecma_op_object_is_fast_array (object_p));
1149   uint32_t index = ecma_string_get_array_index (property_name_p);
1150 
1151   if (index == ECMA_STRING_NOT_ARRAY_INDEX)
1152   {
1153     return ecma_op_general_object_define_own_property (object_p, property_name_p, property_desc_p);
1154   }
1155 
1156   bool update_length = (index >= ext_object_p->u.array.length);
1157 
1158   if (update_length && !ecma_is_property_writable (ext_object_p->u.array.u.length_prop))
1159   {
1160     return ecma_reject (property_desc_p->flags & ECMA_PROP_IS_THROW);
1161   }
1162 
1163   ecma_property_descriptor_t prop_desc;
1164 
1165   prop_desc = *property_desc_p;
1166   prop_desc.flags &= (uint16_t) ~ECMA_PROP_IS_THROW;
1167 
1168   ecma_value_t completition = ecma_op_general_object_define_own_property (object_p,
1169                                                                           property_name_p,
1170                                                                           &prop_desc);
1171   JERRY_ASSERT (ecma_is_value_boolean (completition));
1172 
1173   if (ecma_is_value_false (completition))
1174   {
1175     return ecma_reject (property_desc_p->flags & ECMA_PROP_IS_THROW);
1176   }
1177 
1178   if (update_length)
1179   {
1180     ext_object_p->u.array.length = index + 1;
1181   }
1182 
1183   return ECMA_VALUE_TRUE;
1184 } /* ecma_op_array_object_define_own_property */
1185 
1186 /**
1187  * Get the length of the an array object
1188  *
1189  * @return the array length
1190  */
1191 extern inline uint32_t JERRY_ATTR_ALWAYS_INLINE
ecma_array_get_length(ecma_object_t * array_p)1192 ecma_array_get_length (ecma_object_t *array_p) /**< array object */
1193 {
1194   JERRY_ASSERT (ecma_get_object_type (array_p) == ECMA_OBJECT_TYPE_ARRAY);
1195 
1196   return ((ecma_extended_object_t *) array_p)->u.array.length;
1197 } /* ecma_array_get_length */
1198 
1199 /**
1200  * List names of a String object's lazy instantiated properties
1201  *
1202  * @return string values collection
1203  */
1204 void
ecma_op_array_list_lazy_property_names(ecma_object_t * obj_p,uint32_t opts,ecma_collection_t * main_collection_p,ecma_collection_t * non_enum_collection_p)1205 ecma_op_array_list_lazy_property_names (ecma_object_t *obj_p, /**< a String object */
1206                                         uint32_t opts, /**< listing options using flags
1207                                                         *   from ecma_list_properties_options_t */
1208                                         ecma_collection_t *main_collection_p, /**< 'main'  collection */
1209                                         ecma_collection_t *non_enum_collection_p) /**< skipped
1210                                                                                    *   'non-enumerable'
1211                                                                                    *   collection */
1212 {
1213   JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY);
1214 
1215   ecma_collection_t *for_non_enumerable_p = (opts & ECMA_LIST_ENUMERABLE) ? non_enum_collection_p : main_collection_p;
1216 
1217   if ((opts & ECMA_LIST_ARRAY_INDICES) == 0)
1218   {
1219     ecma_collection_push_back (for_non_enumerable_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH));
1220   }
1221 } /* ecma_op_array_list_lazy_property_names */
1222 
1223 /**
1224  * @}
1225  * @}
1226  */
1227