1425bb815Sopenharmony_ci/* Copyright JS Foundation and other contributors, http://js.foundation
2425bb815Sopenharmony_ci *
3425bb815Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4425bb815Sopenharmony_ci * you may not use this file except in compliance with the License.
5425bb815Sopenharmony_ci * You may obtain a copy of the License at
6425bb815Sopenharmony_ci *
7425bb815Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8425bb815Sopenharmony_ci *
9425bb815Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10425bb815Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS
11425bb815Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12425bb815Sopenharmony_ci * See the License for the specific language governing permissions and
13425bb815Sopenharmony_ci * limitations under the License.
14425bb815Sopenharmony_ci */
15425bb815Sopenharmony_ci#include "jcontext.h"
16425bb815Sopenharmony_ci#include "ecma-alloc.h"
17425bb815Sopenharmony_ci#include "ecma-array-object.h"
18425bb815Sopenharmony_ci#include "ecma-builtins.h"
19425bb815Sopenharmony_ci#include "ecma-builtin-helpers.h"
20425bb815Sopenharmony_ci#include "ecma-exceptions.h"
21425bb815Sopenharmony_ci#include "ecma-function-object.h"
22425bb815Sopenharmony_ci#include "ecma-gc.h"
23425bb815Sopenharmony_ci#include "ecma-helpers.h"
24425bb815Sopenharmony_ci#include "ecma-iterator-object.h"
25425bb815Sopenharmony_ci#include "ecma-container-object.h"
26425bb815Sopenharmony_ci#include "ecma-property-hashmap.h"
27425bb815Sopenharmony_ci#include "ecma-objects.h"
28425bb815Sopenharmony_ci
29425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER)
30425bb815Sopenharmony_ci
31425bb815Sopenharmony_ci/** \addtogroup ecma ECMA
32425bb815Sopenharmony_ci * @{
33425bb815Sopenharmony_ci *
34425bb815Sopenharmony_ci * \addtogroup \addtogroup ecmamaphelpers ECMA builtin Map/Set helper functions
35425bb815Sopenharmony_ci * @{
36425bb815Sopenharmony_ci */
37425bb815Sopenharmony_ci
38425bb815Sopenharmony_ci/**
39425bb815Sopenharmony_ci * Create a new internal buffer.
40425bb815Sopenharmony_ci *
41425bb815Sopenharmony_ci * Note:
42425bb815Sopenharmony_ci *   The first element of the collection tracks the size of the buffer.
43425bb815Sopenharmony_ci *   ECMA_VALUE_EMPTY values are not calculated into the size.
44425bb815Sopenharmony_ci *
45425bb815Sopenharmony_ci * @return pointer to the internal buffer
46425bb815Sopenharmony_ci */
47425bb815Sopenharmony_cistatic inline ecma_collection_t *
48425bb815Sopenharmony_ciecma_op_create_internal_buffer (void)
49425bb815Sopenharmony_ci{
50425bb815Sopenharmony_ci  ecma_collection_t *collection_p = ecma_new_collection ();
51425bb815Sopenharmony_ci  ecma_collection_push_back (collection_p, (ecma_value_t) 0);
52425bb815Sopenharmony_ci
53425bb815Sopenharmony_ci  return collection_p;
54425bb815Sopenharmony_ci} /* ecma_op_create_internal_buffer */
55425bb815Sopenharmony_ci
56425bb815Sopenharmony_ci/**
57425bb815Sopenharmony_ci * Append values to the internal buffer.
58425bb815Sopenharmony_ci */
59425bb815Sopenharmony_cistatic void
60425bb815Sopenharmony_ciecma_op_internal_buffer_append (ecma_collection_t *container_p, /**< internal container pointer */
61425bb815Sopenharmony_ci                                ecma_value_t key_arg, /**< key argument */
62425bb815Sopenharmony_ci                                ecma_value_t value_arg, /**< value argument */
63425bb815Sopenharmony_ci                                lit_magic_string_id_t lit_id) /**< class id */
64425bb815Sopenharmony_ci{
65425bb815Sopenharmony_ci  JERRY_ASSERT (container_p != NULL);
66425bb815Sopenharmony_ci
67425bb815Sopenharmony_ci  if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL)
68425bb815Sopenharmony_ci  {
69425bb815Sopenharmony_ci    ecma_value_t values[] = { ecma_copy_value_if_not_object (key_arg), ecma_copy_value_if_not_object (value_arg) };
70425bb815Sopenharmony_ci    ecma_collection_append (container_p, values, 2);
71425bb815Sopenharmony_ci  }
72425bb815Sopenharmony_ci  else
73425bb815Sopenharmony_ci  {
74425bb815Sopenharmony_ci    ecma_collection_push_back (container_p, ecma_copy_value_if_not_object (key_arg));
75425bb815Sopenharmony_ci  }
76425bb815Sopenharmony_ci
77425bb815Sopenharmony_ci  ECMA_CONTAINER_SET_SIZE (container_p, ECMA_CONTAINER_GET_SIZE (container_p) + 1);
78425bb815Sopenharmony_ci} /* ecma_op_internal_buffer_append */
79425bb815Sopenharmony_ci
80425bb815Sopenharmony_ci/**
81425bb815Sopenharmony_ci * Update the value of a given entry.
82425bb815Sopenharmony_ci */
83425bb815Sopenharmony_cistatic inline void
84425bb815Sopenharmony_ciecma_op_internal_buffer_update (ecma_value_t *entry_p, /**< entry pointer */
85425bb815Sopenharmony_ci                                ecma_value_t value_arg, /**< value argument */
86425bb815Sopenharmony_ci                                lit_magic_string_id_t lit_id) /**< class id */
87425bb815Sopenharmony_ci{
88425bb815Sopenharmony_ci  JERRY_ASSERT (entry_p != NULL);
89425bb815Sopenharmony_ci
90425bb815Sopenharmony_ci  if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL)
91425bb815Sopenharmony_ci  {
92425bb815Sopenharmony_ci    ecma_free_value_if_not_object (((ecma_container_pair_t *) entry_p)->value);
93425bb815Sopenharmony_ci
94425bb815Sopenharmony_ci    ((ecma_container_pair_t *) entry_p)->value = ecma_copy_value_if_not_object (value_arg);
95425bb815Sopenharmony_ci  }
96425bb815Sopenharmony_ci} /* ecma_op_internal_buffer_update */
97425bb815Sopenharmony_ci
98425bb815Sopenharmony_ci/**
99425bb815Sopenharmony_ci * Delete element from the internal buffer.
100425bb815Sopenharmony_ci */
101425bb815Sopenharmony_cistatic void
102425bb815Sopenharmony_ciecma_op_internal_buffer_delete (ecma_collection_t *container_p, /**< internal container pointer */
103425bb815Sopenharmony_ci                                ecma_container_pair_t *entry_p, /**< entry pointer */
104425bb815Sopenharmony_ci                                lit_magic_string_id_t lit_id) /**< class id */
105425bb815Sopenharmony_ci{
106425bb815Sopenharmony_ci  JERRY_ASSERT (container_p != NULL);
107425bb815Sopenharmony_ci  JERRY_ASSERT (entry_p != NULL);
108425bb815Sopenharmony_ci
109425bb815Sopenharmony_ci  ecma_free_value_if_not_object (entry_p->key);
110425bb815Sopenharmony_ci  entry_p->key = ECMA_VALUE_EMPTY;
111425bb815Sopenharmony_ci
112425bb815Sopenharmony_ci  if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL)
113425bb815Sopenharmony_ci  {
114425bb815Sopenharmony_ci    ecma_free_value_if_not_object (entry_p->value);
115425bb815Sopenharmony_ci    entry_p->value = ECMA_VALUE_EMPTY;
116425bb815Sopenharmony_ci  }
117425bb815Sopenharmony_ci
118425bb815Sopenharmony_ci  ECMA_CONTAINER_SET_SIZE (container_p, ECMA_CONTAINER_GET_SIZE (container_p) - 1);
119425bb815Sopenharmony_ci} /* ecma_op_internal_buffer_delete */
120425bb815Sopenharmony_ci
121425bb815Sopenharmony_ci/**
122425bb815Sopenharmony_ci * Find an entry in the collection.
123425bb815Sopenharmony_ci *
124425bb815Sopenharmony_ci * @return pointer to the appropriate entry.
125425bb815Sopenharmony_ci */
126425bb815Sopenharmony_cistatic ecma_value_t *
127425bb815Sopenharmony_ciecma_op_internal_buffer_find (ecma_collection_t *container_p, /**< internal container pointer */
128425bb815Sopenharmony_ci                              ecma_value_t key_arg, /**< key argument */
129425bb815Sopenharmony_ci                              lit_magic_string_id_t lit_id) /**< class id */
130425bb815Sopenharmony_ci{
131425bb815Sopenharmony_ci  JERRY_ASSERT (container_p != NULL);
132425bb815Sopenharmony_ci
133425bb815Sopenharmony_ci  uint8_t entry_size = ecma_op_container_entry_size (lit_id);
134425bb815Sopenharmony_ci  uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
135425bb815Sopenharmony_ci  ecma_value_t *start_p = ECMA_CONTAINER_START (container_p);
136425bb815Sopenharmony_ci
137425bb815Sopenharmony_ci  for (uint32_t i = 0; i < entry_count; i += entry_size)
138425bb815Sopenharmony_ci  {
139425bb815Sopenharmony_ci    ecma_value_t *entry_p = start_p + i;
140425bb815Sopenharmony_ci
141425bb815Sopenharmony_ci    if (ecma_op_same_value_zero (*entry_p, key_arg))
142425bb815Sopenharmony_ci    {
143425bb815Sopenharmony_ci      return entry_p;
144425bb815Sopenharmony_ci    }
145425bb815Sopenharmony_ci  }
146425bb815Sopenharmony_ci
147425bb815Sopenharmony_ci  return NULL;
148425bb815Sopenharmony_ci} /* ecma_op_internal_buffer_find */
149425bb815Sopenharmony_ci
150425bb815Sopenharmony_ci/**
151425bb815Sopenharmony_ci * Get the value that belongs to the key.
152425bb815Sopenharmony_ci *
153425bb815Sopenharmony_ci * Note: in case of Set containers, the values are the same as the keys.
154425bb815Sopenharmony_ci *
155425bb815Sopenharmony_ci * @return ecma value
156425bb815Sopenharmony_ci */
157425bb815Sopenharmony_cistatic ecma_value_t
158425bb815Sopenharmony_ciecma_op_container_get_value (ecma_value_t *entry_p, /**< entry (key) pointer */
159425bb815Sopenharmony_ci                             lit_magic_string_id_t lit_id) /**< class id */
160425bb815Sopenharmony_ci{
161425bb815Sopenharmony_ci  JERRY_ASSERT (entry_p != NULL);
162425bb815Sopenharmony_ci
163425bb815Sopenharmony_ci  if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL)
164425bb815Sopenharmony_ci  {
165425bb815Sopenharmony_ci    return ((ecma_container_pair_t *) entry_p)->value;
166425bb815Sopenharmony_ci  }
167425bb815Sopenharmony_ci
168425bb815Sopenharmony_ci  return *entry_p;
169425bb815Sopenharmony_ci} /* ecma_op_container_get_value */
170425bb815Sopenharmony_ci
171425bb815Sopenharmony_ci/**
172425bb815Sopenharmony_ci * Get the size (in ecma_value_t) of the stored entries.
173425bb815Sopenharmony_ci *
174425bb815Sopenharmony_ci * @return size of the entries.
175425bb815Sopenharmony_ci */
176425bb815Sopenharmony_ciuint8_t
177425bb815Sopenharmony_ciecma_op_container_entry_size (lit_magic_string_id_t lit_id) /**< class id */
178425bb815Sopenharmony_ci{
179425bb815Sopenharmony_ci  if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL)
180425bb815Sopenharmony_ci  {
181425bb815Sopenharmony_ci    return ECMA_CONTAINER_PAIR_SIZE;
182425bb815Sopenharmony_ci  }
183425bb815Sopenharmony_ci
184425bb815Sopenharmony_ci  return ECMA_CONTAINER_VALUE_SIZE;
185425bb815Sopenharmony_ci} /* ecma_op_container_entry_size */
186425bb815Sopenharmony_ci
187425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET)
188425bb815Sopenharmony_ci/**
189425bb815Sopenharmony_ci * Release the entries in the WeakSet container.
190425bb815Sopenharmony_ci */
191425bb815Sopenharmony_cistatic void
192425bb815Sopenharmony_ciecma_op_container_free_weakset_entries (ecma_object_t *object_p, /**< object pointer */
193425bb815Sopenharmony_ci                                        ecma_collection_t *container_p) /** internal buffer pointer */
194425bb815Sopenharmony_ci{
195425bb815Sopenharmony_ci  JERRY_ASSERT (object_p != NULL);
196425bb815Sopenharmony_ci  JERRY_ASSERT (container_p != NULL);
197425bb815Sopenharmony_ci
198425bb815Sopenharmony_ci  uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
199425bb815Sopenharmony_ci  ecma_value_t *start_p = ECMA_CONTAINER_START (container_p);
200425bb815Sopenharmony_ci
201425bb815Sopenharmony_ci  for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_VALUE_SIZE)
202425bb815Sopenharmony_ci  {
203425bb815Sopenharmony_ci    ecma_value_t *entry_p = start_p + i;
204425bb815Sopenharmony_ci
205425bb815Sopenharmony_ci    if (ecma_is_value_empty (*entry_p))
206425bb815Sopenharmony_ci    {
207425bb815Sopenharmony_ci      continue;
208425bb815Sopenharmony_ci    }
209425bb815Sopenharmony_ci
210425bb815Sopenharmony_ci    ecma_op_container_unref_weak (ecma_get_object_from_value (*entry_p), ecma_make_object_value (object_p));
211425bb815Sopenharmony_ci    ecma_op_container_remove_weak_entry (object_p, *entry_p);
212425bb815Sopenharmony_ci
213425bb815Sopenharmony_ci    *entry_p = ECMA_VALUE_EMPTY;
214425bb815Sopenharmony_ci  }
215425bb815Sopenharmony_ci} /* ecma_op_container_free_weakset_entries */
216425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */
217425bb815Sopenharmony_ci
218425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP)
219425bb815Sopenharmony_ci/**
220425bb815Sopenharmony_ci * Release the entries in the WeakMap container.
221425bb815Sopenharmony_ci */
222425bb815Sopenharmony_cistatic void
223425bb815Sopenharmony_ciecma_op_container_free_weakmap_entries (ecma_object_t *object_p, /**< object pointer */
224425bb815Sopenharmony_ci                                        ecma_collection_t *container_p) /**< internal buffer pointer */
225425bb815Sopenharmony_ci{
226425bb815Sopenharmony_ci  JERRY_ASSERT (object_p != NULL);
227425bb815Sopenharmony_ci  JERRY_ASSERT (container_p != NULL);
228425bb815Sopenharmony_ci
229425bb815Sopenharmony_ci  uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
230425bb815Sopenharmony_ci  ecma_value_t *start_p = ECMA_CONTAINER_START (container_p);
231425bb815Sopenharmony_ci
232425bb815Sopenharmony_ci  for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_PAIR_SIZE)
233425bb815Sopenharmony_ci  {
234425bb815Sopenharmony_ci    ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i);
235425bb815Sopenharmony_ci
236425bb815Sopenharmony_ci    if (ecma_is_value_empty (entry_p->key))
237425bb815Sopenharmony_ci    {
238425bb815Sopenharmony_ci      continue;
239425bb815Sopenharmony_ci    }
240425bb815Sopenharmony_ci
241425bb815Sopenharmony_ci    ecma_op_container_unref_weak (ecma_get_object_from_value (entry_p->key), ecma_make_object_value (object_p));
242425bb815Sopenharmony_ci    ecma_op_container_remove_weak_entry (object_p, entry_p->key);
243425bb815Sopenharmony_ci
244425bb815Sopenharmony_ci    ecma_free_value_if_not_object (entry_p->value);
245425bb815Sopenharmony_ci
246425bb815Sopenharmony_ci    entry_p->key = ECMA_VALUE_EMPTY;
247425bb815Sopenharmony_ci    entry_p->value = ECMA_VALUE_EMPTY;
248425bb815Sopenharmony_ci  }
249425bb815Sopenharmony_ci} /* ecma_op_container_free_weakmap_entries */
250425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */
251425bb815Sopenharmony_ci
252425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_SET)
253425bb815Sopenharmony_ci/**
254425bb815Sopenharmony_ci * Release the entries in the Set container.
255425bb815Sopenharmony_ci */
256425bb815Sopenharmony_cistatic void
257425bb815Sopenharmony_ciecma_op_container_free_set_entries (ecma_collection_t *container_p)
258425bb815Sopenharmony_ci{
259425bb815Sopenharmony_ci  JERRY_ASSERT (container_p != NULL);
260425bb815Sopenharmony_ci
261425bb815Sopenharmony_ci  uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
262425bb815Sopenharmony_ci  ecma_value_t *start_p = ECMA_CONTAINER_START (container_p);
263425bb815Sopenharmony_ci
264425bb815Sopenharmony_ci  for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_VALUE_SIZE)
265425bb815Sopenharmony_ci  {
266425bb815Sopenharmony_ci    ecma_value_t *entry_p = start_p + i;
267425bb815Sopenharmony_ci
268425bb815Sopenharmony_ci    if (ecma_is_value_empty (*entry_p))
269425bb815Sopenharmony_ci    {
270425bb815Sopenharmony_ci      continue;
271425bb815Sopenharmony_ci    }
272425bb815Sopenharmony_ci
273425bb815Sopenharmony_ci    ecma_free_value_if_not_object (*entry_p);
274425bb815Sopenharmony_ci    *entry_p = ECMA_VALUE_EMPTY;
275425bb815Sopenharmony_ci  }
276425bb815Sopenharmony_ci} /* ecma_op_container_free_set_entries */
277425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */
278425bb815Sopenharmony_ci
279425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_MAP)
280425bb815Sopenharmony_ci/**
281425bb815Sopenharmony_ci * Release the entries in the Map container.
282425bb815Sopenharmony_ci */
283425bb815Sopenharmony_cistatic void
284425bb815Sopenharmony_ciecma_op_container_free_map_entries (ecma_collection_t *container_p)
285425bb815Sopenharmony_ci{
286425bb815Sopenharmony_ci  JERRY_ASSERT (container_p != NULL);
287425bb815Sopenharmony_ci
288425bb815Sopenharmony_ci  uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
289425bb815Sopenharmony_ci  ecma_value_t *start_p = ECMA_CONTAINER_START (container_p);
290425bb815Sopenharmony_ci
291425bb815Sopenharmony_ci  for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_PAIR_SIZE)
292425bb815Sopenharmony_ci  {
293425bb815Sopenharmony_ci    ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i);
294425bb815Sopenharmony_ci
295425bb815Sopenharmony_ci    if (ecma_is_value_empty (entry_p->key))
296425bb815Sopenharmony_ci    {
297425bb815Sopenharmony_ci      continue;
298425bb815Sopenharmony_ci    }
299425bb815Sopenharmony_ci
300425bb815Sopenharmony_ci    ecma_free_value_if_not_object (entry_p->key);
301425bb815Sopenharmony_ci    ecma_free_value_if_not_object (entry_p->value);
302425bb815Sopenharmony_ci
303425bb815Sopenharmony_ci    entry_p->key = ECMA_VALUE_EMPTY;
304425bb815Sopenharmony_ci    entry_p->value = ECMA_VALUE_EMPTY;
305425bb815Sopenharmony_ci  }
306425bb815Sopenharmony_ci} /* ecma_op_container_free_map_entries */
307425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */
308425bb815Sopenharmony_ci
309425bb815Sopenharmony_ci/**
310425bb815Sopenharmony_ci * Release the internal buffer and the stored entries.
311425bb815Sopenharmony_ci */
312425bb815Sopenharmony_civoid
313425bb815Sopenharmony_ciecma_op_container_free_entries (ecma_object_t *object_p) /**< collection object pointer */
314425bb815Sopenharmony_ci{
315425bb815Sopenharmony_ci  JERRY_ASSERT (object_p != NULL);
316425bb815Sopenharmony_ci
317425bb815Sopenharmony_ci  ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p;
318425bb815Sopenharmony_ci  ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
319425bb815Sopenharmony_ci                                                                    map_object_p->u.class_prop.u.value);
320425bb815Sopenharmony_ci
321425bb815Sopenharmony_ci  switch (map_object_p->u.class_prop.class_id)
322425bb815Sopenharmony_ci  {
323425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET)
324425bb815Sopenharmony_ci    case LIT_MAGIC_STRING_WEAKSET_UL:
325425bb815Sopenharmony_ci    {
326425bb815Sopenharmony_ci      ecma_op_container_free_weakset_entries (object_p, container_p);
327425bb815Sopenharmony_ci      break;
328425bb815Sopenharmony_ci    }
329425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */
330425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP)
331425bb815Sopenharmony_ci    case LIT_MAGIC_STRING_WEAKMAP_UL:
332425bb815Sopenharmony_ci    {
333425bb815Sopenharmony_ci      ecma_op_container_free_weakmap_entries (object_p, container_p);
334425bb815Sopenharmony_ci      break;
335425bb815Sopenharmony_ci    }
336425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */
337425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_SET)
338425bb815Sopenharmony_ci    case LIT_MAGIC_STRING_SET_UL:
339425bb815Sopenharmony_ci    {
340425bb815Sopenharmony_ci      ecma_op_container_free_set_entries (container_p);
341425bb815Sopenharmony_ci      break;
342425bb815Sopenharmony_ci    }
343425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */
344425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_MAP)
345425bb815Sopenharmony_ci    case LIT_MAGIC_STRING_MAP_UL:
346425bb815Sopenharmony_ci    {
347425bb815Sopenharmony_ci      ecma_op_container_free_map_entries (container_p);
348425bb815Sopenharmony_ci      break;
349425bb815Sopenharmony_ci    }
350425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */
351425bb815Sopenharmony_ci    default:
352425bb815Sopenharmony_ci    {
353425bb815Sopenharmony_ci      break;
354425bb815Sopenharmony_ci    }
355425bb815Sopenharmony_ci  }
356425bb815Sopenharmony_ci
357425bb815Sopenharmony_ci  ECMA_CONTAINER_SET_SIZE (container_p, 0);
358425bb815Sopenharmony_ci} /* ecma_op_container_free_entries */
359425bb815Sopenharmony_ci
360425bb815Sopenharmony_ci/**
361425bb815Sopenharmony_ci * Handle calling [[Construct]] of built-in Map/Set like objects
362425bb815Sopenharmony_ci *
363425bb815Sopenharmony_ci * @return ecma value
364425bb815Sopenharmony_ci */
365425bb815Sopenharmony_ciecma_value_t
366425bb815Sopenharmony_ciecma_op_container_create (const ecma_value_t *arguments_list_p, /**< arguments list */
367425bb815Sopenharmony_ci                          ecma_length_t arguments_list_len, /**< number of arguments */
368425bb815Sopenharmony_ci                          lit_magic_string_id_t lit_id, /**< internal class id */
369425bb815Sopenharmony_ci                          ecma_builtin_id_t proto_id) /**< prototype builtin id */
370425bb815Sopenharmony_ci{
371425bb815Sopenharmony_ci  JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
372425bb815Sopenharmony_ci  JERRY_ASSERT (lit_id == LIT_MAGIC_STRING_MAP_UL
373425bb815Sopenharmony_ci                || lit_id == LIT_MAGIC_STRING_SET_UL
374425bb815Sopenharmony_ci                || lit_id == LIT_MAGIC_STRING_WEAKMAP_UL
375425bb815Sopenharmony_ci                || lit_id == LIT_MAGIC_STRING_WEAKSET_UL);
376425bb815Sopenharmony_ci  JERRY_ASSERT (JERRY_CONTEXT (current_new_target) != NULL);
377425bb815Sopenharmony_ci
378425bb815Sopenharmony_ci  ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target), proto_id);
379425bb815Sopenharmony_ci
380425bb815Sopenharmony_ci  if (JERRY_UNLIKELY (proto_p == NULL))
381425bb815Sopenharmony_ci  {
382425bb815Sopenharmony_ci    return ECMA_VALUE_ERROR;
383425bb815Sopenharmony_ci  }
384425bb815Sopenharmony_ci
385425bb815Sopenharmony_ci  ecma_collection_t *container_p = ecma_op_create_internal_buffer ();
386425bb815Sopenharmony_ci  ecma_object_t *object_p  = ecma_create_object (proto_p,
387425bb815Sopenharmony_ci                                                 sizeof (ecma_extended_object_t),
388425bb815Sopenharmony_ci                                                 ECMA_OBJECT_TYPE_CLASS);
389425bb815Sopenharmony_ci  ecma_deref_object (proto_p);
390425bb815Sopenharmony_ci  ecma_extended_object_t *map_obj_p = (ecma_extended_object_t *) object_p;
391425bb815Sopenharmony_ci  map_obj_p->u.class_prop.extra_info = ECMA_CONTAINER_FLAGS_EMPTY;
392425bb815Sopenharmony_ci  map_obj_p->u.class_prop.class_id = (uint16_t) lit_id;
393425bb815Sopenharmony_ci
394425bb815Sopenharmony_ci  if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_WEAKSET_UL)
395425bb815Sopenharmony_ci  {
396425bb815Sopenharmony_ci    map_obj_p->u.class_prop.extra_info |= ECMA_CONTAINER_FLAGS_WEAK;
397425bb815Sopenharmony_ci  }
398425bb815Sopenharmony_ci
399425bb815Sopenharmony_ci  ECMA_SET_INTERNAL_VALUE_POINTER (map_obj_p->u.class_prop.u.value, container_p);
400425bb815Sopenharmony_ci
401425bb815Sopenharmony_ci  ecma_value_t set_value = ecma_make_object_value (object_p);
402425bb815Sopenharmony_ci  ecma_value_t result = set_value;
403425bb815Sopenharmony_ci
404425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
405425bb815Sopenharmony_ci  if (arguments_list_len == 0)
406425bb815Sopenharmony_ci  {
407425bb815Sopenharmony_ci    return result;
408425bb815Sopenharmony_ci  }
409425bb815Sopenharmony_ci
410425bb815Sopenharmony_ci  ecma_value_t iterable = arguments_list_p[0];
411425bb815Sopenharmony_ci
412425bb815Sopenharmony_ci  if (ecma_is_value_undefined (iterable) || ecma_is_value_null (iterable))
413425bb815Sopenharmony_ci  {
414425bb815Sopenharmony_ci    return result;
415425bb815Sopenharmony_ci  }
416425bb815Sopenharmony_ci
417425bb815Sopenharmony_ci  lit_magic_string_id_t adder_string_id;
418425bb815Sopenharmony_ci  if (lit_id == LIT_MAGIC_STRING_MAP_UL || lit_id == LIT_MAGIC_STRING_WEAKMAP_UL)
419425bb815Sopenharmony_ci  {
420425bb815Sopenharmony_ci    adder_string_id = LIT_MAGIC_STRING_SET;
421425bb815Sopenharmony_ci  }
422425bb815Sopenharmony_ci  else
423425bb815Sopenharmony_ci  {
424425bb815Sopenharmony_ci    adder_string_id = LIT_MAGIC_STRING_ADD;
425425bb815Sopenharmony_ci  }
426425bb815Sopenharmony_ci
427425bb815Sopenharmony_ci  result = ecma_op_object_get_by_magic_id (object_p, adder_string_id);
428425bb815Sopenharmony_ci  if (ECMA_IS_VALUE_ERROR (result))
429425bb815Sopenharmony_ci  {
430425bb815Sopenharmony_ci    goto cleanup_object;
431425bb815Sopenharmony_ci  }
432425bb815Sopenharmony_ci
433425bb815Sopenharmony_ci  if (!ecma_op_is_callable (result))
434425bb815Sopenharmony_ci  {
435425bb815Sopenharmony_ci    ecma_free_value (result);
436425bb815Sopenharmony_ci    result = ecma_raise_type_error (ECMA_ERR_MSG ("add/set function is not callable."));
437425bb815Sopenharmony_ci    goto cleanup_object;
438425bb815Sopenharmony_ci  }
439425bb815Sopenharmony_ci
440425bb815Sopenharmony_ci  ecma_object_t *adder_func_p = ecma_get_object_from_value (result);
441425bb815Sopenharmony_ci
442425bb815Sopenharmony_ci  result = ecma_op_get_iterator (iterable, ECMA_VALUE_EMPTY);
443425bb815Sopenharmony_ci
444425bb815Sopenharmony_ci  if (ECMA_IS_VALUE_ERROR (result))
445425bb815Sopenharmony_ci  {
446425bb815Sopenharmony_ci    goto cleanup_adder;
447425bb815Sopenharmony_ci  }
448425bb815Sopenharmony_ci
449425bb815Sopenharmony_ci  const ecma_value_t iter = result;
450425bb815Sopenharmony_ci
451425bb815Sopenharmony_ci  while (true)
452425bb815Sopenharmony_ci  {
453425bb815Sopenharmony_ci    result = ecma_op_iterator_step (iter);
454425bb815Sopenharmony_ci
455425bb815Sopenharmony_ci    if (ECMA_IS_VALUE_ERROR (result))
456425bb815Sopenharmony_ci    {
457425bb815Sopenharmony_ci      goto cleanup_iter;
458425bb815Sopenharmony_ci    }
459425bb815Sopenharmony_ci
460425bb815Sopenharmony_ci    if (ecma_is_value_false (result))
461425bb815Sopenharmony_ci    {
462425bb815Sopenharmony_ci      break;
463425bb815Sopenharmony_ci    }
464425bb815Sopenharmony_ci
465425bb815Sopenharmony_ci    const ecma_value_t next = result;
466425bb815Sopenharmony_ci    result = ecma_op_iterator_value (next);
467425bb815Sopenharmony_ci    ecma_free_value (next);
468425bb815Sopenharmony_ci
469425bb815Sopenharmony_ci    if (ECMA_IS_VALUE_ERROR (result))
470425bb815Sopenharmony_ci    {
471425bb815Sopenharmony_ci      goto cleanup_iter;
472425bb815Sopenharmony_ci    }
473425bb815Sopenharmony_ci
474425bb815Sopenharmony_ci    if (lit_id == LIT_MAGIC_STRING_SET_UL || lit_id == LIT_MAGIC_STRING_WEAKSET_UL)
475425bb815Sopenharmony_ci    {
476425bb815Sopenharmony_ci      const ecma_value_t value = result;
477425bb815Sopenharmony_ci
478425bb815Sopenharmony_ci      ecma_value_t arguments[] = { value };
479425bb815Sopenharmony_ci      result = ecma_op_function_call (adder_func_p, set_value, arguments, 1);
480425bb815Sopenharmony_ci
481425bb815Sopenharmony_ci      ecma_free_value (value);
482425bb815Sopenharmony_ci    }
483425bb815Sopenharmony_ci    else
484425bb815Sopenharmony_ci    {
485425bb815Sopenharmony_ci      if (!ecma_is_value_object (result))
486425bb815Sopenharmony_ci      {
487425bb815Sopenharmony_ci        ecma_free_value (result);
488425bb815Sopenharmony_ci        ecma_raise_type_error (ECMA_ERR_MSG ("Iterator value is not an object."));
489425bb815Sopenharmony_ci        result = ecma_op_iterator_close (iter);
490425bb815Sopenharmony_ci        JERRY_ASSERT (ECMA_IS_VALUE_ERROR (result));
491425bb815Sopenharmony_ci        goto cleanup_iter;
492425bb815Sopenharmony_ci      }
493425bb815Sopenharmony_ci
494425bb815Sopenharmony_ci      ecma_object_t *next_object_p = ecma_get_object_from_value (result);
495425bb815Sopenharmony_ci
496425bb815Sopenharmony_ci      result = ecma_op_object_get_by_uint32_index (next_object_p, 0);
497425bb815Sopenharmony_ci
498425bb815Sopenharmony_ci      if (ECMA_IS_VALUE_ERROR (result))
499425bb815Sopenharmony_ci      {
500425bb815Sopenharmony_ci        ecma_deref_object (next_object_p);
501425bb815Sopenharmony_ci        ecma_op_iterator_close (iter);
502425bb815Sopenharmony_ci        goto cleanup_iter;
503425bb815Sopenharmony_ci      }
504425bb815Sopenharmony_ci
505425bb815Sopenharmony_ci      const ecma_value_t key = result;
506425bb815Sopenharmony_ci
507425bb815Sopenharmony_ci      result = ecma_op_object_get_by_uint32_index (next_object_p, 1);
508425bb815Sopenharmony_ci
509425bb815Sopenharmony_ci      if (ECMA_IS_VALUE_ERROR (result))
510425bb815Sopenharmony_ci      {
511425bb815Sopenharmony_ci        ecma_deref_object (next_object_p);
512425bb815Sopenharmony_ci        ecma_free_value (key);
513425bb815Sopenharmony_ci        ecma_op_iterator_close (iter);
514425bb815Sopenharmony_ci        goto cleanup_iter;
515425bb815Sopenharmony_ci      }
516425bb815Sopenharmony_ci
517425bb815Sopenharmony_ci      const ecma_value_t value = result;
518425bb815Sopenharmony_ci      ecma_value_t arguments[] = { key, value };
519425bb815Sopenharmony_ci      result = ecma_op_function_call (adder_func_p, set_value, arguments, 2);
520425bb815Sopenharmony_ci
521425bb815Sopenharmony_ci      ecma_free_value (key);
522425bb815Sopenharmony_ci      ecma_free_value (value);
523425bb815Sopenharmony_ci      ecma_deref_object (next_object_p);
524425bb815Sopenharmony_ci    }
525425bb815Sopenharmony_ci
526425bb815Sopenharmony_ci    if (ECMA_IS_VALUE_ERROR (result))
527425bb815Sopenharmony_ci    {
528425bb815Sopenharmony_ci      ecma_op_iterator_close (iter);
529425bb815Sopenharmony_ci      goto cleanup_iter;
530425bb815Sopenharmony_ci    }
531425bb815Sopenharmony_ci
532425bb815Sopenharmony_ci    ecma_free_value (result);
533425bb815Sopenharmony_ci  }
534425bb815Sopenharmony_ci
535425bb815Sopenharmony_ci  ecma_free_value (iter);
536425bb815Sopenharmony_ci  ecma_deref_object (adder_func_p);
537425bb815Sopenharmony_ci  return ecma_make_object_value (object_p);
538425bb815Sopenharmony_ci
539425bb815Sopenharmony_cicleanup_iter:
540425bb815Sopenharmony_ci  ecma_free_value (iter);
541425bb815Sopenharmony_cicleanup_adder:
542425bb815Sopenharmony_ci  ecma_deref_object (adder_func_p);
543425bb815Sopenharmony_cicleanup_object:
544425bb815Sopenharmony_ci  ecma_deref_object (object_p);
545425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
546425bb815Sopenharmony_ci
547425bb815Sopenharmony_ci  return result;
548425bb815Sopenharmony_ci} /* ecma_op_container_create */
549425bb815Sopenharmony_ci
550425bb815Sopenharmony_ci/**
551425bb815Sopenharmony_ci * Get Map/Set object pointer
552425bb815Sopenharmony_ci *
553425bb815Sopenharmony_ci * Note:
554425bb815Sopenharmony_ci *   If the function returns with NULL, the error object has
555425bb815Sopenharmony_ci *   already set, and the caller must return with ECMA_VALUE_ERROR
556425bb815Sopenharmony_ci *
557425bb815Sopenharmony_ci * @return pointer to the Map/Set if this_arg is a valid Map/Set object
558425bb815Sopenharmony_ci *         NULL otherwise
559425bb815Sopenharmony_ci */
560425bb815Sopenharmony_cistatic ecma_extended_object_t *
561425bb815Sopenharmony_ciecma_op_container_get_object (ecma_value_t this_arg, /**< this argument */
562425bb815Sopenharmony_ci                              lit_magic_string_id_t lit_id) /**< internal class id */
563425bb815Sopenharmony_ci{
564425bb815Sopenharmony_ci  if (ecma_is_value_object (this_arg))
565425bb815Sopenharmony_ci  {
566425bb815Sopenharmony_ci    ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) ecma_get_object_from_value (this_arg);
567425bb815Sopenharmony_ci
568425bb815Sopenharmony_ci    if (ecma_get_object_type ((ecma_object_t *) map_object_p) == ECMA_OBJECT_TYPE_CLASS
569425bb815Sopenharmony_ci        && map_object_p->u.class_prop.class_id == lit_id)
570425bb815Sopenharmony_ci    {
571425bb815Sopenharmony_ci      return map_object_p;
572425bb815Sopenharmony_ci    }
573425bb815Sopenharmony_ci  }
574425bb815Sopenharmony_ci
575425bb815Sopenharmony_ci#if ENABLED (JERRY_ERROR_MESSAGES)
576425bb815Sopenharmony_ci  ecma_raise_standard_error_with_format (ECMA_ERROR_TYPE,
577425bb815Sopenharmony_ci                                         "Expected a % object.",
578425bb815Sopenharmony_ci                                         ecma_make_string_value (ecma_get_magic_string (lit_id)));
579425bb815Sopenharmony_ci#else /* !ENABLED (JERRY_ERROR_MESSAGES) */
580425bb815Sopenharmony_ci  ecma_raise_type_error (NULL);
581425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ERROR_MESSAGES) */
582425bb815Sopenharmony_ci
583425bb815Sopenharmony_ci  return NULL;
584425bb815Sopenharmony_ci} /* ecma_op_container_get_object */
585425bb815Sopenharmony_ci
586425bb815Sopenharmony_ci/**
587425bb815Sopenharmony_ci * Returns with the size of the Map/Set object.
588425bb815Sopenharmony_ci *
589425bb815Sopenharmony_ci * @return size of the Map/Set object as ecma-value.
590425bb815Sopenharmony_ci */
591425bb815Sopenharmony_ciecma_value_t
592425bb815Sopenharmony_ciecma_op_container_size (ecma_value_t this_arg, /**< this argument */
593425bb815Sopenharmony_ci                        lit_magic_string_id_t lit_id) /**< internal class id */
594425bb815Sopenharmony_ci{
595425bb815Sopenharmony_ci  ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
596425bb815Sopenharmony_ci
597425bb815Sopenharmony_ci  if (map_object_p == NULL)
598425bb815Sopenharmony_ci  {
599425bb815Sopenharmony_ci    return ECMA_VALUE_ERROR;
600425bb815Sopenharmony_ci  }
601425bb815Sopenharmony_ci
602425bb815Sopenharmony_ci  ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
603425bb815Sopenharmony_ci                                                                    map_object_p->u.class_prop.u.value);
604425bb815Sopenharmony_ci
605425bb815Sopenharmony_ci  return ecma_make_uint32_value (ECMA_CONTAINER_GET_SIZE (container_p));
606425bb815Sopenharmony_ci} /* ecma_op_container_size */
607425bb815Sopenharmony_ci
608425bb815Sopenharmony_ci/**
609425bb815Sopenharmony_ci * The generic Map/WeakMap prototype object's 'get' routine
610425bb815Sopenharmony_ci *
611425bb815Sopenharmony_ci * @return ecma value
612425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
613425bb815Sopenharmony_ci */
614425bb815Sopenharmony_ciecma_value_t
615425bb815Sopenharmony_ciecma_op_container_get (ecma_value_t this_arg, /**< this argument */
616425bb815Sopenharmony_ci                       ecma_value_t key_arg, /**< key argument */
617425bb815Sopenharmony_ci                       lit_magic_string_id_t lit_id) /**< internal class id */
618425bb815Sopenharmony_ci{
619425bb815Sopenharmony_ci  ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
620425bb815Sopenharmony_ci
621425bb815Sopenharmony_ci  if (map_object_p == NULL)
622425bb815Sopenharmony_ci  {
623425bb815Sopenharmony_ci    return ECMA_VALUE_ERROR;
624425bb815Sopenharmony_ci  }
625425bb815Sopenharmony_ci
626425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP)
627425bb815Sopenharmony_ci  if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL && !ecma_is_value_object (key_arg))
628425bb815Sopenharmony_ci  {
629425bb815Sopenharmony_ci    return ECMA_VALUE_UNDEFINED;
630425bb815Sopenharmony_ci  }
631425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */
632425bb815Sopenharmony_ci
633425bb815Sopenharmony_ci  ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
634425bb815Sopenharmony_ci                                                                    map_object_p->u.class_prop.u.value);
635425bb815Sopenharmony_ci
636425bb815Sopenharmony_ci  if (ECMA_CONTAINER_GET_SIZE (container_p) == 0)
637425bb815Sopenharmony_ci  {
638425bb815Sopenharmony_ci    return ECMA_VALUE_UNDEFINED;
639425bb815Sopenharmony_ci  }
640425bb815Sopenharmony_ci
641425bb815Sopenharmony_ci  ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id);
642425bb815Sopenharmony_ci
643425bb815Sopenharmony_ci  if (entry_p == NULL)
644425bb815Sopenharmony_ci  {
645425bb815Sopenharmony_ci    return ECMA_VALUE_UNDEFINED;
646425bb815Sopenharmony_ci  }
647425bb815Sopenharmony_ci
648425bb815Sopenharmony_ci  return ecma_copy_value (((ecma_container_pair_t *) entry_p)->value);
649425bb815Sopenharmony_ci} /* ecma_op_container_get */
650425bb815Sopenharmony_ci
651425bb815Sopenharmony_ci/**
652425bb815Sopenharmony_ci * The generic Map/Set prototype object's 'has' routine
653425bb815Sopenharmony_ci *
654425bb815Sopenharmony_ci * @return ecma value
655425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
656425bb815Sopenharmony_ci */
657425bb815Sopenharmony_ciecma_value_t
658425bb815Sopenharmony_ciecma_op_container_has (ecma_value_t this_arg, /**< this argument */
659425bb815Sopenharmony_ci                       ecma_value_t key_arg, /**< key argument */
660425bb815Sopenharmony_ci                       lit_magic_string_id_t lit_id) /**< internal class id */
661425bb815Sopenharmony_ci{
662425bb815Sopenharmony_ci  ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
663425bb815Sopenharmony_ci
664425bb815Sopenharmony_ci  if (map_object_p == NULL)
665425bb815Sopenharmony_ci  {
666425bb815Sopenharmony_ci    return ECMA_VALUE_ERROR;
667425bb815Sopenharmony_ci  }
668425bb815Sopenharmony_ci
669425bb815Sopenharmony_ci  ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
670425bb815Sopenharmony_ci                                                                    map_object_p->u.class_prop.u.value);
671425bb815Sopenharmony_ci
672425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET)
673425bb815Sopenharmony_ci  if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0
674425bb815Sopenharmony_ci      && !ecma_is_value_object (key_arg))
675425bb815Sopenharmony_ci  {
676425bb815Sopenharmony_ci    return ECMA_VALUE_FALSE;
677425bb815Sopenharmony_ci  }
678425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) ||  ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */
679425bb815Sopenharmony_ci
680425bb815Sopenharmony_ci  if (ECMA_CONTAINER_GET_SIZE (container_p) == 0)
681425bb815Sopenharmony_ci  {
682425bb815Sopenharmony_ci    return ECMA_VALUE_FALSE;
683425bb815Sopenharmony_ci  }
684425bb815Sopenharmony_ci
685425bb815Sopenharmony_ci  ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id);
686425bb815Sopenharmony_ci
687425bb815Sopenharmony_ci  return ecma_make_boolean_value (entry_p != NULL);
688425bb815Sopenharmony_ci} /* ecma_op_container_has */
689425bb815Sopenharmony_ci
690425bb815Sopenharmony_ci/**
691425bb815Sopenharmony_ci * Set a weak reference from a container to a key object
692425bb815Sopenharmony_ci */
693425bb815Sopenharmony_cistatic void
694425bb815Sopenharmony_ciecma_op_container_set_weak (ecma_object_t *const key_p, /**< key object */
695425bb815Sopenharmony_ci                            ecma_extended_object_t *const container_p) /**< container */
696425bb815Sopenharmony_ci{
697425bb815Sopenharmony_ci  if (JERRY_UNLIKELY (ecma_op_object_is_fast_array (key_p)))
698425bb815Sopenharmony_ci  {
699425bb815Sopenharmony_ci    ecma_fast_array_convert_to_normal (key_p);
700425bb815Sopenharmony_ci  }
701425bb815Sopenharmony_ci
702425bb815Sopenharmony_ci  ecma_string_t *weak_refs_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_WEAK_REFS);
703425bb815Sopenharmony_ci  ecma_property_t *property_p = ecma_find_named_property (key_p, weak_refs_string_p);
704425bb815Sopenharmony_ci  ecma_collection_t *refs_p;
705425bb815Sopenharmony_ci
706425bb815Sopenharmony_ci  if (property_p == NULL)
707425bb815Sopenharmony_ci  {
708425bb815Sopenharmony_ci    ecma_property_value_t *value_p = ecma_create_named_data_property (key_p,
709425bb815Sopenharmony_ci                                                                      weak_refs_string_p,
710425bb815Sopenharmony_ci                                                                      ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
711425bb815Sopenharmony_ci                                                                      &property_p);
712425bb815Sopenharmony_ci    ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY (property_p);
713425bb815Sopenharmony_ci    refs_p = ecma_new_collection ();
714425bb815Sopenharmony_ci    ECMA_SET_INTERNAL_VALUE_POINTER (value_p->value, refs_p);
715425bb815Sopenharmony_ci  }
716425bb815Sopenharmony_ci  else
717425bb815Sopenharmony_ci  {
718425bb815Sopenharmony_ci    refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, (ECMA_PROPERTY_VALUE_PTR (property_p)->value));
719425bb815Sopenharmony_ci  }
720425bb815Sopenharmony_ci
721425bb815Sopenharmony_ci  const ecma_value_t container_value = ecma_make_object_value ((ecma_object_t *) container_p);
722425bb815Sopenharmony_ci  for (uint32_t i = 0; i < refs_p->item_count; i++)
723425bb815Sopenharmony_ci  {
724425bb815Sopenharmony_ci    if (ecma_is_value_empty (refs_p->buffer_p[i]))
725425bb815Sopenharmony_ci    {
726425bb815Sopenharmony_ci      refs_p->buffer_p[i] = container_value;
727425bb815Sopenharmony_ci      return;
728425bb815Sopenharmony_ci    }
729425bb815Sopenharmony_ci  }
730425bb815Sopenharmony_ci
731425bb815Sopenharmony_ci  ecma_collection_push_back (refs_p, container_value);
732425bb815Sopenharmony_ci} /* ecma_op_container_set_weak */
733425bb815Sopenharmony_ci
734425bb815Sopenharmony_ci/**
735425bb815Sopenharmony_ci * Helper method for the Map.prototype.set and Set.prototype.add methods to swap the sign of the given value if needed
736425bb815Sopenharmony_ci *
737425bb815Sopenharmony_ci * See also:
738425bb815Sopenharmony_ci *          ECMA-262 v6, 23.2.3.1 step 6
739425bb815Sopenharmony_ci *          ECMA-262 v6, 23.1.3.9 step 6
740425bb815Sopenharmony_ci *
741425bb815Sopenharmony_ci * @return ecma value
742425bb815Sopenharmony_ci */
743425bb815Sopenharmony_cistatic ecma_value_t
744425bb815Sopenharmony_ciecma_op_container_set_noramlize_zero (ecma_value_t this_arg) /*< this arg */
745425bb815Sopenharmony_ci{
746425bb815Sopenharmony_ci  if (ecma_is_value_number (this_arg))
747425bb815Sopenharmony_ci  {
748425bb815Sopenharmony_ci    ecma_number_t number_value = ecma_get_number_from_value (this_arg);
749425bb815Sopenharmony_ci
750425bb815Sopenharmony_ci    if (JERRY_UNLIKELY (ecma_number_is_zero (number_value) && ecma_number_is_negative (number_value)))
751425bb815Sopenharmony_ci    {
752425bb815Sopenharmony_ci      return ecma_make_integer_value (0);
753425bb815Sopenharmony_ci    }
754425bb815Sopenharmony_ci  }
755425bb815Sopenharmony_ci
756425bb815Sopenharmony_ci  return this_arg;
757425bb815Sopenharmony_ci} /* ecma_op_container_set_noramlize_zero */
758425bb815Sopenharmony_ci
759425bb815Sopenharmony_ci/**
760425bb815Sopenharmony_ci * The generic Map prototype object's 'set' and Set prototype object's 'add' routine
761425bb815Sopenharmony_ci *
762425bb815Sopenharmony_ci * @return ecma value
763425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
764425bb815Sopenharmony_ci */
765425bb815Sopenharmony_ciecma_value_t
766425bb815Sopenharmony_ciecma_op_container_set (ecma_value_t this_arg, /**< this argument */
767425bb815Sopenharmony_ci                       ecma_value_t key_arg, /**< key argument */
768425bb815Sopenharmony_ci                       ecma_value_t value_arg, /**< value argument */
769425bb815Sopenharmony_ci                       lit_magic_string_id_t lit_id) /**< internal class id */
770425bb815Sopenharmony_ci{
771425bb815Sopenharmony_ci  ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
772425bb815Sopenharmony_ci
773425bb815Sopenharmony_ci  if (map_object_p == NULL)
774425bb815Sopenharmony_ci  {
775425bb815Sopenharmony_ci    return ECMA_VALUE_ERROR;
776425bb815Sopenharmony_ci  }
777425bb815Sopenharmony_ci
778425bb815Sopenharmony_ci  ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
779425bb815Sopenharmony_ci                                                                    map_object_p->u.class_prop.u.value);
780425bb815Sopenharmony_ci
781425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) ||  ENABLED (JERRY_ES2015_BUILTIN_WEAKSET)
782425bb815Sopenharmony_ci  if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0
783425bb815Sopenharmony_ci      && !ecma_is_value_object (key_arg))
784425bb815Sopenharmony_ci  {
785425bb815Sopenharmony_ci    return ecma_raise_type_error (ECMA_ERR_MSG ("Key must be an object"));
786425bb815Sopenharmony_ci  }
787425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) ||  ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */
788425bb815Sopenharmony_ci
789425bb815Sopenharmony_ci  ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id);
790425bb815Sopenharmony_ci
791425bb815Sopenharmony_ci  if (entry_p == NULL)
792425bb815Sopenharmony_ci  {
793425bb815Sopenharmony_ci    ecma_op_internal_buffer_append (container_p,
794425bb815Sopenharmony_ci                                    ecma_op_container_set_noramlize_zero (key_arg),
795425bb815Sopenharmony_ci                                    value_arg,
796425bb815Sopenharmony_ci                                    lit_id);
797425bb815Sopenharmony_ci
798425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) ||  ENABLED (JERRY_ES2015_BUILTIN_WEAKSET)
799425bb815Sopenharmony_ci    if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0)
800425bb815Sopenharmony_ci    {
801425bb815Sopenharmony_ci      ecma_object_t *key_p = ecma_get_object_from_value (key_arg);
802425bb815Sopenharmony_ci      ecma_op_container_set_weak (key_p, map_object_p);
803425bb815Sopenharmony_ci    }
804425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) ||  ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */
805425bb815Sopenharmony_ci  }
806425bb815Sopenharmony_ci  else
807425bb815Sopenharmony_ci  {
808425bb815Sopenharmony_ci    ecma_op_internal_buffer_update (entry_p, ecma_op_container_set_noramlize_zero (value_arg), lit_id);
809425bb815Sopenharmony_ci  }
810425bb815Sopenharmony_ci
811425bb815Sopenharmony_ci  ecma_ref_object ((ecma_object_t *) map_object_p);
812425bb815Sopenharmony_ci  return this_arg;
813425bb815Sopenharmony_ci} /* ecma_op_container_set */
814425bb815Sopenharmony_ci
815425bb815Sopenharmony_ci/**
816425bb815Sopenharmony_ci * The generic Map/Set prototype object's 'forEach' routine
817425bb815Sopenharmony_ci *
818425bb815Sopenharmony_ci * @return ecma value
819425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
820425bb815Sopenharmony_ci */
821425bb815Sopenharmony_ciecma_value_t
822425bb815Sopenharmony_ciecma_op_container_foreach (ecma_value_t this_arg, /**< this argument */
823425bb815Sopenharmony_ci                           ecma_value_t predicate, /**< callback function */
824425bb815Sopenharmony_ci                           ecma_value_t predicate_this_arg, /**< this argument for
825425bb815Sopenharmony_ci                                                             *   invoke predicate */
826425bb815Sopenharmony_ci                           lit_magic_string_id_t lit_id) /**< internal class id */
827425bb815Sopenharmony_ci{
828425bb815Sopenharmony_ci  ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
829425bb815Sopenharmony_ci
830425bb815Sopenharmony_ci  if (map_object_p == NULL)
831425bb815Sopenharmony_ci  {
832425bb815Sopenharmony_ci    return ECMA_VALUE_ERROR;
833425bb815Sopenharmony_ci  }
834425bb815Sopenharmony_ci
835425bb815Sopenharmony_ci  if (!ecma_op_is_callable (predicate))
836425bb815Sopenharmony_ci  {
837425bb815Sopenharmony_ci    return ecma_raise_type_error (ECMA_ERR_MSG ("Callback function is not callable."));
838425bb815Sopenharmony_ci  }
839425bb815Sopenharmony_ci
840425bb815Sopenharmony_ci  JERRY_ASSERT (ecma_is_value_object (predicate));
841425bb815Sopenharmony_ci  ecma_object_t *func_object_p = ecma_get_object_from_value (predicate);
842425bb815Sopenharmony_ci  ecma_value_t ret_value = ECMA_VALUE_UNDEFINED;
843425bb815Sopenharmony_ci
844425bb815Sopenharmony_ci  ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
845425bb815Sopenharmony_ci                                                                    map_object_p->u.class_prop.u.value);
846425bb815Sopenharmony_ci
847425bb815Sopenharmony_ci  uint8_t entry_size = ecma_op_container_entry_size (lit_id);
848425bb815Sopenharmony_ci
849425bb815Sopenharmony_ci  for (uint32_t i = 0; i < ECMA_CONTAINER_ENTRY_COUNT (container_p); i += entry_size)
850425bb815Sopenharmony_ci  {
851425bb815Sopenharmony_ci    ecma_value_t *entry_p = ECMA_CONTAINER_START (container_p) + i;
852425bb815Sopenharmony_ci
853425bb815Sopenharmony_ci    if (ecma_is_value_empty (*entry_p))
854425bb815Sopenharmony_ci    {
855425bb815Sopenharmony_ci      continue;
856425bb815Sopenharmony_ci    }
857425bb815Sopenharmony_ci
858425bb815Sopenharmony_ci    ecma_value_t key_arg = *entry_p;
859425bb815Sopenharmony_ci    ecma_value_t value_arg = ecma_op_container_get_value (entry_p, lit_id);
860425bb815Sopenharmony_ci
861425bb815Sopenharmony_ci    ecma_value_t call_args[] = { value_arg, key_arg, this_arg };
862425bb815Sopenharmony_ci    ecma_value_t call_value = ecma_op_function_call (func_object_p, predicate_this_arg, call_args, 3);
863425bb815Sopenharmony_ci
864425bb815Sopenharmony_ci    if (ECMA_IS_VALUE_ERROR (call_value))
865425bb815Sopenharmony_ci    {
866425bb815Sopenharmony_ci      ret_value = call_value;
867425bb815Sopenharmony_ci      break;
868425bb815Sopenharmony_ci    }
869425bb815Sopenharmony_ci
870425bb815Sopenharmony_ci    ecma_free_value (call_value);
871425bb815Sopenharmony_ci  }
872425bb815Sopenharmony_ci
873425bb815Sopenharmony_ci  return ret_value;
874425bb815Sopenharmony_ci} /* ecma_op_container_foreach */
875425bb815Sopenharmony_ci
876425bb815Sopenharmony_ci/**
877425bb815Sopenharmony_ci * The Map/Set prototype object's 'clear' routine
878425bb815Sopenharmony_ci *
879425bb815Sopenharmony_ci * @return ecma value
880425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
881425bb815Sopenharmony_ci */
882425bb815Sopenharmony_ciecma_value_t
883425bb815Sopenharmony_ciecma_op_container_clear (ecma_value_t this_arg, /**< this argument */
884425bb815Sopenharmony_ci                         lit_magic_string_id_t lit_id) /**< internal class id */
885425bb815Sopenharmony_ci{
886425bb815Sopenharmony_ci  ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
887425bb815Sopenharmony_ci
888425bb815Sopenharmony_ci  if (map_object_p == NULL)
889425bb815Sopenharmony_ci  {
890425bb815Sopenharmony_ci    return ECMA_VALUE_ERROR;
891425bb815Sopenharmony_ci  }
892425bb815Sopenharmony_ci
893425bb815Sopenharmony_ci  ecma_op_container_free_entries ((ecma_object_t *) map_object_p);
894425bb815Sopenharmony_ci
895425bb815Sopenharmony_ci  return ECMA_VALUE_UNDEFINED;
896425bb815Sopenharmony_ci} /* ecma_op_container_clear */
897425bb815Sopenharmony_ci
898425bb815Sopenharmony_ci/**
899425bb815Sopenharmony_ci * The generic Map/Set prototype object's 'delete' routine
900425bb815Sopenharmony_ci *
901425bb815Sopenharmony_ci * @return ecma value
902425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
903425bb815Sopenharmony_ci */
904425bb815Sopenharmony_ciecma_value_t
905425bb815Sopenharmony_ciecma_op_container_delete (ecma_value_t this_arg, /**< this argument */
906425bb815Sopenharmony_ci                          ecma_value_t key_arg, /**< key argument */
907425bb815Sopenharmony_ci                          lit_magic_string_id_t lit_id) /**< internal class id */
908425bb815Sopenharmony_ci{
909425bb815Sopenharmony_ci  ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
910425bb815Sopenharmony_ci
911425bb815Sopenharmony_ci  if (map_object_p == NULL)
912425bb815Sopenharmony_ci  {
913425bb815Sopenharmony_ci    return ECMA_VALUE_ERROR;
914425bb815Sopenharmony_ci  }
915425bb815Sopenharmony_ci
916425bb815Sopenharmony_ci  ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
917425bb815Sopenharmony_ci                                                                    map_object_p->u.class_prop.u.value);
918425bb815Sopenharmony_ci
919425bb815Sopenharmony_ci  ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id);
920425bb815Sopenharmony_ci
921425bb815Sopenharmony_ci  if (entry_p == NULL)
922425bb815Sopenharmony_ci  {
923425bb815Sopenharmony_ci    return ECMA_VALUE_FALSE;
924425bb815Sopenharmony_ci  }
925425bb815Sopenharmony_ci
926425bb815Sopenharmony_ci  ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, lit_id);
927425bb815Sopenharmony_ci  return ECMA_VALUE_TRUE;
928425bb815Sopenharmony_ci} /* ecma_op_container_delete */
929425bb815Sopenharmony_ci
930425bb815Sopenharmony_ci/**
931425bb815Sopenharmony_ci * The generic WeakMap/WeakSet prototype object's 'delete' routine
932425bb815Sopenharmony_ci *
933425bb815Sopenharmony_ci * @return ecma value
934425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
935425bb815Sopenharmony_ci */
936425bb815Sopenharmony_ciecma_value_t
937425bb815Sopenharmony_ciecma_op_container_delete_weak (ecma_value_t this_arg, /**< this argument */
938425bb815Sopenharmony_ci                               ecma_value_t key_arg, /**< key argument */
939425bb815Sopenharmony_ci                               lit_magic_string_id_t lit_id) /**< internal class id */
940425bb815Sopenharmony_ci{
941425bb815Sopenharmony_ci  ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
942425bb815Sopenharmony_ci
943425bb815Sopenharmony_ci  if (map_object_p == NULL)
944425bb815Sopenharmony_ci  {
945425bb815Sopenharmony_ci    return ECMA_VALUE_ERROR;
946425bb815Sopenharmony_ci  }
947425bb815Sopenharmony_ci
948425bb815Sopenharmony_ci  if (!ecma_is_value_object (key_arg))
949425bb815Sopenharmony_ci  {
950425bb815Sopenharmony_ci    return ECMA_VALUE_FALSE;
951425bb815Sopenharmony_ci  }
952425bb815Sopenharmony_ci
953425bb815Sopenharmony_ci  ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
954425bb815Sopenharmony_ci                                                                    map_object_p->u.class_prop.u.value);
955425bb815Sopenharmony_ci
956425bb815Sopenharmony_ci  ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id);
957425bb815Sopenharmony_ci
958425bb815Sopenharmony_ci  if (entry_p == NULL)
959425bb815Sopenharmony_ci  {
960425bb815Sopenharmony_ci    return ECMA_VALUE_FALSE;
961425bb815Sopenharmony_ci  }
962425bb815Sopenharmony_ci
963425bb815Sopenharmony_ci  ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, lit_id);
964425bb815Sopenharmony_ci
965425bb815Sopenharmony_ci  ecma_object_t *key_object_p = ecma_get_object_from_value (key_arg);
966425bb815Sopenharmony_ci  ecma_op_container_unref_weak (key_object_p, ecma_make_object_value ((ecma_object_t *) map_object_p));
967425bb815Sopenharmony_ci
968425bb815Sopenharmony_ci  return ECMA_VALUE_TRUE;
969425bb815Sopenharmony_ci} /* ecma_op_container_delete_weak */
970425bb815Sopenharmony_ci
971425bb815Sopenharmony_ci/**
972425bb815Sopenharmony_ci * Helper function to remove a weak reference to an object.
973425bb815Sopenharmony_ci *
974425bb815Sopenharmony_ci * @return ecma value
975425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
976425bb815Sopenharmony_ci */
977425bb815Sopenharmony_civoid
978425bb815Sopenharmony_ciecma_op_container_unref_weak (ecma_object_t *object_p, /**< this argument */
979425bb815Sopenharmony_ci                              ecma_value_t ref_holder) /**< key argument */
980425bb815Sopenharmony_ci{
981425bb815Sopenharmony_ci  ecma_string_t *weak_refs_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_WEAK_REFS);
982425bb815Sopenharmony_ci
983425bb815Sopenharmony_ci  ecma_property_t *property_p = ecma_find_named_property (object_p, weak_refs_string_p);
984425bb815Sopenharmony_ci  JERRY_ASSERT (property_p != NULL);
985425bb815Sopenharmony_ci
986425bb815Sopenharmony_ci  ecma_collection_t *refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
987425bb815Sopenharmony_ci                                                               ECMA_PROPERTY_VALUE_PTR (property_p)->value);
988425bb815Sopenharmony_ci  for (uint32_t i = 0; i < refs_p->item_count; i++)
989425bb815Sopenharmony_ci  {
990425bb815Sopenharmony_ci    if (refs_p->buffer_p[i] == ref_holder)
991425bb815Sopenharmony_ci    {
992425bb815Sopenharmony_ci      refs_p->buffer_p[i] = ECMA_VALUE_EMPTY;
993425bb815Sopenharmony_ci      break;
994425bb815Sopenharmony_ci    }
995425bb815Sopenharmony_ci  }
996425bb815Sopenharmony_ci} /* ecma_op_container_unref_weak */
997425bb815Sopenharmony_ci
998425bb815Sopenharmony_ci/**
999425bb815Sopenharmony_ci * Helper function to remove a key/value pair from a weak container object
1000425bb815Sopenharmony_ci */
1001425bb815Sopenharmony_civoid
1002425bb815Sopenharmony_ciecma_op_container_remove_weak_entry (ecma_object_t *object_p, /**< internal container object */
1003425bb815Sopenharmony_ci                                     ecma_value_t key_arg) /**< key */
1004425bb815Sopenharmony_ci{
1005425bb815Sopenharmony_ci  ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p;
1006425bb815Sopenharmony_ci
1007425bb815Sopenharmony_ci  ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
1008425bb815Sopenharmony_ci                                                                    map_object_p->u.class_prop.u.value);
1009425bb815Sopenharmony_ci
1010425bb815Sopenharmony_ci  ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, map_object_p->u.class_prop.class_id);
1011425bb815Sopenharmony_ci
1012425bb815Sopenharmony_ci  JERRY_ASSERT (entry_p != NULL);
1013425bb815Sopenharmony_ci
1014425bb815Sopenharmony_ci  ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, map_object_p->u.class_prop.class_id);
1015425bb815Sopenharmony_ci} /* ecma_op_container_remove_weak_entry */
1016425bb815Sopenharmony_ci
1017425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
1018425bb815Sopenharmony_ci
1019425bb815Sopenharmony_ci/**
1020425bb815Sopenharmony_ci * The Create{Set, Map}Iterator Abstract operation
1021425bb815Sopenharmony_ci *
1022425bb815Sopenharmony_ci * See also:
1023425bb815Sopenharmony_ci *          ECMA-262 v6, 23.1.5.1
1024425bb815Sopenharmony_ci *          ECMA-262 v6, 23.2.5.1
1025425bb815Sopenharmony_ci *
1026425bb815Sopenharmony_ci * Note:
1027425bb815Sopenharmony_ci *     Returned value must be freed with ecma_free_value.
1028425bb815Sopenharmony_ci *
1029425bb815Sopenharmony_ci * @return Map/Set iterator object, if success
1030425bb815Sopenharmony_ci *         error - otherwise
1031425bb815Sopenharmony_ci */
1032425bb815Sopenharmony_ciecma_value_t
1033425bb815Sopenharmony_ciecma_op_container_create_iterator (ecma_value_t this_arg, /**< this argument */
1034425bb815Sopenharmony_ci                                   uint8_t type, /**< any combination of
1035425bb815Sopenharmony_ci                                                  *   ecma_iterator_type_t bits */
1036425bb815Sopenharmony_ci                                   lit_magic_string_id_t lit_id, /**< internal class id */
1037425bb815Sopenharmony_ci                                   ecma_builtin_id_t proto_id, /**< prototype builtin id */
1038425bb815Sopenharmony_ci                                   ecma_pseudo_array_type_t iterator_type) /**< type of the iterator */
1039425bb815Sopenharmony_ci{
1040425bb815Sopenharmony_ci  ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id);
1041425bb815Sopenharmony_ci
1042425bb815Sopenharmony_ci  if (map_object_p == NULL)
1043425bb815Sopenharmony_ci  {
1044425bb815Sopenharmony_ci    return ECMA_VALUE_ERROR;
1045425bb815Sopenharmony_ci  }
1046425bb815Sopenharmony_ci
1047425bb815Sopenharmony_ci  return ecma_op_create_iterator_object (this_arg,
1048425bb815Sopenharmony_ci                                         ecma_builtin_get (proto_id),
1049425bb815Sopenharmony_ci                                         (uint8_t) iterator_type,
1050425bb815Sopenharmony_ci                                         type);
1051425bb815Sopenharmony_ci} /* ecma_op_container_create_iterator */
1052425bb815Sopenharmony_ci
1053425bb815Sopenharmony_ci/**
1054425bb815Sopenharmony_ci * Get the index of the iterator object.
1055425bb815Sopenharmony_ci *
1056425bb815Sopenharmony_ci * @return index of the iterator.
1057425bb815Sopenharmony_ci */
1058425bb815Sopenharmony_cistatic uint32_t
1059425bb815Sopenharmony_ciecma_op_iterator_get_index (ecma_object_t *iter_obj_p)  /**< iterator object pointer */
1060425bb815Sopenharmony_ci{
1061425bb815Sopenharmony_ci  uint32_t index = ((ecma_extended_object_t *) iter_obj_p)->u.pseudo_array.u1.iterator_index;
1062425bb815Sopenharmony_ci
1063425bb815Sopenharmony_ci  if (JERRY_UNLIKELY (index == ECMA_ITERATOR_INDEX_LIMIT))
1064425bb815Sopenharmony_ci  {
1065425bb815Sopenharmony_ci    ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX);
1066425bb815Sopenharmony_ci    ecma_property_t *property_p = ecma_find_named_property (iter_obj_p, prop_name_p);
1067425bb815Sopenharmony_ci    ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
1068425bb815Sopenharmony_ci
1069425bb815Sopenharmony_ci    return (uint32_t) (ecma_get_number_from_value (value_p->value));
1070425bb815Sopenharmony_ci  }
1071425bb815Sopenharmony_ci
1072425bb815Sopenharmony_ci  return index;
1073425bb815Sopenharmony_ci} /* ecma_op_iterator_get_index */
1074425bb815Sopenharmony_ci
1075425bb815Sopenharmony_ci/**
1076425bb815Sopenharmony_ci * Set the index of the iterator object.
1077425bb815Sopenharmony_ci */
1078425bb815Sopenharmony_cistatic void
1079425bb815Sopenharmony_ciecma_op_iterator_set_index (ecma_object_t *iter_obj_p, /**< iterator object pointer */
1080425bb815Sopenharmony_ci                            uint32_t index) /* iterator index to set */
1081425bb815Sopenharmony_ci{
1082425bb815Sopenharmony_ci  if (JERRY_UNLIKELY (index >= ECMA_ITERATOR_INDEX_LIMIT))
1083425bb815Sopenharmony_ci  {
1084425bb815Sopenharmony_ci    /* After the ECMA_ITERATOR_INDEX_LIMIT limit is reached the [[%Iterator%NextIndex]]
1085425bb815Sopenharmony_ci       property is stored as an internal property */
1086425bb815Sopenharmony_ci    ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX);
1087425bb815Sopenharmony_ci    ecma_property_t *property_p = ecma_find_named_property (iter_obj_p, prop_name_p);
1088425bb815Sopenharmony_ci    ecma_property_value_t *value_p;
1089425bb815Sopenharmony_ci
1090425bb815Sopenharmony_ci    if (property_p == NULL)
1091425bb815Sopenharmony_ci    {
1092425bb815Sopenharmony_ci      value_p = ecma_create_named_data_property (iter_obj_p, prop_name_p, ECMA_PROPERTY_FLAG_WRITABLE, &property_p);
1093425bb815Sopenharmony_ci      value_p->value = ecma_make_uint32_value (index);
1094425bb815Sopenharmony_ci    }
1095425bb815Sopenharmony_ci    else
1096425bb815Sopenharmony_ci    {
1097425bb815Sopenharmony_ci      value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
1098425bb815Sopenharmony_ci      value_p->value = ecma_make_uint32_value (index);
1099425bb815Sopenharmony_ci    }
1100425bb815Sopenharmony_ci  }
1101425bb815Sopenharmony_ci  else
1102425bb815Sopenharmony_ci  {
1103425bb815Sopenharmony_ci    ((ecma_extended_object_t *) iter_obj_p)->u.pseudo_array.u1.iterator_index = (uint16_t) index;
1104425bb815Sopenharmony_ci  }
1105425bb815Sopenharmony_ci} /* ecma_op_iterator_set_index */
1106425bb815Sopenharmony_ci
1107425bb815Sopenharmony_ci/**
1108425bb815Sopenharmony_ci * The %{Set, Map}IteratorPrototype% object's 'next' routine
1109425bb815Sopenharmony_ci *
1110425bb815Sopenharmony_ci * See also:
1111425bb815Sopenharmony_ci *          ECMA-262 v6, 23.1.5.2.1
1112425bb815Sopenharmony_ci *          ECMA-262 v6, 23.2.5.2.1
1113425bb815Sopenharmony_ci *
1114425bb815Sopenharmony_ci * Note:
1115425bb815Sopenharmony_ci *     Returned value must be freed with ecma_free_value.
1116425bb815Sopenharmony_ci *
1117425bb815Sopenharmony_ci * @return iterator result object, if success
1118425bb815Sopenharmony_ci *         error - otherwise
1119425bb815Sopenharmony_ci */
1120425bb815Sopenharmony_ciecma_value_t
1121425bb815Sopenharmony_ciecma_op_container_iterator_next (ecma_value_t this_val, /**< this argument */
1122425bb815Sopenharmony_ci                                 ecma_pseudo_array_type_t iterator_type) /**< type of the iterator */
1123425bb815Sopenharmony_ci{
1124425bb815Sopenharmony_ci  if (!ecma_is_value_object (this_val))
1125425bb815Sopenharmony_ci  {
1126425bb815Sopenharmony_ci    return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not an object."));
1127425bb815Sopenharmony_ci  }
1128425bb815Sopenharmony_ci
1129425bb815Sopenharmony_ci  ecma_object_t *obj_p = ecma_get_object_from_value (this_val);
1130425bb815Sopenharmony_ci  ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p;
1131425bb815Sopenharmony_ci
1132425bb815Sopenharmony_ci  if (ecma_get_object_type (obj_p) != ECMA_OBJECT_TYPE_PSEUDO_ARRAY
1133425bb815Sopenharmony_ci      || ext_obj_p->u.pseudo_array.type != iterator_type)
1134425bb815Sopenharmony_ci  {
1135425bb815Sopenharmony_ci    return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not an iterator."));
1136425bb815Sopenharmony_ci  }
1137425bb815Sopenharmony_ci
1138425bb815Sopenharmony_ci  ecma_value_t iterated_value = ext_obj_p->u.pseudo_array.u2.iterated_value;
1139425bb815Sopenharmony_ci
1140425bb815Sopenharmony_ci  if (ecma_is_value_empty (iterated_value))
1141425bb815Sopenharmony_ci  {
1142425bb815Sopenharmony_ci    return ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE);
1143425bb815Sopenharmony_ci  }
1144425bb815Sopenharmony_ci
1145425bb815Sopenharmony_ci  ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) (ecma_get_object_from_value (iterated_value));
1146425bb815Sopenharmony_ci  lit_magic_string_id_t lit_id = map_object_p->u.class_prop.class_id;
1147425bb815Sopenharmony_ci
1148425bb815Sopenharmony_ci  ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
1149425bb815Sopenharmony_ci                                                                    map_object_p->u.class_prop.u.value);
1150425bb815Sopenharmony_ci  uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
1151425bb815Sopenharmony_ci  uint32_t index = ecma_op_iterator_get_index (obj_p);
1152425bb815Sopenharmony_ci
1153425bb815Sopenharmony_ci  if (index == entry_count)
1154425bb815Sopenharmony_ci  {
1155425bb815Sopenharmony_ci    ext_obj_p->u.pseudo_array.u2.iterated_value = ECMA_VALUE_EMPTY;
1156425bb815Sopenharmony_ci
1157425bb815Sopenharmony_ci    return ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE);
1158425bb815Sopenharmony_ci  }
1159425bb815Sopenharmony_ci
1160425bb815Sopenharmony_ci  uint8_t entry_size = ecma_op_container_entry_size (lit_id);
1161425bb815Sopenharmony_ci  uint8_t iterator_kind = ext_obj_p->u.pseudo_array.extra_info;
1162425bb815Sopenharmony_ci  ecma_value_t *start_p = ECMA_CONTAINER_START (container_p);
1163425bb815Sopenharmony_ci  ecma_value_t ret_value = ECMA_VALUE_UNDEFINED;
1164425bb815Sopenharmony_ci
1165425bb815Sopenharmony_ci  for (uint32_t i = index; i < entry_count; i += entry_size)
1166425bb815Sopenharmony_ci  {
1167425bb815Sopenharmony_ci    ecma_value_t *entry_p = start_p + i;
1168425bb815Sopenharmony_ci
1169425bb815Sopenharmony_ci    if (ecma_is_value_empty (*entry_p))
1170425bb815Sopenharmony_ci    {
1171425bb815Sopenharmony_ci      if (i == (entry_count - entry_size))
1172425bb815Sopenharmony_ci      {
1173425bb815Sopenharmony_ci        ret_value = ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE);
1174425bb815Sopenharmony_ci        break;
1175425bb815Sopenharmony_ci      }
1176425bb815Sopenharmony_ci
1177425bb815Sopenharmony_ci      continue;
1178425bb815Sopenharmony_ci    }
1179425bb815Sopenharmony_ci
1180425bb815Sopenharmony_ci    ecma_op_iterator_set_index (obj_p, i + entry_size);
1181425bb815Sopenharmony_ci
1182425bb815Sopenharmony_ci    ecma_value_t key_arg = *entry_p;
1183425bb815Sopenharmony_ci    ecma_value_t value_arg = ecma_op_container_get_value (entry_p, lit_id);
1184425bb815Sopenharmony_ci
1185425bb815Sopenharmony_ci    if (iterator_kind == ECMA_ITERATOR_KEYS)
1186425bb815Sopenharmony_ci    {
1187425bb815Sopenharmony_ci      ret_value = ecma_create_iter_result_object (key_arg, ECMA_VALUE_FALSE);
1188425bb815Sopenharmony_ci    }
1189425bb815Sopenharmony_ci    else if (iterator_kind == ECMA_ITERATOR_VALUES)
1190425bb815Sopenharmony_ci    {
1191425bb815Sopenharmony_ci      ret_value = ecma_create_iter_result_object (value_arg, ECMA_VALUE_FALSE);
1192425bb815Sopenharmony_ci    }
1193425bb815Sopenharmony_ci    else
1194425bb815Sopenharmony_ci    {
1195425bb815Sopenharmony_ci      JERRY_ASSERT (iterator_kind == ECMA_ITERATOR_KEYS_VALUES);
1196425bb815Sopenharmony_ci
1197425bb815Sopenharmony_ci      ecma_value_t entry_array_value;
1198425bb815Sopenharmony_ci      entry_array_value = ecma_create_array_from_iter_element (value_arg, key_arg);
1199425bb815Sopenharmony_ci
1200425bb815Sopenharmony_ci      ret_value = ecma_create_iter_result_object (entry_array_value, ECMA_VALUE_FALSE);
1201425bb815Sopenharmony_ci      ecma_free_value (entry_array_value);
1202425bb815Sopenharmony_ci    }
1203425bb815Sopenharmony_ci
1204425bb815Sopenharmony_ci    break;
1205425bb815Sopenharmony_ci  }
1206425bb815Sopenharmony_ci
1207425bb815Sopenharmony_ci  return ret_value;
1208425bb815Sopenharmony_ci} /* ecma_op_container_iterator_next */
1209425bb815Sopenharmony_ci
1210425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
1211425bb815Sopenharmony_ci
1212425bb815Sopenharmony_ci/**
1213425bb815Sopenharmony_ci * @}
1214425bb815Sopenharmony_ci * @}
1215425bb815Sopenharmony_ci */
1216425bb815Sopenharmony_ci
1217425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */
1218