Introduce parser scope types, add scope flags, indicating whether scope contains a function declaration, a 'try' statement, 'with' statement or 'delete' operator.

JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com
This commit is contained in:
Ruben Ayrapetyan 2015-08-21 14:09:24 +03:00
parent c3d8cfd73c
commit 91aecc3bd0
5 changed files with 127 additions and 43 deletions

View File

@ -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);
}

View File

@ -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
*/

View File

@ -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 */

View File

@ -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));

View File

@ -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 */