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