Skip to content

Commit b3d9b55

Browse files
committed
Fix named function expression creation.
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 [email protected]
1 parent 3f9dd0f commit b3d9b55

File tree

11 files changed

+171
-142
lines changed

11 files changed

+171
-142
lines changed

jerry-core/ecma/operations/ecma-function-object.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ ecma_object_t *
121121
ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */
122122
const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */
123123
{
124+
JERRY_ASSERT (ecma_is_lexical_environment (scope_p));
125+
124126
/* 1., 4., 13. */
125127
ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
126128

jerry-core/parser/js/byte-code.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,8 @@
560560
-1 + PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION, VM_OC_CLASS_HERITAGE) \
561561
\
562562
/* Basic opcodes. */ \
563+
CBC_OPCODE (CBC_EXT_PUSH_NAMED_FUNC_EXPRESSION, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 1, \
564+
VM_OC_PUSH_NAMED_FUNC_EXPR | VM_OC_GET_LITERAL_LITERAL) \
563565
CBC_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_0, CBC_HAS_LITERAL_ARG, 2, \
564566
VM_OC_PUSH_LIT_0 | VM_OC_GET_LITERAL) \
565567
CBC_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE, CBC_HAS_LITERAL_ARG | CBC_HAS_BYTE_ARG, 2, \

jerry-core/parser/js/common.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,12 @@ typedef enum
6363
LEXER_FLAG_VAR = (1 << 0), /**< local identifier (var, function arg) */
6464
LEXER_FLAG_NO_REG_STORE = (1 << 1), /**< this local identifier cannot be stored in register */
6565
LEXER_FLAG_INITIALIZED = (1 << 2), /**< this local identifier is initialized with a value */
66-
LEXER_FLAG_FUNCTION_NAME = (1 << 3), /**< this local identifier has a reference to the function itself */
67-
LEXER_FLAG_FUNCTION_ARGUMENT = (1 << 4), /**< this local identifier is a function argument */
68-
LEXER_FLAG_UNUSED_IDENT = (1 << 5), /**< this identifier is referenced by sub-functions,
66+
LEXER_FLAG_FUNCTION_ARGUMENT = (1 << 3), /**< this local identifier is a function argument */
67+
LEXER_FLAG_UNUSED_IDENT = (1 << 4), /**< this identifier is referenced by sub-functions,
6968
* but not referenced by the currently parsed function */
70-
LEXER_FLAG_SOURCE_PTR = (1 << 6), /**< the literal is directly referenced in the source code
69+
LEXER_FLAG_SOURCE_PTR = (1 << 5), /**< the literal is directly referenced in the source code
7170
* (no need to allocate memory) */
72-
LEXER_FLAG_LATE_INIT = (1 << 7), /**< initialize this variable after the byte code is freed */
71+
LEXER_FLAG_LATE_INIT = (1 << 6), /**< initialize this variable after the byte code is freed */
7372
} lexer_literal_status_flags_t;
7473

7574
/**

jerry-core/parser/js/js-lexer.c

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,34 +1742,32 @@ lexer_construct_literal_object (parser_context_t *context_p, /**< context */
17421742

17431743
context_p->lit_object.type = LEXER_LITERAL_OBJECT_ANY;
17441744

1745-
if (literal_type == LEXER_IDENT_LITERAL)
1745+
if (literal_type == LEXER_IDENT_LITERAL
1746+
&& (context_p->status_flags & PARSER_INSIDE_WITH)
1747+
&& context_p->lit_object.literal_p->type == LEXER_IDENT_LITERAL)
17461748
{
1747-
if ((context_p->status_flags & PARSER_INSIDE_WITH)
1748-
&& context_p->lit_object.literal_p->type == LEXER_IDENT_LITERAL)
1749-
{
1750-
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE;
1751-
}
1749+
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE;
1750+
}
17521751

1753-
if (literal_p->length == 4
1754-
&& source_p[0] == LIT_CHAR_LOWERCASE_E
1755-
&& source_p[3] == LIT_CHAR_LOWERCASE_L
1756-
&& source_p[1] == LIT_CHAR_LOWERCASE_V
1757-
&& source_p[2] == LIT_CHAR_LOWERCASE_A)
1758-
{
1759-
context_p->lit_object.type = LEXER_LITERAL_OBJECT_EVAL;
1760-
}
1752+
if (literal_p->length == 4
1753+
&& source_p[0] == LIT_CHAR_LOWERCASE_E
1754+
&& source_p[3] == LIT_CHAR_LOWERCASE_L
1755+
&& source_p[1] == LIT_CHAR_LOWERCASE_V
1756+
&& source_p[2] == LIT_CHAR_LOWERCASE_A)
1757+
{
1758+
context_p->lit_object.type = LEXER_LITERAL_OBJECT_EVAL;
1759+
}
17611760

1762-
if (literal_p->length == 9
1763-
&& source_p[0] == LIT_CHAR_LOWERCASE_A
1764-
&& source_p[8] == LIT_CHAR_LOWERCASE_S
1765-
&& memcmp (source_p + 1, "rgument", 7) == 0)
1761+
if (literal_p->length == 9
1762+
&& source_p[0] == LIT_CHAR_LOWERCASE_A
1763+
&& source_p[8] == LIT_CHAR_LOWERCASE_S
1764+
&& memcmp (source_p + 1, "rgument", 7) == 0)
1765+
{
1766+
context_p->lit_object.type = LEXER_LITERAL_OBJECT_ARGUMENTS;
1767+
if (!(context_p->status_flags & PARSER_ARGUMENTS_NOT_NEEDED))
17661768
{
1767-
context_p->lit_object.type = LEXER_LITERAL_OBJECT_ARGUMENTS;
1768-
if (!(context_p->status_flags & PARSER_ARGUMENTS_NOT_NEEDED))
1769-
{
1770-
context_p->status_flags |= PARSER_ARGUMENTS_NEEDED | PARSER_LEXICAL_ENV_NEEDED;
1771-
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE;
1772-
}
1769+
context_p->status_flags |= PARSER_ARGUMENTS_NEEDED | PARSER_LEXICAL_ENV_NEEDED;
1770+
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE;
17731771
}
17741772
}
17751773

jerry-core/parser/js/js-parser-expr.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,52 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */
889889
uint16_t literal1 = 0;
890890
uint16_t literal2 = 0;
891891
uint16_t function_literal_index;
892+
int32_t function_name_index = -1;
893+
894+
if (status_flags & PARSER_IS_FUNC_EXPRESSION)
895+
{
896+
#ifdef JERRY_DEBUGGER
897+
parser_line_counter_t debugger_line = context_p->token.line;
898+
parser_line_counter_t debugger_column = context_p->token.column;
899+
#endif /* JERRY_DEBUGGER */
900+
901+
if (!lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
902+
{
903+
lexer_next_token (context_p);
904+
905+
if (context_p->token.type != LEXER_LITERAL
906+
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
907+
{
908+
parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
909+
}
910+
911+
parser_flush_cbc (context_p);
912+
913+
lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_STRING_LITERAL);
914+
915+
#ifdef JERRY_DEBUGGER
916+
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
917+
{
918+
jerry_debugger_send_string (JERRY_DEBUGGER_FUNCTION_NAME,
919+
JERRY_DEBUGGER_NO_SUBTYPE,
920+
context_p->lit_object.literal_p->u.char_p,
921+
context_p->lit_object.literal_p->prop.length);
922+
923+
/* Reset token position for the function. */
924+
context_p->token.line = debugger_line;
925+
context_p->token.column = debugger_column;
926+
}
927+
#endif /* JERRY_DEBUGGER */
928+
929+
if (context_p->token.literal_is_reserved
930+
|| context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY)
931+
{
932+
status_flags |= PARSER_HAS_NON_STRICT_ARG;
933+
}
934+
935+
function_name_index = context_p->lit_object.index;
936+
}
937+
}
892938

893939
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
894940
{
@@ -930,6 +976,12 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */
930976
parser_emit_cbc_literal (context_p,
931977
CBC_PUSH_LITERAL,
932978
function_literal_index);
979+
980+
if (function_name_index != -1)
981+
{
982+
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_NAMED_FUNC_EXPRESSION);
983+
context_p->last_cbc.value = (uint16_t) function_name_index;
984+
}
933985
}
934986

935987
context_p->last_cbc.literal_type = LEXER_FUNCTION_LITERAL;

jerry-core/parser/js/js-parser-internal.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ typedef enum
4545
PARSER_IS_FUNC_EXPRESSION = (1u << 3), /**< a function expression is parsed */
4646
PARSER_IS_PROPERTY_GETTER = (1u << 4), /**< a property getter function is parsed */
4747
PARSER_IS_PROPERTY_SETTER = (1u << 5), /**< a property setter function is parsed */
48-
PARSER_NAMED_FUNCTION_EXP = (1u << 6), /**< a function expression has a name binding */
4948
PARSER_HAS_NON_STRICT_ARG = (1u << 7), /**< the function has arguments which
5049
* are not supported in strict mode */
5150
PARSER_ARGUMENTS_NEEDED = (1u << 8), /**< arguments object must be created */

jerry-core/parser/js/js-parser-statm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */
413413

414414
if (name_p->status_flags & LEXER_FLAG_INITIALIZED)
415415
{
416-
if (!(name_p->status_flags & (LEXER_FLAG_FUNCTION_NAME | LEXER_FLAG_FUNCTION_ARGUMENT)))
416+
if (!(name_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT))
417417
{
418418
/* Overwrite the previous initialization. */
419419
ecma_compiled_code_t *compiled_code_p;

jerry-core/parser/js/js-parser.c

Lines changed: 9 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -232,17 +232,6 @@ parser_compute_indicies (parser_context_t *context_p, /**< context */
232232

233233
if (literal_p->status_flags & LEXER_FLAG_INITIALIZED)
234234
{
235-
if (literal_p->status_flags & LEXER_FLAG_FUNCTION_NAME)
236-
{
237-
JERRY_ASSERT (literal_p == PARSER_GET_LITERAL (0));
238-
239-
status_flags |= PARSER_NAMED_FUNCTION_EXP;
240-
context_p->status_flags = status_flags;
241-
242-
literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE;
243-
context_p->literal_count++;
244-
}
245-
246235
if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
247236
{
248237
if ((status_flags & PARSER_ARGUMENTS_NEEDED)
@@ -460,14 +449,11 @@ parser_compute_indicies (parser_context_t *context_p, /**< context */
460449
init_index = literal_index;
461450
literal_index++;
462451

463-
if (!(literal_p->status_flags & LEXER_FLAG_FUNCTION_NAME))
464-
{
465-
lexer_literal_t *func_literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator);
452+
lexer_literal_t *func_literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator);
466453

467-
JERRY_ASSERT (func_literal_p != NULL
468-
&& func_literal_p->type == LEXER_FUNCTION_LITERAL);
469-
func_literal_p->prop.index = init_index;
470-
}
454+
JERRY_ASSERT (func_literal_p != NULL
455+
&& func_literal_p->type == LEXER_FUNCTION_LITERAL);
456+
func_literal_p->prop.index = init_index;
471457
}
472458

473459
/* 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 */
547533
ecma_value_t *literal_pool_p, /**< start of literal pool */
548534
uint16_t uninitialized_var_end, /**< end of the uninitialized var group */
549535
uint16_t initialized_var_end, /**< end of the initialized var group */
550-
uint16_t const_literal_end, /**< end of the const literal group */
551536
uint16_t literal_one_byte_limit) /**< maximum value of a literal
552537
* encoded in one byte */
553538
{
@@ -599,12 +584,7 @@ parser_generate_initializers (parser_context_t *context_p, /**< context */
599584
#endif /* !JERRY_NDEBUG */
600585
literal_p->status_flags = (uint8_t) (literal_p->status_flags & ~LEXER_FLAG_INITIALIZED);
601586

602-
603-
if (literal_p->status_flags & LEXER_FLAG_FUNCTION_NAME)
604-
{
605-
init_index = const_literal_end;
606-
}
607-
else if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
587+
if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
608588
{
609589
init_index = (uint16_t) (argument_count - 1);
610590
}
@@ -691,11 +671,7 @@ parser_generate_initializers (parser_context_t *context_p, /**< context */
691671

692672
JERRY_ASSERT (literal_p->type == LEXER_IDENT_LITERAL);
693673

694-
if (literal_p->status_flags & LEXER_FLAG_FUNCTION_NAME)
695-
{
696-
init_index = const_literal_end;
697-
}
698-
else if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
674+
if (literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
699675
{
700676
init_index = (uint16_t) (argument_count - 1);
701677

@@ -1840,7 +1816,6 @@ parser_post_processing (parser_context_t *context_p) /**< context */
18401816
literal_pool_p,
18411817
uninitialized_var_end,
18421818
initialized_var_end,
1843-
const_literal_end,
18441819
literal_one_byte_limit);
18451820

18461821
JERRY_ASSERT (dst_p == byte_code_p + initializers_length);
@@ -2133,12 +2108,6 @@ parser_post_processing (parser_context_t *context_p) /**< context */
21332108
}
21342109
#endif /* JERRY_ENABLE_LINE_INFO */
21352110

2136-
if (context_p->status_flags & PARSER_NAMED_FUNCTION_EXP)
2137-
{
2138-
ECMA_SET_INTERNAL_VALUE_POINTER (literal_pool_p[const_literal_end],
2139-
compiled_code_p);
2140-
}
2141-
21422111
#ifdef JERRY_DEBUGGER
21432112
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
21442113
{
@@ -2612,58 +2581,18 @@ parser_parse_function (parser_context_t *context_p, /**< context */
26122581
}
26132582
#endif /* PARSER_DUMP_BYTE_CODE */
26142583

2615-
#ifdef JERRY_DEBUGGER
2616-
parser_line_counter_t debugger_line = context_p->token.line;
2617-
parser_line_counter_t debugger_column = context_p->token.column;
2618-
#endif /* JERRY_DEBUGGER */
2619-
2620-
lexer_next_token (context_p);
2621-
2622-
if (context_p->status_flags & PARSER_IS_FUNC_EXPRESSION
2623-
&& context_p->token.type == LEXER_LITERAL
2624-
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
2625-
{
2626-
lexer_construct_literal_object (context_p,
2627-
&context_p->token.lit_location,
2628-
LEXER_IDENT_LITERAL);
2629-
2630-
#ifdef JERRY_DEBUGGER
2631-
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
2632-
{
2633-
jerry_debugger_send_string (JERRY_DEBUGGER_FUNCTION_NAME,
2634-
JERRY_DEBUGGER_NO_SUBTYPE,
2635-
context_p->lit_object.literal_p->u.char_p,
2636-
context_p->lit_object.literal_p->prop.length);
2637-
}
2638-
#endif /* JERRY_DEBUGGER */
2639-
2640-
/* The arguments object is created later than the binding to the
2641-
* function expression name, so there is no need to assign special flags. */
2642-
if (context_p->lit_object.type != LEXER_LITERAL_OBJECT_ARGUMENTS)
2643-
{
2644-
uint8_t lexer_flags = LEXER_FLAG_VAR | LEXER_FLAG_INITIALIZED | LEXER_FLAG_FUNCTION_NAME;
2645-
context_p->lit_object.literal_p->status_flags |= lexer_flags;
2646-
}
2647-
2648-
if (context_p->token.literal_is_reserved
2649-
|| context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY)
2650-
{
2651-
context_p->status_flags |= PARSER_HAS_NON_STRICT_ARG;
2652-
}
2653-
2654-
lexer_next_token (context_p);
2655-
}
2656-
26572584
#ifdef JERRY_DEBUGGER
26582585
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
2659-
&& jerry_debugger_send_parse_function (debugger_line, debugger_column))
2586+
&& jerry_debugger_send_parse_function (context_p->token.line, context_p->token.column))
26602587
{
26612588
/* This option has a high memory and performance costs,
26622589
* but it is necessary for executing eval operations by the debugger. */
26632590
context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED | PARSER_NO_REG_STORE;
26642591
}
26652592
#endif /* JERRY_DEBUGGER */
26662593

2594+
lexer_next_token (context_p);
2595+
26672596
if (context_p->token.type != LEXER_LEFT_PAREN)
26682597
{
26692598
parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIST_EXPECTED);

0 commit comments

Comments
 (0)