diff --git a/jerry-core/api/jerry-snapshot.c b/jerry-core/api/jerry-snapshot.c index f16f3b0e7..17829e27c 100644 --- a/jerry-core/api/jerry-snapshot.c +++ b/jerry-core/api/jerry-snapshot.c @@ -417,7 +417,7 @@ static_snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< c } } - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (compiled_code_p)) + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { buffer_p += ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG; literal_start_p = ((ecma_value_t *) buffer_p) - argument_end; @@ -489,7 +489,7 @@ jerry_snapshot_set_offsets (uint32_t *buffer_p, /**< buffer */ } } - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_p)) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { uint8_t *byte_p = (uint8_t *) bytecode_p; byte_p += ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; @@ -582,7 +582,7 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th uint8_t *byte_p = (uint8_t *) bytecode_p; cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) byte_p; - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_p)) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { argument_end = args_p->argument_end; } @@ -596,7 +596,7 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th uint8_t *byte_p = (uint8_t *) bytecode_p; cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) byte_p; - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_p)) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { argument_end = args_p->argument_end; } @@ -1092,7 +1092,7 @@ scan_snapshot_functions (const uint8_t *buffer_p, /**< snapshot buffer start */ } } - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_p)) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { uint8_t *byte_p = (uint8_t *) bytecode_p; byte_p += ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; @@ -1170,7 +1170,7 @@ update_literal_offsets (uint8_t *buffer_p, /**< [in,out] snapshot buffer start * } } - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_p)) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { uint8_t *byte_p = (uint8_t *) bytecode_p; byte_p += ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; diff --git a/jerry-core/ecma/base/ecma-literal-storage.c b/jerry-core/ecma/base/ecma-literal-storage.c index 305f80ec0..e4dc58ce3 100644 --- a/jerry-core/ecma/base/ecma-literal-storage.c +++ b/jerry-core/ecma/base/ecma-literal-storage.c @@ -346,7 +346,7 @@ ecma_save_literals_add_compiled_code (const ecma_compiled_code_t *compiled_code_ const_literal_end = args_p->const_literal_end - register_end; literal_end = args_p->literal_end - register_end; - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (compiled_code_p)) + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { argument_end = args_p->argument_end; } @@ -361,7 +361,7 @@ ecma_save_literals_add_compiled_code (const ecma_compiled_code_t *compiled_code_ const_literal_end = args_p->const_literal_end - register_end; literal_end = args_p->literal_end - register_end; - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (compiled_code_p)) + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { argument_end = args_p->argument_end; } diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index 38404814a..4072f1872 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -47,7 +47,7 @@ ecma_op_resource_name (const ecma_compiled_code_t *bytecode_header_p) ecma_length_t formal_params_number = 0; - if (CBC_NON_STRICT_ARGUMENTS_NEEDED (bytecode_header_p)) + if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { @@ -832,7 +832,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ else { local_env_p = ecma_create_decl_lex_env (scope_p); - if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED) + if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_IS_ARGUMENTS_NEEDED) { ecma_op_create_arguments_object (func_obj_p, local_env_p, @@ -908,7 +908,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ { local_env_p = ecma_create_decl_lex_env (scope_p); - JERRY_ASSERT (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED)); + JERRY_ASSERT (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_IS_ARGUMENTS_NEEDED)); } ecma_value_t ret_value = vm_run (bytecode_data_p, diff --git a/jerry-core/ecma/operations/ecma-objects-arguments.c b/jerry-core/ecma/operations/ecma-objects-arguments.c index e6528fb7c..313db79d5 100644 --- a/jerry-core/ecma/operations/ecma-objects-arguments.c +++ b/jerry-core/ecma/operations/ecma-objects-arguments.c @@ -68,7 +68,9 @@ ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function ecma_object_t *obj_p; - if (!is_strict && arguments_number > 0 && formal_params_number > 0) + if ((bytecode_data_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) + && arguments_number > 0 + && formal_params_number > 0) { size_t formal_params_size = formal_params_number * sizeof (ecma_value_t); diff --git a/jerry-core/include/jerryscript-snapshot.h b/jerry-core/include/jerryscript-snapshot.h index e8d456807..c5421af74 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 (29u) +#define JERRY_SNAPSHOT_VERSION (30u) /** * 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 85404cec6..95f085ed7 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -308,6 +308,8 @@ VM_OC_INIT_LOCALS) \ CBC_OPCODE (CBC_CREATE_CONST, CBC_HAS_LITERAL_ARG, 0, \ VM_OC_INIT_LOCALS) \ + CBC_OPCODE (CBC_CREATE_DESTRUCTURED_ARG, CBC_HAS_LITERAL_ARG, 0, \ + VM_OC_NONE) \ CBC_OPCODE (CBC_INIT_LOCAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ VM_OC_INIT_LOCALS) \ CBC_OPCODE (CBC_CREATE_VAR_EVAL, CBC_HAS_LITERAL_ARG, 0, \ @@ -538,7 +540,7 @@ -1 + PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION, VM_OC_CLASS_HERITAGE) \ CBC_OPCODE (CBC_EXT_INITIALIZER_PUSH_PROP, CBC_NO_FLAG, 0, \ VM_OC_INITIALIZER_PUSH_PROP | VM_OC_GET_STACK) \ - CBC_FORWARD_BRANCH (CBC_EXT_DEFAULT_INITIALIZER, 0, \ + CBC_FORWARD_BRANCH (CBC_EXT_DEFAULT_INITIALIZER, -1, \ VM_OC_DEFAULT_INITIALIZER) \ \ /* Basic opcodes. */ \ @@ -712,21 +714,21 @@ typedef enum CBC_CODE_FLAGS_FULL_LITERAL_ENCODING = (1u << 1), /**< full literal encoding mode is enabled */ CBC_CODE_FLAGS_UINT16_ARGUMENTS = (1u << 2), /**< compiled code data is cbc_uint16_arguments_t */ CBC_CODE_FLAGS_STRICT_MODE = (1u << 3), /**< strict mode is enabled */ - CBC_CODE_FLAGS_ARGUMENTS_NEEDED = (1u << 4), /**< arguments object must be constructed */ - CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED = (1u << 5), /**< no need to create a lexical environment */ - CBC_CODE_FLAGS_ARROW_FUNCTION = (1u << 6), /**< this function is an arrow function */ - CBC_CODE_FLAGS_STATIC_FUNCTION = (1u << 7), /**< this function is a static snapshot function */ - CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 8), /**< this function should be ignored by debugger */ - CBC_CODE_FLAGS_CONSTRUCTOR = (1u << 9), /**< this function is a constructor */ - CBC_CODE_FLAGS_REST_PARAMETER = (1u << 10), /**< this function has rest parameter */ + CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED = (1u << 4), /**< mapped arguments object must be constructed */ + CBC_CODE_FLAGS_UNMAPPED_ARGUMENTS_NEEDED = (1u << 5), /**< mapped arguments object must be constructed */ + CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED = (1u << 6), /**< no need to create a lexical environment */ + CBC_CODE_FLAGS_ARROW_FUNCTION = (1u << 7), /**< this function is an arrow function */ + CBC_CODE_FLAGS_STATIC_FUNCTION = (1u << 8), /**< this function is a static snapshot function */ + CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 9), /**< this function should be ignored by debugger */ + CBC_CODE_FLAGS_CONSTRUCTOR = (1u << 10), /**< this function is a constructor */ + CBC_CODE_FLAGS_REST_PARAMETER = (1u << 11), /**< this function has rest parameter */ } cbc_code_flags; /** - * Non-strict arguments object must be constructed + * Any arguments object is needed */ -#define CBC_NON_STRICT_ARGUMENTS_NEEDED(compiled_code_p) \ - (((compiled_code_p)->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED) \ - && !((compiled_code_p)->status_flags & CBC_CODE_FLAGS_STRICT_MODE)) +#define CBC_CODE_FLAGS_IS_ARGUMENTS_NEEDED \ + (CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED | CBC_CODE_FLAGS_UNMAPPED_ARGUMENTS_NEEDED) #define CBC_OPCODE(arg1, arg2, arg3, arg4) arg1, diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 6effd20a6..4faf2cf99 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -388,18 +388,14 @@ parser_append_object_literal_item (parser_context_t *context_p, /**< context */ #endif /* !ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015) -/** - * Definition of parse object initializer. - */ -static void -parser_parse_object_initializer (parser_context_t *context_p, parser_pattern_flags_t flags); - -/** - * Definition of parse array initializer. - */ +/** Forward definition of parse array initializer. */ static void parser_parse_array_initializer (parser_context_t *context_p, parser_pattern_flags_t flags); +/** Forward definition of parse object initializer. */ +static void +parser_parse_object_initializer (parser_context_t *context_p, parser_pattern_flags_t flags); + /** * Description of "get" literal string. */ @@ -2111,7 +2107,6 @@ 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 (context_p, CBC_POP); } if ((flags & (PARSER_PATTERN_TARGET_ON_STACK | PARSER_PATTERN_TARGET_DEFAULT)) != PARSER_PATTERN_TARGET_ON_STACK) @@ -2177,8 +2172,7 @@ parser_pattern_finalize (parser_context_t *context_p, /**< context */ lexer_next_token (context_p); } - if ((flags & PARSER_PATTERN_BINDING) - && !(flags & PARSER_PATTERN_NESTED_PATTERN)) + if ((flags & (PARSER_PATTERN_BINDING | PARSER_PATTERN_NESTED_PATTERN)) == PARSER_PATTERN_BINDING) { /* Pop the result of the expression. */ parser_emit_cbc (context_p, CBC_POP); @@ -2235,9 +2229,8 @@ 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 (context_p, CBC_POP); - parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA | PARSE_EXPR_LEFT_HAND_SIDE); + parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); parser_set_branch_to_current_position (context_p, &skip_init); } @@ -2336,6 +2329,15 @@ parser_pattern_process_assignment (parser_context_t *context_p, /**< context */ parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED); } + if (flags & PARSER_PATTERN_ARGUMENTS) + { + if (context_p->lit_object.literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) + { + parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED); + } + context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_FUNCTION_ARGUMENT; + } + #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) parser_module_append_export_name (context_p); #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ @@ -2461,15 +2463,6 @@ parser_parse_object_initializer (parser_context_t *context_p, /**< context */ lexer_next_token (context_p); - if (push_prop_opcode != CBC_EXT_INITIALIZER_PUSH_PROP - && (context_p->token.type == LEXER_RIGHT_BRACE - || context_p->token.type == LEXER_ASSIGN - || context_p->token.type == LEXER_COMMA)) - { - parser_reparse_as_common_identifier (context_p, start_line, start_column); - lexer_next_token (context_p); - } - if (context_p->token.type == LEXER_COLON) { lexer_next_token (context_p); @@ -2477,6 +2470,24 @@ parser_parse_object_initializer (parser_context_t *context_p, /**< context */ } else { + if (push_prop_opcode != CBC_EXT_INITIALIZER_PUSH_PROP + && (context_p->token.type == LEXER_RIGHT_BRACE + || context_p->token.type == LEXER_ASSIGN + || context_p->token.type == LEXER_COMMA)) + { + parser_reparse_as_common_identifier (context_p, start_line, start_column); + lexer_next_token (context_p); + } + + if (flags & PARSER_PATTERN_ARGUMENTS) + { + if (context_p->lit_object.literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) + { + parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED); + } + context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_FUNCTION_ARGUMENT; + } + #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) parser_module_append_export_name (context_p); #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index d4432f3e6..e1fed8e03 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -51,21 +51,22 @@ typedef enum PARSER_HAS_NON_STRICT_ARG = (1u << 6), /**< the function has arguments which * are not supported in strict mode */ PARSER_ARGUMENTS_NEEDED = (1u << 7), /**< arguments object must be created */ - PARSER_LEXICAL_ENV_NEEDED = (1u << 9), /**< lexical environment object must be created */ - PARSER_INSIDE_WITH = (1u << 10), /**< code block is inside a with statement */ - PARSER_RESOLVE_BASE_FOR_CALLS = (1u << 11), /**< the this object must be resolved when + PARSER_LEXICAL_ENV_NEEDED = (1u << 8), /**< lexical environment object must be created */ + PARSER_INSIDE_WITH = (1u << 9), /**< code block is inside a with statement */ + PARSER_RESOLVE_BASE_FOR_CALLS = (1u << 10), /**< the this object must be resolved when * a function without a base object is called */ - PARSER_HAS_INITIALIZED_VARS = (1u << 12), /**< a CBC_INITIALIZE_VARS instruction must be emitted */ - PARSER_HAS_LATE_LIT_INIT = (1u << 13), /**< allocate memory for this string after + PARSER_HAS_INITIALIZED_VARS = (1u << 11), /**< a CBC_INITIALIZE_VARS instruction must be emitted */ + PARSER_HAS_LATE_LIT_INIT = (1u << 12), /**< allocate memory for this string after * the local parser data is freed */ - PARSER_NO_END_LABEL = (1u << 14), /**< return instruction must be inserted + PARSER_NO_END_LABEL = (1u << 13), /**< return instruction must be inserted * after the last byte code */ - PARSER_DEBUGGER_BREAKPOINT_APPENDED = (1u << 15), /**< pending (unsent) breakpoint + PARSER_DEBUGGER_BREAKPOINT_APPENDED = (1u << 14), /**< pending (unsent) breakpoint * info is available */ #if ENABLED (JERRY_ES2015) - PARSER_INSIDE_BLOCK = (1u << 16), /**< script has a lexical environment for let and const */ - PARSER_IS_ARROW_FUNCTION = (1u << 17), /**< an arrow function is parsed */ - PARSER_ARROW_PARSE_ARGS = (1u << 18), /**< parse the argument list of an arrow function */ + PARSER_INSIDE_BLOCK = (1u << 15), /**< script has a lexical environment for let and const */ + PARSER_IS_ARROW_FUNCTION = (1u << 16), /**< an arrow function is parsed */ + PARSER_ARROW_PARSE_ARGS = (1u << 17), /**< parse the argument list of an arrow function */ + 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 four status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */ PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed (this value must be kept in @@ -107,10 +108,11 @@ typedef enum PARSER_PATTERN_NO_OPTS = 0, /**< parse the expression after '=' */ PARSER_PATTERN_BINDING = (1u << 0), /**< parse BindingPattern */ PARSER_PATTERN_TARGET_ON_STACK = (1u << 1), /**< assignment target is the topmost element on the stack */ - PARSER_PATTERN_TARGET_DEFAULT = (1u << 3), /**< perform default value comparison for assignment target */ - PARSER_PATTERN_NESTED_PATTERN = (1u << 4), /**< parse patter inside a pattern */ - PARSER_PATTERN_LEXICAL = (1u << 5), /**< pattern is a lexical (let/const) declaration */ - PARSER_PATTERN_REST_ELEMENT = (1u << 6), /**< parse rest array initializer */ + 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_REST_ELEMENT = (1u << 5), /**< parse rest array initializer */ + PARSER_PATTERN_ARGUMENTS = (1u << 6), /**< parse arguments binding */ } parser_pattern_flags_t; /** @@ -159,8 +161,23 @@ typedef enum */ #define PARSER_IS_CLASS_CONSTRUCTOR_SUPER(flag) \ (((flag) & PARSER_CLASS_CONSTRUCTOR_SUPER) == PARSER_CLASS_CONSTRUCTOR_SUPER) + +/* 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. */ +#define PARSER_ARGUMENTS_RELATED_FLAGS \ + (PARSER_ARGUMENTS_NEEDED | PARSER_IS_STRICT) + #endif /* ENABLED (JERRY_ES2015) */ +/* Checks whether unmapped arguments are needed. */ +#define PARSER_NEEDS_MAPPED_ARGUMENTS(status_flags) \ + (((status_flags) & PARSER_ARGUMENTS_RELATED_FLAGS) == PARSER_ARGUMENTS_NEEDED) + /* The maximum of PARSER_CBC_STREAM_PAGE_SIZE is 127. */ #define PARSER_CBC_STREAM_PAGE_SIZE \ ((uint32_t) (64 - sizeof (void *))) diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 7f3bd81ad..1cc439a04 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -654,9 +654,14 @@ parse_print_final_cbc (ecma_compiled_code_t *compiled_code_p, /**< compiled code JERRY_DEBUG_MSG (",strict_mode"); } - if (compiled_code_p->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED) + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED) { - JERRY_DEBUG_MSG (",arguments_needed"); + JERRY_DEBUG_MSG (",mapped_arguments_needed"); + } + + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UNMAPPED_ARGUMENTS_NEEDED) + { + JERRY_DEBUG_MSG (",unmapped_arguments_needed"); } if (compiled_code_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) @@ -1148,8 +1153,7 @@ parser_post_processing (parser_context_t *context_p) /**< context */ total_size += literal_length + length; - if ((context_p->status_flags & PARSER_ARGUMENTS_NEEDED) - && !(context_p->status_flags & PARSER_IS_STRICT)) + if (PARSER_NEEDS_MAPPED_ARGUMENTS (context_p->status_flags)) { total_size += context_p->argument_count * sizeof (ecma_value_t); } @@ -1243,7 +1247,14 @@ parser_post_processing (parser_context_t *context_p) /**< context */ if (context_p->status_flags & PARSER_ARGUMENTS_NEEDED) { - compiled_code_p->status_flags |= CBC_CODE_FLAGS_ARGUMENTS_NEEDED; + if (PARSER_NEEDS_MAPPED_ARGUMENTS (context_p->status_flags)) + { + compiled_code_p->status_flags |= CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED; + } + else + { + compiled_code_p->status_flags |= CBC_CODE_FLAGS_UNMAPPED_ARGUMENTS_NEEDED; + } /* Arguments is stored in the lexical environment. */ context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED; @@ -1513,8 +1524,7 @@ parser_post_processing (parser_context_t *context_p) /**< context */ } #endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ - if ((context_p->status_flags & PARSER_ARGUMENTS_NEEDED) - && !(context_p->status_flags & PARSER_IS_STRICT)) + if (PARSER_NEEDS_MAPPED_ARGUMENTS (context_p->status_flags)) { parser_list_iterator_t literal_iterator; uint16_t argument_count = 0; @@ -1557,8 +1567,7 @@ parser_post_processing (parser_context_t *context_p) /**< context */ { ecma_value_t *resource_name_p = (ecma_value_t *) (((uint8_t *) compiled_code_p) + total_size); - if ((context_p->status_flags & PARSER_ARGUMENTS_NEEDED) - && !(context_p->status_flags & PARSER_IS_STRICT)) + if (PARSER_NEEDS_MAPPED_ARGUMENTS (context_p->status_flags)) { resource_name_p -= context_p->argument_count; } @@ -1607,7 +1616,6 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ { #if ENABLED (JERRY_ES2015) bool duplicated_argument_names = false; - bool initializer_found = false; #endif /* ENABLED (JERRY_ES2015) */ JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION); @@ -1637,7 +1645,47 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES); } - context_p->status_flags |= PARSER_FUNCTION_HAS_REST_PARAM; + context_p->status_flags |= PARSER_FUNCTION_HAS_REST_PARAM | PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM; + } + else if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE) + { + if (duplicated_argument_names) + { + parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES); + } + + context_p->status_flags |= PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM; + + parser_emit_cbc_literal (context_p, + CBC_PUSH_LITERAL, + (uint16_t) (PARSER_REGISTER_START + context_p->argument_count)); + + uint32_t flags = (PARSER_PATTERN_BINDING + | PARSER_PATTERN_TARGET_ON_STACK + | PARSER_PATTERN_LEXICAL + | PARSER_PATTERN_ARGUMENTS); + + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER); + flags |= PARSER_PATTERN_TARGET_DEFAULT; + } + + parser_parse_initializer (context_p, (parser_pattern_flags_t) flags); + + 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; + } + + lexer_next_token (context_p); + continue; } #endif /* ENABLED (JERRY_ES2015) */ @@ -1660,12 +1708,10 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ if (JERRY_UNLIKELY (context_p->lit_object.literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)) { #if ENABLED (JERRY_ES2015) - if (initializer_found) + if (context_p->status_flags & PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM) { parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES); } -#endif /* ENABLED (JERRY_ES2015) */ -#if ENABLED (JERRY_ES2015) duplicated_argument_names = true; #endif /* ENABLED (JERRY_ES2015) */ @@ -1698,7 +1744,8 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ { parser_raise_error (context_p, PARSER_ERR_DUPLICATED_ARGUMENT_NAMES); } - initializer_found = true; + + 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); diff --git a/jerry-core/parser/js/js-scanner-internal.h b/jerry-core/parser/js/js-scanner-internal.h index 67ff54726..7bad87245 100644 --- a/jerry-core/parser/js/js-scanner-internal.h +++ b/jerry-core/parser/js/js-scanner-internal.h @@ -49,11 +49,27 @@ typedef enum { SCANNER_LITERAL_IS_ARG = (1 << 0), /**< literal is argument */ SCANNER_LITERAL_IS_VAR = (1 << 1), /**< literal is var */ +#if ENABLED (JERRY_ES2015) + /** literal is a destructured argument binding of a possible arrow function */ + SCANNER_LITERAL_IS_ARROW_DESTRUCTURED_ARG = SCANNER_LITERAL_IS_VAR, +#endif /* ENABLED (JERRY_ES2015) */ SCANNER_LITERAL_IS_FUNC = (1 << 2), /**< literal is function */ - SCANNER_LITERAL_NO_REG = (1 << 3), /**< literal cannot be stored in register */ +#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) + /** literal is a function declared in this block (prevents declaring let/const with the same name) */ + SCANNER_LITERAL_IS_FUNC_DECLARATION = SCANNER_LITERAL_IS_LET, +#endif /* ENABLED (JERRY_ES2015) */ SCANNER_LITERAL_IS_CONST = (1 << 5), /**< literal is const */ #if ENABLED (JERRY_ES2015) + /** literal is a destructured argument binding */ + SCANNER_LITERAL_IS_DESTRUCTURED_ARG = SCANNER_LITERAL_IS_CONST, + /** literal is a local function */ + SCANNER_LITERAL_IS_FUNC_LOCAL = SCANNER_LITERAL_IS_CONST, SCANNER_LITERAL_IS_USED = (1 << 6), /**< literal is used */ #endif /* ENABLED (JERRY_ES2015) */ } scanner_literal_type_flags_t; @@ -61,9 +77,18 @@ typedef enum /* * Known combinations: * - * SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_LET : function declared in this block, might be let or var - * SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_CONST : function declared in this block, must be let - * SCANNER_LITERAL_IS_LET | SCANNER_LITERAL_IS_CONST : module import on global scope, catch block variable otherwise + * SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_FUNC_DECLARATION : + * function declared in this block, might be let or var + * SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_FUNC_LOCAL : + * function is visible only in this block + * SCANNER_LITERAL_IS_LOCAL : + * module import on global scope, catch block variable otherwise + * SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_FUNC : + * a function argument which is reassigned to a function later + * SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_DESTRUCTURED_ARG : + * destructured binding argument + * SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_DESTRUCTURED_ARG | SCANNER_LITERAL_IS_FUNC : + * destructured binding argument which is reassigned to a function later */ /** @@ -104,6 +129,8 @@ typedef enum SCANNER_BINDING_VAR, /**< destructuring var binding */ SCANNER_BINDING_LET, /**< destructuring let binding */ SCANNER_BINDING_CONST, /**< destructuring const binding */ + SCANNER_BINDING_ARG, /**< destructuring arg binding */ + SCANNER_BINDING_ARROW_ARG, /**< possible destructuring arg binding of an arrow function */ } scanner_binding_type_t; /** @@ -222,6 +249,7 @@ void scanner_detect_eval_call (parser_context_t *context_p, scanner_context_t *s void scanner_push_destructuring_pattern (parser_context_t *context_p, scanner_context_t *scanner_context_p, uint8_t binding_type, bool is_nested); void scanner_pop_binding_list (scanner_context_t *scanner_context_p); +void scanner_append_hole (parser_context_t *context_p, scanner_context_t *scanner_context_p); #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/jerry-core/parser/js/js-scanner-util.c b/jerry-core/parser/js/js-scanner-util.c index ca31ccf15..a9f9f297c 100644 --- a/jerry-core/parser/js/js-scanner-util.c +++ b/jerry-core/parser/js/js-scanner-util.c @@ -34,6 +34,31 @@ JERRY_STATIC_ASSERT (PARSER_MAXIMUM_NUMBER_OF_LITERALS + PARSER_MAXIMUM_NUMBER_OF_REGISTERS < PARSER_REGISTER_START, maximum_number_of_literals_plus_registers_must_be_less_than_register_start); +#if ENABLED (JERRY_ES2015) + +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); + +JERRY_STATIC_ASSERT ((SCANNER_LITERAL_IS_CONST & SCANNER_LITERAL_IS_LOCAL) != 0, + is_const_flag_must_use_local_flags); + +JERRY_STATIC_ASSERT ((SCANNER_LITERAL_IS_FUNC_DECLARATION & SCANNER_LITERAL_IS_LOCAL) != 0, + is_func_declaration_flag_must_use_local_flags); + +JERRY_STATIC_ASSERT ((SCANNER_LITERAL_IS_DESTRUCTURED_ARG & SCANNER_LITERAL_IS_LOCAL) != 0, + is_arg_binding_flag_must_use_local_flags); + +JERRY_STATIC_ASSERT (SCANNER_LITERAL_IS_FUNC_DECLARATION != SCANNER_LITERAL_IS_DESTRUCTURED_ARG, + is_func_declaration_must_be_different_from_is_arg_binding); + +#endif /* ENABLED (JERRY_ES2015) */ + /** * Raise a scanner error. */ @@ -116,9 +141,13 @@ scanner_get_stream_size (scanner_info_t *info_p, /**< scanner info block */ #if ENABLED (JERRY_ES2015) case SCANNER_STREAM_TYPE_LET: case SCANNER_STREAM_TYPE_CONST: + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG: #endif /* ENABLED (JERRY_ES2015) */ case SCANNER_STREAM_TYPE_ARG: case SCANNER_STREAM_TYPE_ARG_FUNC: +#if ENABLED (JERRY_ES2015) + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC: +#endif /* ENABLED (JERRY_ES2015) */ case SCANNER_STREAM_TYPE_FUNC: #if ENABLED (JERRY_ES2015) case SCANNER_STREAM_TYPE_FUNC_LOCAL: @@ -395,6 +424,16 @@ scanner_push_literal_pool (parser_context_t *context_p, /**< context */ JERRY_STATIC_ASSERT (PARSER_MAXIMUM_IDENT_LENGTH <= UINT8_MAX, maximum_ident_length_must_fit_in_a_byte); +/** + * Checks whether a literal is equal to "arguments". + */ +static inline bool JERRY_ATTR_ALWAYS_INLINE +scanner_literal_is_arguments (lexer_lit_location_t *literal_p) /**< literal */ +{ + return (literal_p->length == 9 + && lexer_compare_identifiers (literal_p->char_p, (const uint8_t *) "arguments", 9)); +} /* scanner_literal_is_arguments */ + /** * Pop the last literal pool from the end. */ @@ -445,9 +484,7 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ continue; } - if (search_arguments - && literal_p->length == 9 - && lexer_compare_identifiers (literal_p->char_p, (const uint8_t *) "arguments", 9)) + if (search_arguments && scanner_literal_is_arguments (literal_p)) { search_arguments = false; @@ -542,10 +579,12 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ #if ENABLED (JERRY_ES2015) extended_type |= SCANNER_LITERAL_IS_USED; - if (literal_location_p->type & SCANNER_LITERAL_IS_LOCAL) + if ((type & SCANNER_LITERAL_IS_ARG) + || (!(literal_location_p->type & SCANNER_LITERAL_IS_ARG) + && (literal_location_p->type & SCANNER_LITERAL_IS_LOCAL))) { - JERRY_ASSERT (!(type & SCANNER_LITERAL_IS_VAR)); - /* Clears the SCANNER_LITERAL_IS_FUNC flag. */ + /* Clears the SCANNER_LITERAL_IS_VAR and SCANNER_LITERAL_IS_FUNC flags + * for speculative arrow paramters and local (non-var) functions. */ type = 0; } #endif /* ENABLED (JERRY_ES2015) */ @@ -637,9 +676,16 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ if (literal_p->type & SCANNER_LITERAL_IS_ARG) { type = SCANNER_STREAM_TYPE_ARG_FUNC; + +#if ENABLED (JERRY_ES2015) + if (literal_p->type & SCANNER_LITERAL_IS_DESTRUCTURED_ARG) + { + type = SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC; + } +#endif /* ENABLED (JERRY_ES2015) */ } #if ENABLED (JERRY_ES2015) - else if (literal_p->type & SCANNER_LITERAL_IS_CONST) + else if (literal_p->type & SCANNER_LITERAL_IS_FUNC_LOCAL) { type = SCANNER_STREAM_TYPE_FUNC_LOCAL; } @@ -648,6 +694,13 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ else if (literal_p->type & SCANNER_LITERAL_IS_ARG) { type = SCANNER_STREAM_TYPE_ARG; + +#if ENABLED (JERRY_ES2015) + if (literal_p->type & SCANNER_LITERAL_IS_DESTRUCTURED_ARG) + { + type = SCANNER_STREAM_TYPE_DESTRUCTURED_ARG; + } +#endif /* ENABLED (JERRY_ES2015) */ } #if ENABLED (JERRY_ES2015) else if (literal_p->type & SCANNER_LITERAL_IS_LET) @@ -759,10 +812,19 @@ scanner_filter_arguments (parser_context_t *context_p, /**< context */ literal_p->type |= SCANNER_LITERAL_NO_REG; } - if (!(literal_p->type & SCANNER_LITERAL_IS_ARG)) + uint8_t type = literal_p->type; + + if (!(type & SCANNER_LITERAL_IS_ARG) && !(has_arguments && scanner_literal_is_arguments (literal_p))) { break; } + +#if ENABLED (JERRY_ES2015) + if (type & (SCANNER_LITERAL_IS_DESTRUCTURED_ARG | SCANNER_LITERAL_IS_ARROW_DESTRUCTURED_ARG)) + { + break; + } +#endif /* ENABLED (JERRY_ES2015) */ } if (literal_p == NULL) @@ -784,21 +846,49 @@ scanner_filter_arguments (parser_context_t *context_p, /**< context */ parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator); +#if ENABLED (JERRY_ES2015) + /* Destructured args are placed after the other arguments because of register assignments. */ + bool has_destructured_arg = false; +#endif /* ENABLED (JERRY_ES2015) */ + while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) { - if ((literal_p->type & SCANNER_LITERAL_IS_ARG) - || (has_arguments - && literal_p->length == 9 - && lexer_compare_identifiers (literal_p->char_p, (const uint8_t *) "arguments", 9))) + uint8_t type = literal_p->type; + + if ((type & SCANNER_LITERAL_IS_ARG) || (has_arguments && scanner_literal_is_arguments (literal_p))) { + if (no_reg) + { + literal_p->type |= SCANNER_LITERAL_NO_REG; + } + +#if ENABLED (JERRY_ES2015) + if (type & (SCANNER_LITERAL_IS_DESTRUCTURED_ARG | SCANNER_LITERAL_IS_ARROW_DESTRUCTURED_ARG)) + { + has_destructured_arg = true; + + if (type & SCANNER_LITERAL_IS_DESTRUCTURED_ARG) + { + continue; + } + + 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; + } +#endif /* ENABLED (JERRY_ES2015) */ + lexer_lit_location_t *new_literal_p; new_literal_p = (lexer_lit_location_t *) parser_list_append (context_p, &new_literal_pool_p->literal_pool); *new_literal_p = *literal_p; - - if (no_reg) - { - new_literal_p->type |= SCANNER_LITERAL_NO_REG; - } } else { @@ -806,12 +896,37 @@ scanner_filter_arguments (parser_context_t *context_p, /**< context */ lexer_lit_location_t *literal_location_p = scanner_add_custom_literal (context_p, prev_literal_pool_p, literal_p); - if (literal_p->type & SCANNER_LITERAL_NO_REG) + if (type & SCANNER_LITERAL_NO_REG) { - literal_location_p->type |= SCANNER_LITERAL_NO_REG; + type |= SCANNER_LITERAL_NO_REG; + } + +#if ENABLED (JERRY_ES2015) + type |= SCANNER_LITERAL_IS_USED; +#endif /* ENABLED (JERRY_ES2015) */ + + literal_location_p->type |= type; + } + } + +#if ENABLED (JERRY_ES2015) + if (has_destructured_arg) + { + 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) + { + const uint8_t expected_flags = SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_DESTRUCTURED_ARG; + + if ((literal_p->type & expected_flags) == expected_flags) + { + lexer_lit_location_t *new_literal_p; + new_literal_p = (lexer_lit_location_t *) parser_list_append (context_p, &new_literal_pool_p->literal_pool); + *new_literal_p = *literal_p; } } } +#endif /* ENABLED (JERRY_ES2015) */ new_literal_pool_p->prev_p = prev_literal_pool_p; @@ -1059,7 +1174,7 @@ scanner_detect_invalid_var (parser_context_t *context_p, /**< context */ lexer_lit_location_t *var_literal_p) /**< var literal */ { if (var_literal_p->type & SCANNER_LITERAL_IS_LOCAL - && !(var_literal_p->type & SCANNER_LITERAL_IS_FUNC) + && !(var_literal_p->type & (SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_ARG)) && (var_literal_p->type & SCANNER_LITERAL_IS_LOCAL) != SCANNER_LITERAL_IS_LOCAL) { scanner_raise_redeclaration_error (context_p); @@ -1082,6 +1197,7 @@ scanner_detect_invalid_var (parser_context_t *context_p, /**< context */ while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) { if (literal_p->type & SCANNER_LITERAL_IS_LOCAL + && !(literal_p->type & SCANNER_LITERAL_IS_ARG) && (literal_p->type & SCANNER_LITERAL_IS_LOCAL) != SCANNER_LITERAL_IS_LOCAL && literal_p->length == length) { @@ -1106,6 +1222,7 @@ scanner_detect_invalid_var (parser_context_t *context_p, /**< context */ while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL) { if (literal_p->type & SCANNER_LITERAL_IS_LOCAL + && !(literal_p->type & SCANNER_LITERAL_IS_ARG) && (literal_p->type & SCANNER_LITERAL_IS_LOCAL) != SCANNER_LITERAL_IS_LOCAL && literal_p->length == length && lexer_compare_identifiers (literal_p->char_p, char_p, length)) @@ -1197,7 +1314,7 @@ scanner_pop_binding_list (scanner_context_t *scanner_context_p) /**< scanner con { scanner_binding_item_t *next_p = item_p->next_p; - JERRY_ASSERT (item_p->literal_p->type & SCANNER_LITERAL_IS_LOCAL); + JERRY_ASSERT (item_p->literal_p->type & (SCANNER_LITERAL_IS_LOCAL | SCANNER_LITERAL_IS_ARG)); scanner_free (item_p, sizeof (scanner_binding_item_t)); item_p = next_p; @@ -1218,6 +1335,23 @@ scanner_pop_binding_list (scanner_context_t *scanner_context_p) /**< scanner con } } /* scanner_pop_binding_list */ +/** + * Append a hole into the literal pool. + */ +void +scanner_append_hole (parser_context_t *context_p, scanner_context_t *scanner_context_p) +{ + scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p; + + lexer_lit_location_t *literal_p; + literal_p = (lexer_lit_location_t *) parser_list_append (context_p, &literal_pool_p->literal_pool); + + literal_p->char_p = NULL; + literal_p->length = 0; + literal_p->type = SCANNER_LITERAL_IS_ARG; + literal_p->has_escape = 0; +} /* scanner_append_hole */ + #endif /* ENABLED (JERRY_ES2015) */ /** @@ -1635,8 +1769,9 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ JERRY_ASSERT ((option_flags & (SCANNER_CREATE_VARS_IS_FUNCTION_BODY | SCANNER_CREATE_VARS_IS_FUNCTION_ARGS)) || (type != SCANNER_STREAM_TYPE_HOLE - && type != SCANNER_STREAM_TYPE_ARG - && type != SCANNER_STREAM_TYPE_ARG_FUNC)); + && !SCANNER_STREAM_TYPE_IS_ARG (type) + && !SCANNER_STREAM_TYPE_IS_ARG_FUNC (type))); + #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) JERRY_ASSERT (type != SCANNER_STREAM_TYPE_IMPORT || (data_p[0] & SCANNER_STREAM_NO_REG)); #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ @@ -1688,7 +1823,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ next_data_p += 2 + 2; } - if (type == SCANNER_STREAM_TYPE_ARG) + if (SCANNER_STREAM_TYPE_IS_ARG (type)) { if (option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY) { @@ -1697,7 +1832,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ } } else if ((option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_ARGS) - && type != SCANNER_STREAM_TYPE_ARG_FUNC) + && !SCANNER_STREAM_TYPE_IS_ARG_FUNC (type)) { /* Function arguments must come first. */ break; @@ -1710,7 +1845,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ lexer_construct_literal_object (context_p, &literal, LEXER_NEW_IDENT_LITERAL); literal.char_p += data_p[1]; - if (type == SCANNER_STREAM_TYPE_ARG_FUNC && (option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY)) + if (SCANNER_STREAM_TYPE_IS_ARG_FUNC (type) && (option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY)) { JERRY_ASSERT (scope_stack_p >= context_p->scope_stack_p + 2); @@ -1798,6 +1933,8 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ #if ENABLED (JERRY_ES2015) case SCANNER_STREAM_TYPE_LET: case SCANNER_STREAM_TYPE_CONST: + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG: + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC: #endif /* ENABLED (JERRY_ES2015) */ { #if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) @@ -1812,13 +1949,24 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ } #if ENABLED (JERRY_ES2015) - if (type == SCANNER_STREAM_TYPE_LET) + switch (type) { - opcode = CBC_CREATE_LET; - } - else if (type == SCANNER_STREAM_TYPE_CONST) - { - opcode = CBC_CREATE_CONST; + case SCANNER_STREAM_TYPE_LET: + { + opcode = CBC_CREATE_LET; + break; + } + case SCANNER_STREAM_TYPE_CONST: + { + opcode = CBC_CREATE_CONST; + break; + } + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG: + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC: + { + opcode = CBC_CREATE_DESTRUCTURED_ARG; + break; + } } #endif /* ENABLED (JERRY_ES2015) */ @@ -1864,7 +2012,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p); #endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ - if (type != SCANNER_STREAM_TYPE_ARG_FUNC) + if (!SCANNER_STREAM_TYPE_IS_ARG_FUNC (type)) { if (func_init_opcode == CBC_INIT_LOCAL #if ENABLED (JERRY_ES2015) diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index dbbf00eab..28971c183 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -255,6 +255,23 @@ scanner_process_arrow_arg (parser_context_t *context_p, /**< context */ } } } + else if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE) + { + scanner_append_hole (context_p, scanner_context_p); + scanner_push_destructuring_pattern (context_p, scanner_context_p, SCANNER_BINDING_ARROW_ARG, false); + + if (context_p->token.type == LEXER_LEFT_BRACE) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); + scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME; + return; + } + + parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL); + scanner_context_p->mode = SCAN_MODE_BINDING; + lexer_next_token (context_p); + return; + } scanner_pop_literal_pool (context_p, scanner_context_p); @@ -551,31 +568,9 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * } #if ENABLED (JERRY_ES2015) case SCAN_STACK_BINDING_INIT: + case SCAN_STACK_BINDING_LIST_INIT: { - scanner_binding_literal_t binding_literal; - - parser_stack_pop_uint8 (context_p); - parser_stack_pop (context_p, &binding_literal, sizeof (scanner_binding_literal_t)); - - if (binding_literal.literal_p->type & SCANNER_LITERAL_IS_USED) - { - binding_literal.literal_p->type |= SCANNER_LITERAL_NO_REG; - } - - if (context_p->stack_top_uint8 == SCAN_STACK_ARRAY_LITERAL - || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL) - { - scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; - return SCAN_KEEP_TOKEN; - } - - JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_LET - || 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); - - scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT; - return SCAN_NEXT_TOKEN; + break; } case SCAN_STACK_ARROW_ARGUMENTS: { @@ -713,15 +708,25 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_ARRAY_LITERAL || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL || context_p->stack_top_uint8 == SCAN_STACK_LET - || context_p->stack_top_uint8 == SCAN_STACK_CONST); + || 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); 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 |= SCANNER_LITERAL_NO_REG; + item_p->literal_p->type |= flag; } item_p = item_p->next_p; } @@ -737,28 +742,31 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * parser_stack_pop_uint8 (context_p); parser_stack_pop (context_p, &binding_literal, sizeof (scanner_binding_literal_t)); + JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_ARRAY_LITERAL + || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL + || context_p->stack_top_uint8 == SCAN_STACK_LET + || 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_ARROW_ARGUMENTS); + if (binding_literal.literal_p->type & SCANNER_LITERAL_IS_USED) { - binding_literal.literal_p->type |= SCANNER_LITERAL_NO_REG; + 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; + } } - if (context_p->stack_top_uint8 == SCAN_STACK_ARRAY_LITERAL - || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL) - { - scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; - return SCAN_KEEP_TOKEN; - } - - if (context_p->stack_top_uint8 == SCAN_STACK_FOR_LET_START - || context_p->stack_top_uint8 == SCAN_STACK_FOR_CONST_START) - { - scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; - return SCAN_KEEP_TOKEN; - } - - JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_LET - || context_p->stack_top_uint8 == SCAN_STACK_CONST); - /* FALLTHRU */ + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + return SCAN_KEEP_TOKEN; } #endif /* ENABLED (JERRY_ES2015) */ case SCAN_STACK_VAR: @@ -1004,6 +1012,11 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * } scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + + if (context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_PARAMETERS) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + } return SCAN_KEEP_TOKEN; } @@ -1441,7 +1454,7 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ #if ENABLED (JERRY_ES2015) if (literal_p->type & SCANNER_LITERAL_IS_LOCAL - && !(literal_p->type & SCANNER_LITERAL_IS_FUNC)) + && !(literal_p->type & (SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_ARG))) { scanner_raise_redeclaration_error (context_p); } @@ -1449,11 +1462,11 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ if ((context_p->status_flags & PARSER_IS_EVAL) && scanner_scope_find_let_declaration (context_p, literal_p)) { - literal_p->type |= SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_CONST; + literal_p->type |= SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_FUNC_LOCAL; } else { - literal_p->type |= SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_LET; + literal_p->type |= SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_FUNC_DECLARATION; } #else literal_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC; @@ -2589,6 +2602,8 @@ 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) @@ -2600,6 +2615,12 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ { lexer_next_token (context_p); } + + if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE) + { + is_destructuring_binding = true; + break; + } #endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_LITERAL @@ -2621,6 +2642,24 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } #if ENABLED (JERRY_ES2015) + if (is_destructuring_binding) + { + 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; + } + + 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) { parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PARAMETERS); @@ -2792,7 +2831,9 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ { JERRY_ASSERT (scanner_context.binding_type == SCANNER_BINDING_VAR || scanner_context.binding_type == SCANNER_BINDING_LET - || scanner_context.binding_type == SCANNER_BINDING_CONST); + || scanner_context.binding_type == SCANNER_BINDING_CONST + || scanner_context.binding_type == SCANNER_BINDING_ARG + || scanner_context.binding_type == SCANNER_BINDING_ARROW_ARG); if (type == LEXER_THREE_DOTS) { @@ -2837,6 +2878,18 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ literal_p->type |= SCANNER_LITERAL_NO_REG; } } + break; + } + + if (scanner_context.binding_type == SCANNER_BINDING_ARROW_ARG) + { + literal_p->type |= SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_ARROW_DESTRUCTURED_ARG; + + if (literal_p->type & SCANNER_LITERAL_IS_USED) + { + literal_p->type |= SCANNER_LITERAL_ARROW_DESTRUCTURED_ARG_NO_REG; + break; + } } else { @@ -2849,38 +2902,41 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ else { literal_p->type |= SCANNER_LITERAL_IS_CONST; + + 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_NO_REG; - } - else - { - scanner_binding_item_t *binding_item_p; - binding_item_p = (scanner_binding_item_t *) scanner_malloc (context_p, sizeof (scanner_binding_item_t)); - - binding_item_p->next_p = scanner_context.active_binding_list_p->items_p; - binding_item_p->literal_p = literal_p; - - scanner_context.active_binding_list_p->items_p = binding_item_p; - - lexer_next_token (context_p); - if (context_p->token.type != LEXER_ASSIGN) - { - continue; - } - - scanner_binding_literal_t binding_literal; - binding_literal.literal_p = literal_p; - - parser_stack_push (context_p, &binding_literal, sizeof (scanner_binding_literal_t)); - parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_INIT); - - scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; + break; } } + scanner_binding_item_t *binding_item_p; + binding_item_p = (scanner_binding_item_t *) scanner_malloc (context_p, sizeof (scanner_binding_item_t)); + + binding_item_p->next_p = scanner_context.active_binding_list_p->items_p; + binding_item_p->literal_p = literal_p; + + scanner_context.active_binding_list_p->items_p = binding_item_p; + + lexer_next_token (context_p); + if (context_p->token.type != LEXER_ASSIGN) + { + continue; + } + + scanner_binding_literal_t binding_literal; + binding_literal.literal_p = literal_p; + + parser_stack_push (context_p, &binding_literal, sizeof (scanner_binding_literal_t)); + parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_INIT); + + scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; break; } #endif /* ENABLED (JERRY_ES2015) */ @@ -3012,7 +3068,19 @@ scan_completed: JERRY_DEBUG_MSG (" CONST "); break; } + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG: + { + JERRY_DEBUG_MSG (" DESTRUCTURED_ARG "); + break; + } #endif /* ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + case SCANNER_STREAM_TYPE_IMPORT: + { + JERRY_DEBUG_MSG (" IMPORT "); + break; + } +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ case SCANNER_STREAM_TYPE_ARG: { JERRY_DEBUG_MSG (" ARG "); @@ -3023,6 +3091,13 @@ scan_completed: JERRY_DEBUG_MSG (" ARG_FUNC "); break; } +#if ENABLED (JERRY_ES2015) + case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC: + { + JERRY_DEBUG_MSG (" DESTRUCTURED_ARG_FUNC "); + break; + } +#endif /* ENABLED (JERRY_ES2015) */ case SCANNER_STREAM_TYPE_FUNC: { JERRY_DEBUG_MSG (" FUNC "); @@ -3035,13 +3110,6 @@ scan_completed: break; } #endif /* ENABLED (JERRY_ES2015) */ -#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - case SCANNER_STREAM_TYPE_IMPORT: - { - JERRY_DEBUG_MSG (" IMPORT "); - break; - } -#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ default: { JERRY_ASSERT ((data_p[0] & SCANNER_STREAM_TYPE_MASK) == SCANNER_STREAM_TYPE_HOLE); diff --git a/jerry-core/parser/js/js-scanner.h b/jerry-core/parser/js/js-scanner.h index 048dac7b7..06af684bb 100644 --- a/jerry-core/parser/js/js-scanner.h +++ b/jerry-core/parser/js/js-scanner.h @@ -145,13 +145,19 @@ typedef enum #if ENABLED (JERRY_ES2015) SCANNER_STREAM_TYPE_LET, /**< let declaration */ SCANNER_STREAM_TYPE_CONST, /**< const declaration */ + SCANNER_STREAM_TYPE_DESTRUCTURED_ARG, /**< destructuring argument declaration */ #endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) SCANNER_STREAM_TYPE_IMPORT, /**< module import */ #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ SCANNER_STREAM_TYPE_ARG, /**< argument declaration */ /* Function types should be at the end. See the SCANNER_STREAM_TYPE_IS_FUNCTION macro. */ - SCANNER_STREAM_TYPE_ARG_FUNC, /**< argument declaration which is later initialized with a function */ + SCANNER_STREAM_TYPE_ARG_FUNC, /**< argument declaration which + * is later initialized with a function */ +#if ENABLED (JERRY_ES2015) + SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC, /**< destructuring argument declaration which + * is later initialized with a function */ +#endif /* ENABLED (JERRY_ES2015) */ SCANNER_STREAM_TYPE_FUNC, /**< local or global function declaration */ #if ENABLED (JERRY_ES2015) SCANNER_STREAM_TYPE_FUNC_LOCAL, /**< always local function declaration */ @@ -164,10 +170,38 @@ typedef enum #define SCANNER_STREAM_TYPE_MASK 0xf /** - * Mask for decoding the type from the compressed stream. + * Checks whether the decoded type represents a function declaration. */ #define SCANNER_STREAM_TYPE_IS_FUNCTION(type) ((type) >= SCANNER_STREAM_TYPE_ARG_FUNC) +#if ENABLED (JERRY_ES2015) + +/** + * Checks whether the decoded type represents a function argument. + */ +#define SCANNER_STREAM_TYPE_IS_ARG(type) \ + ((type) == SCANNER_STREAM_TYPE_ARG || (type) == SCANNER_STREAM_TYPE_DESTRUCTURED_ARG) + +/** + * Checks whether the decoded type represents both a function argument and a function declaration. + */ +#define SCANNER_STREAM_TYPE_IS_ARG_FUNC(type) \ + ((type) == SCANNER_STREAM_TYPE_ARG_FUNC || (type) == SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC) + +#else /* !ENABLED (JERRY_ES2015) */ + +/** + * Checks whether the decoded type represents a function argument. + */ +#define SCANNER_STREAM_TYPE_IS_ARG(type) ((type) == SCANNER_STREAM_TYPE_ARG) + +/** + * Checks whether the decoded type represents both a function argument and a function declaration. + */ +#define SCANNER_STREAM_TYPE_IS_ARG_FUNC(type) ((type) == SCANNER_STREAM_TYPE_ARG_FUNC) + +#endif /* ENABLED (JERRY_ES2015) */ + /** * Constants for u8_arg flags in scanner_function_info_t. */ diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 7ad2663b7..4dabf6388 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -806,6 +806,7 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ #if ENABLED (JERRY_ES2015) case CBC_CREATE_LET: case CBC_CREATE_CONST: + case CBC_CREATE_DESTRUCTURED_ARG: #endif /* ENABLED (JERRY_ES2015) */ { uint32_t literal_index; @@ -1832,10 +1833,15 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_DEFAULT_INITIALIZER: { + JERRY_ASSERT (stack_top_p > frame_ctx_p->registers_p + register_end); + if (stack_top_p[-1] != ECMA_VALUE_UNDEFINED) { byte_code_p = byte_code_start_p + branch_offset; + continue; } + + stack_top_p--; continue; } case VM_OC_REST_INITIALIZER: diff --git a/tests/jerry/es2015/function-param-init2.js b/tests/jerry/es2015/function-param-init2.js index f44df5d0d..a5dea86c4 100644 --- a/tests/jerry/es2015/function-param-init2.js +++ b/tests/jerry/es2015/function-param-init2.js @@ -61,6 +61,8 @@ var arguments = 10; function j(a = arguments[1]) { assert(a === 2); + a = 3; + assert(arguments[0] === undefined) } j(undefined,2); @@ -72,10 +74,27 @@ function k(a = 2) } k(); -function i(a = 3) +function l(a = 3) { const d = 6; assert(d === 6); eval("assert(a === 3)"); } -i(); +l(); + +function m(a, b = 2) +{ + assert(a === 1); + assert(arguments[0] === 1); + assert(b === 2); + assert(arguments[1] === undefined); + + a = 8; + b = 9; + + assert(a === 8); + assert(arguments[0] === 1); + assert(b === 9); + assert(arguments[1] === undefined); +} +m(1); diff --git a/tests/jerry/es2015/function-pattern1.js b/tests/jerry/es2015/function-pattern1.js new file mode 100644 index 000000000..f8643fc60 --- /dev/null +++ b/tests/jerry/es2015/function-pattern1.js @@ -0,0 +1,93 @@ +// 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 must_throw (str, type = SyntaxError) +{ + try + { + eval (str); + assert (false); + } + catch (e) + { + assert (e instanceof type) + } +} + +must_throw ("function f(a, [a]) {}"); +must_throw ("function f([a], a) {}"); +must_throw ("function f(a = b, [b]) {}; f()", ReferenceError); +must_throw ("function f([a+b]) {}"); +must_throw ("function f([a().b]) {}"); + +function a1([a,b]) { + var a, b; + + assert(a === 1); + assert(b === undefined); + + var a = 3; + assert(a === 3); +} +a1([1]); + +function a2([a,b]) { + eval("var a, b"); + assert(a === 1); + assert(b === undefined); + + eval("var a = 3"); + assert(a === 3); +} +a2([1]); + +function f1(a, [b], c, [d], e) +{ + assert (a === 1); + assert (b === 2); + assert (c === 3); + assert (d === 4); + assert (e === 5); +} +f1(1, [2], 3, [4], 5) + +function f2(a, [b], c, [d], e) +{ + eval(""); + assert (a === 1); + assert (b === 2); + assert (c === 3); + assert (d === 4); + assert (e === 5); +} +f2(1, [2], 3, [4], 5) + +var g1 = (a, [b], c, [d], e) => { + assert (a === 1); + assert (b === 2); + assert (c === 3); + assert (d === 4); + assert (e === 5); +} +g1(1, [2], 3, [4], 5) + +var g2 = (a, [b], c, [d], e) => { + eval(""); + assert (a === 1); + assert (b === 2); + assert (c === 3); + assert (d === 4); + assert (e === 5); +} +g2(1, [2], 3, [4], 5) diff --git a/tests/jerry/es2015/function-pattern2.js b/tests/jerry/es2015/function-pattern2.js new file mode 100644 index 000000000..3508883c1 --- /dev/null +++ b/tests/jerry/es2015/function-pattern2.js @@ -0,0 +1,61 @@ +// 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. + +assert((function([a], b, {c}) {}).length === 3); + +function f([a = "x", b = "y", c = "z"]) +{ + assert(a === "a"); + assert(b === "b"); + assert(c === "z"); +} +f("ab") + +function g({ ["x" + "y"]: { a = 4, b = 5 }, }) +{ + assert(a === 1); + assert(b === 5); +} +g({ xy: { a:1 } }); + +function h([,,a,,b,,]) +{ + assert(a === 3); + assert(b === 5); +} +h([1,2,3,4,5,6,7,8]) + +function i([a] = [42], b = a) +{ + assert(a === 42); + assert(b === 42); +} +i(); + +function j(a, [[b = a, [c] = [b], { d } = { d:eval("c") }], e = d + 1] = [[]]) +{ + assert(a === 8); + assert(b === 8); + assert(c === 8); + assert(d === 8); + assert(e === 9); +} +j(8); + +function k([a = function() { return a; }]) +{ + assert(typeof a === "function"); + assert(a() === a); +} +k([]); diff --git a/tests/jerry/es2015/function-rest-parameter.js b/tests/jerry/es2015/function-rest-parameter.js index 35f60c162..e4b536f91 100644 --- a/tests/jerry/es2015/function-rest-parameter.js +++ b/tests/jerry/es2015/function-rest-parameter.js @@ -78,3 +78,18 @@ assert (g2 () === 11); assert (g2 (1) === 3); assert (g2 (1, 2) === 3); assert (g2 (1, 2, 3) === 4); + +function args(a, ...b) +{ + assert(a === 1); + assert(arguments[0] === 1); + + a = 5; + + assert(a === 5); + assert(arguments[0] === 1); + + assert(arguments[1] === 2); + assert(b[0] === 2) +} +args(1, 2); diff --git a/tests/unit-core/test-snapshot.c b/tests/unit-core/test-snapshot.c index 2928a6cf0..55f1dd237 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, 0x1D, 0x00, 0x00, 0x00, + 0x4A, 0x52, 0x52, 0x59, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x01, 0x00, 0x21, 0x00, 0x01, 0x00, + 0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00, - 0x2C, 0x00, 0xBF, 0x4D, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x01, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x2C, 0x00, 0xC0, 0x4E, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x00, - 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4F, 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,