From 83ee9cfca3d7a423a1c8bdc4abdbfa88794a9a18 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Wed, 12 Dec 2018 12:50:03 +0100 Subject: [PATCH] Fix named function expression creation. (#2634) Create a local lexical environment with the name of the function. While this is not too memory efficient, some corner cases requires its existence. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- .../ecma/operations/ecma-function-object.c | 2 + jerry-core/parser/js/byte-code.h | 2 + jerry-core/parser/js/common.h | 9 +- jerry-core/parser/js/js-lexer.c | 48 +++++----- jerry-core/parser/js/js-parser-expr.c | 52 +++++++++++ jerry-core/parser/js/js-parser-internal.h | 1 - jerry-core/parser/js/js-parser-statm.c | 2 +- jerry-core/parser/js/js-parser.c | 89 ++----------------- jerry-core/vm/vm.c | 72 +++++++-------- jerry-core/vm/vm.h | 1 + tests/jerry/function-expr-named.js | 51 +++++++++++ 11 files changed, 182 insertions(+), 147 deletions(-) create mode 100644 tests/jerry/function-expr-named.js diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index 5a122075d..f5a11ed11 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -121,6 +121,8 @@ ecma_object_t * ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */ const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */ { + JERRY_ASSERT (ecma_is_lexical_environment (scope_p)); + /* 1., 4., 13. */ ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index d913fd187..f5ebdb37d 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -560,6 +560,8 @@ -1 + PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION, VM_OC_CLASS_HERITAGE) \ \ /* Basic opcodes. */ \ + CBC_OPCODE (CBC_EXT_PUSH_NAMED_FUNC_EXPRESSION, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 1, \ + VM_OC_PUSH_NAMED_FUNC_EXPR | VM_OC_GET_LITERAL_LITERAL) \ CBC_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_0, CBC_HAS_LITERAL_ARG, 2, \ VM_OC_PUSH_LIT_0 | VM_OC_GET_LITERAL) \ CBC_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE, CBC_HAS_LITERAL_ARG | CBC_HAS_BYTE_ARG, 2, \ diff --git a/jerry-core/parser/js/common.h b/jerry-core/parser/js/common.h index 789eb2642..e0506aed3 100644 --- a/jerry-core/parser/js/common.h +++ b/jerry-core/parser/js/common.h @@ -63,13 +63,12 @@ typedef enum LEXER_FLAG_VAR = (1 << 0), /**< local identifier (var, function arg) */ LEXER_FLAG_NO_REG_STORE = (1 << 1), /**< this local identifier cannot be stored in register */ LEXER_FLAG_INITIALIZED = (1 << 2), /**< this local identifier is initialized with a value */ - LEXER_FLAG_FUNCTION_NAME = (1 << 3), /**< this local identifier has a reference to the function itself */ - LEXER_FLAG_FUNCTION_ARGUMENT = (1 << 4), /**< this local identifier is a function argument */ - LEXER_FLAG_UNUSED_IDENT = (1 << 5), /**< this identifier is referenced by sub-functions, + LEXER_FLAG_FUNCTION_ARGUMENT = (1 << 3), /**< this local identifier is a function argument */ + LEXER_FLAG_UNUSED_IDENT = (1 << 4), /**< this identifier is referenced by sub-functions, * but not referenced by the currently parsed function */ - LEXER_FLAG_SOURCE_PTR = (1 << 6), /**< the literal is directly referenced in the source code + LEXER_FLAG_SOURCE_PTR = (1 << 5), /**< the literal is directly referenced in the source code * (no need to allocate memory) */ - LEXER_FLAG_LATE_INIT = (1 << 7), /**< initialize this variable after the byte code is freed */ + LEXER_FLAG_LATE_INIT = (1 << 6), /**< initialize this variable after the byte code is freed */ } lexer_literal_status_flags_t; /** diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index c95b7f271..f3ba9cc7e 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -1742,35 +1742,33 @@ lexer_construct_literal_object (parser_context_t *context_p, /**< context */ context_p->lit_object.type = LEXER_LITERAL_OBJECT_ANY; - if (literal_type == LEXER_IDENT_LITERAL) + if (literal_type == LEXER_IDENT_LITERAL + && (context_p->status_flags & PARSER_INSIDE_WITH) + && context_p->lit_object.literal_p->type == LEXER_IDENT_LITERAL) { - if ((context_p->status_flags & PARSER_INSIDE_WITH) - && context_p->lit_object.literal_p->type == LEXER_IDENT_LITERAL) + context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE; + } + + if (literal_p->length == 4 + && source_p[0] == LIT_CHAR_LOWERCASE_E + && source_p[3] == LIT_CHAR_LOWERCASE_L + && source_p[1] == LIT_CHAR_LOWERCASE_V + && source_p[2] == LIT_CHAR_LOWERCASE_A) + { + context_p->lit_object.type = LEXER_LITERAL_OBJECT_EVAL; + } + + if (literal_p->length == 9 + && source_p[0] == LIT_CHAR_LOWERCASE_A + && source_p[8] == LIT_CHAR_LOWERCASE_S + && memcmp (source_p + 1, "rgument", 7) == 0) + { + context_p->lit_object.type = LEXER_LITERAL_OBJECT_ARGUMENTS; + if (!(context_p->status_flags & PARSER_ARGUMENTS_NOT_NEEDED)) { + context_p->status_flags |= PARSER_ARGUMENTS_NEEDED | PARSER_LEXICAL_ENV_NEEDED; context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE; } - - if (literal_p->length == 4 - && source_p[0] == LIT_CHAR_LOWERCASE_E - && source_p[3] == LIT_CHAR_LOWERCASE_L - && source_p[1] == LIT_CHAR_LOWERCASE_V - && source_p[2] == LIT_CHAR_LOWERCASE_A) - { - context_p->lit_object.type = LEXER_LITERAL_OBJECT_EVAL; - } - - if (literal_p->length == 9 - && source_p[0] == LIT_CHAR_LOWERCASE_A - && source_p[8] == LIT_CHAR_LOWERCASE_S - && memcmp (source_p + 1, "rgument", 7) == 0) - { - context_p->lit_object.type = LEXER_LITERAL_OBJECT_ARGUMENTS; - if (!(context_p->status_flags & PARSER_ARGUMENTS_NOT_NEEDED)) - { - context_p->status_flags |= PARSER_ARGUMENTS_NEEDED | PARSER_LEXICAL_ENV_NEEDED; - context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE; - } - } } if (destination_start_p != local_byte_array) diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index a42027b62..9e4f46d11 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -889,6 +889,52 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */ uint16_t literal1 = 0; uint16_t literal2 = 0; uint16_t function_literal_index; + int32_t function_name_index = -1; + + if (status_flags & PARSER_IS_FUNC_EXPRESSION) + { +#ifdef JERRY_DEBUGGER + parser_line_counter_t debugger_line = context_p->token.line; + parser_line_counter_t debugger_column = context_p->token.column; +#endif /* JERRY_DEBUGGER */ + + if (!lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)) + { + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_LITERAL + || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { + parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); + } + + parser_flush_cbc (context_p); + + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_STRING_LITERAL); + +#ifdef JERRY_DEBUGGER + if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) + { + jerry_debugger_send_string (JERRY_DEBUGGER_FUNCTION_NAME, + JERRY_DEBUGGER_NO_SUBTYPE, + context_p->lit_object.literal_p->u.char_p, + context_p->lit_object.literal_p->prop.length); + + /* Reset token position for the function. */ + context_p->token.line = debugger_line; + context_p->token.column = debugger_column; + } +#endif /* JERRY_DEBUGGER */ + + if (context_p->token.literal_is_reserved + || context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY) + { + status_flags |= PARSER_HAS_NON_STRICT_ARG; + } + + function_name_index = context_p->lit_object.index; + } + } if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { @@ -930,6 +976,12 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */ parser_emit_cbc_literal (context_p, CBC_PUSH_LITERAL, function_literal_index); + + if (function_name_index != -1) + { + context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_NAMED_FUNC_EXPRESSION); + context_p->last_cbc.value = (uint16_t) function_name_index; + } } context_p->last_cbc.literal_type = LEXER_FUNCTION_LITERAL; diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index d9a9aa7f3..5c9002fdd 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -45,7 +45,6 @@ typedef enum PARSER_IS_FUNC_EXPRESSION = (1u << 3), /**< a function expression is parsed */ PARSER_IS_PROPERTY_GETTER = (1u << 4), /**< a property getter function is parsed */ PARSER_IS_PROPERTY_SETTER = (1u << 5), /**< a property setter function is parsed */ - PARSER_NAMED_FUNCTION_EXP = (1u << 6), /**< a function expression has a name binding */ PARSER_HAS_NON_STRICT_ARG = (1u << 7), /**< the function has arguments which * are not supported in strict mode */ PARSER_ARGUMENTS_NEEDED = (1u << 8), /**< arguments object must be created */ diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 4330ef4c7..d17061c33 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -413,7 +413,7 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */ if (name_p->status_flags & LEXER_FLAG_INITIALIZED) { - if (!(name_p->status_flags & (LEXER_FLAG_FUNCTION_NAME | LEXER_FLAG_FUNCTION_ARGUMENT))) + if (!(name_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)) { /* Overwrite the previous initialization. */ ecma_compiled_code_t *compiled_code_p; diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 4f145e30a..45346b7f4 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -232,17 +232,6 @@ parser_compute_indicies (parser_context_t *context_p, /**< context */ if (literal_p->status_flags & LEXER_FLAG_INITIALIZED) { - if (literal_p->status_flags & LEXER_FLAG_FUNCTION_NAME) - { - JERRY_ASSERT (literal_p == PARSER_GET_LITERAL (0)); - - status_flags |= PARSER_NAMED_FUNCTION_EXP; - context_p->status_flags = status_flags; - - literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE; - context_p->literal_count++; - } - if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) { if ((status_flags & PARSER_ARGUMENTS_NEEDED) @@ -460,14 +449,11 @@ parser_compute_indicies (parser_context_t *context_p, /**< context */ init_index = literal_index; literal_index++; - if (!(literal_p->status_flags & LEXER_FLAG_FUNCTION_NAME)) - { - lexer_literal_t *func_literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator); + lexer_literal_t *func_literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator); - JERRY_ASSERT (func_literal_p != NULL - && func_literal_p->type == LEXER_FUNCTION_LITERAL); - func_literal_p->prop.index = init_index; - } + JERRY_ASSERT (func_literal_p != NULL + && func_literal_p->type == LEXER_FUNCTION_LITERAL); + func_literal_p->prop.index = init_index; } /* A CBC_INITIALIZE_VAR instruction or part of a CBC_INITIALIZE_VARS instruction. */ @@ -547,7 +533,6 @@ parser_generate_initializers (parser_context_t *context_p, /**< context */ ecma_value_t *literal_pool_p, /**< start of literal pool */ uint16_t uninitialized_var_end, /**< end of the uninitialized var group */ uint16_t initialized_var_end, /**< end of the initialized var group */ - uint16_t const_literal_end, /**< end of the const literal group */ uint16_t literal_one_byte_limit) /**< maximum value of a literal * encoded in one byte */ { @@ -599,12 +584,7 @@ parser_generate_initializers (parser_context_t *context_p, /**< context */ #endif /* !JERRY_NDEBUG */ literal_p->status_flags = (uint8_t) (literal_p->status_flags & ~LEXER_FLAG_INITIALIZED); - - if (literal_p->status_flags & LEXER_FLAG_FUNCTION_NAME) - { - init_index = const_literal_end; - } - else if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) + if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) { init_index = (uint16_t) (argument_count - 1); } @@ -691,11 +671,7 @@ parser_generate_initializers (parser_context_t *context_p, /**< context */ JERRY_ASSERT (literal_p->type == LEXER_IDENT_LITERAL); - if (literal_p->status_flags & LEXER_FLAG_FUNCTION_NAME) - { - init_index = const_literal_end; - } - else if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) + if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT) { init_index = (uint16_t) (argument_count - 1); @@ -1840,7 +1816,6 @@ parser_post_processing (parser_context_t *context_p) /**< context */ literal_pool_p, uninitialized_var_end, initialized_var_end, - const_literal_end, literal_one_byte_limit); JERRY_ASSERT (dst_p == byte_code_p + initializers_length); @@ -2133,12 +2108,6 @@ parser_post_processing (parser_context_t *context_p) /**< context */ } #endif /* JERRY_ENABLE_LINE_INFO */ - if (context_p->status_flags & PARSER_NAMED_FUNCTION_EXP) - { - ECMA_SET_INTERNAL_VALUE_POINTER (literal_pool_p[const_literal_end], - compiled_code_p); - } - #ifdef JERRY_DEBUGGER if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) { @@ -2612,51 +2581,9 @@ parser_parse_function (parser_context_t *context_p, /**< context */ } #endif /* PARSER_DUMP_BYTE_CODE */ -#ifdef JERRY_DEBUGGER - parser_line_counter_t debugger_line = context_p->token.line; - parser_line_counter_t debugger_column = context_p->token.column; -#endif /* JERRY_DEBUGGER */ - - lexer_next_token (context_p); - - if (context_p->status_flags & PARSER_IS_FUNC_EXPRESSION - && context_p->token.type == LEXER_LITERAL - && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) - { - lexer_construct_literal_object (context_p, - &context_p->token.lit_location, - LEXER_IDENT_LITERAL); - -#ifdef JERRY_DEBUGGER - if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) - { - jerry_debugger_send_string (JERRY_DEBUGGER_FUNCTION_NAME, - JERRY_DEBUGGER_NO_SUBTYPE, - context_p->lit_object.literal_p->u.char_p, - context_p->lit_object.literal_p->prop.length); - } -#endif /* JERRY_DEBUGGER */ - - /* The arguments object is created later than the binding to the - * function expression name, so there is no need to assign special flags. */ - if (context_p->lit_object.type != LEXER_LITERAL_OBJECT_ARGUMENTS) - { - uint8_t lexer_flags = LEXER_FLAG_VAR | LEXER_FLAG_INITIALIZED | LEXER_FLAG_FUNCTION_NAME; - context_p->lit_object.literal_p->status_flags |= lexer_flags; - } - - if (context_p->token.literal_is_reserved - || context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY) - { - context_p->status_flags |= PARSER_HAS_NON_STRICT_ARG; - } - - lexer_next_token (context_p); - } - #ifdef JERRY_DEBUGGER if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) - && jerry_debugger_send_parse_function (debugger_line, debugger_column)) + && jerry_debugger_send_parse_function (context_p->token.line, context_p->token.column)) { /* This option has a high memory and performance costs, * but it is necessary for executing eval operations by the debugger. */ @@ -2664,6 +2591,8 @@ parser_parse_function (parser_context_t *context_p, /**< context */ } #endif /* JERRY_DEBUGGER */ + lexer_next_token (context_p); + if (context_p->token.type != LEXER_LEFT_PAREN) { parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIST_EXPECTED); diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 2c9962060..f6c06b762 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -714,17 +714,6 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ uint16_t register_end; ecma_value_t *literal_start_p = frame_ctx_p->literal_start_p; bool is_strict = ((frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0); - ecma_value_t self_reference; - -#ifdef JERRY_ENABLE_SNAPSHOT_EXEC - self_reference = 0; - if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) - { - ECMA_SET_INTERNAL_VALUE_POINTER (self_reference, bytecode_header_p); - } -#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ - ECMA_SET_INTERNAL_VALUE_POINTER (self_reference, bytecode_header_p); -#endif /* Prepare. */ if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_FULL_LITERAL_ENCODING)) @@ -793,7 +782,6 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { uint32_t value_index; ecma_value_t lit_value; - bool is_immutable_binding = false; READ_LITERAL_INDEX (value_index); @@ -803,7 +791,6 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } else { - is_immutable_binding = (self_reference == literal_start_p[value_index]); lit_value = vm_construct_literal_object (frame_ctx_p, literal_start_p[value_index]); } @@ -816,29 +803,22 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); - if (JERRY_LIKELY (!is_immutable_binding)) + vm_var_decl (frame_ctx_p, name_p); + + ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (frame_ctx_p->lex_env_p, name_p); + + ecma_value_t put_value_result = ecma_op_put_value_lex_env_base (ref_base_lex_env_p, + name_p, + is_strict, + lit_value); + + JERRY_ASSERT (ecma_is_value_boolean (put_value_result) + || ecma_is_value_empty (put_value_result) + || ECMA_IS_VALUE_ERROR (put_value_result)); + + if (ECMA_IS_VALUE_ERROR (put_value_result)) { - vm_var_decl (frame_ctx_p, name_p); - - ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (frame_ctx_p->lex_env_p, name_p); - - ecma_value_t put_value_result = ecma_op_put_value_lex_env_base (ref_base_lex_env_p, - name_p, - is_strict, - lit_value); - - JERRY_ASSERT (ecma_is_value_boolean (put_value_result) - || ecma_is_value_empty (put_value_result) - || ECMA_IS_VALUE_ERROR (put_value_result)); - - if (ECMA_IS_VALUE_ERROR (put_value_result)) - { - ecma_free_value (JERRY_CONTEXT (error_value)); - } - } - else - { - ecma_op_create_immutable_binding (frame_ctx_p->lex_env_p, name_p, lit_value); + ecma_free_value (JERRY_CONTEXT (error_value)); } if (value_index >= register_end) @@ -1165,6 +1145,28 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ *stack_top_p++ = ecma_make_object_value (obj_p); continue; } + case VM_OC_PUSH_NAMED_FUNC_EXPR: + { + ecma_object_t *func_p = ecma_get_object_from_value (left_value); + + JERRY_ASSERT (ecma_get_object_type (func_p) == ECMA_OBJECT_TYPE_FUNCTION); + + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) func_p; + + JERRY_ASSERT (frame_ctx_p->lex_env_p == ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, + ext_func_p->u.function.scope_cp)); + + ecma_object_t *name_lex_env = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p); + + ecma_op_create_immutable_binding (name_lex_env, ecma_get_string_from_value (right_value), left_value); + + ECMA_SET_INTERNAL_VALUE_POINTER (ext_func_p->u.function.scope_cp, name_lex_env); + + ecma_free_value (right_value); + ecma_deref_object (name_lex_env); + *stack_top_p++ = left_value; + continue; + } #ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER case VM_OC_SET_COMPUTED_PROPERTY: { diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index a457a1fa8..c7c98fbeb 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -120,6 +120,7 @@ typedef enum VM_OC_PUSH_LIT_POS_BYTE, /**< push literal and number between 1 and 256 */ VM_OC_PUSH_LIT_NEG_BYTE, /**< push literal and number between -1 and -256 */ VM_OC_PUSH_OBJECT, /**< push object */ + VM_OC_PUSH_NAMED_FUNC_EXPR, /**< push named function expression */ VM_OC_SET_PROPERTY, /**< set property */ #ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER VM_OC_SET_COMPUTED_PROPERTY, /**< set computed property */ diff --git a/tests/jerry/function-expr-named.js b/tests/jerry/function-expr-named.js new file mode 100644 index 000000000..63d0b4d01 --- /dev/null +++ b/tests/jerry/function-expr-named.js @@ -0,0 +1,51 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var expr = "Dummy value"; + +var f = function expr() { + assert(expr === f); + expr = 6; + assert(expr === f); + assert(!(delete expr)); + assert(expr === f); +} + +f(); + +f = function expr() { + assert(expr === undefined); + var expr = 6; + assert(expr === 6); +} + +f(); + +var f = function expr() { + assert(expr === f); + eval("var expr = 8"); + assert(expr === 8); +} + +f(); + +var f = function expr(i) { + assert(expr === f); + + if (i > 0) { + expr(i - 1); + } +} + +f(10);