• 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 #include "jcontext.h"
16 #include "ecma-alloc.h"
17 #include "ecma-array-object.h"
18 #include "ecma-builtins.h"
19 #include "ecma-builtin-helpers.h"
20 #include "ecma-exceptions.h"
21 #include "ecma-function-object.h"
22 #include "ecma-gc.h"
23 #include "ecma-helpers.h"
24 #include "ecma-iterator-object.h"
25 #include "ecma-container-object.h"
26 #include "ecma-property-hashmap.h"
27 #include "ecma-objects.h"
28 
29 #if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER)
30 
31 /** \addtogroup ecma ECMA
32  * @{
33  *
34  * \addtogroup \addtogroup ecmamaphelpers ECMA builtin Map/Set helper functions
35  * @{
36  */
37 
38 /**
39  * Create a new internal buffer.
40  *
41  * Note:
42  *   The first element of the collection tracks the size of the buffer.
43  *   ECMA_VALUE_EMPTY values are not calculated into the size.
44  *
45  * @return pointer to the internal buffer
46  */
47 static inline ecma_collection_t *
ecma_op_create_internal_buffer(void)48 ecma_op_create_internal_buffer (void)
49 {
50   ecma_collection_t *collection_p = ecma_new_collection ();
51   ecma_collection_push_back (collection_p, (ecma_value_t) 0);
52 
53   return collection_p;
54 } /* ecma_op_create_internal_buffer */
55 
56 /**
57  * Append values to the internal buffer.
58  */
59 static void
ecma_op_internal_buffer_append(ecma_collection_t * container_p,ecma_value_t key_arg,ecma_value_t value_arg,lit_magic_string_id_t lit_id)60 ecma_op_internal_buffer_append (ecma_collection_t *container_p, /**< internal container pointer */
61                                 ecma_value_t key_arg, /**< key argument */
62                                 ecma_value_t value_arg, /**< value argument */
63                                 lit_magic_string_id_t lit_id) /**< class id */
64 {
65   JERRY_ASSERT (container_p != NULL);
66 
67   if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL)
68   {
69     ecma_value_t values[] = { ecma_copy_value_if_not_object (key_arg), ecma_copy_value_if_not_object (value_arg) };
70     ecma_collection_append (container_p, values, 2);
71   }
72   else
73   {
74     ecma_collection_push_back (container_p, ecma_copy_value_if_not_object (key_arg));
75   }
76 
77   ECMA_CONTAINER_SET_SIZE (container_p, ECMA_CONTAINER_GET_SIZE (container_p) + 1);
78 } /* ecma_op_internal_buffer_append */
79 
80 /**
81  * Update the value of a given entry.
82  */
83 static inline void
ecma_op_internal_buffer_update(ecma_value_t * entry_p,ecma_value_t value_arg,lit_magic_string_id_t lit_id)84 ecma_op_internal_buffer_update (ecma_value_t *entry_p, /**< entry pointer */
85                                 ecma_value_t value_arg, /**< value argument */
86                                 lit_magic_string_id_t lit_id) /**< class id */
87 {
88   JERRY_ASSERT (entry_p != NULL);
89 
90   if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL)
91   {
92     ecma_free_value_if_not_object (((ecma_container_pair_t *) entry_p)->value);
93 
94     ((ecma_container_pair_t *) entry_p)->value = ecma_copy_value_if_not_object (value_arg);
95   }
96 } /* ecma_op_internal_buffer_update */
97 
98 /**
99  * Delete element from the internal buffer.
100  */
101 static void
ecma_op_internal_buffer_delete(ecma_collection_t * container_p,ecma_container_pair_t * entry_p,lit_magic_string_id_t lit_id)102 ecma_op_internal_buffer_delete (ecma_collection_t *container_p, /**< internal container pointer */
103                                 ecma_container_pair_t *entry_p, /**< entry pointer */
104                                 lit_magic_string_id_t lit_id) /**< class id */
105 {
106   JERRY_ASSERT (container_p != NULL);
107   JERRY_ASSERT (entry_p != NULL);
108 
109   ecma_free_value_if_not_object (entry_p->key);
110   entry_p->key = ECMA_VALUE_EMPTY;
111 
112   if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL)
113   {
114     ecma_free_value_if_not_object (entry_p->value);
115     entry_p->value = ECMA_VALUE_EMPTY;
116   }
117 
118   ECMA_CONTAINER_SET_SIZE (container_p, ECMA_CONTAINER_GET_SIZE (container_p) - 1);
119 } /* ecma_op_internal_buffer_delete */
120 
121 /**
122  * Find an entry in the collection.
123  *
124  * @return pointer to the appropriate entry.
125  */
126 static ecma_value_t *
ecma_op_internal_buffer_find(ecma_collection_t * container_p,ecma_value_t key_arg,lit_magic_string_id_t lit_id)127 ecma_op_internal_buffer_find (ecma_collection_t *container_p, /**< internal container pointer */
128                               ecma_value_t key_arg, /**< key argument */
129                               lit_magic_string_id_t lit_id) /**< class id */
130 {
131   JERRY_ASSERT (container_p != NULL);
132 
133   uint8_t entry_size = ecma_op_container_entry_size (lit_id);
134   uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
135   ecma_value_t *start_p = ECMA_CONTAINER_START (container_p);
136 
137   for (uint32_t i = 0; i < entry_count; i += entry_size)
138   {
139     ecma_value_t *entry_p = start_p + i;
140 
141     if (ecma_op_same_value_zero (*entry_p, key_arg))
142     {
143       return entry_p;
144     }
145   }
146 
147   return NULL;
148 } /* ecma_op_internal_buffer_find */
149 
150 /**
151  * Get the value that belongs to the key.
152  *
153  * Note: in case of Set containers, the values are the same as the keys.
154  *
155  * @return ecma value
156  */
157 static ecma_value_t
ecma_op_container_get_value(ecma_value_t * entry_p,lit_magic_string_id_t lit_id)158 ecma_op_container_get_value (ecma_value_t *entry_p, /**< entry (key) pointer */
159                              lit_magic_string_id_t lit_id) /**< class id */
160 {
161   JERRY_ASSERT (entry_p != NULL);
162 
163   if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL)
164   {
165     return ((ecma_container_pair_t *) entry_p)->value;
166   }
167 
168   return *entry_p;
169 } /* ecma_op_container_get_value */
170 
171 /**
172  * Get the size (in ecma_value_t) of the stored entries.
173  *
174  * @return size of the entries.
175  */
176 uint8_t
ecma_op_container_entry_size(lit_magic_string_id_t lit_id)177 ecma_op_container_entry_size (lit_magic_string_id_t lit_id) /**< class id */
178 {
179   if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL)
180   {
181     return ECMA_CONTAINER_PAIR_SIZE;
182   }
183 
184   return ECMA_CONTAINER_VALUE_SIZE;
185 } /* ecma_op_container_entry_size */
186 
187 #if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET)
188 /**
189  * Release the entries in the WeakSet container.
190  */
191 static void
ecma_op_container_free_weakset_entries(ecma_object_t * object_p,ecma_collection_t * container_p)192 ecma_op_container_free_weakset_entries (ecma_object_t *object_p, /**< object pointer */
193                                         ecma_collection_t *container_p) /** internal buffer pointer */
194 {
195   JERRY_ASSERT (object_p != NULL);
196   JERRY_ASSERT (container_p != NULL);
197 
198   uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
199   ecma_value_t *start_p = ECMA_CONTAINER_START (container_p);
200 
201   for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_VALUE_SIZE)
202   {
203     ecma_value_t *entry_p = start_p + i;
204 
205     if (ecma_is_value_empty (*entry_p))
206     {
207       continue;
208     }
209 
210     ecma_op_container_unref_weak (ecma_get_object_from_value (*entry_p), ecma_make_object_value (object_p));
211     ecma_op_container_remove_weak_entry (object_p, *entry_p);
212 
213     *entry_p = ECMA_VALUE_EMPTY;
214   }
215 } /* ecma_op_container_free_weakset_entries */
216 #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */
217 
218 #if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP)
219 /**
220  * Release the entries in the WeakMap container.
221  */
222 static void
ecma_op_container_free_weakmap_entries(ecma_object_t * object_p,ecma_collection_t * container_p)223 ecma_op_container_free_weakmap_entries (ecma_object_t *object_p, /**< object pointer */
224                                         ecma_collection_t *container_p) /**< internal buffer pointer */
225 {
226   JERRY_ASSERT (object_p != NULL);
227   JERRY_ASSERT (container_p != NULL);
228 
229   uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
230   ecma_value_t *start_p = ECMA_CONTAINER_START (container_p);
231 
232   for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_PAIR_SIZE)
233   {
234     ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i);
235 
236     if (ecma_is_value_empty (entry_p->key))
237     {
238       continue;
239     }
240 
241     ecma_op_container_unref_weak (ecma_get_object_from_value (entry_p->key), ecma_make_object_value (object_p));
242     ecma_op_container_remove_weak_entry (object_p, entry_p->key);
243 
244     ecma_free_value_if_not_object (entry_p->value);
245 
246     entry_p->key = ECMA_VALUE_EMPTY;
247     entry_p->value = ECMA_VALUE_EMPTY;
248   }
249 } /* ecma_op_container_free_weakmap_entries */
250 #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */
251 
252 #if ENABLED (JERRY_ES2015_BUILTIN_SET)
253 /**
254  * Release the entries in the Set container.
255  */
256 static void
ecma_op_container_free_set_entries(ecma_collection_t * container_p)257 ecma_op_container_free_set_entries (ecma_collection_t *container_p)
258 {
259   JERRY_ASSERT (container_p != NULL);
260 
261   uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
262   ecma_value_t *start_p = ECMA_CONTAINER_START (container_p);
263 
264   for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_VALUE_SIZE)
265   {
266     ecma_value_t *entry_p = start_p + i;
267 
268     if (ecma_is_value_empty (*entry_p))
269     {
270       continue;
271     }
272 
273     ecma_free_value_if_not_object (*entry_p);
274     *entry_p = ECMA_VALUE_EMPTY;
275   }
276 } /* ecma_op_container_free_set_entries */
277 #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */
278 
279 #if ENABLED (JERRY_ES2015_BUILTIN_MAP)
280 /**
281  * Release the entries in the Map container.
282  */
283 static void
ecma_op_container_free_map_entries(ecma_collection_t * container_p)284 ecma_op_container_free_map_entries (ecma_collection_t *container_p)
285 {
286   JERRY_ASSERT (container_p != NULL);
287 
288   uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
289   ecma_value_t *start_p = ECMA_CONTAINER_START (container_p);
290 
291   for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_PAIR_SIZE)
292   {
293     ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i);
294 
295     if (ecma_is_value_empty (entry_p->key))
296     {
297       continue;
298     }
299 
300     ecma_free_value_if_not_object (entry_p->key);
301     ecma_free_value_if_not_object (entry_p->value);
302 
303     entry_p->key = ECMA_VALUE_EMPTY;
304     entry_p->value = ECMA_VALUE_EMPTY;
305   }
306 } /* ecma_op_container_free_map_entries */
307 #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */
308 
309 /**
310  * Release the internal buffer and the stored entries.
311  */
312 void
ecma_op_container_free_entries(ecma_object_t * object_p)313 ecma_op_container_free_entries (ecma_object_t *object_p) /**< collection object pointer */
314 {
315   JERRY_ASSERT (object_p != NULL);
316 
317   ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p;
318   ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
319                                                                     map_object_p->u.class_prop.u.value);
320 
321   switch (map_object_p->u.class_prop.class_id)
322   {
323 #if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET)
324     case LIT_MAGIC_STRING_WEAKSET_UL:
325     {
326       ecma_op_container_free_weakset_entries (object_p, container_p);
327       break;
328     }
329 #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */
330 #if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP)
331     case LIT_MAGIC_STRING_WEAKMAP_UL:
332     {
333       ecma_op_container_free_weakmap_entries (object_p, container_p);
334       break;
335     }
336 #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */
337 #if ENABLED (JERRY_ES2015_BUILTIN_SET)
338     case LIT_MAGIC_STRING_SET_UL:
339     {
340       ecma_op_container_free_set_entries (container_p);
341       break;
342     }
343 #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */
344 #if ENABLED (JERRY_ES2015_BUILTIN_MAP)
345     case LIT_MAGIC_STRING_MAP_UL:
346     {
347       ecma_op_container_free_map_entries (container_p);
348       break;
349     }
350 #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */
351     default:
352     {
353       break;
354     }
355   }
356 
357   ECMA_CONTAINER_SET_SIZE (container_p, 0);
358 } /* ecma_op_container_free_entries */
359 
360 /**
361  * Handle calling [[Construct]] of built-in Map/Set like objects
362  *
363  * @return ecma value
364  */
365 ecma_value_t
ecma_op_container_create(const ecma_value_t * arguments_list_p,ecma_length_t arguments_list_len,lit_magic_string_id_t lit_id,ecma_builtin_id_t proto_id)366 ecma_op_container_create (const ecma_value_t *arguments_list_p, /**< arguments list */
367                           ecma_length_t arguments_list_len, /**< number of arguments */
368                           lit_magic_string_id_t lit_id, /**< internal class id */
369                           ecma_builtin_id_t proto_id) /**< prototype builtin id */
370 {
371   JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
372   JERRY_ASSERT (lit_id == LIT_MAGIC_STRING_MAP_UL
373                 || lit_id == LIT_MAGIC_STRING_SET_UL
374                 || lit_id == LIT_MAGIC_STRING_WEAKMAP_UL
375                 || lit_id == LIT_MAGIC_STRING_WEAKSET_UL);
376   JERRY_ASSERT (JERRY_CONTEXT (current_new_target) != NULL);
377 
378   ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target), proto_id);
379 
380   if (JERRY_UNLIKELY (proto_p == NULL))
381   {
382     return ECMA_VALUE_ERROR;
383   }
384 
385   ecma_collection_t *container_p = ecma_op_create_internal_buffer ();
386   ecma_object_t *object_p  = ecma_create_object (proto_p,
387                                                  sizeof (ecma_extended_object_t),
388                                                  ECMA_OBJECT_TYPE_CLASS);
389   ecma_deref_object (proto_p);
390   ecma_extended_object_t *map_obj_p = (ecma_extended_object_t *) object_p;
391   map_obj_p->u.class_prop.extra_info = ECMA_CONTAINER_FLAGS_EMPTY;
392   map_obj_p->u.class_prop.class_id = (uint16_t) lit_id;
393 
394   if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_WEAKSET_UL)
395   {
396     map_obj_p->u.class_prop.extra_info |= ECMA_CONTAINER_FLAGS_WEAK;
397   }
398 
399   ECMA_SET_INTERNAL_VALUE_POINTER (map_obj_p->u.class_prop.u.value, container_p);
400 
401   ecma_value_t set_value = ecma_make_object_value (object_p);
402   ecma_value_t result = set_value;
403 
404 #if ENABLED (JERRY_ES2015)
405   if (arguments_list_len == 0)
406   {
407     return result;
408   }
409 
410   ecma_value_t iterable = arguments_list_p[0];
411 
412   if (ecma_is_value_undefined (iterable) || ecma_is_value_null (iterable))
413   {
414     return result;
415   }
416 
417   lit_magic_string_id_t adder_string_id;
418   if (lit_id == LIT_MAGIC_STRING_MAP_UL || lit_id == LIT_MAGIC_STRING_WEAKMAP_UL)
419   {
420     adder_string_id = LIT_MAGIC_STRING_SET;
421   }
422   else
423   {
424     adder_string_id = LIT_MAGIC_STRING_ADD;
425   }
426 
427   result = ecma_op_object_get_by_magic_id (object_p, adder_string_id);
428   if (ECMA_IS_VALUE_ERROR (result))
429   {
430     goto cleanup_object;
431   }
432 
433   if (!ecma_op_is_callable (result))
434   {
435     ecma_free_value (result);
436     result = ecma_raise_type_error (ECMA_ERR_MSG ("add/set function is not callable."));
437     goto cleanup_object;
438   }
439 
440   ecma_object_t *adder_func_p = ecma_get_object_from_value (result);
441 
442   result = ecma_op_get_iterator (iterable, ECMA_VALUE_EMPTY);
443 
444   if (ECMA_IS_VALUE_ERROR (result))
445   {
446     goto cleanup_adder;
447   }
448 
449   const ecma_value_t iter = result;
450 
451   while (true)
452   {
453     result = ecma_op_iterator_step (iter);
454 
455     if (ECMA_IS_VALUE_ERROR (result))
456     {
457       goto cleanup_iter;
458     }
459 
460     if (ecma_is_value_false (result))
461     {
462       break;
463     }
464 
465     const ecma_value_t next = result;
466     result = ecma_op_iterator_value (next);
467     ecma_free_value (next);
468 
469     if (ECMA_IS_VALUE_ERROR (result))
470     {
471       goto cleanup_iter;
472     }
473 
474     if (lit_id == LIT_MAGIC_STRING_SET_UL || lit_id == LIT_MAGIC_STRING_WEAKSET_UL)
475     {
476       const ecma_value_t value = result;
477 
478       ecma_value_t arguments[] = { value };
479       result = ecma_op_function_call (adder_func_p, set_value, arguments, 1);
480 
481       ecma_free_value (value);
482     }
483     else
484     {
485       if (!ecma_is_value_object (result))
486       {
487         ecma_free_value (result);
488         ecma_raise_type_error (ECMA_ERR_MSG ("Iterator value is not an object."));
489         result = ecma_op_iterator_close (iter);
490         JERRY_ASSERT (ECMA_IS_VALUE_ERROR (result));
491         goto cleanup_iter;
492       }
493 
494       ecma_object_t *next_object_p = ecma_get_object_from_value (result);
495 
496       result = ecma_op_object_get_by_uint32_index (next_object_p, 0);
497 
498       if (ECMA_IS_VALUE_ERROR (result))
499       {
500         ecma_deref_object (next_object_p);
501         ecma_op_iterator_close (iter);
502         goto cleanup_iter;
503       }
504 
505       const ecma_value_t key = result;
506 
507       result = ecma_op_object_get_by_uint32_index (next_object_p, 1);
508 
509       if (ECMA_IS_VALUE_ERROR (result))
510       {
511         ecma_deref_object (next_object_p);
512         ecma_free_value (key);
513         ecma_op_iterator_close (iter);
514         goto cleanup_iter;
515       }
516 
517       const ecma_value_t value = result;
518       ecma_value_t arguments[] = { key, value };
519       result = ecma_op_function_call (adder_func_p, set_value, arguments, 2);
520 
521       ecma_free_value (key);
522       ecma_free_value (value);
523       ecma_deref_object (next_object_p);
524     }
525 
526     if (ECMA_IS_VALUE_ERROR (result))
527     {
528       ecma_op_iterator_close (iter);
529       goto cleanup_iter;
530     }
531 
532     ecma_free_value (result);
533   }
534 
535   ecma_free_value (iter);
536   ecma_deref_object (adder_func_p);
537   return ecma_make_object_value (object_p);
538 
539 cleanup_iter:
540   ecma_free_value (iter);
541 cleanup_adder:
542   ecma_deref_object (adder_func_p);
543 cleanup_object:
544   ecma_deref_object (object_p);
545 #endif /* ENABLED (JERRY_ES2015) */
546 
547   return result;
548 } /* ecma_op_container_create */
549 
550 /**
551  * Get Map/Set object pointer
552  *
553  * Note:
554  *   If the function returns with NULL, the error object has
555  *   already set, and the caller must return with ECMA_VALUE_ERROR
556  *
557  * @return pointer to the Map/Set if this_arg is a valid Map/Set object
558  *         NULL otherwise
559  */
560 static ecma_extended_object_t *
ecma_op_container_get_object(ecma_value_t this_arg,lit_magic_string_id_t lit_id)561 ecma_op_container_get_object (ecma_value_t this_arg, /**< this argument */
562                               lit_magic_string_id_t lit_id) /**< internal class id */
563 {
564   if (ecma_is_value_object (this_arg))
565   {
566     ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) ecma_get_object_from_value (this_arg);
567 
568     if (ecma_get_object_type ((ecma_object_t *) map_object_p) == ECMA_OBJECT_TYPE_CLASS
569         && map_object_p->u.class_prop.class_id == lit_id)
570     {
571       return map_object_p;
572     }
573   }
574 
575 #if ENABLED (JERRY_ERROR_MESSAGES)
576   ecma_raise_standard_error_with_format (ECMA_ERROR_TYPE,
577                                          "Expected a % object.",
578                                          ecma_make_string_value (ecma_get_magic_string (lit_id)));
579 #else /* !ENABLED (JERRY_ERROR_MESSAGES) */
580   ecma_raise_type_error (NULL);
581 #endif /* ENABLED (JERRY_ERROR_MESSAGES) */
582 
583   return NULL;
584 } /* ecma_op_container_get_object */
585 
586 /**
587  * Returns with the size of the Map/Set object.
588  *
589  * @return size of the Map/Set object as ecma-value.
590  */
591 ecma_value_t
ecma_op_container_size(ecma_value_t this_arg,lit_magic_string_id_t lit_id)592 ecma_op_container_size (ecma_value_t this_arg, /**< this argument */
593                         lit_magic_string_id_t lit_id) /**< internal class id */
594 {
595   ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
596 
597   if (map_object_p == NULL)
598   {
599     return ECMA_VALUE_ERROR;
600   }
601 
602   ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
603                                                                     map_object_p->u.class_prop.u.value);
604 
605   return ecma_make_uint32_value (ECMA_CONTAINER_GET_SIZE (container_p));
606 } /* ecma_op_container_size */
607 
608 /**
609  * The generic Map/WeakMap prototype object's 'get' routine
610  *
611  * @return ecma value
612  *         Returned value must be freed with ecma_free_value.
613  */
614 ecma_value_t
ecma_op_container_get(ecma_value_t this_arg,ecma_value_t key_arg,lit_magic_string_id_t lit_id)615 ecma_op_container_get (ecma_value_t this_arg, /**< this argument */
616                        ecma_value_t key_arg, /**< key argument */
617                        lit_magic_string_id_t lit_id) /**< internal class id */
618 {
619   ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
620 
621   if (map_object_p == NULL)
622   {
623     return ECMA_VALUE_ERROR;
624   }
625 
626 #if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP)
627   if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL && !ecma_is_value_object (key_arg))
628   {
629     return ECMA_VALUE_UNDEFINED;
630   }
631 #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */
632 
633   ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
634                                                                     map_object_p->u.class_prop.u.value);
635 
636   if (ECMA_CONTAINER_GET_SIZE (container_p) == 0)
637   {
638     return ECMA_VALUE_UNDEFINED;
639   }
640 
641   ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id);
642 
643   if (entry_p == NULL)
644   {
645     return ECMA_VALUE_UNDEFINED;
646   }
647 
648   return ecma_copy_value (((ecma_container_pair_t *) entry_p)->value);
649 } /* ecma_op_container_get */
650 
651 /**
652  * The generic Map/Set prototype object's 'has' routine
653  *
654  * @return ecma value
655  *         Returned value must be freed with ecma_free_value.
656  */
657 ecma_value_t
ecma_op_container_has(ecma_value_t this_arg,ecma_value_t key_arg,lit_magic_string_id_t lit_id)658 ecma_op_container_has (ecma_value_t this_arg, /**< this argument */
659                        ecma_value_t key_arg, /**< key argument */
660                        lit_magic_string_id_t lit_id) /**< internal class id */
661 {
662   ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
663 
664   if (map_object_p == NULL)
665   {
666     return ECMA_VALUE_ERROR;
667   }
668 
669   ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
670                                                                     map_object_p->u.class_prop.u.value);
671 
672 #if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET)
673   if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0
674       && !ecma_is_value_object (key_arg))
675   {
676     return ECMA_VALUE_FALSE;
677   }
678 #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) ||  ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */
679 
680   if (ECMA_CONTAINER_GET_SIZE (container_p) == 0)
681   {
682     return ECMA_VALUE_FALSE;
683   }
684 
685   ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id);
686 
687   return ecma_make_boolean_value (entry_p != NULL);
688 } /* ecma_op_container_has */
689 
690 /**
691  * Set a weak reference from a container to a key object
692  */
693 static void
ecma_op_container_set_weak(ecma_object_t * const key_p,ecma_extended_object_t * const container_p)694 ecma_op_container_set_weak (ecma_object_t *const key_p, /**< key object */
695                             ecma_extended_object_t *const container_p) /**< container */
696 {
697   if (JERRY_UNLIKELY (ecma_op_object_is_fast_array (key_p)))
698   {
699     ecma_fast_array_convert_to_normal (key_p);
700   }
701 
702   ecma_string_t *weak_refs_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_WEAK_REFS);
703   ecma_property_t *property_p = ecma_find_named_property (key_p, weak_refs_string_p);
704   ecma_collection_t *refs_p;
705 
706   if (property_p == NULL)
707   {
708     ecma_property_value_t *value_p = ecma_create_named_data_property (key_p,
709                                                                       weak_refs_string_p,
710                                                                       ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
711                                                                       &property_p);
712     ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY (property_p);
713     refs_p = ecma_new_collection ();
714     ECMA_SET_INTERNAL_VALUE_POINTER (value_p->value, refs_p);
715   }
716   else
717   {
718     refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, (ECMA_PROPERTY_VALUE_PTR (property_p)->value));
719   }
720 
721   const ecma_value_t container_value = ecma_make_object_value ((ecma_object_t *) container_p);
722   for (uint32_t i = 0; i < refs_p->item_count; i++)
723   {
724     if (ecma_is_value_empty (refs_p->buffer_p[i]))
725     {
726       refs_p->buffer_p[i] = container_value;
727       return;
728     }
729   }
730 
731   ecma_collection_push_back (refs_p, container_value);
732 } /* ecma_op_container_set_weak */
733 
734 /**
735  * Helper method for the Map.prototype.set and Set.prototype.add methods to swap the sign of the given value if needed
736  *
737  * See also:
738  *          ECMA-262 v6, 23.2.3.1 step 6
739  *          ECMA-262 v6, 23.1.3.9 step 6
740  *
741  * @return ecma value
742  */
743 static ecma_value_t
ecma_op_container_set_noramlize_zero(ecma_value_t this_arg)744 ecma_op_container_set_noramlize_zero (ecma_value_t this_arg) /*< this arg */
745 {
746   if (ecma_is_value_number (this_arg))
747   {
748     ecma_number_t number_value = ecma_get_number_from_value (this_arg);
749 
750     if (JERRY_UNLIKELY (ecma_number_is_zero (number_value) && ecma_number_is_negative (number_value)))
751     {
752       return ecma_make_integer_value (0);
753     }
754   }
755 
756   return this_arg;
757 } /* ecma_op_container_set_noramlize_zero */
758 
759 /**
760  * The generic Map prototype object's 'set' and Set prototype object's 'add' routine
761  *
762  * @return ecma value
763  *         Returned value must be freed with ecma_free_value.
764  */
765 ecma_value_t
ecma_op_container_set(ecma_value_t this_arg,ecma_value_t key_arg,ecma_value_t value_arg,lit_magic_string_id_t lit_id)766 ecma_op_container_set (ecma_value_t this_arg, /**< this argument */
767                        ecma_value_t key_arg, /**< key argument */
768                        ecma_value_t value_arg, /**< value argument */
769                        lit_magic_string_id_t lit_id) /**< internal class id */
770 {
771   ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
772 
773   if (map_object_p == NULL)
774   {
775     return ECMA_VALUE_ERROR;
776   }
777 
778   ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
779                                                                     map_object_p->u.class_prop.u.value);
780 
781 #if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) ||  ENABLED (JERRY_ES2015_BUILTIN_WEAKSET)
782   if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0
783       && !ecma_is_value_object (key_arg))
784   {
785     return ecma_raise_type_error (ECMA_ERR_MSG ("Key must be an object"));
786   }
787 #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) ||  ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */
788 
789   ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id);
790 
791   if (entry_p == NULL)
792   {
793     ecma_op_internal_buffer_append (container_p,
794                                     ecma_op_container_set_noramlize_zero (key_arg),
795                                     value_arg,
796                                     lit_id);
797 
798 #if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) ||  ENABLED (JERRY_ES2015_BUILTIN_WEAKSET)
799     if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0)
800     {
801       ecma_object_t *key_p = ecma_get_object_from_value (key_arg);
802       ecma_op_container_set_weak (key_p, map_object_p);
803     }
804 #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) ||  ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */
805   }
806   else
807   {
808     ecma_op_internal_buffer_update (entry_p, ecma_op_container_set_noramlize_zero (value_arg), lit_id);
809   }
810 
811   ecma_ref_object ((ecma_object_t *) map_object_p);
812   return this_arg;
813 } /* ecma_op_container_set */
814 
815 /**
816  * The generic Map/Set prototype object's 'forEach' routine
817  *
818  * @return ecma value
819  *         Returned value must be freed with ecma_free_value.
820  */
821 ecma_value_t
ecma_op_container_foreach(ecma_value_t this_arg,ecma_value_t predicate,ecma_value_t predicate_this_arg,lit_magic_string_id_t lit_id)822 ecma_op_container_foreach (ecma_value_t this_arg, /**< this argument */
823                            ecma_value_t predicate, /**< callback function */
824                            ecma_value_t predicate_this_arg, /**< this argument for
825                                                              *   invoke predicate */
826                            lit_magic_string_id_t lit_id) /**< internal class id */
827 {
828   ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
829 
830   if (map_object_p == NULL)
831   {
832     return ECMA_VALUE_ERROR;
833   }
834 
835   if (!ecma_op_is_callable (predicate))
836   {
837     return ecma_raise_type_error (ECMA_ERR_MSG ("Callback function is not callable."));
838   }
839 
840   JERRY_ASSERT (ecma_is_value_object (predicate));
841   ecma_object_t *func_object_p = ecma_get_object_from_value (predicate);
842   ecma_value_t ret_value = ECMA_VALUE_UNDEFINED;
843 
844   ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
845                                                                     map_object_p->u.class_prop.u.value);
846 
847   uint8_t entry_size = ecma_op_container_entry_size (lit_id);
848 
849   for (uint32_t i = 0; i < ECMA_CONTAINER_ENTRY_COUNT (container_p); i += entry_size)
850   {
851     ecma_value_t *entry_p = ECMA_CONTAINER_START (container_p) + i;
852 
853     if (ecma_is_value_empty (*entry_p))
854     {
855       continue;
856     }
857 
858     ecma_value_t key_arg = *entry_p;
859     ecma_value_t value_arg = ecma_op_container_get_value (entry_p, lit_id);
860 
861     ecma_value_t call_args[] = { value_arg, key_arg, this_arg };
862     ecma_value_t call_value = ecma_op_function_call (func_object_p, predicate_this_arg, call_args, 3);
863 
864     if (ECMA_IS_VALUE_ERROR (call_value))
865     {
866       ret_value = call_value;
867       break;
868     }
869 
870     ecma_free_value (call_value);
871   }
872 
873   return ret_value;
874 } /* ecma_op_container_foreach */
875 
876 /**
877  * The Map/Set prototype object's 'clear' routine
878  *
879  * @return ecma value
880  *         Returned value must be freed with ecma_free_value.
881  */
882 ecma_value_t
ecma_op_container_clear(ecma_value_t this_arg,lit_magic_string_id_t lit_id)883 ecma_op_container_clear (ecma_value_t this_arg, /**< this argument */
884                          lit_magic_string_id_t lit_id) /**< internal class id */
885 {
886   ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
887 
888   if (map_object_p == NULL)
889   {
890     return ECMA_VALUE_ERROR;
891   }
892 
893   ecma_op_container_free_entries ((ecma_object_t *) map_object_p);
894 
895   return ECMA_VALUE_UNDEFINED;
896 } /* ecma_op_container_clear */
897 
898 /**
899  * The generic Map/Set prototype object's 'delete' routine
900  *
901  * @return ecma value
902  *         Returned value must be freed with ecma_free_value.
903  */
904 ecma_value_t
ecma_op_container_delete(ecma_value_t this_arg,ecma_value_t key_arg,lit_magic_string_id_t lit_id)905 ecma_op_container_delete (ecma_value_t this_arg, /**< this argument */
906                           ecma_value_t key_arg, /**< key argument */
907                           lit_magic_string_id_t lit_id) /**< internal class id */
908 {
909   ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
910 
911   if (map_object_p == NULL)
912   {
913     return ECMA_VALUE_ERROR;
914   }
915 
916   ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
917                                                                     map_object_p->u.class_prop.u.value);
918 
919   ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id);
920 
921   if (entry_p == NULL)
922   {
923     return ECMA_VALUE_FALSE;
924   }
925 
926   ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, lit_id);
927   return ECMA_VALUE_TRUE;
928 } /* ecma_op_container_delete */
929 
930 /**
931  * The generic WeakMap/WeakSet prototype object's 'delete' routine
932  *
933  * @return ecma value
934  *         Returned value must be freed with ecma_free_value.
935  */
936 ecma_value_t
ecma_op_container_delete_weak(ecma_value_t this_arg,ecma_value_t key_arg,lit_magic_string_id_t lit_id)937 ecma_op_container_delete_weak (ecma_value_t this_arg, /**< this argument */
938                                ecma_value_t key_arg, /**< key argument */
939                                lit_magic_string_id_t lit_id) /**< internal class id */
940 {
941   ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
942 
943   if (map_object_p == NULL)
944   {
945     return ECMA_VALUE_ERROR;
946   }
947 
948   if (!ecma_is_value_object (key_arg))
949   {
950     return ECMA_VALUE_FALSE;
951   }
952 
953   ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
954                                                                     map_object_p->u.class_prop.u.value);
955 
956   ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id);
957 
958   if (entry_p == NULL)
959   {
960     return ECMA_VALUE_FALSE;
961   }
962 
963   ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, lit_id);
964 
965   ecma_object_t *key_object_p = ecma_get_object_from_value (key_arg);
966   ecma_op_container_unref_weak (key_object_p, ecma_make_object_value ((ecma_object_t *) map_object_p));
967 
968   return ECMA_VALUE_TRUE;
969 } /* ecma_op_container_delete_weak */
970 
971 /**
972  * Helper function to remove a weak reference to an object.
973  *
974  * @return ecma value
975  *         Returned value must be freed with ecma_free_value.
976  */
977 void
ecma_op_container_unref_weak(ecma_object_t * object_p,ecma_value_t ref_holder)978 ecma_op_container_unref_weak (ecma_object_t *object_p, /**< this argument */
979                               ecma_value_t ref_holder) /**< key argument */
980 {
981   ecma_string_t *weak_refs_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_WEAK_REFS);
982 
983   ecma_property_t *property_p = ecma_find_named_property (object_p, weak_refs_string_p);
984   JERRY_ASSERT (property_p != NULL);
985 
986   ecma_collection_t *refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
987                                                                ECMA_PROPERTY_VALUE_PTR (property_p)->value);
988   for (uint32_t i = 0; i < refs_p->item_count; i++)
989   {
990     if (refs_p->buffer_p[i] == ref_holder)
991     {
992       refs_p->buffer_p[i] = ECMA_VALUE_EMPTY;
993       break;
994     }
995   }
996 } /* ecma_op_container_unref_weak */
997 
998 /**
999  * Helper function to remove a key/value pair from a weak container object
1000  */
1001 void
ecma_op_container_remove_weak_entry(ecma_object_t * object_p,ecma_value_t key_arg)1002 ecma_op_container_remove_weak_entry (ecma_object_t *object_p, /**< internal container object */
1003                                      ecma_value_t key_arg) /**< key */
1004 {
1005   ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p;
1006 
1007   ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
1008                                                                     map_object_p->u.class_prop.u.value);
1009 
1010   ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, map_object_p->u.class_prop.class_id);
1011 
1012   JERRY_ASSERT (entry_p != NULL);
1013 
1014   ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, map_object_p->u.class_prop.class_id);
1015 } /* ecma_op_container_remove_weak_entry */
1016 
1017 #if ENABLED (JERRY_ES2015)
1018 
1019 /**
1020  * The Create{Set, Map}Iterator Abstract operation
1021  *
1022  * See also:
1023  *          ECMA-262 v6, 23.1.5.1
1024  *          ECMA-262 v6, 23.2.5.1
1025  *
1026  * Note:
1027  *     Returned value must be freed with ecma_free_value.
1028  *
1029  * @return Map/Set iterator object, if success
1030  *         error - otherwise
1031  */
1032 ecma_value_t
ecma_op_container_create_iterator(ecma_value_t this_arg,uint8_t type,lit_magic_string_id_t lit_id,ecma_builtin_id_t proto_id,ecma_pseudo_array_type_t iterator_type)1033 ecma_op_container_create_iterator (ecma_value_t this_arg, /**< this argument */
1034                                    uint8_t type, /**< any combination of
1035                                                   *   ecma_iterator_type_t bits */
1036                                    lit_magic_string_id_t lit_id, /**< internal class id */
1037                                    ecma_builtin_id_t proto_id, /**< prototype builtin id */
1038                                    ecma_pseudo_array_type_t iterator_type) /**< type of the iterator */
1039 {
1040   ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
1041 
1042   if (map_object_p == NULL)
1043   {
1044     return ECMA_VALUE_ERROR;
1045   }
1046 
1047   return ecma_op_create_iterator_object (this_arg,
1048                                          ecma_builtin_get (proto_id),
1049                                          (uint8_t) iterator_type,
1050                                          type);
1051 } /* ecma_op_container_create_iterator */
1052 
1053 /**
1054  * Get the index of the iterator object.
1055  *
1056  * @return index of the iterator.
1057  */
1058 static uint32_t
ecma_op_iterator_get_index(ecma_object_t * iter_obj_p)1059 ecma_op_iterator_get_index (ecma_object_t *iter_obj_p)  /**< iterator object pointer */
1060 {
1061   uint32_t index = ((ecma_extended_object_t *) iter_obj_p)->u.pseudo_array.u1.iterator_index;
1062 
1063   if (JERRY_UNLIKELY (index == ECMA_ITERATOR_INDEX_LIMIT))
1064   {
1065     ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX);
1066     ecma_property_t *property_p = ecma_find_named_property (iter_obj_p, prop_name_p);
1067     ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
1068 
1069     return (uint32_t) (ecma_get_number_from_value (value_p->value));
1070   }
1071 
1072   return index;
1073 } /* ecma_op_iterator_get_index */
1074 
1075 /**
1076  * Set the index of the iterator object.
1077  */
1078 static void
ecma_op_iterator_set_index(ecma_object_t * iter_obj_p,uint32_t index)1079 ecma_op_iterator_set_index (ecma_object_t *iter_obj_p, /**< iterator object pointer */
1080                             uint32_t index) /* iterator index to set */
1081 {
1082   if (JERRY_UNLIKELY (index >= ECMA_ITERATOR_INDEX_LIMIT))
1083   {
1084     /* After the ECMA_ITERATOR_INDEX_LIMIT limit is reached the [[%Iterator%NextIndex]]
1085        property is stored as an internal property */
1086     ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX);
1087     ecma_property_t *property_p = ecma_find_named_property (iter_obj_p, prop_name_p);
1088     ecma_property_value_t *value_p;
1089 
1090     if (property_p == NULL)
1091     {
1092       value_p = ecma_create_named_data_property (iter_obj_p, prop_name_p, ECMA_PROPERTY_FLAG_WRITABLE, &property_p);
1093       value_p->value = ecma_make_uint32_value (index);
1094     }
1095     else
1096     {
1097       value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
1098       value_p->value = ecma_make_uint32_value (index);
1099     }
1100   }
1101   else
1102   {
1103     ((ecma_extended_object_t *) iter_obj_p)->u.pseudo_array.u1.iterator_index = (uint16_t) index;
1104   }
1105 } /* ecma_op_iterator_set_index */
1106 
1107 /**
1108  * The %{Set, Map}IteratorPrototype% object's 'next' routine
1109  *
1110  * See also:
1111  *          ECMA-262 v6, 23.1.5.2.1
1112  *          ECMA-262 v6, 23.2.5.2.1
1113  *
1114  * Note:
1115  *     Returned value must be freed with ecma_free_value.
1116  *
1117  * @return iterator result object, if success
1118  *         error - otherwise
1119  */
1120 ecma_value_t
ecma_op_container_iterator_next(ecma_value_t this_val,ecma_pseudo_array_type_t iterator_type)1121 ecma_op_container_iterator_next (ecma_value_t this_val, /**< this argument */
1122                                  ecma_pseudo_array_type_t iterator_type) /**< type of the iterator */
1123 {
1124   if (!ecma_is_value_object (this_val))
1125   {
1126     return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not an object."));
1127   }
1128 
1129   ecma_object_t *obj_p = ecma_get_object_from_value (this_val);
1130   ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p;
1131 
1132   if (ecma_get_object_type (obj_p) != ECMA_OBJECT_TYPE_PSEUDO_ARRAY
1133       || ext_obj_p->u.pseudo_array.type != iterator_type)
1134   {
1135     return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not an iterator."));
1136   }
1137 
1138   ecma_value_t iterated_value = ext_obj_p->u.pseudo_array.u2.iterated_value;
1139 
1140   if (ecma_is_value_empty (iterated_value))
1141   {
1142     return ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE);
1143   }
1144 
1145   ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) (ecma_get_object_from_value (iterated_value));
1146   lit_magic_string_id_t lit_id = map_object_p->u.class_prop.class_id;
1147 
1148   ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
1149                                                                     map_object_p->u.class_prop.u.value);
1150   uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
1151   uint32_t index = ecma_op_iterator_get_index (obj_p);
1152 
1153   if (index == entry_count)
1154   {
1155     ext_obj_p->u.pseudo_array.u2.iterated_value = ECMA_VALUE_EMPTY;
1156 
1157     return ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE);
1158   }
1159 
1160   uint8_t entry_size = ecma_op_container_entry_size (lit_id);
1161   uint8_t iterator_kind = ext_obj_p->u.pseudo_array.extra_info;
1162   ecma_value_t *start_p = ECMA_CONTAINER_START (container_p);
1163   ecma_value_t ret_value = ECMA_VALUE_UNDEFINED;
1164 
1165   for (uint32_t i = index; i < entry_count; i += entry_size)
1166   {
1167     ecma_value_t *entry_p = start_p + i;
1168 
1169     if (ecma_is_value_empty (*entry_p))
1170     {
1171       if (i == (entry_count - entry_size))
1172       {
1173         ret_value = ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE);
1174         break;
1175       }
1176 
1177       continue;
1178     }
1179 
1180     ecma_op_iterator_set_index (obj_p, i + entry_size);
1181 
1182     ecma_value_t key_arg = *entry_p;
1183     ecma_value_t value_arg = ecma_op_container_get_value (entry_p, lit_id);
1184 
1185     if (iterator_kind == ECMA_ITERATOR_KEYS)
1186     {
1187       ret_value = ecma_create_iter_result_object (key_arg, ECMA_VALUE_FALSE);
1188     }
1189     else if (iterator_kind == ECMA_ITERATOR_VALUES)
1190     {
1191       ret_value = ecma_create_iter_result_object (value_arg, ECMA_VALUE_FALSE);
1192     }
1193     else
1194     {
1195       JERRY_ASSERT (iterator_kind == ECMA_ITERATOR_KEYS_VALUES);
1196 
1197       ecma_value_t entry_array_value;
1198       entry_array_value = ecma_create_array_from_iter_element (value_arg, key_arg);
1199 
1200       ret_value = ecma_create_iter_result_object (entry_array_value, ECMA_VALUE_FALSE);
1201       ecma_free_value (entry_array_value);
1202     }
1203 
1204     break;
1205   }
1206 
1207   return ret_value;
1208 } /* ecma_op_container_iterator_next */
1209 
1210 #endif /* ENABLED (JERRY_ES2015) */
1211 
1212 /**
1213  * @}
1214  * @}
1215  */
1216 
1217 #endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */
1218