diff --git a/jerry-core/include/jerryscript-snapshot.h b/jerry-core/include/jerryscript-snapshot.h index bc32ed8b07..263d5cd0f0 100644 --- a/jerry-core/include/jerryscript-snapshot.h +++ b/jerry-core/include/jerryscript-snapshot.h @@ -30,7 +30,7 @@ extern "C" /** * Jerry snapshot format version. */ -#define JERRY_SNAPSHOT_VERSION (42u) +#define JERRY_SNAPSHOT_VERSION (43u) /** * Flags for jerry_generate_snapshot and jerry_generate_function_snapshot. diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index b102b4e22a..5453fb331d 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -312,8 +312,14 @@ VM_OC_CREATE_BINDING) \ CBC_OPCODE (CBC_CREATE_LOCAL, CBC_HAS_LITERAL_ARG, 0, \ VM_OC_CREATE_BINDING) \ - CBC_OPCODE (CBC_INIT_LOCAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ - VM_OC_INIT_LOCAL) \ + CBC_OPCODE (CBC_INIT_ARG_OR_CATCH, CBC_HAS_LITERAL_ARG, -1, \ + VM_OC_INIT_BINDING) \ + CBC_OPCODE (CBC_INIT_LET, CBC_HAS_LITERAL_ARG, -1, \ + VM_OC_INIT_BINDING) \ + CBC_OPCODE (CBC_INIT_CONST, CBC_HAS_LITERAL_ARG, -1, \ + VM_OC_INIT_BINDING) \ + CBC_OPCODE (CBC_INIT_ARG_OR_FUNC, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ + VM_OC_INIT_ARG_OR_FUNC) \ CBC_OPCODE (CBC_CREATE_VAR_EVAL, CBC_HAS_LITERAL_ARG, 0, \ VM_OC_VAR_EVAL) \ CBC_OPCODE (CBC_CREATE_VAR_FUNC_EVAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ @@ -498,6 +504,8 @@ VM_OC_MOV_IDENT | VM_OC_GET_STACK | VM_OC_PUT_IDENT) \ CBC_OPCODE (CBC_ASSIGN_LET_CONST, CBC_HAS_LITERAL_ARG, -1, \ VM_OC_ASSIGN_LET_CONST | VM_OC_GET_STACK) \ + CBC_OPCODE (CBC_ASSIGN_LET_CONST_LITERAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ + VM_OC_ASSIGN_LET_CONST | VM_OC_GET_LITERAL) \ CBC_OPCODE (CBC_ASSIGN_SUPER, CBC_NO_FLAG, -3, \ VM_OC_ASSIGN_SUPER) \ CBC_OPCODE (CBC_ASSIGN_SUPER_PUSH_RESULT, CBC_NO_FLAG, -2, \ diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 4da83f2ee8..37392fbac2 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -813,9 +813,15 @@ parser_parse_class (parser_context_t *context_p, /**< context */ if (is_statement) { - parser_emit_cbc_literal (context_p, - class_ident_index >= PARSER_REGISTER_START ? CBC_MOV_IDENT : CBC_ASSIGN_LET_CONST, - class_ident_index); + cbc_opcode_t opcode = CBC_MOV_IDENT; + + if (class_ident_index < PARSER_REGISTER_START) + { + opcode = (scanner_literal_is_created (context_p, class_ident_index) ? CBC_ASSIGN_LET_CONST + : CBC_INIT_LET); + } + + parser_emit_cbc_literal (context_p, (uint16_t) opcode, class_ident_index); } parser_flush_cbc (context_p); @@ -2251,9 +2257,9 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */ */ static uint8_t parser_append_binary_single_assignment_token (parser_context_t *context_p, /**< context */ - bool is_lexical) /**< assign lexical declaration */ + uint32_t pattern_flags) /**< pattern flags */ { - JERRY_UNUSED (is_lexical); + JERRY_UNUSED (pattern_flags); /* Unlike other tokens, the whole byte code is saved for binary * assignment, since it has multiple forms depending on the @@ -2301,7 +2307,7 @@ parser_append_binary_single_assignment_token (parser_context_t *context_p, /**< assign_opcode = CBC_ASSIGN_SET_IDENT; #if ENABLED (JERRY_ES2015) - if (!is_lexical) + if (!(pattern_flags & (PARSER_PATTERN_LET | PARSER_PATTERN_CONST | PARSER_PATTERN_LOCAL))) { if (scanner_literal_is_const_reg (context_p, literal_index)) { @@ -2310,7 +2316,20 @@ parser_append_binary_single_assignment_token (parser_context_t *context_p, /**< } else if (literal_index < PARSER_REGISTER_START) { - assign_opcode = CBC_ASSIGN_LET_CONST; + assign_opcode = CBC_INIT_LET; + + if (scanner_literal_is_created (context_p, literal_index)) + { + assign_opcode = CBC_ASSIGN_LET_CONST; + } + else if (pattern_flags & PARSER_PATTERN_CONST) + { + assign_opcode = CBC_INIT_CONST; + } + else if (pattern_flags & PARSER_PATTERN_LOCAL) + { + assign_opcode = CBC_INIT_ARG_OR_CATCH; + } } #endif /* ENABLED (JERRY_ES2015) */ @@ -2395,7 +2414,7 @@ parser_append_binary_token (parser_context_t *context_p) /**< context */ if (context_p->token.type == LEXER_ASSIGN) { - parser_append_binary_single_assignment_token (context_p, false); + parser_append_binary_single_assignment_token (context_p, 0); return; } @@ -2486,7 +2505,10 @@ parser_process_binary_opcodes (parser_context_t *context_p, /**< context */ JERRY_ASSERT (opcode == CBC_ASSIGN_SET_IDENT || opcode == CBC_ASSIGN_PROP_LITERAL || opcode == CBC_ASSIGN_PROP_THIS_LITERAL - || opcode == CBC_ASSIGN_LET_CONST); + || opcode == CBC_ASSIGN_LET_CONST + || opcode == CBC_INIT_ARG_OR_CATCH + || opcode == CBC_INIT_LET + || opcode == CBC_INIT_CONST); index = parser_stack_pop_uint16 (context_p); } @@ -2601,7 +2623,7 @@ parser_pattern_get_target (parser_context_t *context_p, /**< context */ { JERRY_ASSERT (flags & PARSER_PATTERN_TARGET_ON_STACK); - parser_emit_cbc_forward_branch (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_DEFAULT_INITIALIZER), &skip_init); + parser_emit_cbc_ext_forward_branch (context_p, CBC_EXT_DEFAULT_INITIALIZER, &skip_init); } if ((flags & (PARSER_PATTERN_TARGET_ON_STACK | PARSER_PATTERN_TARGET_DEFAULT)) != PARSER_PATTERN_TARGET_ON_STACK) @@ -2707,8 +2729,7 @@ parser_pattern_form_assignment (parser_context_t *context_p, /**< context */ JERRY_UNUSED (ident_line_counter); parser_stack_push_uint8 (context_p, LEXER_EXPRESSION_START); - bool is_lexical = (flags & (PARSER_PATTERN_LEXICAL | PARSER_PATTERN_LOCAL)) != 0; - uint8_t assign_opcode = parser_append_binary_single_assignment_token (context_p, is_lexical); + uint8_t assign_opcode = parser_append_binary_single_assignment_token (context_p, flags); if (flags & PARSER_PATTERN_ARRAY) { @@ -2724,7 +2745,7 @@ parser_pattern_form_assignment (parser_context_t *context_p, /**< context */ { parser_branch_t skip_init; lexer_next_token (context_p); - parser_emit_cbc_forward_branch (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_DEFAULT_INITIALIZER), &skip_init); + parser_emit_cbc_ext_forward_branch (context_p, CBC_EXT_DEFAULT_INITIALIZER, &skip_init); parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); parser_set_branch_to_current_position (context_p, &skip_init); @@ -2770,7 +2791,8 @@ parser_pattern_process_nested_pattern (parser_context_t *context_p, /**< context parser_pattern_flags_t options = (PARSER_PATTERN_NESTED_PATTERN | PARSER_PATTERN_TARGET_ON_STACK | (flags & (PARSER_PATTERN_BINDING - | PARSER_PATTERN_LEXICAL + | PARSER_PATTERN_LET + | PARSER_PATTERN_CONST | PARSER_PATTERN_LOCAL | PARSER_PATTERN_REST_ELEMENT | PARSER_PATTERN_ARGUMENTS))); @@ -2821,7 +2843,7 @@ parser_pattern_process_assignment (parser_context_t *context_p, /**< context */ lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); - if (flags & PARSER_PATTERN_LEXICAL + if (flags & (PARSER_PATTERN_LET | PARSER_PATTERN_CONST) && context_p->token.keyword_type == LEXER_KEYW_LET) { parser_raise_error (context_p, PARSER_ERR_LEXICAL_LET_BINDING); diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index 8b6256f1cd..6aaf143a14 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -110,11 +110,12 @@ typedef enum PARSER_PATTERN_TARGET_ON_STACK = (1u << 1), /**< assignment target is the topmost element on the stack */ PARSER_PATTERN_TARGET_DEFAULT = (1u << 2), /**< perform default value comparison for assignment target */ PARSER_PATTERN_NESTED_PATTERN = (1u << 3), /**< parse patter inside a pattern */ - PARSER_PATTERN_LEXICAL = (1u << 4), /**< pattern is a lexical (let/const) declaration */ - PARSER_PATTERN_LOCAL = (1u << 5), /**< pattern is a local (catch parameter) declaration */ - PARSER_PATTERN_REST_ELEMENT = (1u << 6), /**< parse rest array initializer */ - PARSER_PATTERN_ARGUMENTS = (1u << 7), /**< parse arguments binding */ - PARSER_PATTERN_ARRAY = (1u << 8), /**< array pattern is being parsed */ + PARSER_PATTERN_LET = (1u << 4), /**< pattern is a let declaration */ + PARSER_PATTERN_CONST = (1u << 5), /**< pattern is a const declaration */ + PARSER_PATTERN_LOCAL = (1u << 6), /**< pattern is a local (catch parameter) declaration */ + PARSER_PATTERN_REST_ELEMENT = (1u << 7), /**< parse rest array initializer */ + PARSER_PATTERN_ARGUMENTS = (1u << 8), /**< parse arguments binding */ + PARSER_PATTERN_ARRAY = (1u << 9), /**< array pattern is being parsed */ } parser_pattern_flags_t; /** @@ -395,12 +396,17 @@ typedef struct * Function statements with the name specified * in map_from should not be copied to global scope. */ -#define PARSER_SCOPE_STACK_NO_FUNCTION_COPY 0x4000 +#define PARSER_SCOPE_STACK_NO_FUNCTION_COPY 0x8000 /** - * The scope stack item represents a const declaration + * The scope stack item represents a const binding stored in register */ -#define PARSER_SCOPE_STACK_IS_CONST 0x8000 +#define PARSER_SCOPE_STACK_IS_CONST_REG 0x4000 + +/** + * The scope stack item represents a binding which has already created with ECMA_VALUE_UNINITIALIZED + */ +#define PARSER_SCOPE_STACK_IS_LOCAL_CREATED (PARSER_SCOPE_STACK_IS_CONST_REG) #endif /* ENABLED (JERRY_ES2015) */ @@ -753,6 +759,7 @@ void scanner_set_location (parser_context_t *context_p, scanner_location_t *loca uint16_t scanner_decode_map_to (parser_scope_stack_t *stack_item_p); #if ENABLED (JERRY_ES2015) bool scanner_literal_is_const_reg (parser_context_t *context_p, uint16_t literal_index); +bool scanner_literal_is_created (parser_context_t *context_p, uint16_t literal_index); #endif /* ENABLED (JERRY_ES2015) */ void scanner_scan_all (parser_context_t *context_p, const uint8_t *arg_list_p, const uint8_t *arg_list_end_p, diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 6f0a39731d..4b63d5c563 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -499,10 +499,15 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */ { parser_pattern_flags_t flags = PARSER_PATTERN_BINDING; - if (declaration_type != LEXER_KEYW_VAR) + if (declaration_type == LEXER_KEYW_LET) { - flags |= PARSER_PATTERN_LEXICAL; + flags |= PARSER_PATTERN_LET; } + else if (declaration_type == LEXER_KEYW_CONST) + { + flags |= PARSER_PATTERN_CONST; + } + parser_parse_initializer_by_next_char (context_p, flags); } else @@ -569,7 +574,16 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */ if (declaration_type != LEXER_KEYW_VAR && (index < PARSER_REGISTER_START)) { - opcode = CBC_ASSIGN_LET_CONST; + opcode = CBC_INIT_LET; + + if (scanner_literal_is_created (context_p, index)) + { + opcode = CBC_ASSIGN_LET_CONST; + } + else if (declaration_type == LEXER_KEYW_CONST) + { + opcode = CBC_INIT_CONST; + } } #endif /* ENABLED (JERRY_ES2015) */ @@ -581,9 +595,15 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */ parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED); uint16_t index = context_p->lit_object.index; - parser_emit_cbc_literal (context_p, - index >= PARSER_REGISTER_START ? CBC_MOV_IDENT : CBC_ASSIGN_LET_CONST, - index); + cbc_opcode_t opcode = CBC_MOV_IDENT; + + if (index < PARSER_REGISTER_START) + { + opcode = (scanner_literal_is_created (context_p, index) ? CBC_ASSIGN_LET_CONST + : CBC_INIT_LET); + } + + parser_emit_cbc_literal (context_p, (uint16_t) opcode, index); } else if (declaration_type == LEXER_KEYW_CONST) { @@ -1289,8 +1309,6 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ #if ENABLED (JERRY_ES2015) if (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE)) { - bool is_var = (token_type == LEXER_KEYW_VAR); - parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT : CBC_EXT_FOR_OF_GET_NEXT); @@ -1303,9 +1321,13 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ parser_pattern_flags_t flags = (PARSER_PATTERN_BINDING | PARSER_PATTERN_TARGET_ON_STACK); - if (!is_var) + if (token_type == LEXER_KEYW_LET) + { + flags |= PARSER_PATTERN_LET; + } + else if (token_type == LEXER_KEYW_CONST) { - flags |= PARSER_PATTERN_LEXICAL; + flags |= PARSER_PATTERN_CONST; } parser_parse_initializer_by_next_char (context_p, flags); @@ -1347,9 +1369,12 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ } #endif /* !JERRY_NDEBUG */ - parser_emit_cbc_literal (context_p, - has_context ? CBC_ASSIGN_LET_CONST : CBC_ASSIGN_SET_IDENT, - literal_index); + JERRY_ASSERT (literal_index >= PARSER_REGISTER_START + || !has_context + || scanner_literal_is_created (context_p, literal_index)); + + uint16_t opcode = (has_context ? CBC_ASSIGN_LET_CONST : CBC_ASSIGN_SET_IDENT); + parser_emit_cbc_literal (context_p, opcode, literal_index); #else /* !ENABLED (JERRY_ES2015) */ parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index); #endif /* ENABLED (JERRY_ES2015) */ @@ -1928,7 +1953,7 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */ { parser_pattern_flags_t flags = (PARSER_PATTERN_BINDING | PARSER_PATTERN_TARGET_ON_STACK - | PARSER_PATTERN_LOCAL); + | PARSER_PATTERN_LET); parser_parse_initializer_by_next_char (context_p, flags); } diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 982f40355f..d425553407 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -1715,7 +1715,7 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ JERRY_ASSERT (context_p->status_flags & PARSER_IS_FUNCTION); JERRY_ASSERT (!(context_p->status_flags & PARSER_LEXICAL_BLOCK_NEEDED)); - bool duplicated_argument_names = false; + bool has_duplicated_arg_names = false; /* TODO: Currently async iterators are not supported, so generators ignore the async modifier. */ if ((context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_ASYNC) @@ -1740,6 +1740,10 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ return; } +#if ENABLED (JERRY_ES2015) + bool has_mapped_arguments = (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_MAPPED_ARGUMENTS) != 0; +#endif /* ENABLED (JERRY_ES2015) */ + scanner_create_variables (context_p, SCANNER_CREATE_VARS_IS_FUNCTION_ARGS); scanner_set_active (context_p); @@ -1762,7 +1766,7 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ } lexer_next_token (context_p); - if (duplicated_argument_names) + if (has_duplicated_arg_names) { parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES); } @@ -1772,7 +1776,7 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE) { - if (duplicated_argument_names) + if (has_duplicated_arg_names) { parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES); } @@ -1841,7 +1845,7 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ { parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES); } - duplicated_argument_names = true; + has_duplicated_arg_names = true; #endif /* ENABLED (JERRY_ES2015) */ context_p->status_flags |= PARSER_HAS_NON_STRICT_ARG; @@ -1851,17 +1855,15 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_FUNCTION_ARGUMENT; } - context_p->argument_count++; - if (context_p->argument_count >= PARSER_MAXIMUM_NUMBER_OF_REGISTERS) - { - parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIMIT_REACHED); - } - lexer_next_token (context_p); #if ENABLED (JERRY_ES2015) + uint16_t literal_index = context_p->lit_object.index; + if (context_p->token.type == LEXER_ASSIGN) { + JERRY_ASSERT (!has_mapped_arguments); + if (context_p->status_flags & PARSER_FUNCTION_HAS_REST_PARAM) { parser_raise_error (context_p, PARSER_ERR_REST_PARAMETER_DEFAULT_INITIALIZER); @@ -1869,7 +1871,7 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ parser_branch_t skip_init; - if (duplicated_argument_names) + if (has_duplicated_arg_names) { parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES); } @@ -1877,17 +1879,51 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ context_p->status_flags |= PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM; /* LEXER_ASSIGN does not overwrite lit_object. */ - parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED); - parser_emit_cbc_literal (context_p, CBC_STRICT_EQUAL_RIGHT_LITERAL, context_p->lit_object.index); - parser_emit_cbc_forward_branch (context_p, CBC_BRANCH_IF_FALSE_FORWARD, &skip_init); + parser_emit_cbc_literal (context_p, + CBC_PUSH_LITERAL, + (uint16_t) (PARSER_REGISTER_START + context_p->argument_count)); + parser_emit_cbc_ext_forward_branch (context_p, CBC_EXT_DEFAULT_INITIALIZER, &skip_init); - parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL); - parser_parse_expression_statement (context_p, PARSE_EXPR_NO_COMMA | PARSE_EXPR_HAS_LITERAL); + lexer_next_token (context_p); + parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); parser_set_branch_to_current_position (context_p, &skip_init); + + uint16_t opcode = CBC_ASSIGN_LET_CONST; + + if (literal_index >= PARSER_REGISTER_START) + { + opcode = CBC_ASSIGN_SET_IDENT; + } + else if (!scanner_literal_is_created (context_p, literal_index)) + { + opcode = CBC_INIT_ARG_OR_CATCH; + } + + parser_emit_cbc_literal (context_p, opcode, literal_index); + } + else if (!has_mapped_arguments && literal_index < PARSER_REGISTER_START) + { + uint16_t opcode = CBC_INIT_ARG_OR_FUNC; + + if (scanner_literal_is_created (context_p, literal_index)) + { + opcode = CBC_ASSIGN_LET_CONST_LITERAL; + } + + parser_emit_cbc_literal_value (context_p, + opcode, + (uint16_t) (PARSER_REGISTER_START + context_p->argument_count), + literal_index); } #endif /* ENABLED (JERRY_ES2015) */ + context_p->argument_count++; + if (context_p->argument_count >= PARSER_MAXIMUM_NUMBER_OF_REGISTERS) + { + parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIMIT_REACHED); + } + if (context_p->token.type != LEXER_COMMA) { break; @@ -1907,6 +1943,8 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ scanner_revert_active (context_p); #if ENABLED (JERRY_ES2015) + JERRY_ASSERT (!has_mapped_arguments || !(context_p->status_flags & PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM)); + if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION) { parser_emit_cbc_ext (context_p, CBC_EXT_CREATE_GENERATOR); diff --git a/jerry-core/parser/js/js-scanner-internal.h b/jerry-core/parser/js/js-scanner-internal.h index 23953e6b4e..8cc94e0eee 100644 --- a/jerry-core/parser/js/js-scanner-internal.h +++ b/jerry-core/parser/js/js-scanner-internal.h @@ -101,6 +101,7 @@ typedef enum SCAN_STACK_COMPUTED_GENERATOR_FUNCTION, /**< computed property name */ SCAN_STACK_TEMPLATE_STRING, /**< template string */ SCAN_STACK_TAGGED_TEMPLATE_LITERAL, /**< tagged template literal */ + SCAN_STACK_PRIVATE_BLOCK_EARLY, /**< private block for single statements (force early declarations) */ SCAN_STACK_PRIVATE_BLOCK, /**< private block for single statements */ SCAN_STACK_ARROW_ARGUMENTS, /**< might be arguments of an arrow function */ SCAN_STACK_ARROW_EXPRESSION, /**< expression body of an arrow function */ @@ -148,10 +149,6 @@ typedef enum SCANNER_LITERAL_IS_ARROW_DESTRUCTURED_ARG = SCANNER_LITERAL_IS_VAR, #endif /* ENABLED (JERRY_ES2015) */ SCANNER_LITERAL_IS_FUNC = (1 << 2), /**< literal is function */ -#if ENABLED (JERRY_ES2015) - /** a destructured argument binding of a possible arrow function cannot be stored in a register */ - SCANNER_LITERAL_ARROW_DESTRUCTURED_ARG_NO_REG = SCANNER_LITERAL_IS_FUNC, -#endif /* ENABLED (JERRY_ES2015) */ SCANNER_LITERAL_NO_REG = (1 << 3), /**< literal cannot be stored in a register */ SCANNER_LITERAL_IS_LET = (1 << 4), /**< literal is let */ #if ENABLED (JERRY_ES2015) @@ -163,6 +160,7 @@ typedef enum /** literal is a destructured argument binding */ SCANNER_LITERAL_IS_DESTRUCTURED_ARG = SCANNER_LITERAL_IS_CONST, SCANNER_LITERAL_IS_USED = (1 << 6), /**< literal is used */ + SCANNER_LITERAL_EARLY_CREATE = (1 << 7), /**< binding should be created early with ECMA_VALUE_UNINITIALIZED */ #endif /* ENABLED (JERRY_ES2015) */ } scanner_literal_type_flags_t; @@ -258,7 +256,7 @@ typedef enum SCANNER_LITERAL_POOL_FUNCTION = (1 << 0), /**< literal pool represents a function */ 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_CAN_EVAL = (1 << 3), /**< prepare for executing eval in this block */ SCANNER_LITERAL_POOL_NO_ARGUMENTS = (1 << 4), /**< arguments object must not be constructed */ #if ENABLED (JERRY_ES2015) SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED = (1 << 5), /**< arguments object should be unmapped */ @@ -268,7 +266,7 @@ typedef enum 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 << 8), /**< function statement (only when async is set) */ + SCANNER_LITERAL_POOL_FUNCTION_STATEMENT = (1 << 8), /**< function statement */ SCANNER_LITERAL_POOL_GENERATOR = (1 << 9), /**< generator function */ SCANNER_LITERAL_POOL_ASYNC = (1 << 10), /**< async function */ #endif /* ENABLED (JERRY_ES2015) */ @@ -339,7 +337,7 @@ lexer_lit_location_t *scanner_add_custom_literal (parser_context_t *context_p, s const lexer_lit_location_t *literal_location_p); lexer_lit_location_t *scanner_add_literal (parser_context_t *context_p, scanner_context_t *scanner_context_p); void scanner_add_reference (parser_context_t *context_p, scanner_context_t *scanner_context_p); -void scanner_append_argument (parser_context_t *context_p, scanner_context_t *scanner_context_p); +lexer_lit_location_t *scanner_append_argument (parser_context_t *context_p, scanner_context_t *scanner_context_p); #if ENABLED (JERRY_ES2015) void scanner_detect_invalid_var (parser_context_t *context_p, scanner_context_t *scanner_context_p, lexer_lit_location_t *var_literal_p); diff --git a/jerry-core/parser/js/js-scanner-ops.c b/jerry-core/parser/js/js-scanner-ops.c index be56720161..5caa264899 100644 --- a/jerry-core/parser/js/js-scanner-ops.c +++ b/jerry-core/parser/js/js-scanner-ops.c @@ -176,15 +176,29 @@ scanner_check_arrow_arg (parser_context_t *context_p, /**< context */ } else { - scanner_append_argument (context_p, scanner_context_p); + lexer_lit_location_t *argument_literal_p = scanner_append_argument (context_p, scanner_context_p); scanner_detect_eval_call (context_p, scanner_context_p); lexer_next_token (context_p); - if (context_p->token.type == LEXER_ASSIGN - || context_p->token.type == LEXER_COMMA - || context_p->token.type == LEXER_RIGHT_PAREN) + if (context_p->token.type == LEXER_ASSIGN) + { + if (argument_literal_p->type & SCANNER_LITERAL_IS_USED) + { + JERRY_ASSERT (argument_literal_p->type & SCANNER_LITERAL_EARLY_CREATE); + return; + } + + scanner_binding_literal_t binding_literal; + binding_literal.literal_p = argument_literal_p; + + parser_stack_push (context_p, &binding_literal, sizeof (scanner_binding_literal_t)); + parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_INIT); + return; + } + + if (context_p->token.type == LEXER_COMMA || context_p->token.type == LEXER_RIGHT_PAREN) { return; } @@ -381,7 +395,7 @@ scanner_scan_bracket (parser_context_t *context_p, /**< context */ arrow_source_p = NULL; #endif /* ENABLED (JERRY_ES2015) */ - scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_NO_REG; + scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_CAN_EVAL; break; } diff --git a/jerry-core/parser/js/js-scanner-util.c b/jerry-core/parser/js/js-scanner-util.c index 1304c9fa96..521bee3a38 100644 --- a/jerry-core/parser/js/js-scanner-util.c +++ b/jerry-core/parser/js/js-scanner-util.c @@ -39,9 +39,6 @@ JERRY_STATIC_ASSERT (PARSER_MAXIMUM_NUMBER_OF_LITERALS + PARSER_MAXIMUM_NUMBER_O JERRY_STATIC_ASSERT ((SCANNER_LITERAL_IS_ARROW_DESTRUCTURED_ARG & SCANNER_LITERAL_IS_LOCAL) == 0, is_arrow_arg_binding_flag_must_not_use_local_flags); -JERRY_STATIC_ASSERT ((SCANNER_LITERAL_ARROW_DESTRUCTURED_ARG_NO_REG & SCANNER_LITERAL_IS_LOCAL) == 0, - arrow_arg_binding_no_reg_flag_must_not_use_local_flags); - JERRY_STATIC_ASSERT ((SCANNER_LITERAL_IS_LET & SCANNER_LITERAL_IS_LOCAL) != 0, is_let_flag_must_use_local_flags); @@ -57,6 +54,9 @@ JERRY_STATIC_ASSERT ((SCANNER_LITERAL_IS_DESTRUCTURED_ARG & SCANNER_LITERAL_IS_L JERRY_STATIC_ASSERT (SCANNER_LITERAL_IS_FUNC_DECLARATION != SCANNER_LITERAL_IS_DESTRUCTURED_ARG, is_func_declaration_must_be_different_from_is_arg_binding); +JERRY_STATIC_ASSERT (PARSER_SCOPE_STACK_IS_CONST_REG == PARSER_SCOPE_STACK_IS_LOCAL_CREATED, + scope_stack_is_const_reg_and_scope_stack_is_local_created_must_be_the_same); + #endif /* ENABLED (JERRY_ES2015) */ /** @@ -468,22 +468,21 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ parser_list_iterator_t literal_iterator; lexer_lit_location_t *literal_p; - bool is_function = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION) != 0; - bool no_reg = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_NO_REG) != 0; - bool search_arguments = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_NO_ARGUMENTS) == 0; - bool arguments_required = (no_reg && search_arguments); + uint16_t status_flags = literal_pool_p->status_flags; + bool arguments_required = ((status_flags & (SCANNER_LITERAL_POOL_CAN_EVAL | SCANNER_LITERAL_POOL_NO_ARGUMENTS)) + == SCANNER_LITERAL_POOL_CAN_EVAL); - uint8_t no_reg_types = 0; + uint8_t can_eval_types = 0; #if ENABLED (JERRY_ES2015) if (prev_literal_pool_p == NULL && !(context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL)) { - no_reg_types |= SCANNER_LITERAL_IS_FUNC; + can_eval_types |= SCANNER_LITERAL_IS_FUNC; } #endif /* ENABLED (JERRY_ES2015) */ - if (no_reg && prev_literal_pool_p != NULL) + if ((status_flags & SCANNER_LITERAL_POOL_CAN_EVAL) && prev_literal_pool_p != NULL) { - prev_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_NO_REG; + prev_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_CAN_EVAL; } #if ENABLED (JERRY_DEBUGGER) @@ -491,7 +490,7 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ { /* When debugger is enabled, identifiers are not stored in registers. However, * this does not affect 'eval' detection, so 'arguments' object is not created. */ - no_reg = true; + status_flags |= SCANNER_LITERAL_POOL_CAN_EVAL; } #endif /* ENABLED (JERRY_DEBUGGER) */ @@ -510,9 +509,9 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ continue; } - if (search_arguments && scanner_literal_is_arguments (literal_p)) + if (!(status_flags & SCANNER_LITERAL_POOL_NO_ARGUMENTS) && scanner_literal_is_arguments (literal_p)) { - search_arguments = false; + status_flags |= SCANNER_LITERAL_POOL_NO_ARGUMENTS; if (type & (SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_LOCAL)) { @@ -527,7 +526,7 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ } #if ENABLED (JERRY_ES2015) - if (is_function + if ((status_flags & SCANNER_LITERAL_POOL_FUNCTION) && (type & (SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_FUNC_DECLARATION)) == SCANNER_LITERAL_IS_FUNC) { if (prev_literal_pool_p == NULL @@ -543,10 +542,12 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ } #endif /* ENABLED (JERRY_ES2015) */ - if ((is_function && (type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_ARG))) - || (type & SCANNER_LITERAL_IS_LOCAL)) + if ((type & SCANNER_LITERAL_IS_LOCAL) + || ((type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_ARG)) + && (status_flags & SCANNER_LITERAL_POOL_FUNCTION))) { - JERRY_ASSERT (is_function || !(literal_p->type & SCANNER_LITERAL_IS_ARG)); + JERRY_ASSERT ((status_flags & SCANNER_LITERAL_POOL_FUNCTION) + || !(literal_p->type & SCANNER_LITERAL_IS_ARG)); if (literal_p->length == 0) { @@ -556,7 +557,7 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ no_declarations++; - if (no_reg || (type & no_reg_types)) + if ((status_flags & SCANNER_LITERAL_POOL_CAN_EVAL) || (type & can_eval_types)) { type |= SCANNER_LITERAL_NO_REG; literal_p->type = type; @@ -602,9 +603,9 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ prev_source_p = literal_p->char_p + literal_p->length; - if (is_function + if ((status_flags & SCANNER_LITERAL_POOL_FUNCTION) #if ENABLED (JERRY_ES2015) - || ((type & SCANNER_LITERAL_IS_FUNC) && (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IS_STRICT)) + || ((type & SCANNER_LITERAL_IS_FUNC) && (status_flags & SCANNER_LITERAL_POOL_IS_STRICT)) #endif /* ENABLED (JERRY_ES2015) */ || !(type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC))) { @@ -620,7 +621,7 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ literal_p); uint8_t extended_type = literal_location_p->type; - if (is_function || (type & SCANNER_LITERAL_NO_REG)) + if ((status_flags & SCANNER_LITERAL_POOL_FUNCTION) || (type & SCANNER_LITERAL_NO_REG)) { extended_type |= SCANNER_LITERAL_NO_REG; } @@ -628,6 +629,11 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ #if ENABLED (JERRY_ES2015) extended_type |= SCANNER_LITERAL_IS_USED; + if (status_flags & SCANNER_LITERAL_POOL_FUNCTION_STATEMENT) + { + extended_type |= SCANNER_LITERAL_EARLY_CREATE; + } + const uint8_t mask = (SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_LOCAL); if ((type & SCANNER_LITERAL_IS_ARG) @@ -641,13 +647,13 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ #endif /* ENABLED (JERRY_ES2015) */ type = (uint8_t) (type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC)); - JERRY_ASSERT (type == 0 || !is_function); + JERRY_ASSERT (type == 0 || !(status_flags & SCANNER_LITERAL_POOL_FUNCTION)); literal_location_p->type = (uint8_t) (extended_type | type); } } - if (is_function || (compressed_size > 1)) + if ((status_flags & SCANNER_LITERAL_POOL_FUNCTION) || (compressed_size > 1)) { compressed_size += sizeof (scanner_info_t); @@ -670,15 +676,15 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ uint8_t *data_p = (uint8_t *) (info_p + 1); - if (is_function) + if (status_flags & SCANNER_LITERAL_POOL_FUNCTION) { info_p->type = SCANNER_TYPE_FUNCTION; - uint8_t status_flags = 0; + uint8_t u8_arg = 0; if (arguments_required) { - status_flags |= SCANNER_FUNCTION_ARGUMENTS_NEEDED; + u8_arg |= SCANNER_FUNCTION_ARGUMENTS_NEEDED; if (no_declarations < PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK) { @@ -691,30 +697,34 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ const uint16_t is_unmapped = SCANNER_LITERAL_POOL_IS_STRICT; #endif /* ENABLED (JERRY_ES2015) */ - if (literal_pool_p->status_flags & is_unmapped) + if (status_flags & is_unmapped) { arguments_required = false; } + else + { + u8_arg |= SCANNER_FUNCTION_MAPPED_ARGUMENTS; + } } #if ENABLED (JERRY_ES2015) - if (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_ASYNC) + if (status_flags & SCANNER_LITERAL_POOL_ASYNC) { - status_flags |= SCANNER_FUNCTION_ASYNC; + u8_arg |= SCANNER_FUNCTION_ASYNC; - if (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION_STATEMENT) + if (status_flags & SCANNER_LITERAL_POOL_FUNCTION_STATEMENT) { - status_flags |= SCANNER_FUNCTION_STATEMENT; + u8_arg |= SCANNER_FUNCTION_STATEMENT; } } - if (no_reg) + if (status_flags & SCANNER_LITERAL_POOL_CAN_EVAL) { - status_flags |= SCANNER_FUNCTION_LEXICAL_ENV_NEEDED; + u8_arg |= SCANNER_FUNCTION_LEXICAL_ENV_NEEDED; } #endif /* ENABLED (JERRY_ES2015) */ - info_p->u8_arg = status_flags; + info_p->u8_arg = u8_arg; info_p->u16_arg = (uint16_t) no_declarations; } else @@ -731,8 +741,9 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) { if (JERRY_UNLIKELY (no_declarations > PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK) - || (!(is_function && (literal_p->type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_ARG))) - && !(literal_p->type & SCANNER_LITERAL_IS_LOCAL))) + || (!(literal_p->type & SCANNER_LITERAL_IS_LOCAL) + && (!(literal_p->type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_ARG)) + || !(status_flags & SCANNER_LITERAL_POOL_FUNCTION)))) { continue; } @@ -781,6 +792,11 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ if (!(literal_p->type & SCANNER_LITERAL_IS_CONST)) { type = SCANNER_STREAM_TYPE_LET; + + if ((status_flags & SCANNER_LITERAL_POOL_CAN_EVAL) && (literal_p->type & SCANNER_LITERAL_NO_REG)) + { + literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; + } } #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) else if (prev_literal_pool_p == NULL) @@ -796,6 +812,16 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ else if (literal_p->type & SCANNER_LITERAL_IS_CONST) { type = SCANNER_STREAM_TYPE_CONST; + + if ((status_flags & SCANNER_LITERAL_POOL_CAN_EVAL) && (literal_p->type & SCANNER_LITERAL_NO_REG)) + { + literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; + } + } + + if (literal_p->type & SCANNER_LITERAL_EARLY_CREATE) + { + type |= SCANNER_STREAM_NO_REG | SCANNER_STREAM_EARLY_CREATE; } #endif /* ENABLED (JERRY_ES2015) */ @@ -847,12 +873,13 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ JERRY_ASSERT (((uint8_t *) info_p) + compressed_size == data_p + 1); } - if (!is_function && prev_literal_pool_p->no_declarations < no_declarations) + if (!(status_flags & SCANNER_LITERAL_POOL_FUNCTION) + && prev_literal_pool_p->no_declarations < no_declarations) { prev_literal_pool_p->no_declarations = (uint16_t) no_declarations; } - if (is_function && prev_literal_pool_p != NULL) + if ((status_flags & SCANNER_LITERAL_POOL_FUNCTION) && prev_literal_pool_p != NULL) { if (prev_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IS_STRICT) { @@ -893,24 +920,31 @@ scanner_filter_arguments (parser_context_t *context_p, /**< context */ scanner_literal_pool_t *prev_literal_pool_p = literal_pool_p->prev_p; parser_list_iterator_t literal_iterator; lexer_lit_location_t *literal_p; - bool no_reg = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_NO_REG) != 0; + bool can_eval = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_CAN_EVAL) != 0; bool has_arguments = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_NO_ARGUMENTS) == 0; - if (no_reg && prev_literal_pool_p != NULL) + if (can_eval && prev_literal_pool_p != NULL) { - prev_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_NO_REG; + prev_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_CAN_EVAL; } - literal_pool_p->status_flags &= (uint16_t) ~SCANNER_LITERAL_POOL_NO_REG; + literal_pool_p->status_flags &= (uint16_t) ~SCANNER_LITERAL_POOL_CAN_EVAL; parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator); while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) { - if (no_reg) +#if ENABLED (JERRY_ES2015) + if (can_eval || (literal_p->type & SCANNER_LITERAL_EARLY_CREATE)) + { + literal_p->type |= SCANNER_LITERAL_NO_REG | SCANNER_LITERAL_EARLY_CREATE; + } +#else /* !ENABLED (JERRY_ES2015) */ + if (can_eval) { literal_p->type |= SCANNER_LITERAL_NO_REG; } +#endif /* ENABLED (JERRY_ES2015) */ uint8_t type = literal_p->type; @@ -957,12 +991,13 @@ scanner_filter_arguments (parser_context_t *context_p, /**< context */ if ((type & SCANNER_LITERAL_IS_ARG) || (has_arguments && scanner_literal_is_arguments (literal_p))) { - if (no_reg) +#if ENABLED (JERRY_ES2015) + if (can_eval || (literal_p->type & SCANNER_LITERAL_EARLY_CREATE)) { - literal_p->type |= SCANNER_LITERAL_NO_REG; + type |= SCANNER_LITERAL_NO_REG | SCANNER_LITERAL_EARLY_CREATE; + literal_p->type = type; } -#if ENABLED (JERRY_ES2015) if (type & (SCANNER_LITERAL_IS_DESTRUCTURED_ARG | SCANNER_LITERAL_IS_ARROW_DESTRUCTURED_ARG)) { has_destructured_arg = true; @@ -975,15 +1010,14 @@ scanner_filter_arguments (parser_context_t *context_p, /**< context */ type &= (uint8_t) ~SCANNER_LITERAL_IS_ARROW_DESTRUCTURED_ARG; type |= SCANNER_LITERAL_IS_DESTRUCTURED_ARG; - if (type & SCANNER_LITERAL_ARROW_DESTRUCTURED_ARG_NO_REG) - { - type &= (uint8_t) ~SCANNER_LITERAL_ARROW_DESTRUCTURED_ARG_NO_REG; - type |= SCANNER_LITERAL_NO_REG; - } - literal_p->type = type; continue; } +#else /* !ENABLED (JERRY_ES2015) */ + if (can_eval) + { + literal_p->type |= SCANNER_LITERAL_NO_REG; + } #endif /* ENABLED (JERRY_ES2015) */ lexer_lit_location_t *new_literal_p; @@ -1131,8 +1165,10 @@ scanner_add_reference (parser_context_t *context_p, /**< context */ /** * Append an argument to the literal pool. If the argument is already present, make it a "hole". + * + * @return newly created literal */ -void +lexer_lit_location_t * scanner_append_argument (parser_context_t *context_p, /**< context */ scanner_context_t *scanner_context_p) /**< scanner context */ { @@ -1155,13 +1191,11 @@ scanner_append_argument (parser_context_t *context_p, /**< context */ { if (memcmp (literal_p->char_p, char_p, length) == 0) { - literal_p->length = 0; break; } } else if (lexer_compare_identifier_to_string (literal_p, char_p, length)) { - literal_p->length = 0; break; } } @@ -1173,16 +1207,31 @@ scanner_append_argument (parser_context_t *context_p, /**< context */ { if (lexer_compare_identifiers (context_p, literal_p, literal_location_p)) { - literal_p->length = 0; break; } } } + uint8_t literal_type = SCANNER_LITERAL_IS_ARG; + + if (literal_p != NULL) + { + literal_p->length = 0; + +#if ENABLED (JERRY_ES2015) + if (literal_p->type & SCANNER_LITERAL_IS_USED) + { + literal_type = SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_EARLY_CREATE; + } +#endif /* ENABLED (JERRY_ES2015) */ + } + literal_p = (lexer_lit_location_t *) parser_list_append (context_p, &literal_pool_p->literal_pool); + *literal_p = context_p->token.lit_location; + literal_p->type = literal_type; - literal_p->type = SCANNER_LITERAL_IS_ARG; + return literal_p; } /* scanner_append_argument */ /** @@ -1195,7 +1244,7 @@ scanner_detect_eval_call (parser_context_t *context_p, /**< context */ if (context_p->token.keyword_type == LEXER_KEYW_EVAL && lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)) { - scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_NO_REG; + scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_CAN_EVAL; } } /* scanner_detect_eval_call */ @@ -1887,6 +1936,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ scanner_info_t *info_p = context_p->next_scanner_info_p; const uint8_t *next_data_p = (const uint8_t *) (info_p + 1); uint8_t info_type = info_p->type; + uint8_t info_u8_arg = info_p->u8_arg; lexer_lit_location_t literal; parser_scope_stack_t *scope_stack_p; parser_scope_stack_t *scope_stack_end_p; @@ -1950,7 +2000,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ continue; } - if (info_p->u8_arg & SCANNER_FUNCTION_ARGUMENTS_NEEDED) + if (info_u8_arg & SCANNER_FUNCTION_MAPPED_ARGUMENTS) { scanner_create_unused_literal (context_p, LEXER_FLAG_FUNCTION_ARGUMENT); } @@ -2038,7 +2088,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ if (JERRY_UNLIKELY (context_p->status_flags & PARSER_LEXICAL_BLOCK_NEEDED) && (function_map_p[0].map_to & PARSER_SCOPE_STACK_REGISTER_MASK) == 0) { - opcode = CBC_INIT_LOCAL; + opcode = CBC_INIT_ARG_OR_FUNC; } #endif /* ENABLED (JERRY_ES2015) */ @@ -2072,7 +2122,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ #endif /* ENABLED (JERRY_ES2015) */ uint16_t map_to; - uint16_t func_init_opcode = CBC_INIT_LOCAL; + uint16_t func_init_opcode = CBC_INIT_ARG_OR_FUNC; if (!(data_p[0] & SCANNER_STREAM_NO_REG) && scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS) @@ -2091,7 +2141,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ { case SCANNER_STREAM_TYPE_CONST: { - scope_stack_p->map_to |= PARSER_SCOPE_STACK_IS_CONST; + scope_stack_p->map_to |= PARSER_SCOPE_STACK_IS_CONST_REG; /* FALLTHRU */ } case SCANNER_STREAM_TYPE_LET: @@ -2114,7 +2164,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ map_to = context_p->lit_object.index; #if ENABLED (JERRY_ES2015) - scope_stack_p->map_to = 0; + uint16_t scope_stack_map_to = 0; #else /* !ENABLED (JERRY_ES2015) */ scope_stack_p->map_to = map_to; #endif /* ENABLED (JERRY_ES2015) */ @@ -2127,16 +2177,18 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ switch (type) { #if ENABLED (JERRY_ES2015) - case SCANNER_STREAM_TYPE_CONST: - { - scope_stack_p->map_to |= PARSER_SCOPE_STACK_IS_CONST; - /* FALLTHRU */ - } case SCANNER_STREAM_TYPE_LET: + case SCANNER_STREAM_TYPE_CONST: case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG: case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC: { - scope_stack_p->map_to |= PARSER_SCOPE_STACK_NO_FUNCTION_COPY; + scope_stack_map_to |= PARSER_SCOPE_STACK_NO_FUNCTION_COPY; + + if (!(data_p[0] & SCANNER_STREAM_EARLY_CREATE)) + { + break; + } + scope_stack_map_to |= PARSER_SCOPE_STACK_IS_LOCAL_CREATED; /* FALLTHRU */ } case SCANNER_STREAM_TYPE_LOCAL: @@ -2183,13 +2235,25 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ #endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ #if ENABLED (JERRY_ES2015) - scope_stack_p->map_to |= PARSER_SCOPE_STACK_NO_FUNCTION_COPY; -#endif /* ENABLED (JERRY_ES2015) */ + scope_stack_map_to |= PARSER_SCOPE_STACK_NO_FUNCTION_COPY; - parser_emit_cbc_literal_value (context_p, - CBC_INIT_LOCAL, - (uint16_t) (PARSER_REGISTER_START + scope_stack_reg_top), - map_to); + /* Argument initializers of functions with mapped arguments (e.g. function f(a,b,a) {}) are + * generated here. The other initializers are handled by parser_parse_function_arguments(). */ + if (info_u8_arg & SCANNER_FUNCTION_MAPPED_ARGUMENTS) + { +#endif /* ENABLED (JERRY_ES2015) */ + parser_emit_cbc_literal_value (context_p, + CBC_INIT_ARG_OR_FUNC, + (uint16_t) (PARSER_REGISTER_START + scope_stack_reg_top), + map_to); +#if ENABLED (JERRY_ES2015) + } + else if (data_p[0] & SCANNER_STREAM_EARLY_CREATE) + { + parser_emit_cbc_literal (context_p, CBC_CREATE_LOCAL, map_to); + scope_stack_map_to |= PARSER_SCOPE_STACK_IS_LOCAL_CREATED; + } +#endif /* ENABLED (JERRY_ES2015) */ if (scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS) { @@ -2198,6 +2262,10 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ break; } } + +#if ENABLED (JERRY_ES2015) + scope_stack_p->map_to = scope_stack_map_to; +#endif /* ENABLED (JERRY_ES2015) */ } scope_stack_p++; @@ -2219,7 +2287,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ if (!SCANNER_STREAM_TYPE_IS_ARG_FUNC (type)) { - if (func_init_opcode == CBC_INIT_LOCAL && (option_flags & SCANNER_CREATE_VARS_IS_SCRIPT)) + if (func_init_opcode == CBC_INIT_ARG_OR_FUNC && (option_flags & SCANNER_CREATE_VARS_IS_SCRIPT)) { #if ENABLED (JERRY_ES2015) literal.char_p -= data_p[1]; @@ -2246,7 +2314,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ if (info_type == SCANNER_TYPE_FUNCTION && !(option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY) - && (info_p->u8_arg & SCANNER_FUNCTION_ARGUMENTS_NEEDED)) + && (info_u8_arg & SCANNER_FUNCTION_ARGUMENTS_NEEDED)) { JERRY_ASSERT (info_type == SCANNER_TYPE_FUNCTION); @@ -2336,7 +2404,7 @@ scanner_decode_map_to (parser_scope_stack_t *stack_item_p) /**< scope stack item /** * Checks whether the literal is a const in the current scope. * - * @return true if the literal is a const + * @return true if the literal is a const, false otherwise */ bool scanner_literal_is_const_reg (parser_context_t *context_p, /**< context */ @@ -2360,9 +2428,35 @@ scanner_literal_is_const_reg (parser_context_t *context_p, /**< context */ } while (literal_index != (scope_stack_p->map_to & PARSER_SCOPE_STACK_REGISTER_MASK)); - return (scope_stack_p->map_to & PARSER_SCOPE_STACK_IS_CONST) != 0; + return (scope_stack_p->map_to & PARSER_SCOPE_STACK_IS_CONST_REG) != 0; } /* scanner_literal_is_const_reg */ +/** + * Checks whether the literal is created before. + * + * @return true if the literal is created before, false otherwise + */ +bool +scanner_literal_is_created (parser_context_t *context_p, /**< context */ + uint16_t literal_index) /**< literal index */ +{ + JERRY_ASSERT (literal_index < PARSER_REGISTER_START); + + parser_scope_stack_t *scope_stack_p = context_p->scope_stack_p + context_p->scope_stack_top; + + do + { + /* These literals must be found in the scope stack. */ + JERRY_ASSERT (scope_stack_p > context_p->scope_stack_p); + scope_stack_p--; + } + while (literal_index != scope_stack_p->map_from); + + JERRY_ASSERT ((scope_stack_p->map_to & PARSER_SCOPE_STACK_REGISTER_MASK) == 0); + + return (scope_stack_p->map_to & PARSER_SCOPE_STACK_IS_LOCAL_CREATED) != 0; +} /* scanner_literal_is_created */ + #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index 9b57613875..38866f59cc 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -556,17 +556,11 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * scanner_binding_item_t *item_p = scanner_context_p->active_binding_list_p->items_p; - uint8_t flag = SCANNER_LITERAL_NO_REG; - if (scanner_context_p->binding_type == SCANNER_BINDING_ARROW_ARG) - { - flag = SCANNER_LITERAL_ARROW_DESTRUCTURED_ARG_NO_REG; - } - while (item_p != NULL) { if (item_p->literal_p->type & SCANNER_LITERAL_IS_USED) { - item_p->literal_p->type |= flag; + item_p->literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; } item_p = item_p->next_p; } @@ -588,21 +582,15 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * || context_p->stack_top_uint8 == SCAN_STACK_CONST || context_p->stack_top_uint8 == SCAN_STACK_FOR_LET_START || context_p->stack_top_uint8 == SCAN_STACK_FOR_CONST_START + || context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_PARAMETERS || context_p->stack_top_uint8 == SCAN_STACK_ARROW_ARGUMENTS); + JERRY_ASSERT ((stack_top != SCAN_STACK_ARRAY_LITERAL && stack_top != SCAN_STACK_OBJECT_LITERAL) + || SCANNER_NEEDS_BINDING_LIST (scanner_context_p->binding_type)); + if (binding_literal.literal_p->type & SCANNER_LITERAL_IS_USED) { - stack_top = (scan_stack_modes_t) context_p->stack_top_uint8; - - if ((stack_top == SCAN_STACK_ARRAY_LITERAL || stack_top == SCAN_STACK_OBJECT_LITERAL) - && (scanner_context_p->binding_type == SCANNER_BINDING_ARROW_ARG)) - { - binding_literal.literal_p->type |= SCANNER_LITERAL_ARROW_DESTRUCTURED_ARG_NO_REG; - } - else - { - binding_literal.literal_p->type |= SCANNER_LITERAL_NO_REG; - } + binding_literal.literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; } scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; @@ -645,7 +633,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * if (stack_top == SCAN_STACK_FOR_LET_START || stack_top == SCAN_STACK_FOR_CONST_START) { - parser_stack_push_uint8 (context_p, SCAN_STACK_PRIVATE_BLOCK); + parser_stack_push_uint8 (context_p, SCAN_STACK_PRIVATE_BLOCK_EARLY); } #else /* !ENABLED (JERRY_ES2015) */ location_info->info.type = SCANNER_TYPE_FOR_IN; @@ -1372,9 +1360,9 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ { lexer_next_token (context_p); - uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION; - #if ENABLED (JERRY_ES2015) + uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION | SCANNER_LITERAL_POOL_FUNCTION_STATEMENT; + if (context_p->token.type == LEXER_MULTIPLY) { status_flags |= SCANNER_LITERAL_POOL_GENERATOR; @@ -1386,6 +1374,8 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ { context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION; } +#else /* !ENABLED (JERRY_ES2015) */ + uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION; #endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_LITERAL @@ -2092,6 +2082,23 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ continue; } #if ENABLED (JERRY_ES2015) + case SCAN_STACK_PRIVATE_BLOCK_EARLY: + { + parser_list_iterator_t literal_iterator; + lexer_lit_location_t *literal_p; + + parser_list_iterator_init (&scanner_context_p->active_literal_pool_p->literal_pool, &literal_iterator); + + while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) + { + if ((literal_p->type & (SCANNER_LITERAL_IS_LET | SCANNER_LITERAL_IS_CONST)) + && literal_p->type & SCANNER_LITERAL_NO_REG) + { + literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; + } + } + /* FALLTHRU */ + } case SCAN_STACK_PRIVATE_BLOCK: { parser_stack_pop_uint8 (context_p); @@ -2276,7 +2283,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ context_p->source_p = source_p; context_p->source_end_p = source_end_p; - uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS | SCANNER_LITERAL_POOL_NO_REG; + uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS | SCANNER_LITERAL_POOL_CAN_EVAL; if (context_p->status_flags & PARSER_IS_STRICT) { @@ -2578,7 +2585,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ if (literal_p->type & SCANNER_LITERAL_IS_USED) { - literal_p->type |= SCANNER_LITERAL_NO_REG; + literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; } else if (context_p->token.type == LEXER_ASSIGN) { @@ -2684,10 +2691,6 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ if (JERRY_UNLIKELY (scanner_context.async_source_p != NULL)) { literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ASYNC; - if (stack_top == SCAN_STACK_FUNCTION_STATEMENT) - { - literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_FUNCTION_STATEMENT; - } literal_pool_p->source_p = scanner_context.async_source_p; scanner_context.async_source_p = NULL; } @@ -2704,12 +2707,13 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } case SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS: { - bool is_destructuring_binding = false; - #endif /* ENABLED (JERRY_ES2015) */ - if (context_p->token.type != LEXER_RIGHT_PAREN && context_p->token.type != LEXER_EOS) { +#if ENABLED (JERRY_ES2015) + lexer_lit_location_t *argument_literal_p; +#endif /* ENABLED (JERRY_ES2015) */ + while (true) { #if ENABLED (JERRY_ES2015) @@ -2722,7 +2726,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE) { - is_destructuring_binding = true; + argument_literal_p = NULL; break; } #endif /* ENABLED (JERRY_ES2015) */ @@ -2733,7 +2737,11 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } +#if ENABLED (JERRY_ES2015) + argument_literal_p = scanner_append_argument (context_p, &scanner_context); +#else /* !ENABLED (JERRY_ES2015) */ scanner_append_argument (context_p, &scanner_context); +#endif /* ENABLED (JERRY_ES2015) */ lexer_next_token (context_p); @@ -2743,38 +2751,50 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } lexer_next_token (context_p); } - } #if ENABLED (JERRY_ES2015) - if (is_destructuring_binding) - { - scanner_context.active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED; + if (argument_literal_p == NULL) + { + scanner_context.active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED; - parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PARAMETERS); - scanner_append_hole (context_p, &scanner_context); - scanner_push_destructuring_pattern (context_p, &scanner_context, SCANNER_BINDING_ARG, false); + parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PARAMETERS); + scanner_append_hole (context_p, &scanner_context); + scanner_push_destructuring_pattern (context_p, &scanner_context, SCANNER_BINDING_ARG, false); - if (context_p->token.type == LEXER_LEFT_SQUARE) - { - parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL); - scanner_context.mode = SCAN_MODE_BINDING; - break; + if (context_p->token.type == LEXER_LEFT_SQUARE) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL); + scanner_context.mode = SCAN_MODE_BINDING; + break; + } + + parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); + scanner_context.mode = SCAN_MODE_PROPERTY_NAME; + continue; } - parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); - scanner_context.mode = SCAN_MODE_PROPERTY_NAME; - continue; - } + if (context_p->token.type == LEXER_ASSIGN) + { + scanner_context.active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED; - if (context_p->token.type == LEXER_ASSIGN) - { - scanner_context.active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED; + parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PARAMETERS); + scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; - parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PARAMETERS); - scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; - break; - } + if (argument_literal_p->type & SCANNER_LITERAL_IS_USED) + { + JERRY_ASSERT (argument_literal_p->type & SCANNER_LITERAL_EARLY_CREATE); + break; + } + + scanner_binding_literal_t binding_literal; + binding_literal.literal_p = argument_literal_p; + + parser_stack_push (context_p, &binding_literal, sizeof (scanner_binding_literal_t)); + parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_INIT); + break; + } #endif /* ENABLED (JERRY_ES2015) */ + } if (context_p->token.type == LEXER_EOS && stack_top == SCAN_STACK_SCRIPT_FUNCTION) { @@ -3030,7 +3050,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ if (literal_p->type & SCANNER_LITERAL_IS_USED) { - literal_p->type |= SCANNER_LITERAL_ARROW_DESTRUCTURED_ARG_NO_REG; + literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; break; } } @@ -3052,12 +3072,18 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ if (scanner_context.binding_type == SCANNER_BINDING_ARG) { literal_p->type |= SCANNER_LITERAL_IS_ARG; + + if (literal_p->type & SCANNER_LITERAL_IS_USED) + { + literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; + break; + } } } if (literal_p->type & SCANNER_LITERAL_IS_USED) { - literal_p->type |= SCANNER_LITERAL_NO_REG; + literal_p->type |= SCANNER_LITERAL_EARLY_CREATE; break; } } @@ -3298,6 +3324,14 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ length = 2 + 2; } +#if ENABLED (JERRY_ES2015) + if (data_p[0] & SCANNER_STREAM_EARLY_CREATE) + { + JERRY_ASSERT (data_p[0] & SCANNER_STREAM_NO_REG); + JERRY_DEBUG_MSG ("*"); + } +#endif /* ENABLED (JERRY_ES2015) */ + if (data_p[0] & SCANNER_STREAM_NO_REG) { JERRY_DEBUG_MSG ("* "); diff --git a/jerry-core/parser/js/js-scanner.h b/jerry-core/parser/js/js-scanner.h index c8fb58dca2..db1186978e 100644 --- a/jerry-core/parser/js/js-scanner.h +++ b/jerry-core/parser/js/js-scanner.h @@ -131,8 +131,9 @@ typedef struct typedef enum { SCANNER_STREAM_UINT16_DIFF = (1 << 7), /**< relative distance is between -256 and 65535 */ - SCANNER_STREAM_HAS_ESCAPE = (1 << 6), /**< literal has escape */ - SCANNER_STREAM_NO_REG = (1 << 5), /**< identifier cannot be stored in register */ + SCANNER_STREAM_HAS_ESCAPE = (1 << 6), /**< binding has escape */ + SCANNER_STREAM_NO_REG = (1 << 5), /**< binding cannot be stored in register */ + SCANNER_STREAM_EARLY_CREATE = (1 << 4), /**< binding must be created with ECMA_VALUE_UNINITIALIZED */ /* Update SCANNER_STREAM_TYPE_MASK macro if more bits are added. */ } scanner_compressed_stream_flags_t; @@ -210,11 +211,12 @@ typedef enum typedef enum { SCANNER_FUNCTION_ARGUMENTS_NEEDED = (1 << 0), /**< arguments object needs to be created */ + SCANNER_FUNCTION_MAPPED_ARGUMENTS = (1 << 1), /**< arguments object should be mapped */ #if ENABLED (JERRY_ES2015) - 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) + SCANNER_FUNCTION_LEXICAL_ENV_NEEDED = (1 << 2), /**< lexical environment is needed for the function body */ + SCANNER_FUNCTION_STATEMENT = (1 << 3), /**< 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 */ + SCANNER_FUNCTION_ASYNC = (1 << 4), /**< function is async function */ #endif /* ENABLED (JERRY_ES2015) */ } scanner_function_flags_t; diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 80441dd100..33315920cc 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -1366,7 +1366,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ continue; } #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ - case VM_OC_INIT_LOCAL: + case VM_OC_INIT_ARG_OR_FUNC: { uint32_t literal_index, value_index; ecma_value_t lit_value; @@ -1505,6 +1505,44 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } continue; } + case VM_OC_INIT_BINDING: + { + uint32_t literal_index; + + READ_LITERAL_INDEX (literal_index); + + JERRY_ASSERT (literal_index >= register_end); + + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); + + JERRY_ASSERT (ecma_get_lex_env_type (frame_ctx_p->lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + JERRY_ASSERT (ecma_find_named_property (frame_ctx_p->lex_env_p, name_p) == NULL); + + uint8_t prop_attributes = ECMA_PROPERTY_FLAG_WRITABLE; + + if (opcode == CBC_INIT_LET) + { + prop_attributes = ECMA_PROPERTY_ENUMERABLE_WRITABLE; + } + else if (opcode == CBC_INIT_CONST) + { + prop_attributes = ECMA_PROPERTY_FLAG_ENUMERABLE; + } + + ecma_property_value_t *property_value_p; + property_value_p = ecma_create_named_data_property (frame_ctx_p->lex_env_p, + name_p, + prop_attributes, + NULL); + + JERRY_ASSERT (property_value_p->value == ECMA_VALUE_UNDEFINED); + + ecma_value_t value = *(--stack_top_p); + + property_value_p->value = value; + ecma_deref_if_object (value); + continue; + } case VM_OC_THROW_CONST_ERROR: { result = ecma_raise_type_error (ECMA_ERR_MSG ("Constant bindings cannot be reassigned.")); diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index 8d8dd7c590..6cf42f89a3 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -161,7 +161,7 @@ typedef enum VM_OC_ERROR, /**< error while the vm_loop is suspended */ VM_OC_JUMP, /**< jump */ - VM_OC_BRANCH_IF_STRICT_EQUAL, /**< branch if stric equal */ + VM_OC_BRANCH_IF_STRICT_EQUAL, /**< branch if strict equal */ /* These four opcodes must be in this order. */ VM_OC_BRANCH_IF_TRUE, /**< branch if true */ @@ -219,7 +219,7 @@ typedef enum VM_OC_CREATE_BINDING, /**< create variables */ VM_OC_SET_BYTECODE_PTR, /**< setting bytecode pointer */ VM_OC_VAR_EVAL, /**< variable and function evaluation */ - VM_OC_INIT_LOCAL, /**< initialize local variable */ + VM_OC_INIT_ARG_OR_FUNC, /**< create and init a function or argument binding */ #if ENABLED (JERRY_DEBUGGER) VM_OC_BREAKPOINT_ENABLED, /**< enabled breakpoint for debugger */ @@ -235,6 +235,7 @@ typedef enum VM_OC_CHECK_VAR, /**< check redeclared vars in the global scope */ VM_OC_CHECK_LET, /**< check redeclared lets in the global scope */ VM_OC_ASSIGN_LET_CONST, /**< assign values to let/const declarations */ + VM_OC_INIT_BINDING, /**< create and intialize a binding */ VM_OC_THROW_CONST_ERROR, /**< throw invalid assignment to const variable error */ VM_OC_COPY_TO_GLOBAL, /**< copy value to global lex env */ VM_OC_CLONE_CONTEXT, /**< clone lexical environment with let/const declarations */ @@ -298,6 +299,7 @@ typedef enum VM_OC_CHECK_VAR = VM_OC_NONE, /**< check redeclared vars in the global scope */ VM_OC_CHECK_LET = VM_OC_NONE, /**< check redeclared lets in the global scope */ VM_OC_ASSIGN_LET_CONST = VM_OC_NONE, /**< assign values to let/const declarations */ + VM_OC_INIT_BINDING = VM_OC_NONE, /**< create and intialize a binding */ VM_OC_THROW_CONST_ERROR = VM_OC_NONE, /**< throw invalid assignment to const variable error */ VM_OC_COPY_TO_GLOBAL = VM_OC_NONE, /**< copy value to global lex env */ VM_OC_CLONE_CONTEXT = VM_OC_NONE, /**< clone lexical environment with let/const declarations */ diff --git a/tests/jerry/es2015/function-param-init4.js b/tests/jerry/es2015/function-param-init4.js new file mode 100644 index 0000000000..040f1550ca --- /dev/null +++ b/tests/jerry/es2015/function-param-init4.js @@ -0,0 +1,164 @@ +// 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 check_reference_error(code) +{ + try { + eval(code); + assert(false); + } catch (e) { + assert(e instanceof ReferenceError); + } +} + +function f1(a = a) +{ + assert(a === 1) +} +f1(1) +check_reference_error("f1()"); + +function f2([a] = 1 + a) +{ + assert(a === 2) +} +f2([2]) +check_reference_error("f2()"); + +function f3([a = !a]) +{ + assert(a === 2) +} +f3([2]) +check_reference_error("f3([])"); + +function f4([[a]] = a) +{ + assert(a === 3) +} +f4([[3]]) +check_reference_error("f4()"); + +function f5([[a], b = a] = a) +{ + assert(a === 4 && b === 4) +} +f5([[4]]) +check_reference_error("f5()") + +function f6(a = 3 - ((b)), b) +{ + assert(a === 1 && b === 2) +} +f6(1, 2) +check_reference_error("f6(undefined, 2)"); + +function f7(a = b(), [b]) +{ + assert(a === 3 && b === 4) +} +f7(3, [4]) +check_reference_error("f7(undefined, [4])"); + +function f8(a = (function () { return a * 2 })()) +{ + assert(a === 1) +} +f8(1) +check_reference_error("f8()"); + +function f9({a = b, b:{b}}) +{ + assert(a === 2 && b === 3) +} +f9({a:2, b:{b:3}}) +check_reference_error("f9({b:{b:3}})"); + +function f10(a = eval("a")) +{ + assert(a === 1) +} +f10(1) +check_reference_error("f10()"); + +function f11([a] = eval("a")) +{ + assert(a === 2) +} +f11([2]) +check_reference_error("f11()"); + +function f12({a} = eval("a")) +{ + assert(a === 3) +} +f12({a:3}) +check_reference_error("f12()"); + +function f13(a = arguments) +{ + assert(a[0] === undefined) + assert(a[1] === 4) + arguments[0] = 5 + assert(a[0] === 5) +} +f13(undefined, 4) + +function f14(a, b = function() { return a; }(), c = (() => a)()) +{ + assert(a === 6 && b === 6 && c === 6) +} +f14(6) + +function f15(a = (() => b)(), b) +{ + assert(a === 1 && b === 2) +} +f15(1, 2) +check_reference_error("f15(undefined, 2)"); + +var f16 = (a = a) => +{ + assert(a === 1) +} +f16(1) +check_reference_error("f16()"); + +var f17 = ([[a]] = a) => +{ + assert(a === 2) +} +f17([[2]]) +check_reference_error("f17()"); + +var f18 = ({a = b, b:{b}}) => +{ + assert(a === 3 && b === 4) +} +f18({a:3, b:{b:4}}) +check_reference_error("f18({b:{b:4}})"); + +var f19 = (a = eval("a")) => +{ + assert(a === 5) +} +f19(5) +check_reference_error("f19()"); + +var f20 = ([a] = eval("a")) => +{ + assert(a === 6) +} +f20([6]) +check_reference_error("f20()"); diff --git a/tests/jerry/es2015/let15.js b/tests/jerry/es2015/let15.js new file mode 100644 index 0000000000..5b4cdebcb4 --- /dev/null +++ b/tests/jerry/es2015/let15.js @@ -0,0 +1,65 @@ +// 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. + +{ + try { + f() + assert(false) + } catch (e) { + assert(e instanceof ReferenceError) + } + + let a = 1; + + try { + f() + assert(false) + } catch (e) { + assert(e instanceof ReferenceError) + } + + let [b] = [2]; + + try { + f() + assert(false) + } catch (e) { + assert(e instanceof ReferenceError) + } + + const {c} = { c:3 }; + + f(); + function f() { assert(a + b + c === 6) } +} + +{ + let a = 3; + let [b] = [4]; + const {c} = { c:5 }; + + let f = (function () { assert(a + b + c === 12) }) + f(); + + { + function g() { assert(a + b + c === 12) } + g(); + } +} + +{ + class C {} + + assert(function () { return C } () === C); +} diff --git a/tests/unit-core/test-snapshot.c b/tests/unit-core/test-snapshot.c index 96817f97bb..28c5d9eb07 100644 --- a/tests/unit-core/test-snapshot.c +++ b/tests/unit-core/test-snapshot.c @@ -223,15 +223,15 @@ main (void) /* Check the snapshot data. Unused bytes should be filled with zeroes */ const uint8_t expected_data[] = { - 0x4A, 0x52, 0x52, 0x59, 0x2A, 0x00, 0x00, 0x00, + 0x4A, 0x52, 0x52, 0x59, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00, - 0x2C, 0x00, 0xC6, 0x50, 0x00, 0x00, 0x00, 0x00, + 0x2C, 0x00, 0xC9, 0x53, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x00, - 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x73, 0x6E, 0x61, 0x70, 0x73, 0x68, 0x6F, 0x74,