Skip to content

Commit a539050

Browse files
committed
literal storage using hashmap: new hashmap implementation
JerryScript-DCO-1.0-Signed-off-by: Ronan Jezequel [email protected]
1 parent fb8c540 commit a539050

File tree

7 files changed

+241
-480
lines changed

7 files changed

+241
-480
lines changed

jerry-core/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,8 @@ if(ENABLE_AMALGAM)
500500
lit/lit-unicode-folding.inc.h
501501
lit/lit-unicode-ranges-sup.inc.h
502502
lit/lit-unicode-ranges.inc.h
503+
lit/lit-hashmap-impl.h
504+
lit/lit-hashmap.h
503505
vm/opcodes.h
504506
vm/vm-defines.h
505507
vm/vm-stack.h

jerry-core/ecma/base/ecma-literal-storage.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, /**< string
273273
}
274274

275275
#if JERRY_LIT_HASHMAP
276-
const ecma_string_t *hashmap_entry = hashmap_get (&JERRY_CONTEXT (string_hashmap), string_p);
276+
const ecma_string_t *hashmap_entry = hashmap_get (JERRY_CONTEXT (string_hashmap), string_p);
277277
if (hashmap_entry != NULL)
278278
{
279279
ecma_deref_ecma_string (string_p);
@@ -299,7 +299,7 @@ ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, /**< string
299299
*slot = result;
300300

301301
#if JERRY_LIT_HASHMAP
302-
hashmap_put (&JERRY_CONTEXT (string_hashmap), string_p);
302+
hashmap_put (JERRY_CONTEXT (string_hashmap), string_p);
303303
#endif /* JERRY_LIT_HASHMAP */
304304

305305
return ecma_make_string_value (string_p);

jerry-core/jcontext/jcontext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ struct jerry_context_t
140140
jmem_cpointer_t global_symbols_cp[ECMA_BUILTIN_GLOBAL_SYMBOL_COUNT]; /**< global symbols */
141141

142142
#if JERRY_LIT_HASHMAP
143-
struct hashmap_s string_hashmap;
143+
hashmap_t string_hashmap;
144144
#endif /* JERRY_LIT_HASHMAP */
145145

146146
#if JERRY_MODULE_SYSTEM

jerry-core/lit/lit-hashmap-impl.h

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
/* Copyright JS Foundation and other contributors, http://js.foundation
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*
15+
* The lit-hashmap library is based on the public domain software
16+
* available from https://github.com/sheredom/hashmap.h
17+
*/
18+
19+
#include <stdlib.h>
20+
#include <string.h>
21+
22+
#include "ecma-globals.h"
23+
#include "ecma-helpers.h"
24+
25+
/* ------------------------------------------------------------------------------------------------ */
26+
// Configuration
27+
28+
#define HASHMAP_LINEAR_PROBE_LENGTH ((size_t) 8)
29+
30+
/* ------------------------------------------------------------------------------------------------ */
31+
32+
#define HASHMAP_CAST(type, x) ((type) (x))
33+
#define HASHMAP_PTR_CAST(type, x) ((type) (x))
34+
#define HASHMAP_NULL 0
35+
36+
#define HASHMAP_IMPL_INLINE __attribute__ ((always_inline)) inline
37+
38+
/* ------------------------------------------------------------------------------------------------ */
39+
40+
/**
41+
* HashMap object, internal representation
42+
*/
43+
typedef struct
44+
{
45+
size_t log2_capacity; /**< hashmap capacity */
46+
uint32_t used_entries; /**< hashmap size*/
47+
size_t array_size; /**< allocated size */
48+
const ecma_string_t **literals; /**< element array */
49+
} hashmap_impl;
50+
51+
/**
52+
* HashMap iterator object, internal representation
53+
*/
54+
typedef struct
55+
{
56+
hashmap_impl *hmap; /**< pointer to the hashmap */
57+
uint32_t index; /**< iterator start index */
58+
uint32_t slot; /**< iterator slot, from 0 to HASHMAP_LINEAR_PROBE_LENGTH */
59+
lit_string_hash_t key; /**< key beeing looked for */
60+
} hashmap_impl_iter;
61+
62+
/* ------------------------------------------------------------------------------------------------ */
63+
64+
void hashmap_impl_rehash (hashmap_impl *const hashmap);
65+
66+
/* ------------------------------------------------------------------------------------------------ */
67+
68+
HASHMAP_IMPL_INLINE size_t
69+
hashmap_impl_log2 (size_t v)
70+
{
71+
int n = 31 - __builtin_clz ((uint32_t) v);
72+
return (size_t) n;
73+
} /* hashmap_round_log2 */
74+
75+
HASHMAP_IMPL_INLINE uint32_t
76+
hashmap_impl_lithash_to_index (const hashmap_impl *const m, lit_string_hash_t hash)
77+
{
78+
uint32_t v = (hash * 2654435769u) >> (32u - m->log2_capacity);
79+
return v;
80+
} /* hashmap_hash_to_index */
81+
82+
/* ------------------------------------------------------------------------------------------------ */
83+
84+
HASHMAP_IMPL_INLINE void
85+
hashmap_impl_init (size_t initial_capacity, hashmap_impl *hashmap)
86+
{
87+
initial_capacity = ((size_t) 1) << hashmap_impl_log2 (initial_capacity);
88+
size_t array_size = (initial_capacity + HASHMAP_LINEAR_PROBE_LENGTH);
89+
90+
hashmap->literals = jmem_heap_alloc_block (array_size * sizeof (const ecma_string_t *));
91+
memset (hashmap->literals, 0, array_size * sizeof (const ecma_string_t *));
92+
hashmap->log2_capacity = hashmap_impl_log2 (initial_capacity);
93+
hashmap->used_entries = 0;
94+
} /* hashmap_new */
95+
96+
/* ------------------------------------------------------------------------------------------------ */
97+
98+
HASHMAP_IMPL_INLINE int
99+
hashmap_impl_find_empty_slot (const hashmap_impl *const hashmap, const lit_string_hash_t key, uint32_t *const out_index)
100+
{
101+
uint32_t start_index = hashmap_impl_lithash_to_index (hashmap, key);
102+
103+
for (uint32_t offset = 0; offset < HASHMAP_LINEAR_PROBE_LENGTH; offset++)
104+
{
105+
const uint32_t index = start_index + offset;
106+
107+
if (hashmap->literals[index] == NULL)
108+
{
109+
*out_index = index;
110+
return 1;
111+
}
112+
}
113+
114+
return 0;
115+
} /* hashmap_impl_find_empty_slot */
116+
117+
/* ------------------------------------------------------------------------------------------------ */
118+
119+
HASHMAP_IMPL_INLINE void
120+
hashmap_impl_insert (hashmap_impl *hashmap, const ecma_string_t *literal)
121+
{
122+
/* Find a place to put our value. */
123+
uint32_t index;
124+
uint32_t lithash = literal->u.hash;
125+
while (!hashmap_impl_find_empty_slot (hashmap, lithash, &index))
126+
{
127+
hashmap_impl_rehash (hashmap);
128+
}
129+
130+
hashmap->literals[index] = literal;
131+
hashmap->used_entries++;
132+
} /* hashmap_impl_insert */
133+
134+
/* ------------------------------------------------------------------------------------------------ */
135+
136+
HASHMAP_IMPL_INLINE hashmap_impl_iter
137+
hashmap_impl_find (hashmap_impl *hashmap, lit_string_hash_t key)
138+
{
139+
uint32_t start_index = hashmap_impl_lithash_to_index (hashmap, key);
140+
return (hashmap_impl_iter){
141+
.hmap = hashmap,
142+
.index = start_index,
143+
.slot = 0,
144+
.key = key,
145+
};
146+
} /* hashmap_impl_find */
147+
148+
HASHMAP_IMPL_INLINE const ecma_string_t *
149+
hashmap_impl_iter_get (hashmap_impl_iter *iter)
150+
{
151+
const ecma_string_t **literals = iter->hmap->literals;
152+
while (iter->slot < HASHMAP_LINEAR_PROBE_LENGTH)
153+
{
154+
uint32_t index = iter->index + iter->slot;
155+
const ecma_string_t *literal = literals[index];
156+
if (literal && literal->u.hash == iter->key)
157+
{
158+
return literals[index];
159+
}
160+
161+
iter->slot++;
162+
}
163+
return NULL;
164+
} /* hashmap_impl_iter_get */
165+
166+
HASHMAP_IMPL_INLINE const ecma_string_t *
167+
hashmap_impl_iter_next (hashmap_impl_iter *iter)
168+
{
169+
iter->slot++;
170+
return hashmap_impl_iter_get (iter);
171+
} /* hashmap_impl_iter_next */
172+
173+
HASHMAP_IMPL_INLINE void
174+
hashmap_impl_destroy (hashmap_impl *hashmap)
175+
{
176+
size_t l = ((size_t) (1 << hashmap->log2_capacity)) + HASHMAP_LINEAR_PROBE_LENGTH;
177+
jmem_heap_free_block (hashmap->literals, l * sizeof (const ecma_string_t *));
178+
} /* hashmap_impl_destroy */
179+
180+
/* ------------------------------------------------------------------------------------------------ */
181+
182+
void
183+
hashmap_impl_rehash (hashmap_impl *const hashmap)
184+
{
185+
size_t clen = ((size_t) (1 << hashmap->log2_capacity)) + HASHMAP_LINEAR_PROBE_LENGTH;
186+
187+
hashmap_impl new_hashmap;
188+
hashmap_impl_init (clen * 2, &new_hashmap);
189+
190+
size_t l = clen + HASHMAP_LINEAR_PROBE_LENGTH;
191+
for (size_t i = 0; i < l; i++)
192+
{
193+
const ecma_string_t *p = hashmap->literals[i];
194+
if (!p)
195+
continue;
196+
hashmap_impl_insert (&new_hashmap, p);
197+
}
198+
199+
jmem_heap_free_block (hashmap->literals, l * sizeof (const ecma_string_t *));
200+
201+
memcpy (hashmap, &new_hashmap, sizeof (hashmap_impl));
202+
} /* hashmap_impl_rehash */

jerry-core/lit/lit-hashmap-internal.h

Lines changed: 0 additions & 80 deletions
This file was deleted.

0 commit comments

Comments
 (0)