Skip to content

Fix named function expression creation. #2634

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions jerry-core/ecma/operations/ecma-function-object.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 2 additions & 0 deletions jerry-core/parser/js/byte-code.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, \
Expand Down
9 changes: 4 additions & 5 deletions jerry-core/parser/js/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down
46 changes: 22 additions & 24 deletions jerry-core/parser/js/js-lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1742,34 +1742,32 @@ 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;
}
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 == 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)
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->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->status_flags |= PARSER_ARGUMENTS_NEEDED | PARSER_LEXICAL_ENV_NEEDED;
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE;
}
}

Expand Down
52 changes: 52 additions & 0 deletions jerry-core/parser/js/js-parser-expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down
1 change: 0 additions & 1 deletion jerry-core/parser/js/js-parser-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion jerry-core/parser/js/js-parser-statm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
89 changes: 9 additions & 80 deletions jerry-core/parser/js/js-parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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 */
{
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -2612,58 +2581,18 @@ 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. */
context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED | PARSER_NO_REG_STORE;
}
#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);
Expand Down
Loading