From bd9d1d4afd0e6cecdffbf614bc7622fa1e08dadc Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 19 Jun 2015 00:11:22 +0300 Subject: [PATCH] Improve allocation of memory for byte-code array and literal identifiers hash table. - literal identifiers hash table and byte-code array are now allocated in one heap block instead of four blocks; - memory regions with the hash tables and arrays are now linked into linked list using headers at start of the regions instead of using array_list. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- jerry-core/parser/js/bytecode-data.h | 20 +-- .../js/collections/lit-id-hash-table.cpp | 133 +++++++++++++----- .../parser/js/collections/lit-id-hash-table.h | 3 +- jerry-core/parser/js/collections/stack.h | 20 --- jerry-core/parser/js/scopes-tree.cpp | 21 ++- jerry-core/parser/js/scopes-tree.h | 2 +- jerry-core/parser/js/serializer.cpp | 43 ++++-- 7 files changed, 158 insertions(+), 84 deletions(-) diff --git a/jerry-core/parser/js/bytecode-data.h b/jerry-core/parser/js/bytecode-data.h index 207be7ee9..e741d463d 100644 --- a/jerry-core/parser/js/bytecode-data.h +++ b/jerry-core/parser/js/bytecode-data.h @@ -18,6 +18,7 @@ #include "opcodes.h" #include "lit-id-hash-table.h" +#include "mem-allocator.h" /* * All literals are kept in the 'literals' array. @@ -35,11 +36,13 @@ #define BLOCK_SIZE 64 /** - * Pointer to lit_id_hash_table precedes every independent bytecode region + * Header of byte-code memory region, containing byte-code array and literal identifiers hash table */ typedef struct __attribute__ ((aligned (MEM_ALIGNMENT))) { - lit_id_hash_table *lit_id_hash; + mem_cpointer_t lit_id_hash_cp; /**< pointer to literal identifiers hash table + * See also: lit_id_hash_table_init */ + mem_cpointer_t next_opcodes_cp; /**< pointer to next byte-code memory region */ } opcodes_header_t; typedef struct @@ -49,15 +52,16 @@ typedef struct opcode_counter_t opcodes_count; } bytecode_data_t; -/** - * Macros to get a hash table corresponding to a bytecode region - */ -#define GET_HASH_TABLE_FOR_BYTECODE(opcodes) (((opcodes_header_t *) (((uint8_t *) (opcodes)) - \ - sizeof (opcodes_header_t)))->lit_id_hash) - /** * Macros to get a pointer to bytecode header by pointer to opcodes start */ #define GET_BYTECODE_HEADER(opcodes) ((opcodes_header_t *) (((uint8_t *) (opcodes)) - sizeof (opcodes_header_t))) +/** + * Macros to get a hash table corresponding to a bytecode region + */ +#define GET_HASH_TABLE_FOR_BYTECODE(opcodes) (MEM_CP_GET_POINTER (lit_id_hash_table, \ + GET_BYTECODE_HEADER (opcodes)->lit_id_hash_cp)) + + #endif // BYTECODE_DATA_H diff --git a/jerry-core/parser/js/collections/lit-id-hash-table.cpp b/jerry-core/parser/js/collections/lit-id-hash-table.cpp index 924299c6c..8da6188e1 100644 --- a/jerry-core/parser/js/collections/lit-id-hash-table.cpp +++ b/jerry-core/parser/js/collections/lit-id-hash-table.cpp @@ -16,49 +16,114 @@ #include "lit-id-hash-table.h" #include "bytecode-data.h" +/** \addtogroup jsparser ECMAScript parser + * @{ + * + * \addtogroup collections Collections + * @{ + * + * \addtogroup lit_id_hash_table Literal identifiers hash table + * The hash table connects pairs (opcode block, idx_t value) with literal identifiers. + * @{ + */ + +/** + * Initialize literal identifiers hash table + * + * @return pointer to header of the table + */ lit_id_hash_table * -lit_id_hash_table_init (size_t buckets_count, size_t blocks_count) +lit_id_hash_table_init (uint8_t *table_buffer_p, /**< buffer to initialize hash table in */ + size_t buffer_size, /**< size of the buffer */ + size_t buckets_count, /**< number of pairs */ + size_t blocks_count) /**< number of opcode blocks */ { - size_t size = mem_heap_recommend_allocation_size (sizeof (lit_id_hash_table)); - lit_id_hash_table *table = (lit_id_hash_table *) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_LONG_TERM); - memset (table, 0, size); - size = mem_heap_recommend_allocation_size (sizeof (lit_cpointer_t) * buckets_count); - table->raw_buckets = (lit_cpointer_t *) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_LONG_TERM); - memset (table->raw_buckets, 0, size); - size = mem_heap_recommend_allocation_size (sizeof (lit_cpointer_t *) * blocks_count); - table->buckets = (lit_cpointer_t **) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_LONG_TERM); - memset (table->buckets, 0, size); - table->current_bucket_pos = 0; - return table; -} + const size_t header_size = JERRY_ALIGNUP (sizeof (lit_id_hash_table), MEM_ALIGNMENT); + const size_t raw_buckets_size = JERRY_ALIGNUP (sizeof (lit_cpointer_t) * buckets_count, MEM_ALIGNMENT); + const size_t buckets_size = JERRY_ALIGNUP (sizeof (lit_cpointer_t*) * blocks_count, MEM_ALIGNMENT); -void -lit_id_hash_table_free (lit_id_hash_table *table) -{ - JERRY_ASSERT (table); - mem_heap_free_block ((uint8_t *) table->raw_buckets); - mem_heap_free_block ((uint8_t *) table->buckets); - mem_heap_free_block ((uint8_t *) table); -} + JERRY_ASSERT (header_size + raw_buckets_size + buckets_size <= buffer_size); -void -lit_id_hash_table_insert (lit_id_hash_table *table, idx_t uid, opcode_counter_t oc, lit_cpointer_t lit_cp) + lit_id_hash_table *table_p = (lit_id_hash_table *) table_buffer_p; + + table_p->current_bucket_pos = 0; + table_p->raw_buckets = (lit_cpointer_t*) (table_buffer_p + header_size); + table_p->buckets = (lit_cpointer_t **) (table_buffer_p + header_size + raw_buckets_size); + + memset (table_p->buckets, 0, buckets_size); + + return table_p; +} /* lit_id_hash_table_init */ + +/** + * Get size of buffer, necessary to hold hash table with specified parameters + * + * @return size of buffer + */ +size_t +lit_id_hash_table_get_size_for_table (size_t buckets_count, /**< number of pairs */ + size_t blocks_count) /**< number of opcode blocks */ { - JERRY_ASSERT (table); + const size_t header_size = JERRY_ALIGNUP (sizeof (lit_id_hash_table), MEM_ALIGNMENT); + const size_t raw_buckets_size = JERRY_ALIGNUP (sizeof (lit_cpointer_t) * buckets_count, MEM_ALIGNMENT); + const size_t buckets_size = JERRY_ALIGNUP (sizeof (lit_cpointer_t*) * blocks_count, MEM_ALIGNMENT); + + return header_size + raw_buckets_size + buckets_size; +} /* lit_id_hash_table_get_size_for_table */ + +/** + * Free literal identifiers hash table + */ +void +lit_id_hash_table_free (lit_id_hash_table *table_p) /**< table's header */ +{ + JERRY_ASSERT (table_p != NULL); + + mem_heap_free_block ((uint8_t *) table_p); +} /* lit_id_hash_table_free */ + +/** + * Register pair in the hash table + */ +void +lit_id_hash_table_insert (lit_id_hash_table *table_p, /**< table's header */ + idx_t uid, /**< value of byte-code instruction's argument */ + opcode_counter_t oc, /**< opcode counter of the instruction */ + lit_cpointer_t lit_cp) /**< literal identifier */ +{ + JERRY_ASSERT (table_p != NULL); + size_t block_id = oc / BLOCK_SIZE; - if (table->buckets[block_id] == NULL) + + if (table_p->buckets[block_id] == NULL) { - table->buckets[block_id] = table->raw_buckets + table->current_bucket_pos; + table_p->buckets[block_id] = table_p->raw_buckets + table_p->current_bucket_pos; } - table->buckets[block_id][uid] = lit_cp; - table->current_bucket_pos++; -} + table_p->buckets[block_id][uid] = lit_cp; + table_p->current_bucket_pos++; +} /* lit_id_hash_table_insert */ + +/** + * Lookup literal identifier by pair + * + * @return literal identifier + */ lit_cpointer_t -lit_id_hash_table_lookup (lit_id_hash_table *table, idx_t uid, opcode_counter_t oc) +lit_id_hash_table_lookup (lit_id_hash_table *table_p, /**< table's header */ + idx_t uid, /**< value of byte-code instruction's argument */ + opcode_counter_t oc) /**< opcode counter of the instruction */ { - JERRY_ASSERT (table); + JERRY_ASSERT (table_p != NULL); + size_t block_id = oc / BLOCK_SIZE; - JERRY_ASSERT (table->buckets[block_id]); - return table->buckets[block_id][uid]; -} + JERRY_ASSERT (table_p->buckets[block_id] != NULL); + + return table_p->buckets[block_id][uid]; +} /* lit_id_hash_table_lookup */ + +/** + * @} + * @} + * @} + */ diff --git a/jerry-core/parser/js/collections/lit-id-hash-table.h b/jerry-core/parser/js/collections/lit-id-hash-table.h index 94ef73469..6905652e5 100644 --- a/jerry-core/parser/js/collections/lit-id-hash-table.h +++ b/jerry-core/parser/js/collections/lit-id-hash-table.h @@ -28,7 +28,8 @@ typedef struct lit_cpointer_t **buckets; } lit_id_hash_table; -lit_id_hash_table *lit_id_hash_table_init (size_t, size_t); +lit_id_hash_table *lit_id_hash_table_init (uint8_t*, size_t, size_t, size_t); +size_t lit_id_hash_table_get_size_for_table (size_t, size_t); void lit_id_hash_table_free (lit_id_hash_table *); void lit_id_hash_table_insert (lit_id_hash_table *, idx_t, opcode_counter_t, lit_cpointer_t); lit_cpointer_t lit_id_hash_table_lookup (lit_id_hash_table *, idx_t, opcode_counter_t); diff --git a/jerry-core/parser/js/collections/stack.h b/jerry-core/parser/js/collections/stack.h index 7cd14f5e8..77b4dd9e3 100644 --- a/jerry-core/parser/js/collections/stack.h +++ b/jerry-core/parser/js/collections/stack.h @@ -117,24 +117,6 @@ static void NAME##_stack_push (TYPE value) { \ NAME.data = array_list_append (NAME.data, &value); \ } -#define DEFINE_CONVERT_TO_RAW_DATA(NAME, TYPE) \ -static TYPE *convert_##NAME##_to_raw_data (void) __attr_unused___; \ -static TYPE *convert_##NAME##_to_raw_data (void) { \ - if (array_list_len (NAME.data) == 0) \ - { \ - return NULL; \ - } \ - size_t size = mem_heap_recommend_allocation_size (array_list_len (NAME.data) * sizeof (NAME##_stack_value_type)); \ - TYPE *DATA = (TYPE *) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_LONG_TERM); \ - if (DATA == NULL) \ - { \ - printf ("Out of memory\n"); \ - JERRY_UNREACHABLE (); \ - } \ - memcpy (DATA, array_list_element (NAME.data, 0), array_list_len (NAME.data) * sizeof (NAME##_stack_value_type)); \ - return DATA; \ -} - #define STACK_PUSH(NAME, VALUE) \ do { NAME##_stack_push (VALUE); } while (0) @@ -207,7 +189,6 @@ NAME##_stack NAME; \ DEFINE_STACK_ELEMENT (NAME, TYPE) \ DEFINE_SET_STACK_ELEMENT (NAME, TYPE) \ DEFINE_STACK_HEAD (NAME, TYPE) \ -DEFINE_CONVERT_TO_RAW_DATA (NAME, TYPE) \ DEFINE_SET_STACK_HEAD (NAME, TYPE) \ DEFINE_STACK_PUSH (NAME, TYPE) @@ -217,7 +198,6 @@ static NAME##_stack NAME; \ DEFINE_STACK_ELEMENT (NAME, TYPE) \ DEFINE_SET_STACK_ELEMENT (NAME, TYPE) \ DEFINE_STACK_HEAD (NAME, TYPE) \ -DEFINE_CONVERT_TO_RAW_DATA (NAME, TYPE) \ DEFINE_SET_STACK_HEAD (NAME, TYPE) \ DEFINE_STACK_PUSH (NAME, TYPE) diff --git a/jerry-core/parser/js/scopes-tree.cpp b/jerry-core/parser/js/scopes-tree.cpp index 5700c2b0b..3bf84afa9 100644 --- a/jerry-core/parser/js/scopes-tree.cpp +++ b/jerry-core/parser/js/scopes-tree.cpp @@ -600,7 +600,10 @@ merge_subscopes (scopes_tree tree, opcode_t *data, lit_id_hash_table *lit_ids) Reorder function declarations. Rewrite opcodes' temporary uids with their keys in literal indexes 'hash' table. */ opcode_t * -scopes_tree_raw_data (scopes_tree tree, lit_id_hash_table *lit_ids) +scopes_tree_raw_data (scopes_tree tree, /**< scopes tree to convert to byte-code array */ + uint8_t *buffer_p, /**< buffer for byte-code array and literal identifiers hash table */ + size_t opcodes_array_size, /**< size of space for byte-code array */ + lit_id_hash_table *lit_ids) /**< literal identifiers hash table */ { JERRY_ASSERT (lit_ids); assert_tree (tree); @@ -613,10 +616,12 @@ scopes_tree_raw_data (scopes_tree tree, lit_id_hash_table *lit_ids) global_oc = 0; /* Dump bytecode and fill literal indexes 'hash' table. */ - // +1 for valgrind - size_t size = sizeof (opcodes_header_t) + (size_t) (scopes_tree_count_opcodes (tree) + 1) * sizeof (opcode_t); - opcodes_header_t *opcodes_data = (opcodes_header_t *) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_LONG_TERM); - memset (opcodes_data, 0, size); + JERRY_ASSERT (opcodes_array_size >= + sizeof (opcodes_header_t) + (size_t) (scopes_tree_count_opcodes (tree)) * sizeof (opcode_t)); + + opcodes_header_t *opcodes_data = (opcodes_header_t *) buffer_p; + memset (opcodes_data, 0, opcodes_array_size); + opcode_t *opcodes = (opcode_t *)(((uint8_t*) opcodes_data) + sizeof (opcodes_header_t)); merge_subscopes (tree, opcodes, lit_ids); if (lit_id_to_uid != null_hash) @@ -624,9 +629,11 @@ scopes_tree_raw_data (scopes_tree tree, lit_id_hash_table *lit_ids) hash_table_free (lit_id_to_uid); lit_id_to_uid = null_hash; } - opcodes_data->lit_id_hash = lit_ids; + + MEM_CP_SET_POINTER (opcodes_data->lit_id_hash_cp, lit_ids); + return opcodes; -} +} /* scopes_tree_raw_data */ void scopes_tree_set_strict_mode (scopes_tree tree, bool strict_mode) diff --git a/jerry-core/parser/js/scopes-tree.h b/jerry-core/parser/js/scopes-tree.h index a18e42b28..7b7956027 100644 --- a/jerry-core/parser/js/scopes-tree.h +++ b/jerry-core/parser/js/scopes-tree.h @@ -58,7 +58,7 @@ void scopes_tree_set_opcodes_num (scopes_tree, opcode_counter_t); op_meta scopes_tree_op_meta (scopes_tree, opcode_counter_t); size_t scopes_tree_count_literals_in_blocks (scopes_tree); opcode_counter_t scopes_tree_count_opcodes (scopes_tree); -opcode_t *scopes_tree_raw_data (scopes_tree, lit_id_hash_table *); +opcode_t *scopes_tree_raw_data (scopes_tree, uint8_t *, size_t, lit_id_hash_table *); void scopes_tree_set_strict_mode (scopes_tree, bool); bool scopes_tree_strict_mode (scopes_tree); diff --git a/jerry-core/parser/js/serializer.cpp b/jerry-core/parser/js/serializer.cpp index e65a111f0..03073a4ee 100644 --- a/jerry-core/parser/js/serializer.cpp +++ b/jerry-core/parser/js/serializer.cpp @@ -20,7 +20,6 @@ static bytecode_data_t bytecode_data; static scopes_tree current_scope; -static array_list bytecodes_cache; /**< storage of pointers to byetecodes */ static bool print_opcodes; static void @@ -83,18 +82,37 @@ const opcode_t * serializer_merge_scopes_into_bytecode (void) { bytecode_data.opcodes_count = scopes_tree_count_opcodes (current_scope); - lit_id_hash_table *lit_id_hash = lit_id_hash_table_init (scopes_tree_count_literals_in_blocks (current_scope), - (size_t) bytecode_data.opcodes_count / BLOCK_SIZE + 1); - bytecode_data.opcodes = scopes_tree_raw_data (current_scope, lit_id_hash); - bytecodes_cache = array_list_append (bytecodes_cache, &bytecode_data.opcodes); + + const size_t buckets_count = scopes_tree_count_literals_in_blocks (current_scope); + const size_t blocks_count = (size_t) bytecode_data.opcodes_count / BLOCK_SIZE + 1; + const size_t opcodes_count = scopes_tree_count_opcodes (current_scope); + + const size_t opcodes_array_size = JERRY_ALIGNUP (sizeof (opcodes_header_t) + opcodes_count * sizeof (opcode_t), + MEM_ALIGNMENT); + const size_t lit_id_hash_table_size = JERRY_ALIGNUP (lit_id_hash_table_get_size_for_table (buckets_count, + blocks_count), + MEM_ALIGNMENT); + + uint8_t *buffer_p = (uint8_t*) mem_heap_alloc_block (opcodes_array_size + lit_id_hash_table_size, + MEM_HEAP_ALLOC_LONG_TERM); + + lit_id_hash_table *lit_id_hash = lit_id_hash_table_init (buffer_p + opcodes_array_size, + lit_id_hash_table_size, + buckets_count, blocks_count); + + const opcode_t *opcodes_p = scopes_tree_raw_data (current_scope, buffer_p, opcodes_array_size, lit_id_hash); + + opcodes_header_t *header_p = (opcodes_header_t*) buffer_p; + MEM_CP_SET_POINTER (header_p->next_opcodes_cp, bytecode_data.opcodes); + bytecode_data.opcodes = opcodes_p; if (print_opcodes) { lit_dump_literals (); - serializer_print_opcodes (bytecode_data.opcodes, bytecode_data.opcodes_count); + serializer_print_opcodes (opcodes_p, bytecode_data.opcodes_count); } - return bytecode_data.opcodes; + return opcodes_p; } void @@ -176,8 +194,6 @@ serializer_init () bytecode_data.opcodes = NULL; lit_init (); - - bytecodes_cache = array_list_init (sizeof (opcode_t *)); } void serializer_set_show_opcodes (bool show_opcodes) @@ -195,10 +211,11 @@ serializer_free (void) lit_finalize (); - for (size_t i = 0; i < array_list_len (bytecodes_cache); ++i) + while (bytecode_data.opcodes != NULL) { - lit_id_hash_table_free (GET_BYTECODE_HEADER (*(opcode_t **) array_list_element (bytecodes_cache, i))->lit_id_hash); - mem_heap_free_block (GET_BYTECODE_HEADER (*(opcode_t **) array_list_element (bytecodes_cache, i))); + opcodes_header_t *header_p = GET_BYTECODE_HEADER (bytecode_data.opcodes); + bytecode_data.opcodes = MEM_CP_GET_POINTER (opcode_t, header_p->next_opcodes_cp); + + mem_heap_free_block (header_p); } - array_list_free (bytecodes_cache); }