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:
committed by
Akos Kiss
parent
4f0b075f85
commit
83ee9cfca3
@@ -121,6 +121,8 @@ ecma_object_t *
|
|||||||
ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */
|
ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */
|
||||||
const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */
|
const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */
|
||||||
{
|
{
|
||||||
|
JERRY_ASSERT (ecma_is_lexical_environment (scope_p));
|
||||||
|
|
||||||
/* 1., 4., 13. */
|
/* 1., 4., 13. */
|
||||||
ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
|
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) \
|
-1 + PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION, VM_OC_CLASS_HERITAGE) \
|
||||||
\
|
\
|
||||||
/* Basic opcodes. */ \
|
/* 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, \
|
CBC_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_0, CBC_HAS_LITERAL_ARG, 2, \
|
||||||
VM_OC_PUSH_LIT_0 | VM_OC_GET_LITERAL) \
|
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, \
|
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_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_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_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 << 3), /**< this local identifier is a function argument */
|
||||||
LEXER_FLAG_FUNCTION_ARGUMENT = (1 << 4), /**< this local identifier is a function argument */
|
LEXER_FLAG_UNUSED_IDENT = (1 << 4), /**< this identifier is referenced by sub-functions,
|
||||||
LEXER_FLAG_UNUSED_IDENT = (1 << 5), /**< this identifier is referenced by sub-functions,
|
|
||||||
* but not referenced by the currently parsed function */
|
* 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) */
|
* (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;
|
} 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;
|
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->status_flags |= LEXER_FLAG_NO_REG_STORE;
|
||||||
&& context_p->lit_object.literal_p->type == LEXER_IDENT_LITERAL)
|
}
|
||||||
|
|
||||||
|
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;
|
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)
|
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 literal1 = 0;
|
||||||
uint16_t literal2 = 0;
|
uint16_t literal2 = 0;
|
||||||
uint16_t function_literal_index;
|
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)
|
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,
|
parser_emit_cbc_literal (context_p,
|
||||||
CBC_PUSH_LITERAL,
|
CBC_PUSH_LITERAL,
|
||||||
function_literal_index);
|
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;
|
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_FUNC_EXPRESSION = (1u << 3), /**< a function expression is parsed */
|
||||||
PARSER_IS_PROPERTY_GETTER = (1u << 4), /**< a property getter function 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_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
|
PARSER_HAS_NON_STRICT_ARG = (1u << 7), /**< the function has arguments which
|
||||||
* are not supported in strict mode */
|
* are not supported in strict mode */
|
||||||
PARSER_ARGUMENTS_NEEDED = (1u << 8), /**< arguments object must be created */
|
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_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. */
|
/* Overwrite the previous initialization. */
|
||||||
ecma_compiled_code_t *compiled_code_p;
|
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_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 (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
|
||||||
{
|
{
|
||||||
if ((status_flags & PARSER_ARGUMENTS_NEEDED)
|
if ((status_flags & PARSER_ARGUMENTS_NEEDED)
|
||||||
@@ -460,14 +449,11 @@ parser_compute_indicies (parser_context_t *context_p, /**< context */
|
|||||||
init_index = literal_index;
|
init_index = literal_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
|
JERRY_ASSERT (func_literal_p != NULL
|
||||||
&& func_literal_p->type == LEXER_FUNCTION_LITERAL);
|
&& func_literal_p->type == LEXER_FUNCTION_LITERAL);
|
||||||
func_literal_p->prop.index = init_index;
|
func_literal_p->prop.index = init_index;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A CBC_INITIALIZE_VAR instruction or part of a CBC_INITIALIZE_VARS instruction. */
|
/* 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 */
|
ecma_value_t *literal_pool_p, /**< start of literal pool */
|
||||||
uint16_t uninitialized_var_end, /**< end of the uninitialized var group */
|
uint16_t uninitialized_var_end, /**< end of the uninitialized var group */
|
||||||
uint16_t initialized_var_end, /**< end of the initialized 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
|
uint16_t literal_one_byte_limit) /**< maximum value of a literal
|
||||||
* encoded in one byte */
|
* encoded in one byte */
|
||||||
{
|
{
|
||||||
@@ -599,12 +584,7 @@ parser_generate_initializers (parser_context_t *context_p, /**< context */
|
|||||||
#endif /* !JERRY_NDEBUG */
|
#endif /* !JERRY_NDEBUG */
|
||||||
literal_p->status_flags = (uint8_t) (literal_p->status_flags & ~LEXER_FLAG_INITIALIZED);
|
literal_p->status_flags = (uint8_t) (literal_p->status_flags & ~LEXER_FLAG_INITIALIZED);
|
||||||
|
|
||||||
|
if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
|
||||||
if (literal_p->status_flags & LEXER_FLAG_FUNCTION_NAME)
|
|
||||||
{
|
|
||||||
init_index = const_literal_end;
|
|
||||||
}
|
|
||||||
else if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
|
|
||||||
{
|
{
|
||||||
init_index = (uint16_t) (argument_count - 1);
|
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);
|
JERRY_ASSERT (literal_p->type == LEXER_IDENT_LITERAL);
|
||||||
|
|
||||||
if (literal_p->status_flags & LEXER_FLAG_FUNCTION_NAME)
|
if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
|
||||||
{
|
|
||||||
init_index = const_literal_end;
|
|
||||||
}
|
|
||||||
else if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
|
|
||||||
{
|
{
|
||||||
init_index = (uint16_t) (argument_count - 1);
|
init_index = (uint16_t) (argument_count - 1);
|
||||||
|
|
||||||
@@ -1840,7 +1816,6 @@ parser_post_processing (parser_context_t *context_p) /**< context */
|
|||||||
literal_pool_p,
|
literal_pool_p,
|
||||||
uninitialized_var_end,
|
uninitialized_var_end,
|
||||||
initialized_var_end,
|
initialized_var_end,
|
||||||
const_literal_end,
|
|
||||||
literal_one_byte_limit);
|
literal_one_byte_limit);
|
||||||
|
|
||||||
JERRY_ASSERT (dst_p == byte_code_p + initializers_length);
|
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 */
|
#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
|
#ifdef JERRY_DEBUGGER
|
||||||
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
|
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 */
|
#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
|
#ifdef JERRY_DEBUGGER
|
||||||
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
|
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,
|
/* This option has a high memory and performance costs,
|
||||||
* but it is necessary for executing eval operations by the debugger. */
|
* 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 */
|
#endif /* JERRY_DEBUGGER */
|
||||||
|
|
||||||
|
lexer_next_token (context_p);
|
||||||
|
|
||||||
if (context_p->token.type != LEXER_LEFT_PAREN)
|
if (context_p->token.type != LEXER_LEFT_PAREN)
|
||||||
{
|
{
|
||||||
parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIST_EXPECTED);
|
parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIST_EXPECTED);
|
||||||
|
|||||||
+37
-35
@@ -714,17 +714,6 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
|||||||
uint16_t register_end;
|
uint16_t register_end;
|
||||||
ecma_value_t *literal_start_p = frame_ctx_p->literal_start_p;
|
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);
|
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. */
|
/* Prepare. */
|
||||||
if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_FULL_LITERAL_ENCODING))
|
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;
|
uint32_t value_index;
|
||||||
ecma_value_t lit_value;
|
ecma_value_t lit_value;
|
||||||
bool is_immutable_binding = false;
|
|
||||||
|
|
||||||
READ_LITERAL_INDEX (value_index);
|
READ_LITERAL_INDEX (value_index);
|
||||||
|
|
||||||
@@ -803,7 +791,6 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
is_immutable_binding = (self_reference == literal_start_p[value_index]);
|
|
||||||
lit_value = vm_construct_literal_object (frame_ctx_p,
|
lit_value = vm_construct_literal_object (frame_ctx_p,
|
||||||
literal_start_p[value_index]);
|
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]);
|
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_free_value (JERRY_CONTEXT (error_value));
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value_index >= register_end)
|
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);
|
*stack_top_p++ = ecma_make_object_value (obj_p);
|
||||||
continue;
|
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
|
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
|
||||||
case VM_OC_SET_COMPUTED_PROPERTY:
|
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_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_LIT_NEG_BYTE, /**< push literal and number between -1 and -256 */
|
||||||
VM_OC_PUSH_OBJECT, /**< push object */
|
VM_OC_PUSH_OBJECT, /**< push object */
|
||||||
|
VM_OC_PUSH_NAMED_FUNC_EXPR, /**< push named function expression */
|
||||||
VM_OC_SET_PROPERTY, /**< set property */
|
VM_OC_SET_PROPERTY, /**< set property */
|
||||||
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
|
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
|
||||||
VM_OC_SET_COMPUTED_PROPERTY, /**< set computed property */
|
VM_OC_SET_COMPUTED_PROPERTY, /**< set computed property */
|
||||||
|
|||||||
@@ -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);
|
||||||
Reference in New Issue
Block a user