From e2807c28fa9f4320d59e1ed1cb1842a8337dd7ba Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Fri, 24 Apr 2020 16:55:12 +0200 Subject: [PATCH] Implement separate context for arguments. (#3686) Fixes #3396. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/parser/js/js-parser-expr.c | 5 + jerry-core/parser/js/js-parser-internal.h | 43 +++-- jerry-core/parser/js/js-parser-statm.c | 17 +- jerry-core/parser/js/js-parser.c | 67 ++++++- jerry-core/parser/js/js-scanner-internal.h | 14 +- jerry-core/parser/js/js-scanner-util.c | 181 +++++++++--------- jerry-core/parser/js/js-scanner.h | 6 +- tests/jerry/es2015/function-param-init3.js | 68 +++++++ .../es2015/regression-test-issue-3396.js | 19 ++ 9 files changed, 292 insertions(+), 128 deletions(-) create mode 100644 tests/jerry/es2015/function-param-init3.js create mode 100644 tests/jerry/es2015/regression-test-issue-3396.js diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 2bf911538..ee6e6298d 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -2008,6 +2008,11 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */ context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED; #if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_FUNCTION_IS_PARSING_ARGS) + { + context_p->status_flags |= PARSER_LEXICAL_BLOCK_NEEDED; + } + if (context_p->status_flags & (PARSER_ALLOW_SUPER_CALL | PARSER_ALLOW_SUPER | PARSER_ALLOW_NEW_TARGET)) { parser_emit_cbc_ext_call (context_p, diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index 1475cbe10..52c3bb617 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -58,25 +58,27 @@ typedef enum PARSER_DEBUGGER_BREAKPOINT_APPENDED = (1u << 11), /**< pending (unsent) breakpoint * info is available */ #if ENABLED (JERRY_ES2015) - PARSER_LEXICAL_BLOCK_NEEDED = (1u << 12), /**< script needs a lexical environment for let and const */ + PARSER_LEXICAL_BLOCK_NEEDED = (1u << 12), /**< global script: needs a lexical environment for let and const + * function: needs a lexical environment for arguments */ PARSER_IS_ARROW_FUNCTION = (1u << 13), /**< an arrow function is parsed */ PARSER_IS_GENERATOR_FUNCTION = (1u << 14), /**< a generator function is parsed */ PARSER_IS_ASYNC_FUNCTION = (1u << 15), /**< an async function is parsed */ PARSER_DISALLOW_YIELD = (1u << 16), /**< throw SyntaxError for yield expression */ - PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM = (1u << 17), /**< function has a non simple parameter */ - PARSER_FUNCTION_HAS_REST_PARAM = (1u << 18), /**< function has rest parameter */ + PARSER_FUNCTION_IS_PARSING_ARGS = (1u << 17), /**< set when parsing function arguments */ + PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM = (1u << 18), /**< function has a non simple parameter */ + PARSER_FUNCTION_HAS_REST_PARAM = (1u << 19), /**< function has rest parameter */ /* These 4 status flags must be in this order. See PARSER_SAVED_FLAGS_OFFSET. */ - PARSER_CLASS_CONSTRUCTOR = (1u << 19), /**< a class constructor is parsed + PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed * Note: PARSER_ALLOW_SUPER must be present */ - PARSER_ALLOW_SUPER = (1u << 20), /**< allow super property access */ - PARSER_ALLOW_SUPER_CALL = (1u << 21), /**< allow super constructor call + PARSER_ALLOW_SUPER = (1u << 21), /**< allow super property access */ + PARSER_ALLOW_SUPER_CALL = (1u << 22), /**< allow super constructor call * Note: PARSER_CLASS_CONSTRUCTOR must be present */ - PARSER_ALLOW_NEW_TARGET = (1u << 22), /**< allow new.target parsing in the current context */ + PARSER_ALLOW_NEW_TARGET = (1u << 23), /**< allow new.target parsing in the current context */ #endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 23), /**< parsing a function or class default export */ - PARSER_MODULE_STORE_IDENT = (1u << 24), /**< store identifier of the current export statement */ + PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 24), /**< parsing a function or class default export */ + PARSER_MODULE_STORE_IDENT = (1u << 25), /**< store identifier of the current export statement */ #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ PARSER_HAS_LATE_LIT_INIT = (1u << 30), /**< there are identifier or string literals which construction * is postponed after the local parser data is freed */ @@ -115,6 +117,18 @@ typedef enum PARSER_PATTERN_ARRAY = (1u << 8), /**< array pattern is being parsed */ } parser_pattern_flags_t; +/** + * Check type for scanner_is_context_needed function. + */ +typedef enum +{ + PARSER_CHECK_BLOCK_CONTEXT, /**< check block context */ +#if ENABLED (JERRY_ES2015) + PARSER_CHECK_GLOBAL_CONTEXT, /**< check global context */ + PARSER_CHECK_FUNCTION_CONTEXT, /**< check function context */ +#endif /* ENABLED (JERRY_ES2015) */ +} parser_check_context_type_t; + /** * Mask for strict mode code */ @@ -168,13 +182,17 @@ typedef enum #define PARSER_SAVE_STATUS_FLAGS(opts) \ ((uint16_t) (((opts) >> PARSER_SAVED_FLAGS_OFFSET) & PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK)) -/* All flags that affect exotic arguments object creation. */ +/** + * All flags that affect exotic arguments object creation. + */ #define PARSER_ARGUMENTS_RELATED_FLAGS \ (PARSER_ARGUMENTS_NEEDED | PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM | PARSER_IS_STRICT) #else /* !ENABLED (JERRY_ES2015) */ -/* All flags that affect exotic arguments object creation. */ +/** + * All flags that affect exotic arguments object creation. + */ #define PARSER_ARGUMENTS_RELATED_FLAGS \ (PARSER_ARGUMENTS_NEEDED | PARSER_IS_STRICT) @@ -720,9 +738,8 @@ void scanner_seek (parser_context_t *context_p); void scanner_reverse_info_list (parser_context_t *context_p); void scanner_cleanup (parser_context_t *context_p); -bool scanner_is_context_needed (parser_context_t *context_p); +bool scanner_is_context_needed (parser_context_t *context_p, parser_check_context_type_t check_type); #if ENABLED (JERRY_ES2015) -bool scanner_is_global_context_needed (parser_context_t *context_p); bool scanner_scope_find_let_declaration (parser_context_t *context_p, lexer_lit_location_t *literal_p); bool scanner_try_scan_new_target (parser_context_t *context_p); void scanner_check_variables (parser_context_t *context_p); diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 2d53b47f6..a900539e1 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -383,7 +383,7 @@ parser_push_block_context (parser_context_t *context_p, /**< context */ bool is_context_needed = false; - if (scanner_is_context_needed (context_p)) + if (scanner_is_context_needed (context_p, PARSER_CHECK_BLOCK_CONTEXT)) { parser_block_context_t block_context; @@ -1875,7 +1875,7 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */ block_found = true; #endif /* !JERRY_NDEBUG */ - if (scanner_is_context_needed (context_p)) + if (scanner_is_context_needed (context_p, PARSER_CHECK_BLOCK_CONTEXT)) { parser_emit_cbc_ext (context_p, CBC_EXT_TRY_CREATE_ENV); } @@ -1952,7 +1952,7 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */ { JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK); - if (scanner_is_context_needed (context_p)) + if (scanner_is_context_needed (context_p, PARSER_CHECK_BLOCK_CONTEXT)) { parser_emit_cbc_ext (context_p, CBC_EXT_TRY_CREATE_ENV); } @@ -2838,7 +2838,7 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ { JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK); - if (scanner_is_context_needed (context_p)) + if (scanner_is_context_needed (context_p, PARSER_CHECK_BLOCK_CONTEXT)) { parser_emit_cbc_ext (context_p, CBC_EXT_TRY_CREATE_ENV); } @@ -3082,10 +3082,6 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ { parser_stack_pop_uint8 (context_p); context_p->last_statement.current_p = NULL; - JERRY_ASSERT (context_p->stack_depth == 0); -#ifndef JERRY_NDEBUG - JERRY_ASSERT (context_p->context_stack_depth == 0); -#endif /* !JERRY_NDEBUG */ /* There is no lexer_next_token here, since the * next token belongs to the parent context. */ return; @@ -3226,11 +3222,6 @@ consume_last_statement: } } - JERRY_ASSERT (context_p->stack_depth == 0); -#ifndef JERRY_NDEBUG - JERRY_ASSERT (context_p->context_stack_depth == context_p->stack_depth); -#endif /* !JERRY_NDEBUG */ - parser_stack_pop_uint8 (context_p); context_p->last_statement.current_p = NULL; diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index cb9590d41..79c039b0f 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -918,6 +918,30 @@ parser_post_processing (parser_context_t *context_p) /**< context */ ecma_value_t *literal_pool_p; uint8_t *dst_p; +#if ENABLED (JERRY_ES2015) + if ((context_p->status_flags & (PARSER_IS_FUNCTION | PARSER_LEXICAL_BLOCK_NEEDED)) + == (PARSER_IS_FUNCTION | PARSER_LEXICAL_BLOCK_NEEDED)) + { + PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION); +#ifndef JERRY_NDEBUG + PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION); +#endif /* !JERRY_NDEBUG */ + + context_p->status_flags &= (uint32_t) ~PARSER_LEXICAL_BLOCK_NEEDED; + + parser_emit_cbc (context_p, CBC_CONTEXT_END); + + parser_branch_t branch; + parser_stack_pop (context_p, &branch, sizeof (parser_branch_t)); + parser_set_branch_to_current_position (context_p, &branch); + } +#endif /* ENABLED (JERRY_ES2015) */ + + JERRY_ASSERT (context_p->stack_depth == 0); +#ifndef JERRY_NDEBUG + JERRY_ASSERT (context_p->context_stack_depth == 0); +#endif /* !JERRY_NDEBUG */ + if ((size_t) context_p->stack_limit + (size_t) context_p->register_count > PARSER_MAXIMUM_STACK_LIMIT) { parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED); @@ -1308,6 +1332,7 @@ parser_post_processing (parser_context_t *context_p) /**< context */ if (context_p->status_flags & PARSER_LEXICAL_BLOCK_NEEDED) { + JERRY_ASSERT (!(context_p->status_flags & PARSER_IS_FUNCTION)); compiled_code_p->status_flags |= CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED; } #endif /* ENABLED (JERRY_ES2015) */ @@ -1682,6 +1707,9 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION); #if ENABLED (JERRY_ES2015) + JERRY_ASSERT (context_p->status_flags & PARSER_IS_FUNCTION); + JERRY_ASSERT (!(context_p->status_flags & PARSER_LEXICAL_BLOCK_NEEDED)); + bool duplicated_argument_names = false; /* TODO: Currently async iterators are not supported, so generators ignore the async modifier. */ @@ -1710,6 +1738,10 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ scanner_create_variables (context_p, SCANNER_CREATE_VARS_IS_FUNCTION_ARGS); scanner_set_active (context_p); +#if ENABLED (JERRY_ES2015) + context_p->status_flags |= PARSER_FUNCTION_IS_PARSING_ARGS; +#endif /* ENABLED (JERRY_ES2015) */ + while (true) { #if ENABLED (JERRY_ES2015) @@ -1867,6 +1899,8 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ parser_raise_error (context_p, error); } + scanner_revert_active (context_p); + #if ENABLED (JERRY_ES2015) if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION) { @@ -1874,10 +1908,30 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ parser_emit_cbc (context_p, CBC_POP); } - context_p->status_flags &= (uint32_t) ~PARSER_DISALLOW_YIELD; + if (context_p->status_flags & PARSER_LEXICAL_BLOCK_NEEDED) + { + if ((context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_LEXICAL_ENV_NEEDED) + || scanner_is_context_needed (context_p, PARSER_CHECK_FUNCTION_CONTEXT)) + { + context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED; + + parser_branch_t branch; + parser_emit_cbc_forward_branch (context_p, CBC_BLOCK_CREATE_CONTEXT, &branch); + parser_stack_push (context_p, &branch, sizeof (parser_branch_t)); + +#ifndef JERRY_NDEBUG + context_p->context_stack_depth = PARSER_BLOCK_CONTEXT_STACK_ALLOCATION; +#endif /* !JERRY_NDEBUG */ + } + else + { + context_p->status_flags &= (uint32_t) ~PARSER_LEXICAL_BLOCK_NEEDED; + } + } + + context_p->status_flags &= (uint32_t) ~(PARSER_DISALLOW_YIELD | PARSER_FUNCTION_IS_PARSING_ARGS); #endif /* ENABLED (JERRY_ES2015) */ - scanner_revert_active (context_p); scanner_create_variables (context_p, SCANNER_CREATE_VARS_IS_FUNCTION_BODY); } /* parser_parse_function_arguments */ @@ -2070,7 +2124,7 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ && context.next_scanner_info_p->type == SCANNER_TYPE_FUNCTION); #if ENABLED (JERRY_ES2015) - if (scanner_is_global_context_needed (&context)) + if (scanner_is_context_needed (&context, PARSER_CHECK_GLOBAL_CONTEXT)) { context.status_flags |= PARSER_LEXICAL_BLOCK_NEEDED; } @@ -2189,6 +2243,13 @@ parser_save_context (parser_context_t *context_p, /**< context */ } #endif /* ENABLED (JERRY_DEBUGGER) */ +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_FUNCTION_IS_PARSING_ARGS) + { + context_p->status_flags |= PARSER_LEXICAL_BLOCK_NEEDED; + } +#endif /* ENABLED (JERRY_ES2015) */ + /* Save private part of the context. */ saved_context_p->status_flags = context_p->status_flags; diff --git a/jerry-core/parser/js/js-scanner-internal.h b/jerry-core/parser/js/js-scanner-internal.h index c6000ddc6..7c0967582 100644 --- a/jerry-core/parser/js/js-scanner-internal.h +++ b/jerry-core/parser/js/js-scanner-internal.h @@ -259,18 +259,18 @@ typedef enum SCANNER_LITERAL_POOL_BLOCK = (1 << 1), /**< literal pool represents a code block */ SCANNER_LITERAL_POOL_IS_STRICT = (1 << 2), /**< literal pool represents a strict mode code block */ SCANNER_LITERAL_POOL_NO_REG = (1 << 3), /**< variable declarations cannot be kept in registers */ - SCANNER_LITERAL_POOL_NO_ARGUMENTS = (1 << 5), /**< arguments object must not be constructed */ + SCANNER_LITERAL_POOL_NO_ARGUMENTS = (1 << 4), /**< arguments object must not be constructed */ #if ENABLED (JERRY_ES2015) - SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED = (1 << 6), /**< arguments object should be unmapped */ + SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED = (1 << 5), /**< arguments object should be unmapped */ #endif /* ENABLED (JERRY_ES2015) */ - SCANNER_LITERAL_POOL_IN_WITH = (1 << 7), /**< literal pool is in a with statement */ + SCANNER_LITERAL_POOL_IN_WITH = (1 << 6), /**< literal pool is in a with statement */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - SCANNER_LITERAL_POOL_IN_EXPORT = (1 << 8), /**< the declared variables are exported by the module system */ + SCANNER_LITERAL_POOL_IN_EXPORT = (1 << 7), /**< the declared variables are exported by the module system */ #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ #if ENABLED (JERRY_ES2015) - SCANNER_LITERAL_POOL_FUNCTION_STATEMENT = (1 << 9), /**< function statement (only if async is set) */ - SCANNER_LITERAL_POOL_GENERATOR = (1 << 10), /**< generator function */ - SCANNER_LITERAL_POOL_ASYNC = (1 << 11), /**< async function */ + SCANNER_LITERAL_POOL_FUNCTION_STATEMENT = (1 << 8), /**< function statement (only when async is set) */ + SCANNER_LITERAL_POOL_GENERATOR = (1 << 9), /**< generator function */ + SCANNER_LITERAL_POOL_ASYNC = (1 << 10), /**< async function */ #endif /* ENABLED (JERRY_ES2015) */ } scanner_literal_pool_flags_t; diff --git a/jerry-core/parser/js/js-scanner-util.c b/jerry-core/parser/js/js-scanner-util.c index be84e8ced..c62b281ff 100644 --- a/jerry-core/parser/js/js-scanner-util.c +++ b/jerry-core/parser/js/js-scanner-util.c @@ -477,7 +477,7 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ { no_reg_types |= SCANNER_LITERAL_IS_FUNC; } -#endif /* !ENABLED (JERRY_ES2015) */ +#endif /* ENABLED (JERRY_ES2015) */ if (no_reg && prev_literal_pool_p != NULL) { @@ -694,6 +694,11 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ status_flags |= SCANNER_FUNCTION_STATEMENT; } } + + if (no_reg) + { + status_flags |= SCANNER_FUNCTION_LEXICAL_ENV_NEEDED; + } #endif /* ENABLED (JERRY_ES2015) */ info_p->u8_arg = status_flags; @@ -1567,98 +1572,85 @@ scanner_cleanup (parser_context_t *context_p) /**< context */ * false - otherwise */ bool -scanner_is_context_needed (parser_context_t *context_p) /**< context */ -{ - scanner_info_t *info_p = context_p->next_scanner_info_p; - const uint8_t *data_p = ((const uint8_t *) info_p) + sizeof (scanner_info_t); - - JERRY_ASSERT (info_p->type == SCANNER_TYPE_BLOCK); - - uint32_t scope_stack_reg_top = context_p->scope_stack_reg_top; - - while (data_p[0] != SCANNER_STREAM_TYPE_END) - { - uint32_t type = data_p[0] & SCANNER_STREAM_TYPE_MASK; - -#if ENABLED (JERRY_ES2015) - JERRY_ASSERT (type == SCANNER_STREAM_TYPE_VAR - || type == SCANNER_STREAM_TYPE_LET - || type == SCANNER_STREAM_TYPE_CONST - || type == SCANNER_STREAM_TYPE_LOCAL - || type == SCANNER_STREAM_TYPE_FUNC); -#else /* !ENABLED (JERRY_ES2015) */ - JERRY_ASSERT (type == SCANNER_STREAM_TYPE_VAR); -#endif /* ENABLED (JERRY_ES2015) */ - - size_t length; - - if (!(data_p[0] & SCANNER_STREAM_UINT16_DIFF)) - { - if (data_p[2] != 0) - { - length = 2 + 1; - } - else - { - length = 2 + 1 + sizeof (const uint8_t *); - } - } - else - { - length = 2 + 2; - } - - if (!(data_p[0] & SCANNER_STREAM_NO_REG) - && scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS) - { - scope_stack_reg_top++; - } - else - { - return true; - } - - data_p += length; - } - - return false; -} /* scanner_is_context_needed */ - -#if ENABLED (JERRY_ES2015) - -/** - * Checks whether a global context needs to be created for a script. - * - * @return true - if context is needed, - * false - otherwise - */ -bool -scanner_is_global_context_needed (parser_context_t *context_p) /**< context */ +scanner_is_context_needed (parser_context_t *context_p, /**< context */ + parser_check_context_type_t check_type) /**< context type */ { scanner_info_t *info_p = context_p->next_scanner_info_p; const uint8_t *data_p = (const uint8_t *) (info_p + 1); - uint32_t scope_stack_reg_top = 0; - JERRY_ASSERT (info_p->type == SCANNER_TYPE_FUNCTION); + JERRY_UNUSED (check_type); + +#if ENABLED (JERRY_ES2015) + JERRY_ASSERT ((check_type == PARSER_CHECK_BLOCK_CONTEXT ? info_p->type == SCANNER_TYPE_BLOCK + : info_p->type == SCANNER_TYPE_FUNCTION)); + + uint32_t scope_stack_reg_top = (check_type != PARSER_CHECK_GLOBAL_CONTEXT ? context_p->scope_stack_reg_top + : 0); +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_ASSERT (check_type == PARSER_CHECK_BLOCK_CONTEXT); + JERRY_ASSERT (info_p->type == SCANNER_TYPE_BLOCK); + + uint32_t scope_stack_reg_top = context_p->scope_stack_reg_top; +#endif /* !JERRY_NDEBUG */ while (data_p[0] != SCANNER_STREAM_TYPE_END) { uint8_t data = data_p[0]; + +#if ENABLED (JERRY_ES2015) uint32_t type = data & SCANNER_STREAM_TYPE_MASK; - /* FIXME: a private declarative lexical environment should always be present - * for modules. Remove SCANNER_STREAM_TYPE_IMPORT after it is implemented. */ - JERRY_ASSERT (type == SCANNER_STREAM_TYPE_VAR - || type == SCANNER_STREAM_TYPE_LET - || type == SCANNER_STREAM_TYPE_CONST - || type == SCANNER_STREAM_TYPE_FUNC - || type == SCANNER_STREAM_TYPE_IMPORT); + if (JERRY_UNLIKELY (type == SCANNER_STREAM_TYPE_HOLE)) + { + JERRY_ASSERT (check_type == PARSER_CHECK_FUNCTION_CONTEXT); + data_p++; + continue; + } - /* Only let/const can be stored in registers */ - JERRY_ASSERT ((data & SCANNER_STREAM_NO_REG) - || (type == SCANNER_STREAM_TYPE_FUNC && (context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL)) - || type == SCANNER_STREAM_TYPE_LET - || type == SCANNER_STREAM_TYPE_CONST); +#ifndef JERRY_NDEBUG + if (check_type == PARSER_CHECK_BLOCK_CONTEXT) + { + JERRY_ASSERT (type == SCANNER_STREAM_TYPE_VAR + || type == SCANNER_STREAM_TYPE_LET + || type == SCANNER_STREAM_TYPE_CONST + || type == SCANNER_STREAM_TYPE_LOCAL + || type == SCANNER_STREAM_TYPE_FUNC); + } + else if (check_type == PARSER_CHECK_GLOBAL_CONTEXT) + { + /* FIXME: a private declarative lexical environment should always be present + * for modules. Remove SCANNER_STREAM_TYPE_IMPORT after it is implemented. */ + JERRY_ASSERT (type == SCANNER_STREAM_TYPE_VAR + || type == SCANNER_STREAM_TYPE_LET + || type == SCANNER_STREAM_TYPE_CONST + || type == SCANNER_STREAM_TYPE_FUNC + || type == SCANNER_STREAM_TYPE_IMPORT); + + /* Only let/const can be stored in registers */ + JERRY_ASSERT ((data & SCANNER_STREAM_NO_REG) + || (type == SCANNER_STREAM_TYPE_FUNC && (context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL)) + || type == SCANNER_STREAM_TYPE_LET + || type == SCANNER_STREAM_TYPE_CONST); + } + else + { + JERRY_ASSERT (check_type == PARSER_CHECK_FUNCTION_CONTEXT); + + JERRY_ASSERT (type == SCANNER_STREAM_TYPE_VAR + || type == SCANNER_STREAM_TYPE_LET + || type == SCANNER_STREAM_TYPE_CONST + || type == SCANNER_STREAM_TYPE_LOCAL + || type == SCANNER_STREAM_TYPE_DESTRUCTURED_ARG + || type == SCANNER_STREAM_TYPE_ARG + || type == SCANNER_STREAM_TYPE_ARG_FUNC + || type == SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC + || type == SCANNER_STREAM_TYPE_FUNC); + } +#endif /* !JERRY_NDEBUG */ + +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_ASSERT ((data & SCANNER_STREAM_TYPE_MASK) == SCANNER_STREAM_TYPE_VAR); +#endif /* ENABLED (JERRY_ES2015) */ if (!(data & SCANNER_STREAM_UINT16_DIFF)) { @@ -1676,26 +1668,35 @@ scanner_is_global_context_needed (parser_context_t *context_p) /**< context */ data_p += 2 + 2; } - if (type == SCANNER_STREAM_TYPE_VAR - || (type == SCANNER_STREAM_TYPE_FUNC && !(context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL)) - || type == SCANNER_STREAM_TYPE_IMPORT) +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (check_type == PARSER_CHECK_GLOBAL_CONTEXT) + && (type == SCANNER_STREAM_TYPE_VAR + || (type == SCANNER_STREAM_TYPE_FUNC && !(context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL)) + || type == SCANNER_STREAM_TYPE_IMPORT)) { continue; } - if (!(data & SCANNER_STREAM_NO_REG) - && scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS) + if (JERRY_UNLIKELY (check_type == PARSER_CHECK_FUNCTION_CONTEXT) + && (SCANNER_STREAM_TYPE_IS_ARG (type) || SCANNER_STREAM_TYPE_IS_ARG_FUNC (type))) { - scope_stack_reg_top++; + continue; } - else +#endif /* ENABLED (JERRY_ES2015) */ + + if ((data & SCANNER_STREAM_NO_REG) + || scope_stack_reg_top >= PARSER_MAXIMUM_NUMBER_OF_REGISTERS) { return true; } + + scope_stack_reg_top++; } return false; -} /* scanner_is_global_context_needed */ +} /* scanner_is_context_needed */ + +#if ENABLED (JERRY_ES2015) /** * Try to scan/parse the ".target" part in the "new.target" expression. diff --git a/jerry-core/parser/js/js-scanner.h b/jerry-core/parser/js/js-scanner.h index 5e4832d66..613e208eb 100644 --- a/jerry-core/parser/js/js-scanner.h +++ b/jerry-core/parser/js/js-scanner.h @@ -209,8 +209,10 @@ typedef enum { SCANNER_FUNCTION_ARGUMENTS_NEEDED = (1 << 0), /**< arguments object needs to be created */ #if ENABLED (JERRY_ES2015) - SCANNER_FUNCTION_STATEMENT = (1 << 1), /**< function is (async) function statement */ - SCANNER_FUNCTION_ASYNC = (1 << 2), /**< function is async function expression */ + SCANNER_FUNCTION_LEXICAL_ENV_NEEDED = (1 << 1), /**< lexical environment is needed for the function body */ + SCANNER_FUNCTION_STATEMENT = (1 << 2), /**< function is function statement (not arrow expression) + * this flag must be combined with the type of function (e.g. async) */ + SCANNER_FUNCTION_ASYNC = (1 << 3), /**< function is async function */ #endif /* ENABLED (JERRY_ES2015) */ } scanner_function_flags_t; diff --git a/tests/jerry/es2015/function-param-init3.js b/tests/jerry/es2015/function-param-init3.js new file mode 100644 index 000000000..e2e177a49 --- /dev/null +++ b/tests/jerry/es2015/function-param-init3.js @@ -0,0 +1,68 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// 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. + +var d = 1 +function f(a = function () { return d }) +{ + var d = 2 + assert(d === 2) + assert(a() === 1) +} +f() + +var g = (a = () => d) => { + var d = 2 + assert(d === 2) + assert(a() === 1) +} +g() + +var h = ([{a}] = [{a: function () { return d }}]) => { + var d = 2 + assert(d === 2) + assert(a() === 1) +} +h() + +function i(a = ((eval))("(function () { return d })")) +{ + var d = 2 + assert(d === 2) + assert(a() === 1) +} +i() + +function j(a = (([1, ((() => d))])[1])) +{ + var d = 2 + assert(d === 2) + assert(a() === 1) +} +j() + +var m = 0 +function l(a) +{ + m = a + return m +} + +function k(a = l(() => d)) +{ + var d = 2 + assert(d === 2) + assert(a() === 1) + assert(m() === 1) +} +k() diff --git a/tests/jerry/es2015/regression-test-issue-3396.js b/tests/jerry/es2015/regression-test-issue-3396.js new file mode 100644 index 000000000..c40e6f0c0 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3396.js @@ -0,0 +1,19 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// 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. + +function i($, b = (eval("var x"))) { + function x() {} + eval() +} +i()