Skip to content

Commit

Permalink
literal storage using hashmap
Browse files Browse the repository at this point in the history
JerryScript-DCO-1.0-Signed-off-by: Ronan Jezequel [email protected]
  • Loading branch information
ronanj committed Mar 20, 2024
1 parent cefd391 commit fb8c540
Show file tree
Hide file tree
Showing 10 changed files with 695 additions and 27 deletions.
2 changes: 2 additions & 0 deletions jerry-core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ set(JERRY_SYSTEM_ALLOCATOR OFF CACHE BOOL "Enable system all
set(JERRY_VALGRIND OFF CACHE BOOL "Enable Valgrind support?")
set(JERRY_VM_HALT OFF CACHE BOOL "Enable VM execution stop callback?")
set(JERRY_VM_THROW OFF CACHE BOOL "Enable VM throw callback?")
set(JERRY_LIT_HASHMAP OFF CACHE BOOL "Enable literal hashmap storage?")
set(JERRY_GLOBAL_HEAP_SIZE "(512)" CACHE STRING "Size of memory heap, in kilobytes")
set(JERRY_GC_LIMIT "(0)" CACHE STRING "Heap usage limit to trigger garbage collection")
set(JERRY_STACK_LIMIT "(0)" CACHE STRING "Maximum stack usage size, in kilobytes")
Expand Down Expand Up @@ -304,6 +305,7 @@ set(SOURCE_CORE_FILES
lit/lit-char-helpers.c
lit/lit-magic-strings.c
lit/lit-strings.c
lit/lit-hashmap.c
parser/js/byte-code.c
parser/js/common.c
parser/js/js-lexer.c
Expand Down
7 changes: 7 additions & 0 deletions jerry-core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,13 @@
* Advanced section configurations.
*/

/**
* The JERRY_LIT_HASHMAP uses an hashmap for faster literal storage.
*/
#ifndef JERRY_LIT_HASHMAP
#define JERRY_LIT_HASHMAP 0
#endif /* !defined (JERRY_LIT_HASHMAP) */

/**
* Allow configuring attributes on a few constant data inside the engine.
*
Expand Down
133 changes: 106 additions & 27 deletions jerry-core/ecma/base/ecma-literal-storage.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,23 +153,68 @@ ecma_finalize_lit_storage (void)
} /* ecma_finalize_lit_storage */

/**
* Find or create a literal string.
* Create a new literal string slot "pool".
*
* @return ecma_string_t compressed pointer
* @return jmem_cpointer_t slot pointer
*/
ecma_value_t
ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, /**< string to be searched */
lit_utf8_size_t size, /**< size of the string */
bool is_ascii) /**< encode of the string */

static jmem_cpointer_t *
ecma_allocate_new_string_slot (void)
{
ecma_string_t *string_p =
(is_ascii ? ecma_new_ecma_string_from_ascii (chars_p, size) : ecma_new_ecma_string_from_utf8 (chars_p, size));
ecma_lit_storage_item_t *new_item_p;
new_item_p = (ecma_lit_storage_item_t *) jmem_pools_alloc (sizeof (ecma_lit_storage_item_t));

if (ECMA_IS_DIRECT_STRING (string_p))
for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
{
return ecma_make_string_value (string_p);
new_item_p->values[i] = JMEM_CP_NULL;
}

new_item_p->next_cp = JERRY_CONTEXT (string_list_first_cp);
JMEM_CP_SET_NON_NULL_POINTER (JERRY_CONTEXT (string_list_first_cp), new_item_p);

return new_item_p->values + 0;
} /* ecma_allocate_new_string_slot */

#if JERRY_LIT_HASHMAP
/**
* Find an empty a literal string slot.
*
* @return jmem_cpointer_t slot pointer
*/

static jmem_cpointer_t *
ecma_find_empty_literal_string_slot (void)
{
jmem_cpointer_t string_list_cp = JERRY_CONTEXT (string_list_first_cp);

while (string_list_cp != JMEM_CP_NULL)
{
ecma_lit_storage_item_t *string_list_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_lit_storage_item_t, string_list_cp);

for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
{
if (string_list_p->values[i] == JMEM_CP_NULL)
{
return string_list_p->values + i;
}
}
string_list_cp = string_list_p->next_cp;
}

return ecma_allocate_new_string_slot ();
} /* ecma_find_empty_literal_string_slot */
#endif /* JERRY_LIT_HASHMAP */

/**
* Find an empty or similar a literal string slot.
*
* @return jmem_cpointer_t slot pointer
*/

#if !JERRY_LIT_HASHMAP
static jmem_cpointer_t *
ecma_find_empty_or_same_literal_string_slot (ecma_string_t *string_p /**< string to be searched */)
{
jmem_cpointer_t string_list_cp = JERRY_CONTEXT (string_list_first_cp);
jmem_cpointer_t *empty_cpointer_p = NULL;

Expand All @@ -189,42 +234,76 @@ ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, /**< string
else
{
ecma_string_t *value_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, string_list_p->values[i]);

if (ecma_compare_ecma_strings (string_p, value_p))
{
/* Return with string if found in the list. */
ecma_deref_ecma_string (string_p);
return ecma_make_string_value (value_p);
return string_list_p->values + i;
}
}
}

string_list_cp = string_list_p->next_cp;
}

ECMA_SET_STRING_AS_STATIC (string_p);
jmem_cpointer_t result;
JMEM_CP_SET_NON_NULL_POINTER (result, string_p);

if (empty_cpointer_p != NULL)
{
*empty_cpointer_p = result;
return ecma_make_string_value (string_p);
return empty_cpointer_p;
}

ecma_lit_storage_item_t *new_item_p;
new_item_p = (ecma_lit_storage_item_t *) jmem_pools_alloc (sizeof (ecma_lit_storage_item_t));
return ecma_allocate_new_string_slot ();
} /* ecma_find_empty_or_same_literal_string_slot */
#endif /* !JERRY_LIT_HASHMAP */

new_item_p->values[0] = result;
for (int i = 1; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
/**
* Find or create a literal string.
*
* @return ecma_string_t compressed pointer
*/

ecma_value_t
ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, /**< string to be searched */
lit_utf8_size_t size, /**< size of the string */
bool is_ascii) /**< encode of the string */
{
ecma_string_t *string_p =
(is_ascii ? ecma_new_ecma_string_from_ascii (chars_p, size) : ecma_new_ecma_string_from_utf8 (chars_p, size));

if (ECMA_IS_DIRECT_STRING (string_p))
{
new_item_p->values[i] = JMEM_CP_NULL;
return ecma_make_string_value (string_p);
}

new_item_p->next_cp = JERRY_CONTEXT (string_list_first_cp);
JMEM_CP_SET_NON_NULL_POINTER (JERRY_CONTEXT (string_list_first_cp), new_item_p);
#if JERRY_LIT_HASHMAP
const ecma_string_t *hashmap_entry = hashmap_get (&JERRY_CONTEXT (string_hashmap), string_p);
if (hashmap_entry != NULL)
{
ecma_deref_ecma_string (string_p);
return ecma_make_string_value (hashmap_entry);
}
// Since the string is not found, just find an empty slot
jmem_cpointer_t *slot = ecma_find_empty_literal_string_slot ();
#else /* JERRY_LIT_HASHMAP */
jmem_cpointer_t *slot = ecma_find_empty_or_same_literal_string_slot (string_p);
if (*slot != JMEM_CP_NULL)
{
// The string has been found
ecma_string_t *value_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, *slot);
ecma_deref_ecma_string (string_p);
return ecma_make_string_value (value_p);
}
#endif /* JERRY_LIT_HASHMAP */

// String has not been found...
ECMA_SET_STRING_AS_STATIC (string_p);
jmem_cpointer_t result;
JMEM_CP_SET_NON_NULL_POINTER (result, string_p);
*slot = result;

#if JERRY_LIT_HASHMAP
hashmap_put (&JERRY_CONTEXT (string_hashmap), string_p);
#endif /* JERRY_LIT_HASHMAP */

return ecma_make_string_value (string_p);

} /* ecma_find_or_create_literal_string */

/**
Expand Down
5 changes: 5 additions & 0 deletions jerry-core/jcontext/jcontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "debugger.h"
#include "jmem.h"
#include "js-parser-internal.h"
#include "lit-hashmap.h"
#include "re-bytecode.h"
#include "vm-defines.h"

Expand Down Expand Up @@ -138,6 +139,10 @@ struct jerry_context_t
#endif /* JERRY_BUILTIN_BIGINT */
jmem_cpointer_t global_symbols_cp[ECMA_BUILTIN_GLOBAL_SYMBOL_COUNT]; /**< global symbols */

#if JERRY_LIT_HASHMAP
struct hashmap_s string_hashmap;
#endif /* JERRY_LIT_HASHMAP */

#if JERRY_MODULE_SYSTEM
ecma_module_t *module_current_p; /**< current module context */
jerry_module_state_changed_cb_t module_state_changed_callback_p; /**< callback which is called after the
Expand Down
10 changes: 10 additions & 0 deletions jerry-core/jmem/jmem-heap.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "jmem.h"
#include "jrt-bit-fields.h"
#include "jrt-libc-includes.h"
#include "lit-hashmap.h"

#define JMEM_ALLOCATOR_INTERNAL
#include "jmem-allocator-internal.h"
Expand Down Expand Up @@ -103,6 +104,11 @@ jmem_heap_init (void)
JMEM_VALGRIND_NOACCESS_SPACE (JERRY_HEAP_CONTEXT (area), JMEM_HEAP_AREA_SIZE);

#endif /* !JERRY_SYSTEM_ALLOCATOR */

#if JERRY_LIT_HASHMAP
hashmap_init (&JERRY_CONTEXT (string_hashmap));
#endif /* JERRY_LIT_HASHMAP */

JMEM_HEAP_STAT_INIT ();
} /* jmem_heap_init */

Expand All @@ -112,6 +118,10 @@ jmem_heap_init (void)
void
jmem_heap_finalize (void)
{
#if JERRY_LIT_HASHMAP
hashmap_destroy (&JERRY_CONTEXT (string_hashmap));
#endif /* JERRY_LIT_HASHMAP */

JERRY_ASSERT (JERRY_CONTEXT (jmem_heap_allocated_size) == 0);
#if !JERRY_SYSTEM_ALLOCATOR
JMEM_VALGRIND_NOACCESS_SPACE (&JERRY_HEAP_CONTEXT (first), JMEM_HEAP_SIZE);
Expand Down
80 changes: 80 additions & 0 deletions jerry-core/lit/lit-hashmap-internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/*
The lit-hashmap library is based on the public domain software
available from https://github.com/sheredom/hashmap.h
*/

#ifndef LIT_HASHMAP_INTERNAL_H
#define LIT_HASHMAP_INTERNAL_H

#include "lit-hashmap.h"

#define HASHMAP_ALWAYS_INLINE __attribute__ ((always_inline)) inline
#define HASHMAP_LINEAR_PROBE_LENGTH (8)

/**
* hashmap creation options.
*/

typedef struct hashmap_create_options_s
{
hashmap_uint32_t initial_capacity; /**< initial hashmap capacity */
} hashmap_create_options_t;

/// @brief Create a hashmap.
/// @param options The options to create the hashmap with.
/// @param out_hashmap The storage for the created hashmap.
/// @return On success 0 is returned.
///
/// The options members work as follows:
/// - initial_capacity The initial capacity of the hashmap.
/// - hasher Which hashing function to use with the hashmap (by default the
// crc32 with Robert Jenkins' mix is used).
int hashmap_create_ex (struct hashmap_create_options_s options, struct hashmap_s *const out_hashmap);

/// @brief Iterate over all the elements in a hashmap.
/// @param hashmap The hashmap to iterate over.
/// @param iterator The function pointer to call on each element.
/// @param context The context to pass as the first argument to f.
/// @return If the entire hashmap was iterated then 0 is returned.
/// Otherwise if the callback function f returned positive then the positive
/// value is returned. If the callback function returns -1, the current item
/// is removed and iteration continues.
int hashmap_iterate_pairs (struct hashmap_s *const hashmap,
int (*iterator) (void *const, struct hashmap_element_s *const),
void *const context);

/// @brief Get the size of the hashmap.
/// @param hashmap The hashmap to get the size of.
/// @return The size of the hashmap.
HASHMAP_ALWAYS_INLINE hashmap_uint32_t hashmap_num_entries (const struct hashmap_s *const hashmap);

/// @brief Get the capacity of the hashmap.
/// @param hashmap The hashmap to get the size of.
/// @return The capacity of the hashmap.
HASHMAP_ALWAYS_INLINE hashmap_uint32_t hashmap_capacity (const struct hashmap_s *const hashmap);

HASHMAP_ALWAYS_INLINE hashmap_uint32_t hashmap_hash_helper_int_helper (const struct hashmap_s *const m,
const ecma_string_t *const key);
HASHMAP_ALWAYS_INLINE int hashmap_hash_helper (const struct hashmap_s *const m,
const ecma_string_t *const key,
hashmap_uint32_t *const out_index);
int hashmap_rehash_iterator (void *const new_hash, struct hashmap_element_s *const e);
HASHMAP_ALWAYS_INLINE int hashmap_rehash_helper (struct hashmap_s *const m);
HASHMAP_ALWAYS_INLINE hashmap_uint32_t hashmap_clz (const hashmap_uint32_t x);

#endif // LIT_HASHMAP_INTERNAL_H
Loading

0 comments on commit fb8c540

Please sign in to comment.