diff --git a/jerry-core/parser/js/opcodes-dumper.cpp b/jerry-core/parser/js/opcodes-dumper.cpp index 98bd16164..674af1b5a 100644 --- a/jerry-core/parser/js/opcodes-dumper.cpp +++ b/jerry-core/parser/js/opcodes-dumper.cpp @@ -1269,19 +1269,14 @@ dump_function_end_for_rewrite (void) } void -rewrite_function_end (varg_list_type vlt) +rewrite_function_end () { vm_instr_counter_t oc; - if (vlt == VARG_FUNC_DECL) { oc = (vm_instr_counter_t) (get_diff_from (STACK_TOP (function_ends)) + serializer_count_instrs_in_subscopes ()); } - else - { - JERRY_ASSERT (vlt == VARG_FUNC_EXPR); - oc = (vm_instr_counter_t) (get_diff_from (STACK_TOP (function_ends))); - } + idx_t id1, id2; split_instr_counter (oc, &id1, &id2); const vm_instr_t instr = getop_meta (OPCODE_META_TYPE_FUNCTION_END, id1, id2); diff --git a/jerry-core/parser/js/opcodes-dumper.h b/jerry-core/parser/js/opcodes-dumper.h index 38d977190..3bb4391e9 100644 --- a/jerry-core/parser/js/opcodes-dumper.h +++ b/jerry-core/parser/js/opcodes-dumper.h @@ -93,7 +93,7 @@ operand dump_prop_getter_res (operand, operand); void dump_prop_setter (operand, operand, operand); void dump_function_end_for_rewrite (void); -void rewrite_function_end (varg_list_type); +void rewrite_function_end (); void dump_this (operand); operand dump_this_res (void); diff --git a/jerry-core/parser/js/parser.cpp b/jerry-core/parser/js/parser.cpp index 384c7fc20..fd953431c 100644 --- a/jerry-core/parser/js/parser.cpp +++ b/jerry-core/parser/js/parser.cpp @@ -379,11 +379,16 @@ parse_property_assignment (void) return; } - bool is_outer_scope_strict = is_strict_mode (); + 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)); + 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))); + skip_newlines (); const operand func = parse_argument_list (VARG_FUNC_EXPR, empty_operand (), NULL); @@ -404,13 +409,21 @@ parse_property_assignment (void) token_after_newlines_must_be (TOK_CLOSE_BRACE); dump_ret (); - rewrite_function_end (VARG_FUNC_EXPR); + rewrite_function_end (); inside_function = was_in_function; - scopes_tree_set_strict_mode (STACK_TOP (scopes), is_outer_scope_strict); + scopes_tree fe_scope_tree = STACK_TOP (scopes); + + STACK_DROP (scopes, 1); + serializer_set_scope (STACK_TOP (scopes)); lexer_set_strict_mode (scopes_tree_strict_mode (STACK_TOP (scopes))); + serializer_dump_subscope (fe_scope_tree); + scopes_tree_free (fe_scope_tree); + + STACK_CHECK_USAGE (scopes); + if (is_setter) { dump_prop_setter_decl (name, func); @@ -664,7 +677,7 @@ parse_function_declaration (void) next_token_must_be (TOK_CLOSE_BRACE); dump_ret (); - rewrite_function_end (VARG_FUNC_DECL); + rewrite_function_end (); inside_function = was_in_function; @@ -685,19 +698,23 @@ parse_function_declaration (void) static operand parse_function_expression (void) { + STACK_DECLARE_USAGE (scopes); assert_keyword (KW_FUNCTION); operand res; - bool is_outer_scope_strict = is_strict_mode (); - jsp_early_error_start_checking_of_vargs (); + STACK_PUSH (scopes, scopes_tree_init (NULL)); + 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))); + skip_newlines (); if (token_is (TOK_NAME)) { const operand name = literal_operand (token_data_as_lit_cp ()); - jsp_early_error_check_for_eval_and_arguments_in_strict_mode (name, is_outer_scope_strict, tok.loc); + jsp_early_error_check_for_eval_and_arguments_in_strict_mode (name, is_strict_mode (), tok.loc); skip_newlines (); res = parse_argument_list (VARG_FUNC_EXPR, name, NULL); @@ -727,17 +744,21 @@ parse_function_expression (void) next_token_must_be (TOK_CLOSE_BRACE); dump_ret (); - rewrite_function_end (VARG_FUNC_EXPR); + rewrite_function_end (); inside_function = was_in_function; jsp_early_error_check_for_syntax_errors_in_formal_param_list (is_strict_mode (), tok.loc); - scopes_tree_set_strict_mode (STACK_TOP (scopes), is_outer_scope_strict); + serializer_set_scope (STACK_HEAD (scopes, 2)); + serializer_dump_subscope (STACK_TOP (scopes)); + scopes_tree_free (STACK_TOP (scopes)); + STACK_DROP (scopes, 1); lexer_set_strict_mode (scopes_tree_strict_mode (STACK_TOP (scopes))); + STACK_CHECK_USAGE (scopes); return res; -} +} /* parse_function_expression */ /* array_literal : '[' LT!* assignment_expression? (LT!* ',' (LT!* assignment_expression)?)* LT!* ']' LT!* diff --git a/jerry-core/parser/js/serializer.cpp b/jerry-core/parser/js/serializer.cpp index 19482ea88..8125c7324 100644 --- a/jerry-core/parser/js/serializer.cpp +++ b/jerry-core/parser/js/serializer.cpp @@ -89,6 +89,44 @@ serializer_set_scope (scopes_tree new_scope) current_scope = new_scope; } +/** + * Dump scope to current scope + * + * NOTE: + * This function is used for processing of function expressions as they should not be hoisted. + * After parsing a function expression, it is immediately dumped to current scope via call of this function. + */ +void +serializer_dump_subscope (scopes_tree tree) /**< scope to dump */ +{ + JERRY_ASSERT (tree != NULL); + vm_instr_counter_t instr_pos; + bool header = true; + for (instr_pos = 0; instr_pos < tree->instrs_num; instr_pos++) + { + op_meta *om = (op_meta *) linked_list_element (tree->instrs, instr_pos); + if (om->op.op_idx != VM_OP_VAR_DECL + && om->op.op_idx != VM_OP_META && !header) + { + break; + } + if (om->op.op_idx == VM_OP_REG_VAR_DECL) + { + header = false; + } + scopes_tree_add_op_meta (current_scope, *om); + } + for (uint8_t child_id = 0; child_id < tree->t.children_num; child_id++) + { + serializer_dump_subscope (*(scopes_tree *) linked_list_element (tree->t.children, child_id)); + } + for (; instr_pos < tree->instrs_num; instr_pos++) + { + op_meta *om = (op_meta *) linked_list_element (tree->instrs, instr_pos); + scopes_tree_add_op_meta (current_scope, *om); + } +} /* serializer_dump_subscope */ + const vm_instr_t * serializer_merge_scopes_into_bytecode (void) { diff --git a/jerry-core/parser/js/serializer.h b/jerry-core/parser/js/serializer.h index fed71d025..4f8b2a706 100644 --- a/jerry-core/parser/js/serializer.h +++ b/jerry-core/parser/js/serializer.h @@ -29,6 +29,7 @@ vm_instr_t serializer_get_instr (const vm_instr_t*, vm_instr_counter_t); lit_cpointer_t serializer_get_literal_cp_by_uid (uint8_t, const vm_instr_t*, vm_instr_counter_t); void serializer_set_strings_buffer (const ecma_char_t *); void serializer_set_scope (scopes_tree); +void serializer_dump_subscope (scopes_tree); const vm_instr_t *serializer_merge_scopes_into_bytecode (void); void serializer_dump_op_meta (op_meta); vm_instr_counter_t serializer_get_current_instr_counter (void); diff --git a/tests/jerry/function-scopes.js b/tests/jerry/function-scopes.js new file mode 100644 index 000000000..27f8f92d1 --- /dev/null +++ b/tests/jerry/function-scopes.js @@ -0,0 +1,36 @@ +// Copyright 2015 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. + +try { + (function() { + function decl() {} + })(); + decl(); + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); +} + +try { + var o = { + get p() { + function decl() { + } + } + }; + decl(); + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); +}