diff --git a/jerry-core/ecma/operations/ecma-eval.cpp b/jerry-core/ecma/operations/ecma-eval.cpp index c6aa95185..630c64296 100644 --- a/jerry-core/ecma/operations/ecma-eval.cpp +++ b/jerry-core/ecma/operations/ecma-eval.cpp @@ -91,10 +91,12 @@ ecma_op_eval_chars_buffer (const jerry_api_char_t *code_p, /**< code characters bool is_strict_call = (is_direct && is_called_from_strict_mode_code); + bool code_contains_functions; parse_status = parser_parse_eval (code_p, code_buffer_size, is_strict_call, - &instrs_p); + &instrs_p, + &code_contains_functions); if (parse_status == JSP_STATUS_SYNTAX_ERROR) { @@ -158,7 +160,7 @@ ecma_op_eval_chars_buffer (const jerry_api_char_t *code_p, /**< code characters JERRY_ASSERT (ecma_is_completion_value_throw (completion)); } - if (!parser_is_code_contains_functions ()) + if (!code_contains_functions) { serializer_remove_instructions (instrs_p); } diff --git a/jerry-core/parser/js/parser.cpp b/jerry-core/parser/js/parser.cpp index 611e27f80..e71d54892 100644 --- a/jerry-core/parser/js/parser.cpp +++ b/jerry-core/parser/js/parser.cpp @@ -50,10 +50,6 @@ static token tok; static bool inside_eval = false; static bool inside_function = false; static bool parser_show_instrs = false; -/** - * flag, indicating that code contains function declarations or function expressions - */ -static bool code_contains_functions = false; enum { @@ -383,14 +379,14 @@ parse_property_assignment (void) return; } - code_contains_functions = true; - STACK_DECLARE_USAGE (scopes); const operand name = parse_property_name (); jsp_early_error_add_prop_name (name, is_setter ? PROP_SET : PROP_GET); - STACK_PUSH (scopes, scopes_tree_init (NULL)); + scopes_tree_set_contains_functions (STACK_TOP (scopes)); + + STACK_PUSH (scopes, scopes_tree_init (NULL, SCOPE_TYPE_FUNCTION)); serializer_set_scope (STACK_TOP (scopes)); scopes_tree_set_strict_mode (STACK_TOP (scopes), scopes_tree_strict_mode (STACK_HEAD (scopes, 2))); lexer_set_strict_mode (scopes_tree_strict_mode (STACK_TOP (scopes))); @@ -652,8 +648,6 @@ parse_function_declaration (void) { STACK_DECLARE_USAGE (scopes); - code_contains_functions = true; - assert_keyword (KW_FUNCTION); jsp_label_t *masked_label_set_p = jsp_label_mask_set (); @@ -664,7 +658,10 @@ parse_function_declaration (void) jsp_early_error_check_for_eval_and_arguments_in_strict_mode (name, is_strict_mode (), tok.loc); skip_newlines (); - STACK_PUSH (scopes, scopes_tree_init (STACK_TOP (scopes))); + + scopes_tree_set_contains_functions (STACK_TOP (scopes)); + + STACK_PUSH (scopes, scopes_tree_init (STACK_TOP (scopes), SCOPE_TYPE_FUNCTION)); serializer_set_scope (STACK_TOP (scopes)); scopes_tree_set_strict_mode (STACK_TOP (scopes), scopes_tree_strict_mode (STACK_HEAD (scopes, 2))); lexer_set_strict_mode (scopes_tree_strict_mode (STACK_TOP (scopes))); @@ -709,13 +706,13 @@ parse_function_expression (void) STACK_DECLARE_USAGE (scopes); assert_keyword (KW_FUNCTION); - code_contains_functions = true; - operand res; jsp_early_error_start_checking_of_vargs (); - STACK_PUSH (scopes, scopes_tree_init (NULL)); + scopes_tree_set_contains_functions (STACK_TOP (scopes)); + + STACK_PUSH (scopes, scopes_tree_init (NULL, SCOPE_TYPE_FUNCTION)); serializer_set_scope (STACK_TOP (scopes)); scopes_tree_set_strict_mode (STACK_TOP (scopes), scopes_tree_strict_mode (STACK_HEAD (scopes, 2))); lexer_set_strict_mode (scopes_tree_strict_mode (STACK_TOP (scopes))); @@ -1191,6 +1188,8 @@ parse_unary_expression (operand *this_arg_gl, operand *prop_gl) { if (is_keyword (KW_DELETE)) { + scopes_tree_set_contains_delete (STACK_TOP (scopes)); + skip_newlines (); expr = parse_unary_expression (NULL, NULL); expr = dump_delete_res (expr, is_strict_mode (), tok.loc); @@ -2361,6 +2360,8 @@ parse_with_statement (void) } const operand expr = parse_expression_inside_parens (); + scopes_tree_set_contains_with (STACK_TOP (scopes)); + bool is_raised = jsp_label_raise_nested_jumpable_border (); vm_instr_counter_t with_begin_oc = dump_with_for_rewrite (expr); @@ -2542,6 +2543,8 @@ parse_try_statement (void) { assert_keyword (KW_TRY); + scopes_tree_set_contains_try (STACK_TOP (scopes)); + bool is_raised = jsp_label_raise_nested_jumpable_border (); dump_try_for_rewrite (); @@ -3030,18 +3033,27 @@ parse_source_element_list (bool is_global) /**< flag, indicating that we parsing static jsp_status_t parser_parse_program (const jerry_api_char_t *source_p, /**< source code buffer */ size_t source_size, /**< source code size in bytes */ - bool in_function, /**< flag indicating if we are parsing body of a function */ + bool in_dyn_constructed_function, /**< flag indicating if we are parsing body of a function, + * constructed using 'new Function (...)'-like expression */ bool in_eval, /**< flag indicating if we are parsing body of eval code */ bool is_strict, /**< flag, indicating whether current code * inherited strict mode from code of an outer scope */ - const vm_instr_t **out_instrs_p) /**< out: generated byte-code array + const vm_instr_t **out_instrs_p, /**< out: generated byte-code array * (in case there were no syntax errors) */ + bool *out_contains_functions_p) /**< out: optional (can be NULL, if the output is not needed) + * flag, indicating whether the compiled byte-code + * contains a function declaration / expression */ { JERRY_ASSERT (out_instrs_p != NULL); - inside_function = in_function; + JERRY_ASSERT (!(in_dyn_constructed_function && in_eval)); + + inside_function = in_dyn_constructed_function; inside_eval = in_eval; - code_contains_functions = false; + + scope_type_t scope_type = (in_dyn_constructed_function ? SCOPE_TYPE_FUNCTION + : (in_eval ? SCOPE_TYPE_EVAL + : SCOPE_TYPE_GLOBAL)); #ifndef JERRY_NDEBUG volatile bool is_parse_finished = false; @@ -3057,7 +3069,7 @@ parser_parse_program (const jerry_api_char_t *source_p, /**< source code buffer jsp_early_error_init (); STACK_INIT (scopes); - STACK_PUSH (scopes, scopes_tree_init (NULL)); + STACK_PUSH (scopes, scopes_tree_init (NULL, scope_type)); serializer_set_scope (STACK_TOP (scopes)); scopes_tree_set_strict_mode (STACK_TOP (scopes), is_strict); @@ -3080,7 +3092,7 @@ parser_parse_program (const jerry_api_char_t *source_p, /**< source code buffer skip_newlines (); JERRY_ASSERT (token_is (TOK_EOF)); - if (in_function) + if (in_dyn_constructed_function) { dump_ret (); } @@ -3103,6 +3115,13 @@ parser_parse_program (const jerry_api_char_t *source_p, /**< source code buffer dumper_free (); + if (out_contains_functions_p != NULL) + { + scopes_tree scope = STACK_TOP (scopes); + + *out_contains_functions_p = scope->contains_functions; + } + serializer_set_scope (NULL); scopes_tree_free (STACK_TOP (scopes)); STACK_DROP (scopes, 1); @@ -3155,7 +3174,7 @@ parser_parse_script (const jerry_api_char_t *source, /**< source script */ const vm_instr_t **out_instrs_p) /**< out: generated byte-code array * (in case there were no syntax errors) */ { - return parser_parse_program (source, source_size, false, false, false, out_instrs_p); + return parser_parse_program (source, source_size, false, false, false, out_instrs_p, NULL); } /* parser_parse_script */ /** @@ -3169,10 +3188,14 @@ parser_parse_eval (const jerry_api_char_t *source, /**< string passed to eval() size_t source_size, /**< string size in bytes */ bool is_strict, /**< flag, indicating whether eval is called * from strict code in direct mode */ - const vm_instr_t **out_instrs_p) /**< out: generated byte-code array + const vm_instr_t **out_instrs_p, /**< out: generated byte-code array * (in case there were no syntax errors) */ + bool *out_contains_functions_p) /**< out: flag, indicating whether the compiled byte-code + * contains a function declaration / expression */ { - return parser_parse_program (source, source_size, false, true, is_strict, out_instrs_p); + JERRY_ASSERT (out_contains_functions_p != NULL); + + return parser_parse_program (source, source_size, false, true, is_strict, out_instrs_p, out_contains_functions_p); } /* parser_parse_eval */ /** @@ -3205,20 +3228,10 @@ parser_parse_new_function (const jerry_api_char_t **params, /**< array of argume true, false, false, - out_instrs_p); + out_instrs_p, + NULL); } /* parser_parse_new_function */ -/** - * Indicates whether code contains functions - * - * @return true/false - */ -bool -parser_is_code_contains_functions () -{ - return code_contains_functions; -} /* parser_is_code_contains_functions */ - /** * Tell parser whether to dump bytecode */ diff --git a/jerry-core/parser/js/parser.h b/jerry-core/parser/js/parser.h index 38c48e248..091571542 100644 --- a/jerry-core/parser/js/parser.h +++ b/jerry-core/parser/js/parser.h @@ -30,8 +30,7 @@ typedef enum void parser_set_show_instrs (bool); jsp_status_t parser_parse_script (const jerry_api_char_t *, size_t, const vm_instr_t **); -jsp_status_t parser_parse_eval (const jerry_api_char_t *, size_t, bool, const vm_instr_t **); +jsp_status_t parser_parse_eval (const jerry_api_char_t *, size_t, bool, const vm_instr_t **, bool *); jsp_status_t parser_parse_new_function (const jerry_api_char_t **, const size_t *, size_t, const vm_instr_t **); -bool parser_is_code_contains_functions (); #endif /* PARSER_H */ diff --git a/jerry-core/parser/js/scopes-tree.cpp b/jerry-core/parser/js/scopes-tree.cpp index dec36a100..8035ed2ac 100644 --- a/jerry-core/parser/js/scopes-tree.cpp +++ b/jerry-core/parser/js/scopes-tree.cpp @@ -743,6 +743,46 @@ scopes_tree_set_eval_used (scopes_tree tree) /**< scope */ tree->ref_eval = true; } /* scopes_tree_set_eval_used */ +/** + * Set up a flag, indicating that 'with' statement is contained in a scope + */ +void +scopes_tree_set_contains_with (scopes_tree tree) /**< scope */ +{ + assert_tree (tree); + tree->contains_with = true; +} /* scopes_tree_set_contains_with */ + +/** + * Set up a flag, indicating that 'try' statement is contained in a scope + */ +void +scopes_tree_set_contains_try (scopes_tree tree) /**< scope */ +{ + assert_tree (tree); + tree->contains_try = true; +} /* scopes_tree_set_contains_try */ + +/** + * Set up a flag, indicating that 'delete' operator is contained in a scope + */ +void +scopes_tree_set_contains_delete (scopes_tree tree) /**< scope */ +{ + assert_tree (tree); + tree->contains_delete = true; +} /* scopes_tree_set_contains_delete */ + +/** + * Set up a flag, indicating that there is a function declaration / expression inside a scope + */ +void +scopes_tree_set_contains_functions (scopes_tree tree) /**< scope */ +{ + assert_tree (tree); + tree->contains_functions = true; +} /* scopes_tree_set_contains_functions */ + bool scopes_tree_strict_mode (scopes_tree tree) { @@ -756,7 +796,8 @@ scopes_tree_strict_mode (scopes_tree tree) * @return initialized scope */ scopes_tree -scopes_tree_init (scopes_tree parent) /**< parent scope */ +scopes_tree_init (scopes_tree parent, /**< parent scope */ + scope_type_t type) /**< scope type */ { scopes_tree tree = (scopes_tree) jsp_mm_alloc (sizeof (scopes_tree_int)); memset (tree, 0, sizeof (scopes_tree_int)); @@ -775,9 +816,14 @@ scopes_tree_init (scopes_tree parent) /**< parent scope */ parent->t.children_num++; } tree->instrs_count = 0; + tree->type = type; tree->strict_mode = false; - tree->ref_eval = false; tree->ref_arguments = false; + tree->ref_eval = false; + tree->contains_with = false; + tree->contains_try = false; + tree->contains_delete = false; + tree->contains_functions = false; tree->instrs = linked_list_init (sizeof (op_meta)); tree->var_decls_cout = 0; tree->var_decls = linked_list_init (sizeof (op_meta)); diff --git a/jerry-core/parser/js/scopes-tree.h b/jerry-core/parser/js/scopes-tree.h index 301ce871a..21842e35c 100644 --- a/jerry-core/parser/js/scopes-tree.h +++ b/jerry-core/parser/js/scopes-tree.h @@ -39,6 +39,16 @@ typedef struct tree_header uint8_t children_num; } tree_header; +/** + * Scope type + */ +typedef enum +{ + SCOPE_TYPE_GLOBAL, /**< the Global code scope */ + SCOPE_TYPE_FUNCTION, /**< a function code scope */ + SCOPE_TYPE_EVAL /**< an eval code scope */ +} scope_type_t; + /** * Structure for holding scope information during parsing */ @@ -49,14 +59,24 @@ typedef struct vm_instr_counter_t instrs_count; /**< count of instructions */ linked_list var_decls; /**< instructions for variable declarations */ uint8_t var_decls_cout; /**< number of instructions for variable declarations */ + scope_type_t type : 2; /**< scope type */ bool strict_mode: 1; /**< flag, indicating that scope's code should be executed in strict mode */ - bool ref_arguments: 1; /**< flag, indicating that "arguments" variable is used inside the scope */ - bool ref_eval: 1; /**< flag, indicating that "eval" is used inside the scope */ + bool ref_arguments: 1; /**< flag, indicating that "arguments" variable is used inside the scope + * (not depends on subscopes) */ + bool ref_eval: 1; /**< flag, indicating that "eval" is used inside the scope + * (not depends on subscopes) */ + bool contains_with: 1; /**< flag, indicationg whether 'with' statement is contained in the scope + * (not depends on subscopes) */ + bool contains_try: 1; /**< flag, indicationg whether 'try' statement is contained in the scope + * (not depends on subscopes) */ + bool contains_delete: 1; /**< flag, indicationg whether 'delete' operator is contained in the scope + * (not depends on subscopes) */ + bool contains_functions: 1; /**< flag, indicating that the scope contains a function declaration / expression */ } scopes_tree_int; typedef scopes_tree_int * scopes_tree; -scopes_tree scopes_tree_init (scopes_tree); +scopes_tree scopes_tree_init (scopes_tree, scope_type_t); void scopes_tree_free (scopes_tree); vm_instr_counter_t scopes_tree_instrs_num (scopes_tree); vm_instr_counter_t scopes_tree_var_decls_num (scopes_tree); @@ -72,6 +92,10 @@ vm_instr_t *scopes_tree_raw_data (scopes_tree, uint8_t *, size_t, lit_id_hash_ta void scopes_tree_set_strict_mode (scopes_tree, bool); void scopes_tree_set_arguments_used (scopes_tree); void scopes_tree_set_eval_used (scopes_tree); +void scopes_tree_set_contains_with (scopes_tree); +void scopes_tree_set_contains_try (scopes_tree); +void scopes_tree_set_contains_delete (scopes_tree); +void scopes_tree_set_contains_functions (scopes_tree); bool scopes_tree_strict_mode (scopes_tree); #endif /* SCOPES_TREE_H */