mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Fix hoisting of function declaration from function expressions.
JerryScript-DCO-1.0-Signed-off-by: Andrey Shitov a.shitov@samsung.com
This commit is contained in:
parent
531a9d3352
commit
0d855e898d
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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!*
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
36
tests/jerry/function-scopes.js
Normal file
36
tests/jerry/function-scopes.js
Normal file
@ -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);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user