diff --git a/jerry-core/ecma/operations/ecma-eval.cpp b/jerry-core/ecma/operations/ecma-eval.cpp index 84846e9bc..06c41f11a 100644 --- a/jerry-core/ecma/operations/ecma-eval.cpp +++ b/jerry-core/ecma/operations/ecma-eval.cpp @@ -20,6 +20,8 @@ #include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-lex-env.h" +#include "parser.h" +#include "serializer.h" #include "vm.h" /** \addtogroup ecma ECMA @@ -54,15 +56,15 @@ ecma_op_eval (ecma_string_t *code_p, /**< code string */ buf_size); JERRY_ASSERT (buffer_size_req == buf_size); - // FIXME: Get parser feedback about syntax correctness - bool is_syntax_correct = true; - bool is_strict_prologue; - - // FIXME: Call parser - JERRY_UNIMPLEMENTED ("eval operation is not implemented"); + parser_init (); + bool is_syntax_correct = parser_parse_eval ((const char *) code_p, (size_t) buf_size); + const opcode_t* opcodes_p = (const opcode_t*) serializer_get_bytecode (); + serializer_print_opcodes (); + parser_free (); // FIXME: - is_strict_prologue = false; + bool is_strict_prologue = false; + (void) is_strict_prologue; if (!is_syntax_correct) { @@ -95,6 +97,7 @@ ecma_op_eval (ecma_string_t *code_p, /**< code string */ } // FIXME: Call interpreter + (void) opcodes_p; completion = ecma_make_return_completion_value (ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED)); JERRY_UNIMPLEMENTED ("eval operation is not implemented"); diff --git a/jerry-core/jerry.cpp b/jerry-core/jerry.cpp index f152ef736..4b47e1c9f 100644 --- a/jerry-core/jerry.cpp +++ b/jerry-core/jerry.cpp @@ -1215,8 +1215,9 @@ jerry_parse (const char* source_p, /**< script source */ bool is_show_opcodes = ((jerry_flags & JERRY_FLAG_SHOW_OPCODES) != 0); - parser_init (source_p, source_size, is_show_opcodes); - parser_parse_program (); + parser_set_show_opcodes (is_show_opcodes); + parser_init (); + parser_parse_script (source_p, source_size); const opcode_t* opcodes = (const opcode_t*) serializer_get_bytecode (); diff --git a/jerry-core/parser/js/bytecode-data.h b/jerry-core/parser/js/bytecode-data.h index 7e2f88179..207be7ee9 100644 --- a/jerry-core/parser/js/bytecode-data.h +++ b/jerry-core/parser/js/bytecode-data.h @@ -34,12 +34,30 @@ */ #define BLOCK_SIZE 64 +/** + * Pointer to lit_id_hash_table precedes every independent bytecode region + */ +typedef struct __attribute__ ((aligned (MEM_ALIGNMENT))) +{ + lit_id_hash_table *lit_id_hash; +} opcodes_header_t; + typedef struct { const ecma_char_t *strings_buffer; const opcode_t *opcodes; - lit_id_hash_table *lit_id_hash; 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))) + #endif // BYTECODE_DATA_H diff --git a/jerry-core/parser/js/lexer.cpp b/jerry-core/parser/js/lexer.cpp index e5b110b53..2cafb0ae0 100644 --- a/jerry-core/parser/js/lexer.cpp +++ b/jerry-core/parser/js/lexer.cpp @@ -1466,26 +1466,37 @@ lexer_are_tokens_with_same_identifier (token id1, /**< identifier token (TOK_NAM return (id1.uid == id2.uid); } /* lexer_are_tokens_with_same_identifier */ +/** + * Initialize lexer to start parsing of a new source + */ void -lexer_init (const char *source, size_t source_size, bool show_opcodes) +lexer_init_source (const char *source, /**< script source */ + size_t source_size) /**< script source size in bytes */ +{ + saved_token = prev_token = sent_token = empty_token; + + buffer_size = source_size; + lexer_set_source (source); + lexer_set_strict_mode (false); +} /* lexer_init_source */ + +/** + * Intitialize lexer + */ +void +lexer_init (bool show_opcodes) /**< flag indicating if to dump opcodes */ { empty_token.type = TOK_EMPTY; empty_token.uid = 0; empty_token.loc = 0; - saved_token = prev_token = sent_token = empty_token; - #ifndef JERRY_NDEBUG allow_dump_lines = show_opcodes; #else /* JERRY_NDEBUG */ (void) show_opcodes; allow_dump_lines = false; #endif /* JERRY_NDEBUG */ - - buffer_size = source_size; - lexer_set_source (source); - lexer_set_strict_mode (false); -} +} /* lexer_init */ void lexer_free (void) diff --git a/jerry-core/parser/js/lexer.h b/jerry-core/parser/js/lexer.h index 4f1caba8b..914ad9639 100644 --- a/jerry-core/parser/js/lexer.h +++ b/jerry-core/parser/js/lexer.h @@ -19,6 +19,7 @@ #include "lit-literal.h" #define INVALID_VALUE 255 +#define EVAL_RET_VALUE 128 #define INVALID_LITERAL (rcs_cpointer_t::null_cp ()) /* Keywords. */ @@ -168,7 +169,8 @@ typedef struct */ #define TOKEN_EMPTY_INITIALIZER {0, TOK_EMPTY, 0} -void lexer_init (const char *, size_t, bool); +void lexer_init (bool); +void lexer_init_source (const char *, size_t); void lexer_free (void); token lexer_next_token (void); diff --git a/jerry-core/parser/js/opcodes-dumper.cpp b/jerry-core/parser/js/opcodes-dumper.cpp index 5abb95d82..4be1edada 100644 --- a/jerry-core/parser/js/opcodes-dumper.cpp +++ b/jerry-core/parser/js/opcodes-dumper.cpp @@ -695,6 +695,22 @@ literal_operand (lit_cpointer_t lit_cp) return ret; } +/** + * Creates operand for eval's return value + * + * @return constructed operand + */ +operand +eval_ret_operand (void) +{ + operand ret; + + ret.type = OPERAND_TMP; + ret.data.uid = EVAL_RET_VALUE; + + return ret; +} /* eval_ret_operand */ + bool operand_is_empty (operand op) { diff --git a/jerry-core/parser/js/opcodes-dumper.h b/jerry-core/parser/js/opcodes-dumper.h index bb483c90b..f31dfc05f 100644 --- a/jerry-core/parser/js/opcodes-dumper.h +++ b/jerry-core/parser/js/opcodes-dumper.h @@ -48,6 +48,7 @@ typedef enum __attr_packed___ operand empty_operand (void); operand literal_operand (lit_cpointer_t); +operand eval_ret_operand (void); bool operand_is_empty (operand); void dumper_init (void); diff --git a/jerry-core/parser/js/parser.cpp b/jerry-core/parser/js/parser.cpp index 2e40fc6f6..962315836 100644 --- a/jerry-core/parser/js/parser.cpp +++ b/jerry-core/parser/js/parser.cpp @@ -30,7 +30,27 @@ #include "opcodes-dumper.h" #include "serializer.h" +/** + * Flag, indicating whether result of expression + * evaluation should be stored to 'eval result' + * temporary variable. + * + * In other words, the flag indicates whether + * 'eval result' store code should be dumped. + * + * See also: + * parse_expression + */ +typedef enum +{ + JSP_EVAL_RET_STORE_NOT_DUMP, /**< do not dump */ + JSP_EVAL_RET_STORE_DUMP, /**< dump */ +} jsp_eval_ret_store_t; + static token tok; +static bool inside_eval = false; +static bool inside_function = false; +static bool parser_show_opcodes = false; enum { @@ -44,7 +64,7 @@ STATIC_STACK (scopes, scopes_tree) #define OPCODE_IS(OP, ID) (OP.op_idx == __op__idx_##ID) -static operand parse_expression (bool); +static operand parse_expression (bool, jsp_eval_ret_store_t); static void parse_statement (jsp_label_t *outermost_stmt_label_p); static operand parse_assignment_expression (bool); static void parse_source_element_list (bool); @@ -259,6 +279,9 @@ parse_property_assignment (void) token_after_newlines_must_be (TOK_OPEN_BRACE); skip_newlines (); + bool was_in_function = inside_function; + inside_function = true; + jsp_label_t *masked_label_set_p = jsp_label_mask_set (); parse_source_element_list (false); @@ -271,6 +294,9 @@ parse_property_assignment (void) dump_ret (); rewrite_function_end (VARG_FUNC_EXPR); + + inside_function = was_in_function; + if (is_setter) { dump_prop_setter_decl (name, func); @@ -474,9 +500,11 @@ parse_function_declaration (void) dump_function_end_for_rewrite (); token_after_newlines_must_be (TOK_OPEN_BRACE); - skip_newlines (); + bool was_in_function = inside_function; + inside_function = true; + parse_source_element_list (false); next_token_must_be (TOK_CLOSE_BRACE); @@ -484,6 +512,8 @@ parse_function_declaration (void) dump_ret (); rewrite_function_end (VARG_FUNC_DECL); + inside_function = was_in_function; + STACK_DROP (scopes, 1); serializer_set_scope (STACK_TOP (scopes)); lexer_set_strict_mode (scopes_tree_strict_mode (STACK_TOP (scopes))); @@ -522,6 +552,9 @@ parse_function_expression (void) token_after_newlines_must_be (TOK_OPEN_BRACE); skip_newlines (); + bool was_in_function = inside_function; + inside_function = true; + jsp_label_t *masked_label_set_p = jsp_label_mask_set (); parse_source_element_list (false); @@ -534,6 +567,8 @@ parse_function_expression (void) dump_ret (); rewrite_function_end (VARG_FUNC_EXPR); + inside_function = was_in_function; + return res; } @@ -611,7 +646,7 @@ parse_primary_expression (void) skip_newlines (); if (!token_is (TOK_CLOSE_PAREN)) { - operand res = parse_expression (true); + operand res = parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP); token_after_newlines_must_be (TOK_CLOSE_PAREN); return res; } @@ -683,7 +718,7 @@ parse_member_expression (operand *this_arg, operand *prop_gl) if (token_is (TOK_OPEN_SQUARE)) { skip_newlines (); - prop = parse_expression (true); + prop = parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP); next_token_must_be (TOK_CLOSE_SQUARE); } else if (token_is (TOK_DOT)) @@ -774,7 +809,7 @@ parse_call_expression (operand *this_arg_gl, operand *prop_gl) if (tok.type == TOK_OPEN_SQUARE) { skip_newlines (); - prop = parse_expression (true); + prop = parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP); next_token_must_be (TOK_CLOSE_SQUARE); } else if (tok.type == TOK_DOT) @@ -1532,12 +1567,19 @@ parse_assignment_expression (bool in_allowed) return expr; } -/* expression - : assignment_expression (LT!* ',' LT!* assignment_expression)* - ; +/** + * Parse an expression + * + * expression + * : assignment_expression (LT!* ',' LT!* assignment_expression)* + * ; + * + * @return operand which holds result of expression */ static operand -parse_expression (bool in_allowed) +parse_expression (bool in_allowed, /**< flag indicating if 'in' is allowed inside expression to parse */ + jsp_eval_ret_store_t dump_eval_ret_store) /**< flag indicating if 'eval' + * result code store should be dumped */ { operand expr = parse_assignment_expression (in_allowed); @@ -1555,8 +1597,16 @@ parse_expression (bool in_allowed) break; } } + + if (inside_eval + && dump_eval_ret_store == JSP_EVAL_RET_STORE_DUMP + && !inside_function) + { + dump_variable_assignment (eval_ret_operand () , expr); + } + return expr; -} +} /* parse_expression */ /* variable_declaration : Identifier LT!* initialiser? @@ -1646,7 +1696,7 @@ parse_plain_for (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) lab skip_token (); if (!token_is (TOK_CLOSE_PAREN)) { - parse_expression (true); + parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP); } rewrite_jump_to_end (); @@ -1659,7 +1709,7 @@ parse_plain_for (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) lab } else { - const operand cond = parse_expression (true); + const operand cond = parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP); dump_continue_iterations_check (cond); } @@ -1749,7 +1799,7 @@ parse_for_or_for_in_statement (jsp_label_t *outermost_stmt_label_p) /**< outermo } /* expression contains left_hand_side_expression. */ - parse_expression (false); + parse_expression (false, JSP_EVAL_RET_STORE_NOT_DUMP); skip_newlines (); if (token_is (TOK_SEMICOLON)) @@ -1773,7 +1823,7 @@ parse_expression_inside_parens (void) { token_after_newlines_must_be (TOK_OPEN_PAREN); skip_newlines (); - const operand res = parse_expression (true); + const operand res = parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP); token_after_newlines_must_be (TOK_CLOSE_PAREN); return res; } @@ -1963,7 +2013,7 @@ parse_switch_statement (void) if (is_keyword (KW_CASE)) { skip_newlines (); - const operand case_expr = parse_expression (true); + const operand case_expr = parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP); next_token_must_be (TOK_COLON); dump_case_clause_check_for_rewrite (switch_expr, case_expr); skip_newlines (); @@ -2358,7 +2408,7 @@ parse_statement (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) lab skip_token (); if (!token_is (TOK_SEMICOLON) && !token_is (TOK_NEWLINE)) { - const operand op = parse_expression (true); + const operand op = parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP); dump_retval (op); insert_semicolon (); return; @@ -2382,7 +2432,7 @@ parse_statement (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) lab if (is_keyword (KW_THROW)) { skip_token (); - const operand op = parse_expression (true); + const operand op = parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP); insert_semicolon (); dump_throw (op); return; @@ -2418,7 +2468,7 @@ parse_statement (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) lab { lexer_save_token (tok); tok = temp; - parse_expression (true); + parse_expression (true, JSP_EVAL_RET_STORE_DUMP); skip_newlines (); if (!token_is (TOK_SEMICOLON)) { @@ -2429,7 +2479,7 @@ parse_statement (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) lab } else { - parse_expression (true); + parse_expression (true, JSP_EVAL_RET_STORE_DUMP); skip_newlines (); if (!token_is (TOK_SEMICOLON)) { @@ -2748,15 +2798,25 @@ preparse_scope (bool is_global) } } -/* source_element_list - : source_element (LT!* source_element)* - ; */ +/** + * Parse source element list + * + * source_element_list + * : source_element (LT!* source_element)* + * ; + */ static void -parse_source_element_list (bool is_global) +parse_source_element_list (bool is_global) /**< flag indicating if we are parsing the global scope */ { dumper_new_scope (); preparse_scope (is_global); + if (inside_eval + && !inside_function) + { + dump_undefined_assignment (eval_ret_operand ()); + } + skip_newlines (); while (!token_is (TOK_EOF) && !token_is (TOK_CLOSE_BRACE)) { @@ -2766,14 +2826,22 @@ parse_source_element_list (bool is_global) lexer_save_token (tok); rewrite_reg_var_decl (); dumper_finish_scope (); -} +} /* parse_source_element_list */ -/* program - : LT!* source_element_list LT!* EOF! - ; */ -void -parser_parse_program (void) +/** + * Parse program + * + * program + * : LT!* source_element_list LT!* EOF! + * ; + */ +static void +parser_parse_program (const char *source, /**< source code buffer */ + size_t source_size, /**< source code size in bytes */ + bool in_new_function) /**< flag indicating if we are parsing body of a function */ { + lexer_init_source (source, source_size); + STACK_PUSH (scopes, scopes_tree_init (NULL)); serializer_set_scope (STACK_TOP (scopes)); lexer_set_strict_mode (scopes_tree_strict_mode (STACK_TOP (scopes))); @@ -2783,7 +2851,19 @@ parser_parse_program (void) skip_newlines (); JERRY_ASSERT (token_is (TOK_EOF)); - dump_exit (); + + if (in_new_function) + { + dump_ret (); + } + else if (inside_eval) + { + dump_retval (eval_ret_operand ()); + } + else + { + dump_exit (); + } serializer_dump_literals (); serializer_merge_scopes_into_bytecode (); @@ -2791,13 +2871,66 @@ parser_parse_program (void) scopes_tree_free (STACK_TOP (scopes)); STACK_DROP (scopes, 1); -} +} /* parser_parse_program */ + +/** + * Parse source script + */ +void +parser_parse_script (const char *source, /**< source script */ + size_t source_size) /**< source script size it bytes */ +{ + inside_eval = false; + inside_function = false; + parser_parse_program (source, source_size, false); +} /* parser_parse_script */ + +/** + * Parse string passed to eval() call + * + * @return true if parse succeeds + * false otherwise + */ +bool parser_parse_eval (const char *source, /**< string passed to eval() */ + size_t source_size) /**< string size in bytes */ +{ + TODO (implement syntax error processing); + + inside_eval = true; + inside_function = false; + parser_parse_program (source, source_size, false); + return true; +} /* parser_parse_eval */ + +/** + * Parse a function created via new Function call + * + * NOTE: Array of arguments should contain at least one element. + * In case of new Function() call without parameters, empty string should be passed as argument to this + * function. + */ +void +parser_parse_new_function (const char **params, /**< array of arguments of new Function (p1, p2, ..., pn, body) call */ + size_t params_count) /**< total number of arguments passed to new Function (...) */ +{ + inside_eval = false; + inside_function = true; + + // Process arguments + JERRY_ASSERT (params_count > 0); + for (size_t i = 0; i < params_count - 1; ++i) + { + FIXME ("check parameter's name for syntax errors"); + lit_find_or_create_literal_from_charset ((ecma_char_t *) params[i], (ecma_length_t) strlen (params[i])); + } + parser_parse_program (params[params_count - 1], strlen (params[params_count - 1]), true); +} /* parser_parse_new_function */ void -parser_init (const char *source, size_t source_size, bool show_opcodes) +parser_init () { - lexer_init (source, source_size, show_opcodes); - serializer_set_show_opcodes (show_opcodes); + lexer_init (parser_show_opcodes); + serializer_set_show_opcodes (parser_show_opcodes); dumper_init (); syntax_init (); @@ -2806,6 +2939,15 @@ parser_init (const char *source, size_t source_size, bool show_opcodes) jsp_label_init (); } +/** + * Tell parser to dump bytecode + */ +void +parser_set_show_opcodes (bool show_opcodes) /**< flag indicating if to dump bytecode */ +{ + parser_show_opcodes = show_opcodes; +} /* parser_set_show_opcodes */ + void parser_free (void) { diff --git a/jerry-core/parser/js/parser.h b/jerry-core/parser/js/parser.h index c0cb0ec7b..4792d9660 100644 --- a/jerry-core/parser/js/parser.h +++ b/jerry-core/parser/js/parser.h @@ -18,8 +18,11 @@ #include "jrt.h" -void parser_init (const char *, size_t, bool); -void parser_parse_program (void); +void parser_init (); +void parser_set_show_opcodes (bool); +void parser_parse_script (const char *, size_t); +bool parser_parse_eval (const char *, size_t); +void parser_parse_new_function (const char **, size_t); void parser_free (void); #endif diff --git a/jerry-core/parser/js/scopes-tree.cpp b/jerry-core/parser/js/scopes-tree.cpp index ba0cfbee2..91b6b53d8 100644 --- a/jerry-core/parser/js/scopes-tree.cpp +++ b/jerry-core/parser/js/scopes-tree.cpp @@ -613,15 +613,18 @@ scopes_tree_raw_data (scopes_tree tree, lit_id_hash_table *lit_ids) global_oc = 0; /* Dump bytecode and fill literal indexes 'hash' table. */ - size_t size = ((size_t) (scopes_tree_count_opcodes (tree) + 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); + // +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); + 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) { hash_table_free (lit_id_to_uid); lit_id_to_uid = null_hash; } + opcodes_data->lit_id_hash = lit_ids; return opcodes; } diff --git a/jerry-core/parser/js/serializer.cpp b/jerry-core/parser/js/serializer.cpp index 06bb85359..21b4bda1e 100644 --- a/jerry-core/parser/js/serializer.cpp +++ b/jerry-core/parser/js/serializer.cpp @@ -16,10 +16,11 @@ #include "serializer.h" #include "bytecode-data.h" #include "pretty-printer.h" +#include "array-list.h" 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; op_meta @@ -40,15 +41,27 @@ serializer_get_opcode (opcode_counter_t oc) return bytecode_data.opcodes[oc]; } +/** + * Convert literal id (operand value of instruction) to compressed pointer to literal + * + * Bytecode is divided into blocks of fixed size and each block has independent encoding of variable names, + * which are represented by 8 bit numbers - ids. + * This function performs conversion from id to literal. + * + * @return compressed pointer to literal + */ lit_cpointer_t -serializer_get_literal_cp_by_uid (uint8_t id, opcode_counter_t oc) +serializer_get_literal_cp_by_uid (uint8_t id, /**< literal idx */ + const opcode_t *opcodes_p, /**< pointer to bytecode */ + opcode_counter_t oc) /**< position in the bytecode */ { - if (bytecode_data.lit_id_hash == null_hash) + lit_id_hash_table *lit_id_hash = GET_HASH_TABLE_FOR_BYTECODE (opcodes_p == NULL ? bytecode_data.opcodes : opcodes_p); + if (lit_id_hash == null_hash) { return INVALID_LITERAL; } - return lit_id_hash_table_lookup (bytecode_data.lit_id_hash, id, oc); -} + return lit_id_hash_table_lookup (lit_id_hash, id, oc); +} /* serializer_get_literal_cp_by_uid */ const void * serializer_get_bytecode (void) @@ -72,11 +85,11 @@ serializer_set_scope (scopes_tree new_scope) void serializer_merge_scopes_into_bytecode (void) { - JERRY_ASSERT (bytecode_data.lit_id_hash == null_hash); bytecode_data.opcodes_count = scopes_tree_count_opcodes (current_scope); - bytecode_data.lit_id_hash = lit_id_hash_table_init (scopes_tree_count_literals_in_blocks (current_scope), - bytecode_data.opcodes_count); - bytecode_data.opcodes = scopes_tree_raw_data (current_scope, bytecode_data.lit_id_hash); + 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); } void @@ -172,9 +185,10 @@ serializer_init () bytecode_data.strings_buffer = NULL; bytecode_data.opcodes = NULL; - bytecode_data.lit_id_hash = null_hash; lit_init (); + + bytecodes_cache = array_list_init (sizeof (opcode_t *)); } void serializer_set_show_opcodes (bool show_opcodes) @@ -189,12 +203,13 @@ serializer_free (void) { mem_heap_free_block ((uint8_t *) bytecode_data.strings_buffer); } - if (bytecode_data.lit_id_hash != null_hash) - { - lit_id_hash_table_free (bytecode_data.lit_id_hash); - } - - mem_heap_free_block ((uint8_t *) bytecode_data.opcodes); lit_finalize (); + + for (size_t i = 0; i < array_list_len (bytecodes_cache); ++i) + { + 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))); + } + array_list_free (bytecodes_cache); } diff --git a/jerry-core/parser/js/serializer.h b/jerry-core/parser/js/serializer.h index d12774a7f..b62766eca 100644 --- a/jerry-core/parser/js/serializer.h +++ b/jerry-core/parser/js/serializer.h @@ -26,7 +26,7 @@ void serializer_init (); void serializer_set_show_opcodes (bool show_opcodes); op_meta serializer_get_op_meta (opcode_counter_t); opcode_t serializer_get_opcode (opcode_counter_t); -lit_cpointer_t serializer_get_literal_cp_by_uid (uint8_t, opcode_counter_t); +lit_cpointer_t serializer_get_literal_cp_by_uid (uint8_t, const opcode_t*, opcode_counter_t); const void *serializer_get_bytecode (void); void serializer_set_strings_buffer (const ecma_char_t *); void serializer_dump_literals (); diff --git a/jerry-core/vm/opcodes-ecma-try-catch-finally.cpp b/jerry-core/vm/opcodes-ecma-try-catch-finally.cpp index 1d8d008fa..9087d5d5c 100644 --- a/jerry-core/vm/opcodes-ecma-try-catch-finally.cpp +++ b/jerry-core/vm/opcodes-ecma-try-catch-finally.cpp @@ -63,9 +63,9 @@ opfunc_try_block (opcode_t opdata, /**< operation data */ JERRY_ASSERT (next_opcode.op_idx == __op__idx_meta); JERRY_ASSERT (next_opcode.data.meta.type == OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER); - lit_cpointer_t catch_exc_val_var_name_lit_cp = serializer_get_literal_cp_by_uid ( - next_opcode.data.meta.data_1, - int_data->pos); + lit_cpointer_t catch_exc_val_var_name_lit_cp = serializer_get_literal_cp_by_uid (next_opcode.data.meta.data_1, + int_data->opcodes_p, + int_data->pos); int_data->pos++; ecma_string_t *catch_exc_var_name_str_p = ecma_new_ecma_string_from_lit_cp (catch_exc_val_var_name_lit_cp); diff --git a/jerry-core/vm/opcodes-helpers-variables.cpp b/jerry-core/vm/opcodes-helpers-variables.cpp index 91462de16..e6d754866 100644 --- a/jerry-core/vm/opcodes-helpers-variables.cpp +++ b/jerry-core/vm/opcodes-helpers-variables.cpp @@ -91,7 +91,7 @@ get_variable_value (int_data_t *int_data, /**< interpreter context */ else { ecma_string_t var_name_string; - lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (var_idx, int_data->pos); + lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (var_idx, int_data->opcodes_p, int_data->pos); JERRY_ASSERT (lit_cp.packed_value != MEM_CP_NULL); ecma_new_ecma_string_on_stack_from_lit_cp (&var_name_string, lit_cp); @@ -158,7 +158,7 @@ set_variable_value (int_data_t *int_data, /**< interpreter context */ else { ecma_string_t var_name_string; - lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (var_idx, lit_oc); + lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (var_idx, int_data->opcodes_p, lit_oc); JERRY_ASSERT (lit_cp.packed_value != MEM_CP_NULL); ecma_new_ecma_string_on_stack_from_lit_cp (&var_name_string, lit_cp); diff --git a/jerry-core/vm/opcodes-varg.cpp b/jerry-core/vm/opcodes-varg.cpp index 00447ae3a..e395ce5bc 100644 --- a/jerry-core/vm/opcodes-varg.cpp +++ b/jerry-core/vm/opcodes-varg.cpp @@ -97,6 +97,7 @@ fill_params_list (int_data_t *int_data, /**< interpreter context */ JERRY_ASSERT (next_opcode.data.meta.type == OPCODE_META_TYPE_VARG); const lit_cpointer_t param_name_lit_idx = serializer_get_literal_cp_by_uid (next_opcode.data.meta.data_1, + int_data->opcodes_p, int_data->pos); params_names[param_index] = ecma_new_ecma_string_from_lit_cp (param_name_lit_idx); diff --git a/jerry-core/vm/opcodes.cpp b/jerry-core/vm/opcodes.cpp index 150cb6cec..4c2712342 100644 --- a/jerry-core/vm/opcodes.cpp +++ b/jerry-core/vm/opcodes.cpp @@ -96,7 +96,7 @@ opfunc_assignment (opcode_t opdata, /**< operation data */ } else if (type_value_right == OPCODE_ARG_TYPE_STRING) { - lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (src_val_descr, int_data->pos); + lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (src_val_descr, int_data->opcodes_p, int_data->pos); ecma_string_t *string_p = ecma_new_ecma_string_from_lit_cp (lit_cp); ret_value = set_variable_value (int_data, @@ -125,7 +125,7 @@ opfunc_assignment (opcode_t opdata, /**< operation data */ { ecma_number_t *num_p = int_data->tmp_num_p; - lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (src_val_descr, int_data->pos); + lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (src_val_descr, int_data->opcodes_p, int_data->pos); literal_t lit = lit_get_literal_by_cp (lit_cp); JERRY_ASSERT (lit->get_type () == LIT_NUMBER_T); @@ -140,7 +140,7 @@ opfunc_assignment (opcode_t opdata, /**< operation data */ { ecma_number_t *num_p = int_data->tmp_num_p; - lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (src_val_descr, int_data->pos); + lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (src_val_descr, int_data->opcodes_p, int_data->pos); literal_t lit = lit_get_literal_by_cp (lit_cp); JERRY_ASSERT (lit->get_type () == LIT_NUMBER_T); @@ -395,7 +395,9 @@ ecma_completion_value_t opfunc_var_decl (opcode_t opdata, /**< operation data */ int_data_t *int_data) /**< interpreter context */ { - lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (opdata.data.var_decl.variable_name, int_data->pos); + lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (opdata.data.var_decl.variable_name, + int_data->opcodes_p, + int_data->pos); JERRY_ASSERT (lit_cp.packed_value != MEM_CP_NULL); ecma_string_t *var_name_string_p = ecma_new_ecma_string_from_lit_cp (lit_cp); @@ -491,7 +493,9 @@ opfunc_func_decl_n (opcode_t opdata, /**< operation data */ const idx_t function_name_idx = opdata.data.func_decl_n.name_lit_idx; const ecma_length_t params_number = opdata.data.func_decl_n.arg_list; - lit_cpointer_t function_name_lit_cp = serializer_get_literal_cp_by_uid (function_name_idx, int_data->pos); + lit_cpointer_t function_name_lit_cp = serializer_get_literal_cp_by_uid (function_name_idx, + int_data->opcodes_p, + int_data->pos); int_data->pos++; @@ -573,7 +577,9 @@ opfunc_func_expr_n (opcode_t opdata, /**< operation data */ { scope_p = ecma_create_decl_lex_env (int_data->lex_env_p); - lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (function_name_lit_idx, lit_oc); + lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (function_name_lit_idx, + int_data->opcodes_p, + lit_oc); JERRY_ASSERT (lit_cp.packed_value != MEM_CP_NULL); function_name_string_p = ecma_new_ecma_string_from_lit_cp (lit_cp); @@ -1407,7 +1413,7 @@ evaluate_arg_for_typeof (int_data_t *int_data, /**< interpreter context */ } else { - lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (var_idx, int_data->pos); + lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (var_idx, int_data->opcodes_p, int_data->pos); JERRY_ASSERT (lit_cp.packed_value != MEM_CP_NULL); ecma_string_t *var_name_string_p = ecma_new_ecma_string_from_lit_cp (lit_cp); @@ -1523,7 +1529,7 @@ opfunc_delete_var (opcode_t opdata, /**< operation data */ ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); - lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (name_lit_idx, lit_oc); + lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (name_lit_idx, int_data->opcodes_p, lit_oc); JERRY_ASSERT (lit_cp.packed_value != MEM_CP_NULL); ecma_string_t *name_string_p = ecma_new_ecma_string_from_lit_cp (lit_cp); diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index a936d60ee..237f83405 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -87,11 +87,17 @@ typedef enum : idx_t * 'eval' identifier */ } opcode_scope_code_flags_t; +/** + * Forward declaration of opcode structure + */ +struct opcode_t; + /** * Interpreter context */ typedef struct { + const opcode_t *opcodes_p; /**< pointer to array containing currently executed bytecode */ opcode_counter_t pos; /**< current opcode to execute */ ecma_value_t this_binding; /**< this binding for current context */ ecma_object_t *lex_env_p; /**< current lexical environment */ @@ -257,7 +263,7 @@ opcode_counter_t read_meta_opcode_counter (opcode_meta_type expected_type, int_d OP_ARGS_LIST (OP_DATA) #define __OP_STRUCT_FIELD(name, arg1, arg2, arg3) __op_##name name; -typedef struct +typedef struct opcode_t { idx_t op_idx; union diff --git a/jerry-core/vm/pretty-printer.cpp b/jerry-core/vm/pretty-printer.cpp index c8a1320b5..00b1723c6 100644 --- a/jerry-core/vm/pretty-printer.cpp +++ b/jerry-core/vm/pretty-printer.cpp @@ -104,7 +104,7 @@ var_to_str (opcode_t opcode, lit_cpointer_t lit_ids[], opcode_counter_t oc, uint } else { - return lit_cp_to_str (serializer_get_literal_cp_by_uid (raw.uids[current_arg], oc)); + return lit_cp_to_str (serializer_get_literal_cp_by_uid (raw.uids[current_arg], NULL, oc)); } } diff --git a/jerry-core/vm/vm.cpp b/jerry-core/vm/vm.cpp index 203c709da..cabea6ef8 100644 --- a/jerry-core/vm/vm.cpp +++ b/jerry-core/vm/vm.cpp @@ -534,6 +534,7 @@ vm_run_from_pos (opcode_counter_t start_pos, /**< identifier of starting opcode MEM_DEFINE_LOCAL_ARRAY (regs, regs_num, ecma_value_t); int_data_t int_data; + int_data.opcodes_p = __program; int_data.pos = (opcode_counter_t) (start_pos + 1); int_data.this_binding = this_binding_value; int_data.lex_env_p = lex_env_p; diff --git a/tests/unit/test-parser.cpp b/tests/unit/test-parser.cpp index 48f9963f4..2721e68b6 100644 --- a/tests/unit/test-parser.cpp +++ b/tests/unit/test-parser.cpp @@ -74,8 +74,9 @@ main (int __attr_unused___ argc, mem_init (); serializer_init (); - parser_init (program, strlen (program), true); - parser_parse_program (); + parser_set_show_opcodes (true); + parser_init (); + parser_parse_script (program, strlen (program)); parser_free (); opcode_t opcodes[] =