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
16425bb815Sopenharmony_ci#include "ecma-globals.h"
17425bb815Sopenharmony_ci#include "ecma-helpers.h"
18425bb815Sopenharmony_ci#include "ecma-property-hashmap.h"
19425bb815Sopenharmony_ci#include "jrt-libc-includes.h"
20425bb815Sopenharmony_ci#include "jcontext.h"
21425bb815Sopenharmony_ci
22425bb815Sopenharmony_ci/** \addtogroup ecma ECMA
23425bb815Sopenharmony_ci * @{
24425bb815Sopenharmony_ci *
25425bb815Sopenharmony_ci * \addtogroup ecmapropertyhashmap Property hashmap
26425bb815Sopenharmony_ci * @{
27425bb815Sopenharmony_ci */
28425bb815Sopenharmony_ci
29425bb815Sopenharmony_ci#if ENABLED (JERRY_PROPRETY_HASHMAP)
30425bb815Sopenharmony_ci
31425bb815Sopenharmony_ci/**
32425bb815Sopenharmony_ci * Compute the total size of the property hashmap.
33425bb815Sopenharmony_ci */
34425bb815Sopenharmony_ci#define ECMA_PROPERTY_HASHMAP_GET_TOTAL_SIZE(max_property_count) \
35425bb815Sopenharmony_ci  (sizeof (ecma_property_hashmap_t) + (max_property_count * sizeof (jmem_cpointer_t)) + (max_property_count >> 3))
36425bb815Sopenharmony_ci
37425bb815Sopenharmony_ci/**
38425bb815Sopenharmony_ci * Number of items in the stepping table.
39425bb815Sopenharmony_ci */
40425bb815Sopenharmony_ci#define ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS 8
41425bb815Sopenharmony_ci
42425bb815Sopenharmony_ci/**
43425bb815Sopenharmony_ci * Stepping values for searching items in the hashmap.
44425bb815Sopenharmony_ci */
45425bb815Sopenharmony_cistatic const uint8_t ecma_property_hashmap_steps[ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS] JERRY_ATTR_CONST_DATA =
46425bb815Sopenharmony_ci{
47425bb815Sopenharmony_ci  3, 5, 7, 11, 13, 17, 19, 23
48425bb815Sopenharmony_ci};
49425bb815Sopenharmony_ci
50425bb815Sopenharmony_ci/**
51425bb815Sopenharmony_ci * Get the value of a bit in a bitmap.
52425bb815Sopenharmony_ci */
53425bb815Sopenharmony_ci#define ECMA_PROPERTY_HASHMAP_GET_BIT(byte_p, index) \
54425bb815Sopenharmony_ci  ((byte_p)[(index) >> 3] & (1 << ((index) & 0x7)))
55425bb815Sopenharmony_ci
56425bb815Sopenharmony_ci/**
57425bb815Sopenharmony_ci * Clear the value of a bit in a bitmap.
58425bb815Sopenharmony_ci */
59425bb815Sopenharmony_ci#define ECMA_PROPERTY_HASHMAP_CLEAR_BIT(byte_p, index) \
60425bb815Sopenharmony_ci  ((byte_p)[(index) >> 3] = (uint8_t) ((byte_p)[(index) >> 3] & ~(1 << ((index) & 0x7))))
61425bb815Sopenharmony_ci
62425bb815Sopenharmony_ci/**
63425bb815Sopenharmony_ci * Set the value of a bit in a bitmap.
64425bb815Sopenharmony_ci */
65425bb815Sopenharmony_ci#define ECMA_PROPERTY_HASHMAP_SET_BIT(byte_p, index) \
66425bb815Sopenharmony_ci  ((byte_p)[(index) >> 3] = (uint8_t) ((byte_p)[(index) >> 3] | (1 << ((index) & 0x7))))
67425bb815Sopenharmony_ci
68425bb815Sopenharmony_ci/**
69425bb815Sopenharmony_ci * Create a new property hashmap for the object.
70425bb815Sopenharmony_ci * The object must not have a property hashmap.
71425bb815Sopenharmony_ci */
72425bb815Sopenharmony_civoid
73425bb815Sopenharmony_ciecma_property_hashmap_create (ecma_object_t *object_p) /**< object */
74425bb815Sopenharmony_ci{
75425bb815Sopenharmony_ci  if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) != ECMA_PROP_HASHMAP_ALLOC_ON)
76425bb815Sopenharmony_ci  {
77425bb815Sopenharmony_ci    return;
78425bb815Sopenharmony_ci  }
79425bb815Sopenharmony_ci
80425bb815Sopenharmony_ci  jmem_cpointer_t prop_iter_cp = object_p->u1.property_list_cp;
81425bb815Sopenharmony_ci
82425bb815Sopenharmony_ci  if (prop_iter_cp == JMEM_CP_NULL)
83425bb815Sopenharmony_ci  {
84425bb815Sopenharmony_ci    return;
85425bb815Sopenharmony_ci  }
86425bb815Sopenharmony_ci
87425bb815Sopenharmony_ci  uint32_t named_property_count = 0;
88425bb815Sopenharmony_ci
89425bb815Sopenharmony_ci  while (prop_iter_cp != JMEM_CP_NULL)
90425bb815Sopenharmony_ci  {
91425bb815Sopenharmony_ci    ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp);
92425bb815Sopenharmony_ci    JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
93425bb815Sopenharmony_ci
94425bb815Sopenharmony_ci    for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
95425bb815Sopenharmony_ci    {
96425bb815Sopenharmony_ci      ecma_property_types_t type = ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[i]);
97425bb815Sopenharmony_ci
98425bb815Sopenharmony_ci      if (type != ECMA_PROPERTY_TYPE_SPECIAL)
99425bb815Sopenharmony_ci      {
100425bb815Sopenharmony_ci        named_property_count++;
101425bb815Sopenharmony_ci      }
102425bb815Sopenharmony_ci    }
103425bb815Sopenharmony_ci    prop_iter_cp = prop_iter_p->next_property_cp;
104425bb815Sopenharmony_ci  }
105425bb815Sopenharmony_ci
106425bb815Sopenharmony_ci  if (named_property_count < (ECMA_PROPERTY_HASMAP_MINIMUM_SIZE / 2))
107425bb815Sopenharmony_ci  {
108425bb815Sopenharmony_ci    return;
109425bb815Sopenharmony_ci  }
110425bb815Sopenharmony_ci
111425bb815Sopenharmony_ci  /* The max_property_count must be power of 2. */
112425bb815Sopenharmony_ci  uint32_t max_property_count = ECMA_PROPERTY_HASMAP_MINIMUM_SIZE;
113425bb815Sopenharmony_ci
114425bb815Sopenharmony_ci  /* At least 1/3 items must be NULL. */
115425bb815Sopenharmony_ci  while (max_property_count < (named_property_count + (named_property_count >> 1)))
116425bb815Sopenharmony_ci  {
117425bb815Sopenharmony_ci    max_property_count <<= 1;
118425bb815Sopenharmony_ci  }
119425bb815Sopenharmony_ci
120425bb815Sopenharmony_ci  size_t total_size = ECMA_PROPERTY_HASHMAP_GET_TOTAL_SIZE (max_property_count);
121425bb815Sopenharmony_ci
122425bb815Sopenharmony_ci  ecma_property_hashmap_t *hashmap_p = (ecma_property_hashmap_t *) jmem_heap_alloc_block_null_on_error (total_size);
123425bb815Sopenharmony_ci
124425bb815Sopenharmony_ci  if (hashmap_p == NULL)
125425bb815Sopenharmony_ci  {
126425bb815Sopenharmony_ci    return;
127425bb815Sopenharmony_ci  }
128425bb815Sopenharmony_ci
129425bb815Sopenharmony_ci  memset (hashmap_p, 0, total_size);
130425bb815Sopenharmony_ci
131425bb815Sopenharmony_ci  hashmap_p->header.types[0] = ECMA_PROPERTY_TYPE_HASHMAP;
132425bb815Sopenharmony_ci  hashmap_p->header.next_property_cp = object_p->u1.property_list_cp;
133425bb815Sopenharmony_ci  hashmap_p->max_property_count = max_property_count;
134425bb815Sopenharmony_ci  hashmap_p->null_count = max_property_count - named_property_count;
135425bb815Sopenharmony_ci  hashmap_p->unused_count = max_property_count - named_property_count;
136425bb815Sopenharmony_ci
137425bb815Sopenharmony_ci  jmem_cpointer_t *pair_list_p = (jmem_cpointer_t *) (hashmap_p + 1);
138425bb815Sopenharmony_ci  uint8_t *bits_p = (uint8_t *) (pair_list_p + max_property_count);
139425bb815Sopenharmony_ci  uint32_t mask = max_property_count - 1;
140425bb815Sopenharmony_ci
141425bb815Sopenharmony_ci  prop_iter_cp = object_p->u1.property_list_cp;
142425bb815Sopenharmony_ci  ECMA_SET_NON_NULL_POINTER (object_p->u1.property_list_cp, hashmap_p);
143425bb815Sopenharmony_ci
144425bb815Sopenharmony_ci  while (prop_iter_cp != JMEM_CP_NULL)
145425bb815Sopenharmony_ci  {
146425bb815Sopenharmony_ci    ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp);
147425bb815Sopenharmony_ci    JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
148425bb815Sopenharmony_ci
149425bb815Sopenharmony_ci    for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
150425bb815Sopenharmony_ci    {
151425bb815Sopenharmony_ci      if (!ECMA_PROPERTY_IS_NAMED_PROPERTY (prop_iter_p->types[i]))
152425bb815Sopenharmony_ci      {
153425bb815Sopenharmony_ci        continue;
154425bb815Sopenharmony_ci      }
155425bb815Sopenharmony_ci
156425bb815Sopenharmony_ci      ecma_property_pair_t *property_pair_p = (ecma_property_pair_t *) prop_iter_p;
157425bb815Sopenharmony_ci
158425bb815Sopenharmony_ci      uint32_t entry_index = ecma_string_get_property_name_hash (prop_iter_p->types[i],
159425bb815Sopenharmony_ci                                                                 property_pair_p->names_cp[i]);
160425bb815Sopenharmony_ci      uint32_t step = ecma_property_hashmap_steps[entry_index & (ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS - 1)];
161425bb815Sopenharmony_ci
162425bb815Sopenharmony_ci      entry_index &= mask;
163425bb815Sopenharmony_ci#ifndef JERRY_NDEBUG
164425bb815Sopenharmony_ci      /* Because max_property_count (power of 2) and step (a prime
165425bb815Sopenharmony_ci       * number) are relative primes, all entries of the hasmap are
166425bb815Sopenharmony_ci       * visited exactly once before the start entry index is reached
167425bb815Sopenharmony_ci       * again. Furthermore because at least one NULL is present in
168425bb815Sopenharmony_ci       * the hashmap, the while loop must be terminated before the
169425bb815Sopenharmony_ci       * the starting index is reached again. */
170425bb815Sopenharmony_ci      uint32_t start_entry_index = entry_index;
171425bb815Sopenharmony_ci#endif /* !JERRY_NDEBUG */
172425bb815Sopenharmony_ci
173425bb815Sopenharmony_ci      while (pair_list_p[entry_index] != ECMA_NULL_POINTER)
174425bb815Sopenharmony_ci      {
175425bb815Sopenharmony_ci        entry_index = (entry_index + step) & mask;
176425bb815Sopenharmony_ci
177425bb815Sopenharmony_ci#ifndef JERRY_NDEBUG
178425bb815Sopenharmony_ci        JERRY_ASSERT (entry_index != start_entry_index);
179425bb815Sopenharmony_ci#endif /* !JERRY_NDEBUG */
180425bb815Sopenharmony_ci      }
181425bb815Sopenharmony_ci
182425bb815Sopenharmony_ci      ECMA_SET_NON_NULL_POINTER (pair_list_p[entry_index], property_pair_p);
183425bb815Sopenharmony_ci
184425bb815Sopenharmony_ci      if (i != 0)
185425bb815Sopenharmony_ci      {
186425bb815Sopenharmony_ci        ECMA_PROPERTY_HASHMAP_SET_BIT (bits_p, entry_index);
187425bb815Sopenharmony_ci      }
188425bb815Sopenharmony_ci    }
189425bb815Sopenharmony_ci
190425bb815Sopenharmony_ci    prop_iter_cp = prop_iter_p->next_property_cp;
191425bb815Sopenharmony_ci  }
192425bb815Sopenharmony_ci} /* ecma_property_hashmap_create */
193425bb815Sopenharmony_ci
194425bb815Sopenharmony_ci/**
195425bb815Sopenharmony_ci * Free the hashmap of the object.
196425bb815Sopenharmony_ci * The object must have a property hashmap.
197425bb815Sopenharmony_ci */
198425bb815Sopenharmony_civoid
199425bb815Sopenharmony_ciecma_property_hashmap_free (ecma_object_t *object_p) /**< object */
200425bb815Sopenharmony_ci{
201425bb815Sopenharmony_ci  /* Property hash must be exists and must be the first property. */
202425bb815Sopenharmony_ci  JERRY_ASSERT (object_p->u1.property_list_cp != JMEM_CP_NULL);
203425bb815Sopenharmony_ci
204425bb815Sopenharmony_ci  ecma_property_header_t *property_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t,
205425bb815Sopenharmony_ci                                                                  object_p->u1.property_list_cp);
206425bb815Sopenharmony_ci
207425bb815Sopenharmony_ci  JERRY_ASSERT (property_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP);
208425bb815Sopenharmony_ci
209425bb815Sopenharmony_ci  ecma_property_hashmap_t *hashmap_p = (ecma_property_hashmap_t *) property_p;
210425bb815Sopenharmony_ci
211425bb815Sopenharmony_ci  object_p->u1.property_list_cp = property_p->next_property_cp;
212425bb815Sopenharmony_ci
213425bb815Sopenharmony_ci  jmem_heap_free_block (hashmap_p,
214425bb815Sopenharmony_ci                        ECMA_PROPERTY_HASHMAP_GET_TOTAL_SIZE (hashmap_p->max_property_count));
215425bb815Sopenharmony_ci} /* ecma_property_hashmap_free */
216425bb815Sopenharmony_ci
217425bb815Sopenharmony_ci/**
218425bb815Sopenharmony_ci * Insert named property into the hashmap.
219425bb815Sopenharmony_ci */
220425bb815Sopenharmony_civoid
221425bb815Sopenharmony_ciecma_property_hashmap_insert (ecma_object_t *object_p, /**< object */
222425bb815Sopenharmony_ci                              ecma_string_t *name_p, /**< name of the property */
223425bb815Sopenharmony_ci                              ecma_property_pair_t *property_pair_p, /**< property pair */
224425bb815Sopenharmony_ci                              int property_index) /**< property index in the pair (0 or 1) */
225425bb815Sopenharmony_ci{
226425bb815Sopenharmony_ci  JERRY_ASSERT (property_pair_p != NULL);
227425bb815Sopenharmony_ci
228425bb815Sopenharmony_ci  ecma_property_hashmap_t *hashmap_p = ECMA_GET_NON_NULL_POINTER (ecma_property_hashmap_t,
229425bb815Sopenharmony_ci                                                                  object_p->u1.property_list_cp);
230425bb815Sopenharmony_ci
231425bb815Sopenharmony_ci  JERRY_ASSERT (hashmap_p->header.types[0] == ECMA_PROPERTY_TYPE_HASHMAP);
232425bb815Sopenharmony_ci
233425bb815Sopenharmony_ci  /* The NULLs are reduced below 1/8 of the hashmap. */
234425bb815Sopenharmony_ci  if (hashmap_p->null_count < (hashmap_p->max_property_count >> 3))
235425bb815Sopenharmony_ci  {
236425bb815Sopenharmony_ci    ecma_property_hashmap_free (object_p);
237425bb815Sopenharmony_ci    ecma_property_hashmap_create (object_p);
238425bb815Sopenharmony_ci    return;
239425bb815Sopenharmony_ci  }
240425bb815Sopenharmony_ci
241425bb815Sopenharmony_ci  JERRY_ASSERT (property_index < ECMA_PROPERTY_PAIR_ITEM_COUNT);
242425bb815Sopenharmony_ci
243425bb815Sopenharmony_ci  uint32_t entry_index = ecma_string_hash (name_p);
244425bb815Sopenharmony_ci  uint32_t step = ecma_property_hashmap_steps[entry_index & (ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS - 1)];
245425bb815Sopenharmony_ci  uint32_t mask = hashmap_p->max_property_count - 1;
246425bb815Sopenharmony_ci  entry_index &= mask;
247425bb815Sopenharmony_ci
248425bb815Sopenharmony_ci#ifndef JERRY_NDEBUG
249425bb815Sopenharmony_ci  /* See the comment for this variable in ecma_property_hashmap_create. */
250425bb815Sopenharmony_ci  uint32_t start_entry_index = entry_index;
251425bb815Sopenharmony_ci#endif /* !JERRY_NDEBUG */
252425bb815Sopenharmony_ci
253425bb815Sopenharmony_ci  jmem_cpointer_t *pair_list_p = (jmem_cpointer_t *) (hashmap_p + 1);
254425bb815Sopenharmony_ci
255425bb815Sopenharmony_ci  while (pair_list_p[entry_index] != ECMA_NULL_POINTER)
256425bb815Sopenharmony_ci  {
257425bb815Sopenharmony_ci    entry_index = (entry_index + step) & mask;
258425bb815Sopenharmony_ci
259425bb815Sopenharmony_ci#ifndef JERRY_NDEBUG
260425bb815Sopenharmony_ci    JERRY_ASSERT (entry_index != start_entry_index);
261425bb815Sopenharmony_ci#endif /* !JERRY_NDEBUG */
262425bb815Sopenharmony_ci  }
263425bb815Sopenharmony_ci
264425bb815Sopenharmony_ci  ECMA_SET_NON_NULL_POINTER (pair_list_p[entry_index], property_pair_p);
265425bb815Sopenharmony_ci
266425bb815Sopenharmony_ci  uint8_t *bits_p = (uint8_t *) (pair_list_p + hashmap_p->max_property_count);
267425bb815Sopenharmony_ci  bits_p += (entry_index >> 3);
268425bb815Sopenharmony_ci  mask = (uint32_t) (1 << (entry_index & 0x7));
269425bb815Sopenharmony_ci
270425bb815Sopenharmony_ci  if (!(*bits_p & mask))
271425bb815Sopenharmony_ci  {
272425bb815Sopenharmony_ci    /* Deleted entries also has ECMA_NULL_POINTER
273425bb815Sopenharmony_ci     * value, but they are not NULL values. */
274425bb815Sopenharmony_ci    hashmap_p->null_count--;
275425bb815Sopenharmony_ci    JERRY_ASSERT (hashmap_p->null_count > 0);
276425bb815Sopenharmony_ci  }
277425bb815Sopenharmony_ci
278425bb815Sopenharmony_ci  hashmap_p->unused_count--;
279425bb815Sopenharmony_ci  JERRY_ASSERT (hashmap_p->unused_count > 0);
280425bb815Sopenharmony_ci
281425bb815Sopenharmony_ci  if (property_index == 0)
282425bb815Sopenharmony_ci  {
283425bb815Sopenharmony_ci    *bits_p = (uint8_t) ((*bits_p) & ~mask);
284425bb815Sopenharmony_ci  }
285425bb815Sopenharmony_ci  else
286425bb815Sopenharmony_ci  {
287425bb815Sopenharmony_ci    *bits_p = (uint8_t) ((*bits_p) | mask);
288425bb815Sopenharmony_ci  }
289425bb815Sopenharmony_ci} /* ecma_property_hashmap_insert */
290425bb815Sopenharmony_ci
291425bb815Sopenharmony_ci/**
292425bb815Sopenharmony_ci * Delete named property from the hashmap.
293425bb815Sopenharmony_ci *
294425bb815Sopenharmony_ci * @return ECMA_PROPERTY_HASHMAP_DELETE_RECREATE_HASHMAP if hashmap should be recreated
295425bb815Sopenharmony_ci *         ECMA_PROPERTY_HASHMAP_DELETE_HAS_HASHMAP otherwise
296425bb815Sopenharmony_ci */
297425bb815Sopenharmony_ciecma_property_hashmap_delete_status
298425bb815Sopenharmony_ciecma_property_hashmap_delete (ecma_object_t *object_p, /**< object */
299425bb815Sopenharmony_ci                              jmem_cpointer_t name_cp, /**< property name */
300425bb815Sopenharmony_ci                              ecma_property_t *property_p) /**< property */
301425bb815Sopenharmony_ci{
302425bb815Sopenharmony_ci  ecma_property_hashmap_t *hashmap_p = ECMA_GET_NON_NULL_POINTER (ecma_property_hashmap_t,
303425bb815Sopenharmony_ci                                                                  object_p->u1.property_list_cp);
304425bb815Sopenharmony_ci
305425bb815Sopenharmony_ci  JERRY_ASSERT (hashmap_p->header.types[0] == ECMA_PROPERTY_TYPE_HASHMAP);
306425bb815Sopenharmony_ci
307425bb815Sopenharmony_ci  hashmap_p->unused_count++;
308425bb815Sopenharmony_ci
309425bb815Sopenharmony_ci  /* The NULLs are above 3/4 of the hashmap. */
310425bb815Sopenharmony_ci  if (hashmap_p->unused_count > ((hashmap_p->max_property_count * 3) >> 2))
311425bb815Sopenharmony_ci  {
312425bb815Sopenharmony_ci    return ECMA_PROPERTY_HASHMAP_DELETE_RECREATE_HASHMAP;
313425bb815Sopenharmony_ci  }
314425bb815Sopenharmony_ci
315425bb815Sopenharmony_ci  uint32_t entry_index = ecma_string_get_property_name_hash (*property_p, name_cp);
316425bb815Sopenharmony_ci  uint32_t step = ecma_property_hashmap_steps[entry_index & (ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS - 1)];
317425bb815Sopenharmony_ci  uint32_t mask = hashmap_p->max_property_count - 1;
318425bb815Sopenharmony_ci  jmem_cpointer_t *pair_list_p = (jmem_cpointer_t *) (hashmap_p + 1);
319425bb815Sopenharmony_ci  uint8_t *bits_p = (uint8_t *) (pair_list_p + hashmap_p->max_property_count);
320425bb815Sopenharmony_ci
321425bb815Sopenharmony_ci  entry_index &= mask;
322425bb815Sopenharmony_ci
323425bb815Sopenharmony_ci#ifndef JERRY_NDEBUG
324425bb815Sopenharmony_ci  /* See the comment for this variable in ecma_property_hashmap_create. */
325425bb815Sopenharmony_ci  uint32_t start_entry_index = entry_index;
326425bb815Sopenharmony_ci#endif /* !JERRY_NDEBUG */
327425bb815Sopenharmony_ci
328425bb815Sopenharmony_ci  while (true)
329425bb815Sopenharmony_ci  {
330425bb815Sopenharmony_ci    if (pair_list_p[entry_index] != ECMA_NULL_POINTER)
331425bb815Sopenharmony_ci    {
332425bb815Sopenharmony_ci      size_t offset = 0;
333425bb815Sopenharmony_ci
334425bb815Sopenharmony_ci      if (ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index))
335425bb815Sopenharmony_ci      {
336425bb815Sopenharmony_ci        offset = 1;
337425bb815Sopenharmony_ci      }
338425bb815Sopenharmony_ci
339425bb815Sopenharmony_ci      ecma_property_pair_t *property_pair_p = ECMA_GET_NON_NULL_POINTER (ecma_property_pair_t,
340425bb815Sopenharmony_ci                                                                         pair_list_p[entry_index]);
341425bb815Sopenharmony_ci
342425bb815Sopenharmony_ci      if ((property_pair_p->header.types + offset) == property_p)
343425bb815Sopenharmony_ci      {
344425bb815Sopenharmony_ci        JERRY_ASSERT (property_pair_p->names_cp[offset] == name_cp);
345425bb815Sopenharmony_ci
346425bb815Sopenharmony_ci        pair_list_p[entry_index] = ECMA_NULL_POINTER;
347425bb815Sopenharmony_ci        ECMA_PROPERTY_HASHMAP_SET_BIT (bits_p, entry_index);
348425bb815Sopenharmony_ci        return ECMA_PROPERTY_HASHMAP_DELETE_HAS_HASHMAP;
349425bb815Sopenharmony_ci      }
350425bb815Sopenharmony_ci    }
351425bb815Sopenharmony_ci    else
352425bb815Sopenharmony_ci    {
353425bb815Sopenharmony_ci      /* Must be a deleted entry. */
354425bb815Sopenharmony_ci      JERRY_ASSERT (ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index));
355425bb815Sopenharmony_ci    }
356425bb815Sopenharmony_ci
357425bb815Sopenharmony_ci    entry_index = (entry_index + step) & mask;
358425bb815Sopenharmony_ci
359425bb815Sopenharmony_ci#ifndef JERRY_NDEBUG
360425bb815Sopenharmony_ci    JERRY_ASSERT (entry_index != start_entry_index);
361425bb815Sopenharmony_ci#endif /* !JERRY_NDEBUG */
362425bb815Sopenharmony_ci  }
363425bb815Sopenharmony_ci} /* ecma_property_hashmap_delete */
364425bb815Sopenharmony_ci
365425bb815Sopenharmony_ci/**
366425bb815Sopenharmony_ci * Find a named property.
367425bb815Sopenharmony_ci *
368425bb815Sopenharmony_ci * @return pointer to the property if found or NULL otherwise
369425bb815Sopenharmony_ci */
370425bb815Sopenharmony_ciecma_property_t *
371425bb815Sopenharmony_ciecma_property_hashmap_find (ecma_property_hashmap_t *hashmap_p, /**< hashmap */
372425bb815Sopenharmony_ci                            ecma_string_t *name_p, /**< property name */
373425bb815Sopenharmony_ci                            jmem_cpointer_t *property_real_name_cp) /**< [out] property real name */
374425bb815Sopenharmony_ci{
375425bb815Sopenharmony_ci#ifndef JERRY_NDEBUG
376425bb815Sopenharmony_ci  /* A sanity check in debug mode: a named property must be present
377425bb815Sopenharmony_ci   * in both the property hashmap and in the property chain, or missing
378425bb815Sopenharmony_ci   * from both data collection. The following code checks the property
379425bb815Sopenharmony_ci   * chain, and sets the property_found variable. */
380425bb815Sopenharmony_ci  bool property_found = false;
381425bb815Sopenharmony_ci
382425bb815Sopenharmony_ci  jmem_cpointer_t prop_iter_cp = hashmap_p->header.next_property_cp;
383425bb815Sopenharmony_ci
384425bb815Sopenharmony_ci  while (prop_iter_cp != JMEM_CP_NULL && !property_found)
385425bb815Sopenharmony_ci  {
386425bb815Sopenharmony_ci    ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp);
387425bb815Sopenharmony_ci    JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
388425bb815Sopenharmony_ci
389425bb815Sopenharmony_ci    ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;
390425bb815Sopenharmony_ci
391425bb815Sopenharmony_ci    for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
392425bb815Sopenharmony_ci    {
393425bb815Sopenharmony_ci      if (ECMA_PROPERTY_IS_NAMED_PROPERTY (prop_iter_p->types[i]))
394425bb815Sopenharmony_ci      {
395425bb815Sopenharmony_ci        if (ecma_string_compare_to_property_name (prop_iter_p->types[i],
396425bb815Sopenharmony_ci                                                  prop_pair_p->names_cp[i],
397425bb815Sopenharmony_ci                                                  name_p))
398425bb815Sopenharmony_ci        {
399425bb815Sopenharmony_ci          /* Property is found */
400425bb815Sopenharmony_ci          property_found = true;
401425bb815Sopenharmony_ci          break;
402425bb815Sopenharmony_ci        }
403425bb815Sopenharmony_ci      }
404425bb815Sopenharmony_ci    }
405425bb815Sopenharmony_ci
406425bb815Sopenharmony_ci    prop_iter_cp = prop_iter_p->next_property_cp;
407425bb815Sopenharmony_ci  }
408425bb815Sopenharmony_ci#endif /* !JERRY_NDEBUG */
409425bb815Sopenharmony_ci
410425bb815Sopenharmony_ci  uint32_t entry_index = ecma_string_hash (name_p);
411425bb815Sopenharmony_ci  uint32_t step = ecma_property_hashmap_steps[entry_index & (ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS - 1)];
412425bb815Sopenharmony_ci  uint32_t mask = hashmap_p->max_property_count - 1;
413425bb815Sopenharmony_ci  jmem_cpointer_t *pair_list_p = (jmem_cpointer_t *) (hashmap_p + 1);
414425bb815Sopenharmony_ci  uint8_t *bits_p = (uint8_t *) (pair_list_p + hashmap_p->max_property_count);
415425bb815Sopenharmony_ci  entry_index &= mask;
416425bb815Sopenharmony_ci
417425bb815Sopenharmony_ci#ifndef JERRY_NDEBUG
418425bb815Sopenharmony_ci  /* See the comment for this variable in ecma_property_hashmap_create. */
419425bb815Sopenharmony_ci  uint32_t start_entry_index = entry_index;
420425bb815Sopenharmony_ci#endif /* !JERRY_NDEBUG */
421425bb815Sopenharmony_ci
422425bb815Sopenharmony_ci  if (ECMA_IS_DIRECT_STRING (name_p))
423425bb815Sopenharmony_ci  {
424425bb815Sopenharmony_ci    ecma_property_t prop_name_type = (ecma_property_t) ECMA_GET_DIRECT_STRING_TYPE (name_p);
425425bb815Sopenharmony_ci    jmem_cpointer_t property_name_cp = (jmem_cpointer_t) ECMA_GET_DIRECT_STRING_VALUE (name_p);
426425bb815Sopenharmony_ci
427425bb815Sopenharmony_ci    JERRY_ASSERT (prop_name_type > 0);
428425bb815Sopenharmony_ci
429425bb815Sopenharmony_ci    while (true)
430425bb815Sopenharmony_ci    {
431425bb815Sopenharmony_ci      if (pair_list_p[entry_index] != ECMA_NULL_POINTER)
432425bb815Sopenharmony_ci      {
433425bb815Sopenharmony_ci        size_t offset = 0;
434425bb815Sopenharmony_ci        if (ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index))
435425bb815Sopenharmony_ci        {
436425bb815Sopenharmony_ci          offset = 1;
437425bb815Sopenharmony_ci        }
438425bb815Sopenharmony_ci
439425bb815Sopenharmony_ci        ecma_property_pair_t *property_pair_p = ECMA_GET_NON_NULL_POINTER (ecma_property_pair_t,
440425bb815Sopenharmony_ci                                                                           pair_list_p[entry_index]);
441425bb815Sopenharmony_ci
442425bb815Sopenharmony_ci        ecma_property_t *property_p = property_pair_p->header.types + offset;
443425bb815Sopenharmony_ci
444425bb815Sopenharmony_ci        JERRY_ASSERT (ECMA_PROPERTY_IS_NAMED_PROPERTY (*property_p));
445425bb815Sopenharmony_ci
446425bb815Sopenharmony_ci        if (property_pair_p->names_cp[offset] == property_name_cp
447425bb815Sopenharmony_ci            && ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == prop_name_type)
448425bb815Sopenharmony_ci        {
449425bb815Sopenharmony_ci#ifndef JERRY_NDEBUG
450425bb815Sopenharmony_ci          JERRY_ASSERT (property_found);
451425bb815Sopenharmony_ci#endif /* !JERRY_NDEBUG */
452425bb815Sopenharmony_ci
453425bb815Sopenharmony_ci          *property_real_name_cp = property_name_cp;
454425bb815Sopenharmony_ci          return property_p;
455425bb815Sopenharmony_ci        }
456425bb815Sopenharmony_ci      }
457425bb815Sopenharmony_ci      else
458425bb815Sopenharmony_ci      {
459425bb815Sopenharmony_ci        if (!ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index))
460425bb815Sopenharmony_ci        {
461425bb815Sopenharmony_ci#ifndef JERRY_NDEBUG
462425bb815Sopenharmony_ci          JERRY_ASSERT (!property_found);
463425bb815Sopenharmony_ci#endif /* !JERRY_NDEBUG */
464425bb815Sopenharmony_ci
465425bb815Sopenharmony_ci          return NULL;
466425bb815Sopenharmony_ci        }
467425bb815Sopenharmony_ci        /* Otherwise it is a deleted entry. */
468425bb815Sopenharmony_ci      }
469425bb815Sopenharmony_ci
470425bb815Sopenharmony_ci      entry_index = (entry_index + step) & mask;
471425bb815Sopenharmony_ci
472425bb815Sopenharmony_ci#ifndef JERRY_NDEBUG
473425bb815Sopenharmony_ci      JERRY_ASSERT (entry_index != start_entry_index);
474425bb815Sopenharmony_ci#endif /* !JERRY_NDEBUG */
475425bb815Sopenharmony_ci    }
476425bb815Sopenharmony_ci  }
477425bb815Sopenharmony_ci
478425bb815Sopenharmony_ci  while (true)
479425bb815Sopenharmony_ci  {
480425bb815Sopenharmony_ci    if (pair_list_p[entry_index] != ECMA_NULL_POINTER)
481425bb815Sopenharmony_ci    {
482425bb815Sopenharmony_ci      size_t offset = 0;
483425bb815Sopenharmony_ci      if (ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index))
484425bb815Sopenharmony_ci      {
485425bb815Sopenharmony_ci        offset = 1;
486425bb815Sopenharmony_ci      }
487425bb815Sopenharmony_ci
488425bb815Sopenharmony_ci      ecma_property_pair_t *property_pair_p = ECMA_GET_NON_NULL_POINTER (ecma_property_pair_t,
489425bb815Sopenharmony_ci                                                                         pair_list_p[entry_index]);
490425bb815Sopenharmony_ci
491425bb815Sopenharmony_ci      ecma_property_t *property_p = property_pair_p->header.types + offset;
492425bb815Sopenharmony_ci
493425bb815Sopenharmony_ci      JERRY_ASSERT (ECMA_PROPERTY_IS_NAMED_PROPERTY (*property_p));
494425bb815Sopenharmony_ci
495425bb815Sopenharmony_ci      if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_PTR)
496425bb815Sopenharmony_ci      {
497425bb815Sopenharmony_ci        ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, property_pair_p->names_cp[offset]);
498425bb815Sopenharmony_ci
499425bb815Sopenharmony_ci        if (ecma_compare_ecma_non_direct_strings (prop_name_p, name_p))
500425bb815Sopenharmony_ci        {
501425bb815Sopenharmony_ci#ifndef JERRY_NDEBUG
502425bb815Sopenharmony_ci          JERRY_ASSERT (property_found);
503425bb815Sopenharmony_ci#endif /* !JERRY_NDEBUG */
504425bb815Sopenharmony_ci
505425bb815Sopenharmony_ci          *property_real_name_cp = property_pair_p->names_cp[offset];
506425bb815Sopenharmony_ci          return property_p;
507425bb815Sopenharmony_ci        }
508425bb815Sopenharmony_ci      }
509425bb815Sopenharmony_ci    }
510425bb815Sopenharmony_ci    else
511425bb815Sopenharmony_ci    {
512425bb815Sopenharmony_ci      if (!ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index))
513425bb815Sopenharmony_ci      {
514425bb815Sopenharmony_ci#ifndef JERRY_NDEBUG
515425bb815Sopenharmony_ci        JERRY_ASSERT (!property_found);
516425bb815Sopenharmony_ci#endif /* !JERRY_NDEBUG */
517425bb815Sopenharmony_ci
518425bb815Sopenharmony_ci        return NULL;
519425bb815Sopenharmony_ci      }
520425bb815Sopenharmony_ci      /* Otherwise it is a deleted entry. */
521425bb815Sopenharmony_ci    }
522425bb815Sopenharmony_ci
523425bb815Sopenharmony_ci    entry_index = (entry_index + step) & mask;
524425bb815Sopenharmony_ci
525425bb815Sopenharmony_ci#ifndef JERRY_NDEBUG
526425bb815Sopenharmony_ci    JERRY_ASSERT (entry_index != start_entry_index);
527425bb815Sopenharmony_ci#endif /* !JERRY_NDEBUG */
528425bb815Sopenharmony_ci  }
529425bb815Sopenharmony_ci} /* ecma_property_hashmap_find */
530425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
531425bb815Sopenharmony_ci
532425bb815Sopenharmony_ci/**
533425bb815Sopenharmony_ci * @}
534425bb815Sopenharmony_ci * @}
535425bb815Sopenharmony_ci */
536