diff --git a/src/libintstructs/linked-list.c b/src/libintstructs/linked-list.c index c83cc7bd9..a05e8dbf3 100644 --- a/src/libintstructs/linked-list.c +++ b/src/libintstructs/linked-list.c @@ -22,6 +22,7 @@ #define ASSERT_LIST(list) \ do { \ linked_list_header *header = (linked_list_header *) list; \ + JERRY_ASSERT (header); \ JERRY_ASSERT (header->magic == LINKED_LIST_MAGIC); \ } while (0); diff --git a/src/libintstructs/linked-list.h b/src/libintstructs/linked-list.h index 13c3bfcfb..8714120a1 100644 --- a/src/libintstructs/linked-list.h +++ b/src/libintstructs/linked-list.h @@ -32,6 +32,7 @@ __packed linked_list_header; typedef uint8_t* linked_list; +#define null_list NULL linked_list linked_list_init (size_t); void linked_list_free (linked_list); diff --git a/src/libintstructs/stack.h b/src/libintstructs/stack.h index 22f12e0a0..a88edb66e 100644 --- a/src/libintstructs/stack.h +++ b/src/libintstructs/stack.h @@ -40,7 +40,7 @@ STACK(temp_names, uint8_t, uint8_t) #define GLOBAL(NAME, VAR) \ - NAME.data[VAR] + STACK_ELEMENT (NAME, VAR) #define MAX_TEMP_NAME() \ GLOBAL(temp_names, max_temp_name) @@ -54,7 +54,7 @@ void parser_init (void) { - STACK_INIT(uint8_t, temp_names) + STACK_INIT(temp_names) } void @@ -81,11 +81,11 @@ typedef struct \ __packed \ NAME##_stack; -#define STACK_INIT(TYPE, NAME) \ +#define STACK_INIT(NAME) \ do { \ - NAME.blocks = linked_list_init (sizeof (TYPE)); \ + NAME.blocks = linked_list_init (sizeof (NAME##_stack_value_type)); \ NAME.current = NAME##_global_size; \ - NAME.length = NAME.block_len = ((linked_list_header *) NAME.blocks)->block_size / sizeof (TYPE); \ + NAME.length = NAME.block_len = ((linked_list_header *) NAME.blocks)->block_size / sizeof (NAME##_stack_value_type); \ } while (0) #define STACK_FREE(NAME) \ diff --git a/src/libintstructs/tree.h b/src/libintstructs/tree.h index 7995d70ca..4646b5467 100644 --- a/src/libintstructs/tree.h +++ b/src/libintstructs/tree.h @@ -23,6 +23,7 @@ typedef struct tree_header { uint8_t magic; + uint8_t children_num; struct tree_header *parent; linked_list children; } diff --git a/src/libjsparser/lexer.c b/src/libjsparser/lexer.c index ad70a22ff..af44be341 100644 --- a/src/libjsparser/lexer.c +++ b/src/libjsparser/lexer.c @@ -1300,9 +1300,9 @@ lexer_init (const char *source, size_t source_size, bool show_opcodes) buffer_size = source_size; lexer_set_source (source); - STACK_INIT (lp_string, strings); - STACK_INIT (ecma_number_t, numbers); - STACK_INIT (idx_t, num_ids); + STACK_INIT (strings); + STACK_INIT (numbers); + STACK_INIT (num_ids); } void diff --git a/src/libjsparser/parser.c b/src/libjsparser/parser.c index 890fe366b..d49960cc1 100644 --- a/src/libjsparser/parser.c +++ b/src/libjsparser/parser.c @@ -25,6 +25,7 @@ #include "deserializer.h" #include "opcodes-native-call.h" #include "parse-error.h" +#include "scopes-tree.h" #define INVALID_VALUE 255 #define INTRINSICS_COUNT 1 @@ -76,6 +77,14 @@ enum }; STATIC_STACK (nestings, uint8_t, uint8_t) +typedef scopes_tree* scopes_tree_p; + +enum +{ + scopes_global_size +}; +STATIC_STACK (scopes, uint8_t, scopes_tree_p) + enum { temp_name, @@ -3592,6 +3601,10 @@ void parser_parse_program (void) { STACK_DECLARE_USAGE (IDX) + STACK_DECLARE_USAGE (scopes); + + STACK_PUSH (scopes, scopes_tree_init (NULL)); + serializer_set_scope (STACK_TOP (scopes)); skip_newlines (); parse_source_element_list (true); @@ -3601,8 +3614,14 @@ parser_parse_program (void) DUMP_OPCODE_1 (exitval, 0); serializer_adjust_strings (); + serializer_merge_scopes_into_bytecode (); + + scopes_tree_free (STACK_TOP (scopes)); + serializer_set_scope (NULL); + STACK_DROP (scopes, 1); STACK_CHECK_USAGE (IDX); + STACK_CHECK_USAGE (scopes); } void @@ -3620,16 +3639,17 @@ parser_init (const char *source, size_t source_size, bool show_opcodes) serializer_dump_strings_and_nums (identifiers, lexer_get_strings_count (), lexer_get_nums (), lexer_get_nums_count ()); - STACK_INIT (uint8_t, U8); - STACK_INIT (uint8_t, IDX); - STACK_INIT (uint8_t, nestings); - STACK_INIT (uint8_t, temp_names); - STACK_INIT (token, toks); - STACK_INIT (opcode_t, ops); - STACK_INIT (uint16_t, U16); - STACK_INIT (opcode_counter_t, rewritable_continue); - STACK_INIT (opcode_counter_t, rewritable_break); - STACK_INIT (locus, locs); + STACK_INIT (U8); + STACK_INIT (IDX); + STACK_INIT (nestings); + STACK_INIT (temp_names); + STACK_INIT (toks); + STACK_INIT (ops); + STACK_INIT (U16); + STACK_INIT (rewritable_continue); + STACK_INIT (rewritable_break); + STACK_INIT (locs); + STACK_INIT (scopes); HASH_INIT (intrinsics, 1); @@ -3689,6 +3709,7 @@ parser_free (void) STACK_FREE (rewritable_continue); STACK_FREE (rewritable_break); STACK_FREE (locs); + STACK_FREE (scopes); HASH_FREE (intrinsics); diff --git a/src/libjsparser/scopes-tree.c b/src/libjsparser/scopes-tree.c new file mode 100644 index 000000000..84a2b59bb --- /dev/null +++ b/src/libjsparser/scopes-tree.c @@ -0,0 +1,190 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#include "scopes-tree.h" +#include "mem-heap.h" +#include "jerry-libc.h" + +#define NAME_TO_ID(op) (__op__idx_##op) + +static void +assert_tree (scopes_tree *t) +{ + JERRY_ASSERT (t != NULL); + JERRY_ASSERT (t->t.magic == TREE_MAGIC); +} + +opcode_counter_t +scopes_tree_opcodes_num (scopes_tree *t) +{ + assert_tree (t); + return t->opcodes_num; +} + +void +scopes_tree_add_opcode (scopes_tree *tree, opcode_t op) +{ + assert_tree (tree); + linked_list_set_element (tree->opcodes, sizeof (opcode_t), tree->opcodes_num++, &op); +} + +void +scopes_tree_set_opcode (scopes_tree *tree, opcode_counter_t oc, opcode_t op) +{ + assert_tree (tree); + JERRY_ASSERT (oc < tree->opcodes_num); + linked_list_set_element (tree->opcodes, sizeof (opcode_t), oc, &op); +} + +void +scopes_tree_set_opcodes_num (scopes_tree *tree, opcode_counter_t oc) +{ + assert_tree (tree); + JERRY_ASSERT (oc < tree->opcodes_num); + tree->opcodes_num = oc; +} + +opcode_t +scopes_tree_opcode (scopes_tree *tree, opcode_counter_t oc) +{ + assert_tree (tree); + JERRY_ASSERT (oc < tree->opcodes_num); + return *(opcode_t *) linked_list_element (tree->opcodes, sizeof (opcode_t), oc); +} + +static opcode_counter_t +count_opcodes_in_tree (scopes_tree *t) +{ + assert_tree (t); + opcode_counter_t res = t->opcodes_num; + for (uint8_t i = 0; i < t->t.children_num; i++) + { + res = (opcode_counter_t) (res + + count_opcodes_in_tree ((scopes_tree *) linked_list_element (t->t.children, + sizeof (scopes_tree *), + i))); + } + return res; +} + +static opcode_counter_t +merge_subscopes (scopes_tree *tree, opcode_t *data) +{ + assert_tree (tree); + JERRY_ASSERT (data); + bool header = true; + opcode_counter_t opc_index, data_index; + for (opc_index = 0, data_index = 0; opc_index < tree->opcodes_num; opc_index++, data_index++) + { + opcode_t *op = (opcode_t *) linked_list_element (tree->opcodes, sizeof (opcode_t), opc_index); + JERRY_ASSERT (op); + switch (opc_index) + { + case 0: + { + JERRY_ASSERT (op->op_idx == NAME_TO_ID (reg_var_decl)); + data[data_index] = *op; + break; + } + case 1: + { + JERRY_ASSERT (op->op_idx == NAME_TO_ID (nop) || op->op_idx == NAME_TO_ID (meta)); + data[data_index] = *op; + break; + } + default: + { + if (op->op_idx == NAME_TO_ID (var_decl)) + { + data[data_index] = *op; + } + else + { + header = false; + } + } + } + if (!header) + { + break; + } + } + for (uint8_t child_id = 0; child_id < tree->t.children_num; child_id++) + { + data_index = (opcode_counter_t) (data_index + + merge_subscopes ((scopes_tree *) linked_list_element (tree->t.children, + sizeof (scopes_tree *), + child_id), + data + data_index)); + } + for (; opc_index < tree->opcodes_num; opc_index++, data_index++) + { + opcode_t *op = (opcode_t *) linked_list_element (tree->opcodes, sizeof (opcode_t), opc_index); + data[data_index] = *op; + } + return data_index; +} + +opcode_t * +scopes_tree_raw_data (scopes_tree *tree, opcode_counter_t *num) +{ + assert_tree (tree); + opcode_counter_t res = count_opcodes_in_tree (tree); + size_t size = ((size_t) (res + 1) * sizeof (opcode_t)); // +1 for valgrind + opcode_t *opcodes = (opcode_t *) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_LONG_TERM); + __memset (opcodes, 0, size); + opcode_counter_t merged = merge_subscopes (tree, opcodes); + JERRY_ASSERT (merged == res); + *num = res; + return opcodes; +} + +scopes_tree * +scopes_tree_init (scopes_tree *parent) +{ + scopes_tree *tree = (scopes_tree *) mem_heap_alloc_block (sizeof (scopes_tree), MEM_HEAP_ALLOC_SHORT_TERM); + __memset (tree, 0, sizeof (scopes_tree)); + tree->t.magic = TREE_MAGIC; + tree->t.parent = (tree_header *) parent; + tree->t.children = null_list; + tree->t.children_num = 0; + if (parent != NULL) + { + if (parent->t.children_num == 0) + { + parent->t.children = linked_list_init (sizeof (scopes_tree *)); + } + linked_list_set_element (parent->t.children, sizeof (scopes_tree *), parent->t.children_num++, tree); + } + tree->opcodes_num = 0; + tree->opcodes = linked_list_init (sizeof (opcode_t)); + return tree; +} + +void +scopes_tree_free (scopes_tree *tree) +{ + assert_tree (tree); + for (uint8_t i = 0; i < tree->t.children_num; ++i) + { + scopes_tree_free ((scopes_tree *) linked_list_element (tree->t.children, sizeof (scopes_tree *), i)); + } + if (tree->t.children_num != 0) + { + linked_list_free (tree->t.children); + } + linked_list_free (tree->opcodes); + mem_heap_free_block ((uint8_t *) tree); +} diff --git a/src/libjsparser/scopes-tree.h b/src/libjsparser/scopes-tree.h new file mode 100644 index 000000000..7b282a6b3 --- /dev/null +++ b/src/libjsparser/scopes-tree.h @@ -0,0 +1,41 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef SCOPES_TREE_H +#define SCOPES_TREE_H + +#include "tree.h" +#include "linked-list.h" +#include "opcodes.h" + +typedef struct scopes_tree +{ + tree_header t; + opcode_counter_t opcodes_num; + linked_list opcodes; +} +__packed +scopes_tree; + +scopes_tree *scopes_tree_init (scopes_tree *); +void scopes_tree_free (scopes_tree *); +opcode_counter_t scopes_tree_opcodes_num (scopes_tree *); +void scopes_tree_add_opcode (scopes_tree *, opcode_t); +void scopes_tree_set_opcode (scopes_tree *, opcode_counter_t, opcode_t); +void scopes_tree_set_opcodes_num (scopes_tree *, opcode_counter_t); +opcode_t scopes_tree_opcode (scopes_tree *, opcode_counter_t); +opcode_t *scopes_tree_raw_data (scopes_tree *, opcode_counter_t *); + +#endif /* SCOPES_TREE_H */ diff --git a/src/liboptimizer/bytecode-data.h b/src/liboptimizer/bytecode-data.h index c87cfb3d0..cccc1085c 100644 --- a/src/liboptimizer/bytecode-data.h +++ b/src/liboptimizer/bytecode-data.h @@ -20,6 +20,7 @@ #include "stack.h" #include "jerry-libc.h" #include "lp-string.h" +#include "scopes-tree.h" /* bytecode_data contains identifiers, string and num literals. Memory map if the following. @@ -36,17 +37,15 @@ struct { uint8_t strs_count; uint8_t nums_count; + opcode_counter_t opcodes_count; const lp_string *strings; const ecma_number_t *nums; + const opcode_t *opcodes; } __packed bytecode_data; -enum -{ - bytecode_opcodes_global_size -}; -STACK (bytecode_opcodes, opcode_counter_t, opcode_t) +scopes_tree *current_scope; #endif // BYTECODE_DATA_H diff --git a/src/liboptimizer/deserializer.c b/src/liboptimizer/deserializer.c index 1bb19fa16..a5dda7104 100644 --- a/src/liboptimizer/deserializer.c +++ b/src/liboptimizer/deserializer.c @@ -16,8 +16,6 @@ #include "deserializer.h" #include "bytecode-data.h" -static opcode_t *raw_bytecode; - const ecma_char_t * deserialize_string_by_id (uint8_t id) { @@ -42,18 +40,14 @@ deserialize_num_by_id (uint8_t id) const void * deserialize_bytecode (void) { - JERRY_ASSERT (STACK_SIZE (bytecode_opcodes) > 0); - JERRY_ASSERT (raw_bytecode == NULL); - STACK_CONVERT_TO_RAW_DATA (bytecode_opcodes, raw_bytecode); - return raw_bytecode; + JERRY_ASSERT (bytecode_data.opcodes != NULL); + return bytecode_data.opcodes; } opcode_t deserialize_opcode (opcode_counter_t oc) { - JERRY_ASSERT (STACK_SIZE (bytecode_opcodes) > 0); - JERRY_ASSERT (oc < STACK_SIZE (bytecode_opcodes)); - return STACK_ELEMENT (bytecode_opcodes, oc); + return scopes_tree_opcode (current_scope, oc); } uint8_t @@ -65,18 +59,12 @@ deserialize_min_temp (void) void deserializer_init (void) { - raw_bytecode = NULL; - STACK_INIT (opcode_t, bytecode_opcodes); } void deserializer_free (void) { - STACK_FREE (bytecode_opcodes); - if (raw_bytecode) - { - mem_heap_free_block ((uint8_t *) raw_bytecode); - } mem_heap_free_block ((uint8_t *) bytecode_data.strings); mem_heap_free_block ((uint8_t *) bytecode_data.nums); + mem_heap_free_block ((uint8_t *) bytecode_data.opcodes); } diff --git a/src/liboptimizer/serializer.c b/src/liboptimizer/serializer.c index 99e9bac5a..da22c8551 100644 --- a/src/liboptimizer/serializer.c +++ b/src/liboptimizer/serializer.c @@ -22,6 +22,19 @@ static bool print_opcodes; +void +serializer_set_scope (scopes_tree *new_scope) +{ + current_scope = new_scope; +} + +void +serializer_merge_scopes_into_bytecode (void) +{ + bytecode_data.opcodes = scopes_tree_raw_data (current_scope, &bytecode_data.opcodes_count); +} + + void serializer_dump_strings_and_nums (const lp_string strings[], uint8_t strs_count, const ecma_number_t nums[], uint8_t nums_count) @@ -40,28 +53,26 @@ serializer_dump_strings_and_nums (const lp_string strings[], uint8_t strs_count, void serializer_dump_opcode (opcode_t opcode) { - JERRY_ASSERT (STACK_SIZE (bytecode_opcodes) < MAX_OPCODES); + JERRY_ASSERT (scopes_tree_opcodes_num (current_scope) < MAX_OPCODES); if (print_opcodes) { - pp_opcode (STACK_SIZE (bytecode_opcodes), opcode, false); + pp_opcode (scopes_tree_opcodes_num (current_scope), opcode, false); } - STACK_PUSH (bytecode_opcodes, opcode); + scopes_tree_add_opcode (current_scope, opcode); } void serializer_set_writing_position (opcode_counter_t oc) { - JERRY_ASSERT (oc < STACK_SIZE (bytecode_opcodes)); - STACK_DROP (bytecode_opcodes, STACK_SIZE (bytecode_opcodes) - oc); + scopes_tree_set_opcodes_num (current_scope, oc); } void serializer_rewrite_opcode (const opcode_counter_t loc, opcode_t opcode) { - JERRY_ASSERT (loc < STACK_SIZE (bytecode_opcodes)); - STACK_SET_ELEMENT (bytecode_opcodes, loc, opcode); + scopes_tree_set_opcode (current_scope, loc, opcode); if (print_opcodes) { @@ -81,9 +92,9 @@ serializer_print_opcodes (void) __printf ("AFTER OPTIMIZER:\n"); - for (loc = 0; loc < STACK_SIZE (bytecode_opcodes); loc++) + for (loc = 0; loc < bytecode_data.opcodes_count; loc++) { - pp_opcode (loc, STACK_ELEMENT (bytecode_opcodes, loc), false); + pp_opcode (loc, bytecode_data.opcodes[loc], false); } } @@ -102,6 +113,7 @@ serializer_adjust_strings (void) void serializer_init (bool show_opcodes) { + current_scope = NULL; print_opcodes = show_opcodes; } diff --git a/src/liboptimizer/serializer.h b/src/liboptimizer/serializer.h index 9fdf6b30f..c31814e7e 100644 --- a/src/liboptimizer/serializer.h +++ b/src/liboptimizer/serializer.h @@ -20,10 +20,13 @@ #include "opcodes.h" #include "interpreter.h" #include "lp-string.h" +#include "scopes-tree.h" void serializer_init (bool show_opcodes); void serializer_dump_strings_and_nums (const lp_string *, uint8_t, const ecma_number_t *, uint8_t); +void serializer_set_scope (scopes_tree *); +void serializer_merge_scopes_into_bytecode (void); void serializer_dump_opcode (opcode_t); void serializer_set_writing_position (opcode_counter_t); void serializer_rewrite_opcode (const opcode_counter_t, opcode_t);