mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
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
This commit is contained in:
parent
4f0b075f85
commit
83ee9cfca3
@ -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);
|
||||
|
||||
|
||||
@ -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, \
|
||||
|
||||
@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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:
|
||||
{
|
||||
|
||||
@ -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 */
|
||||
|
||||
51
tests/jerry/function-expr-named.js
Normal file
51
tests/jerry/function-expr-named.js
Normal file
@ -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);
|
||||
Loading…
x
Reference in New Issue
Block a user