• 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-builtins.h"
18 #include "ecma-builtin-helpers.h"
19 #include "ecma-conversion.h"
20 #include "ecma-exceptions.h"
21 #include "ecma-function-object.h"
22 #include "ecma-gc.h"
23 #include "ecma-globals.h"
24 #include "ecma-helpers.h"
25 #include "ecma-iterator-object.h"
26 #include "ecma-objects.h"
27 #include "ecma-array-object.h"
28 #include "jcontext.h"
29 #include "jrt.h"
30 
31 #if ENABLED (JERRY_BUILTIN_ARRAY)
32 
33 #define ECMA_BUILTINS_INTERNAL
34 #include "ecma-builtins-internal.h"
35 
36 #define BUILTIN_INC_HEADER_NAME "ecma-builtin-array.inc.h"
37 #define BUILTIN_UNDERSCORED_ID array
38 #include "ecma-builtin-internal-routines-template.inc.h"
39 
40 /** \addtogroup ecma ECMA
41  * @{
42  *
43  * \addtogroup ecmabuiltins
44  * @{
45  *
46  * \addtogroup array ECMA Array object built-in
47  * @{
48  */
49 
50 /**
51  * The Array object's 'isArray' routine
52  *
53  * See also:
54  *          ECMA-262 v5, 15.4.3.2
55  *
56  * @return ecma value
57  *         Returned value must be freed with ecma_free_value.
58  */
59 static ecma_value_t
ecma_builtin_array_object_is_array(ecma_value_t this_arg,ecma_value_t arg)60 ecma_builtin_array_object_is_array (ecma_value_t this_arg, /**< 'this' argument */
61                                     ecma_value_t arg) /**< first argument */
62 {
63   JERRY_UNUSED (this_arg);
64 
65   return ecma_is_value_array (arg);
66 } /* ecma_builtin_array_object_is_array */
67 
68 #if ENABLED (JERRY_ES2015)
69 /**
70  * The Array object's 'from' routine
71  *
72  * See also:
73  *          ECMA-262 v6, 22.1.2.1
74  *
75  * @return ecma value
76  *         Returned value must be freed with ecma_free_value.
77  */
78 static ecma_value_t
ecma_builtin_array_object_from(ecma_value_t this_arg,const ecma_value_t * arguments_list_p,ecma_length_t arguments_list_len)79 ecma_builtin_array_object_from (ecma_value_t this_arg, /**< 'this' argument */
80                                 const ecma_value_t *arguments_list_p, /**< arguments list */
81                                 ecma_length_t arguments_list_len) /**< number of arguments */
82 {
83   /* 1. */
84   ecma_value_t constructor = this_arg;
85   ecma_value_t call_this_arg = ECMA_VALUE_UNDEFINED;
86   ecma_value_t items = arguments_list_p[0];
87   ecma_value_t mapfn = (arguments_list_len > 1) ? arguments_list_p[1] : ECMA_VALUE_UNDEFINED;
88 
89   /* 2. */
90   ecma_object_t *mapfn_obj_p = NULL;
91 
92   /* 3. */
93   if (!ecma_is_value_undefined (mapfn))
94   {
95     /* 3.a */
96     if (!ecma_op_is_callable (mapfn))
97     {
98       return ecma_raise_type_error (ECMA_ERR_MSG ("Callback function is not callable."));
99     }
100 
101     /* 3.b */
102     if (arguments_list_len > 2)
103     {
104       call_this_arg = arguments_list_p[2];
105     }
106 
107     /* 3.c */
108     mapfn_obj_p = ecma_get_object_from_value (mapfn);
109   }
110 
111   /* 4. */
112   ecma_value_t using_iterator = ecma_op_get_method_by_symbol_id (items, LIT_GLOBAL_SYMBOL_ITERATOR);
113 
114   /* 5. */
115   if (ECMA_IS_VALUE_ERROR (using_iterator))
116   {
117     return using_iterator;
118   }
119 
120   ecma_value_t ret_value = ECMA_VALUE_ERROR;
121 
122   /* 6. */
123   if (!ecma_is_value_undefined (using_iterator))
124   {
125     ecma_value_t array;
126 
127     /* 6.a */
128     if (ecma_is_constructor (constructor))
129     {
130       ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor);
131 
132       array = ecma_op_function_construct (constructor_obj_p, constructor_obj_p, NULL, 0);
133 
134       if (ecma_is_value_undefined (array) || ecma_is_value_null (array))
135       {
136         ecma_free_value (using_iterator);
137         return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert undefined or null to object"));
138       }
139     }
140     else
141     {
142       /* 6.b */
143       array = ecma_op_create_array_object (NULL, 0, false);
144     }
145 
146     /* 6.c */
147     if (ECMA_IS_VALUE_ERROR (array))
148     {
149       ecma_free_value (using_iterator);
150       return array;
151     }
152 
153     ecma_object_t *array_obj_p = ecma_get_object_from_value (array);
154 
155     /* 6.d */
156     ecma_value_t iterator = ecma_op_get_iterator (items, using_iterator);
157     ecma_free_value (using_iterator);
158 
159     /* 6.e */
160     if (ECMA_IS_VALUE_ERROR (iterator))
161     {
162       ecma_free_value (array);
163       return iterator;
164     }
165 
166     /* 6.f */
167     uint32_t k = 0;
168 
169     /* 6.g */
170     while (true)
171     {
172       /* 6.g.ii */
173       ecma_value_t next = ecma_op_iterator_step (iterator);
174 
175       /* 6.g.iii */
176       if (ECMA_IS_VALUE_ERROR (next))
177       {
178         goto iterator_cleanup;
179       }
180 
181       /* 6.g.iii */
182       if (ecma_is_value_false (next))
183       {
184         /* 6.g.iv.1 */
185         ecma_value_t len_value = ecma_make_uint32_value (k);
186         ecma_value_t set_status = ecma_op_object_put (array_obj_p,
187                                                       ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH),
188                                                       len_value,
189                                                       true);
190         ecma_free_value (len_value);
191 
192         /* 6.g.iv.2 */
193         if (ECMA_IS_VALUE_ERROR (set_status))
194         {
195           goto iterator_cleanup;
196         }
197 
198         ecma_free_value (iterator);
199         /* 6.g.iv.3 */
200         return array;
201       }
202 
203       /* 6.g.v */
204       ecma_value_t next_value = ecma_op_iterator_value (next);
205 
206       ecma_free_value (next);
207 
208       /* 6.g.vi */
209       if (ECMA_IS_VALUE_ERROR (next_value))
210       {
211         goto iterator_cleanup;
212       }
213 
214       ecma_value_t mapped_value;
215       /* 6.g.vii */
216       if (mapfn_obj_p != NULL)
217       {
218         /* 6.g.vii.1 */
219         ecma_value_t args_p[2] = { next_value, ecma_make_uint32_value (k) };
220         /* 6.g.vii.3 */
221         mapped_value = ecma_op_function_call (mapfn_obj_p, call_this_arg, args_p, 2);
222         ecma_free_value (args_p[1]);
223         ecma_free_value (next_value);
224 
225         /* 6.g.vii.2 */
226         if (ECMA_IS_VALUE_ERROR (mapped_value))
227         {
228           ecma_op_iterator_close (iterator);
229           goto iterator_cleanup;
230         }
231       }
232       else
233       {
234         /* 6.g.viii */
235         mapped_value = next_value;
236       }
237 
238       /* 6.g.ix */
239       const uint32_t flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE | ECMA_IS_THROW;
240       ecma_value_t set_status = ecma_builtin_helper_def_prop_by_index (array_obj_p, k, mapped_value, flags);
241 
242       ecma_free_value (mapped_value);
243 
244       /* 6.g.x */
245       if (ECMA_IS_VALUE_ERROR (set_status))
246       {
247         ecma_op_iterator_close (iterator);
248         goto iterator_cleanup;
249       }
250 
251       /* 6.g.xi */
252       k++;
253     }
254 
255 iterator_cleanup:
256     ecma_free_value (iterator);
257     ecma_free_value (array);
258 
259     return ret_value;
260   }
261 
262   /* 8. */
263   ecma_value_t array_like = ecma_op_to_object (items);
264 
265   /* 9. */
266   if (ECMA_IS_VALUE_ERROR (array_like))
267   {
268     return array_like;
269   }
270 
271   ecma_object_t *array_like_obj_p = ecma_get_object_from_value (array_like);
272 
273   /* 10. */
274   uint32_t len;
275   ecma_value_t len_value = ecma_op_object_get_length (array_like_obj_p, &len);
276 
277   /* 11. */
278   if (ECMA_IS_VALUE_ERROR (len_value))
279   {
280     goto cleanup;
281   }
282 
283   len_value = ecma_make_uint32_value (len);
284 
285   /* 12. */
286   ecma_value_t array;
287 
288   /* 12.a */
289   if (ecma_is_constructor (constructor))
290   {
291     ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor);
292 
293     array = ecma_op_function_construct (constructor_obj_p, constructor_obj_p, &len_value, 1);
294 
295     if (ecma_is_value_undefined (array) || ecma_is_value_null (array))
296     {
297       ecma_free_value (len_value);
298       ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert undefined or null to object"));
299       goto cleanup;
300     }
301   }
302   else
303   {
304     /* 13.a */
305     array = ecma_op_create_array_object (&len_value, 1, true);
306   }
307 
308   ecma_free_value (len_value);
309 
310   /* 14. */
311   if (ECMA_IS_VALUE_ERROR (array))
312   {
313     goto cleanup;
314   }
315 
316   ecma_object_t *array_obj_p = ecma_get_object_from_value (array);
317 
318   /* 15. */
319   uint32_t k = 0;
320 
321   /* 16. */
322   while (k < len)
323   {
324     /* 16.b */
325     ecma_value_t k_value = ecma_op_object_get_by_uint32_index (array_like_obj_p, k);
326 
327     /* 16.c */
328     if (ECMA_IS_VALUE_ERROR (k_value))
329     {
330       goto construct_cleanup;
331     }
332 
333     ecma_value_t mapped_value;
334     /* 16.d */
335     if (mapfn_obj_p != NULL)
336     {
337       /* 16.d.i */
338       ecma_value_t args_p[2] = { k_value, ecma_make_uint32_value (k) };
339       mapped_value = ecma_op_function_call (mapfn_obj_p, call_this_arg, args_p, 2);
340       ecma_free_value (args_p[1]);
341       ecma_free_value (k_value);
342 
343       /* 16.d.ii */
344       if (ECMA_IS_VALUE_ERROR (mapped_value))
345       {
346         goto construct_cleanup;
347       }
348     }
349     else
350     {
351       /* 16.e */
352       mapped_value = k_value;
353     }
354 
355     /* 16.f */
356     const uint32_t flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE | ECMA_IS_THROW;
357     ecma_value_t set_status = ecma_builtin_helper_def_prop_by_index (array_obj_p, k, mapped_value, flags);
358 
359     ecma_free_value (mapped_value);
360 
361     /* 16.g */
362     if (ECMA_IS_VALUE_ERROR (set_status))
363     {
364       goto construct_cleanup;
365     }
366 
367     /* 16.h */
368     k++;
369   }
370 
371   /* 17. */
372   len_value = ecma_make_uint32_value (k);
373   ecma_value_t set_status = ecma_op_object_put (array_obj_p,
374                                                 ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH),
375                                                 len_value,
376                                                 true);
377   ecma_free_value (len_value);
378 
379   /* 18. */
380   if (ECMA_IS_VALUE_ERROR (set_status))
381   {
382     goto construct_cleanup;
383   }
384 
385   /* 19. */
386   ecma_deref_object (array_like_obj_p);
387   return ecma_make_object_value (array_obj_p);
388 
389 construct_cleanup:
390   ecma_deref_object (array_obj_p);
391 cleanup:
392   ecma_deref_object (array_like_obj_p);
393   return ret_value;
394 } /* ecma_builtin_array_object_from */
395 
396 /**
397  * The Array object's 'of' routine
398  *
399  * See also:
400  *          ECMA-262 v6, 22.1.2.3
401  *
402  * @return ecma value
403  *         Returned value must be freed with ecma_free_value.
404  */
405 static ecma_value_t
ecma_builtin_array_object_of(ecma_value_t this_arg,const ecma_value_t * arguments_list_p,ecma_length_t arguments_list_len)406 ecma_builtin_array_object_of (ecma_value_t this_arg, /**< 'this' argument */
407                               const ecma_value_t *arguments_list_p, /**< arguments list */
408                               ecma_length_t arguments_list_len) /**< number of arguments */
409 {
410   if (!ecma_is_constructor (this_arg))
411   {
412     return ecma_op_create_array_object (arguments_list_p, arguments_list_len, false);
413   }
414 
415   ecma_value_t len = ecma_make_uint32_value (arguments_list_len);
416 
417   ecma_value_t ret_val = ecma_op_function_construct (ecma_get_object_from_value (this_arg),
418                                                      ecma_get_object_from_value (this_arg),
419                                                      &len,
420                                                      1);
421 
422   if (ECMA_IS_VALUE_ERROR (ret_val))
423   {
424     ecma_free_value (len);
425     return ret_val;
426   }
427 
428   uint32_t k = 0;
429   ecma_object_t *obj_p = ecma_get_object_from_value (ret_val);
430   const uint32_t prop_status_flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE | ECMA_IS_THROW;
431 
432   while (k < arguments_list_len)
433   {
434     ecma_value_t define_status = ecma_builtin_helper_def_prop_by_index (obj_p,
435                                                                         k,
436                                                                         arguments_list_p[k],
437                                                                         prop_status_flags);
438 
439     if (ECMA_IS_VALUE_ERROR (define_status))
440     {
441       ecma_free_value (len);
442       ecma_deref_object (obj_p);
443       return define_status;
444     }
445 
446     k++;
447   }
448 
449   ret_val = ecma_op_object_put (obj_p,
450                                 ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH),
451                                 len,
452                                 true);
453 
454   ecma_free_value (len);
455 
456   if (ECMA_IS_VALUE_ERROR (ret_val))
457   {
458     ecma_deref_object (obj_p);
459     return ret_val;
460   }
461 
462   return ecma_make_object_value (obj_p);
463 } /* ecma_builtin_array_object_of */
464 
465 /**
466  * 22.1.2.5 get Array [ @@species ] accessor
467  *
468  * @return ecma_value
469  *         returned value must be freed with ecma_free_value
470  */
471 ecma_value_t
ecma_builtin_array_species_get(ecma_value_t this_value)472 ecma_builtin_array_species_get (ecma_value_t this_value) /**< This Value */
473 {
474   return ecma_copy_value (this_value);
475 } /* ecma_builtin_array_species_get */
476 #endif /* ENABLED (JERRY_ES2015) */
477 
478 /**
479  * Handle calling [[Call]] of built-in Array object
480  *
481  * @return ecma value
482  */
483 ecma_value_t
ecma_builtin_array_dispatch_call(const ecma_value_t * arguments_list_p,ecma_length_t arguments_list_len)484 ecma_builtin_array_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */
485                                   ecma_length_t arguments_list_len) /**< number of arguments */
486 {
487   JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
488 
489   return ecma_op_create_array_object (arguments_list_p, arguments_list_len, true);
490 } /* ecma_builtin_array_dispatch_call */
491 
492 /**
493  * Handle calling [[Construct]] of built-in Array object
494  *
495  * @return ecma value
496  */
497 ecma_value_t
ecma_builtin_array_dispatch_construct(const ecma_value_t * arguments_list_p,ecma_length_t arguments_list_len)498 ecma_builtin_array_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
499                                        ecma_length_t arguments_list_len) /**< number of arguments */
500 {
501   JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
502 
503 #if !ENABLED (JERRY_ES2015)
504   return ecma_op_create_array_object (arguments_list_p, arguments_list_len, true);
505 #else /* ENABLED (JERRY_ES2015) */
506   ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target),
507                                                                    ECMA_BUILTIN_ID_ARRAY_PROTOTYPE);
508 
509   if (proto_p == NULL)
510   {
511     return ECMA_VALUE_ERROR;
512   }
513 
514   ecma_value_t result = ecma_op_create_array_object (arguments_list_p, arguments_list_len, true);
515 
516   if (ECMA_IS_VALUE_ERROR (result))
517   {
518     ecma_deref_object (proto_p);
519     return ECMA_VALUE_ERROR;
520   }
521 
522   ecma_object_t *object_p = ecma_get_object_from_value (result);
523   ECMA_SET_NON_NULL_POINTER (object_p->u2.prototype_cp, proto_p);
524   ecma_deref_object (proto_p);
525   return result;
526 #endif /* ENABLED (JERRY_ES2015) */
527 } /* ecma_builtin_array_dispatch_construct */
528 
529 /**
530  * @}
531  * @}
532  * @}
533  */
534 
535 #endif /* ENABLED (JERRY_BUILTIN_ARRAY) */
536