Skip to content

Commit 0db3817

Browse files
committed
Implement proper creation of function arguments, let and const declarations.
After the rework it is possible to detect use before init errors for function arguments. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
1 parent 8d08cec commit 0db3817

File tree

16 files changed

+726
-215
lines changed

16 files changed

+726
-215
lines changed

jerry-core/include/jerryscript-snapshot.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ extern "C"
3030
/**
3131
* Jerry snapshot format version.
3232
*/
33-
#define JERRY_SNAPSHOT_VERSION (42u)
33+
#define JERRY_SNAPSHOT_VERSION (43u)
3434

3535
/**
3636
* Flags for jerry_generate_snapshot and jerry_generate_function_snapshot.

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,14 @@
312312
VM_OC_CREATE_BINDING) \
313313
CBC_OPCODE (CBC_CREATE_LOCAL, CBC_HAS_LITERAL_ARG, 0, \
314314
VM_OC_CREATE_BINDING) \
315-
CBC_OPCODE (CBC_INIT_LOCAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
316-
VM_OC_INIT_LOCAL) \
315+
CBC_OPCODE (CBC_INIT_ARG_OR_CATCH, CBC_HAS_LITERAL_ARG, -1, \
316+
VM_OC_INIT_BINDING) \
317+
CBC_OPCODE (CBC_INIT_LET, CBC_HAS_LITERAL_ARG, -1, \
318+
VM_OC_INIT_BINDING) \
319+
CBC_OPCODE (CBC_INIT_CONST, CBC_HAS_LITERAL_ARG, -1, \
320+
VM_OC_INIT_BINDING) \
321+
CBC_OPCODE (CBC_INIT_ARG_OR_FUNC, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
322+
VM_OC_INIT_ARG_OR_FUNC) \
317323
CBC_OPCODE (CBC_CREATE_VAR_EVAL, CBC_HAS_LITERAL_ARG, 0, \
318324
VM_OC_VAR_EVAL) \
319325
CBC_OPCODE (CBC_CREATE_VAR_FUNC_EVAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
@@ -498,6 +504,8 @@
498504
VM_OC_MOV_IDENT | VM_OC_GET_STACK | VM_OC_PUT_IDENT) \
499505
CBC_OPCODE (CBC_ASSIGN_LET_CONST, CBC_HAS_LITERAL_ARG, -1, \
500506
VM_OC_ASSIGN_LET_CONST | VM_OC_GET_STACK) \
507+
CBC_OPCODE (CBC_ASSIGN_LET_CONST_LITERAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
508+
VM_OC_ASSIGN_LET_CONST | VM_OC_GET_LITERAL) \
501509
CBC_OPCODE (CBC_ASSIGN_SUPER, CBC_NO_FLAG, -3, \
502510
VM_OC_ASSIGN_SUPER) \
503511
CBC_OPCODE (CBC_ASSIGN_SUPER_PUSH_RESULT, CBC_NO_FLAG, -2, \

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

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -813,9 +813,15 @@ parser_parse_class (parser_context_t *context_p, /**< context */
813813

814814
if (is_statement)
815815
{
816-
parser_emit_cbc_literal (context_p,
817-
class_ident_index >= PARSER_REGISTER_START ? CBC_MOV_IDENT : CBC_ASSIGN_LET_CONST,
818-
class_ident_index);
816+
cbc_opcode_t opcode = CBC_MOV_IDENT;
817+
818+
if (class_ident_index < PARSER_REGISTER_START)
819+
{
820+
opcode = (scanner_literal_is_created (context_p, class_ident_index) ? CBC_ASSIGN_LET_CONST
821+
: CBC_INIT_LET);
822+
}
823+
824+
parser_emit_cbc_literal (context_p, (uint16_t) opcode, class_ident_index);
819825
}
820826

821827
parser_flush_cbc (context_p);
@@ -2251,9 +2257,9 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */
22512257
*/
22522258
static uint8_t
22532259
parser_append_binary_single_assignment_token (parser_context_t *context_p, /**< context */
2254-
bool is_lexical) /**< assign lexical declaration */
2260+
uint32_t pattern_flags) /**< pattern flags */
22552261
{
2256-
JERRY_UNUSED (is_lexical);
2262+
JERRY_UNUSED (pattern_flags);
22572263

22582264
/* Unlike other tokens, the whole byte code is saved for binary
22592265
* assignment, since it has multiple forms depending on the
@@ -2301,7 +2307,7 @@ parser_append_binary_single_assignment_token (parser_context_t *context_p, /**<
23012307
assign_opcode = CBC_ASSIGN_SET_IDENT;
23022308

23032309
#if ENABLED (JERRY_ES2015)
2304-
if (!is_lexical)
2310+
if (!(pattern_flags & (PARSER_PATTERN_LET | PARSER_PATTERN_CONST | PARSER_PATTERN_LOCAL)))
23052311
{
23062312
if (scanner_literal_is_const_reg (context_p, literal_index))
23072313
{
@@ -2310,7 +2316,20 @@ parser_append_binary_single_assignment_token (parser_context_t *context_p, /**<
23102316
}
23112317
else if (literal_index < PARSER_REGISTER_START)
23122318
{
2313-
assign_opcode = CBC_ASSIGN_LET_CONST;
2319+
assign_opcode = CBC_INIT_LET;
2320+
2321+
if (scanner_literal_is_created (context_p, literal_index))
2322+
{
2323+
assign_opcode = CBC_ASSIGN_LET_CONST;
2324+
}
2325+
else if (pattern_flags & PARSER_PATTERN_CONST)
2326+
{
2327+
assign_opcode = CBC_INIT_CONST;
2328+
}
2329+
else if (pattern_flags & PARSER_PATTERN_LOCAL)
2330+
{
2331+
assign_opcode = CBC_INIT_ARG_OR_CATCH;
2332+
}
23142333
}
23152334
#endif /* ENABLED (JERRY_ES2015) */
23162335

@@ -2395,7 +2414,7 @@ parser_append_binary_token (parser_context_t *context_p) /**< context */
23952414

23962415
if (context_p->token.type == LEXER_ASSIGN)
23972416
{
2398-
parser_append_binary_single_assignment_token (context_p, false);
2417+
parser_append_binary_single_assignment_token (context_p, 0);
23992418
return;
24002419
}
24012420

@@ -2486,7 +2505,10 @@ parser_process_binary_opcodes (parser_context_t *context_p, /**< context */
24862505
JERRY_ASSERT (opcode == CBC_ASSIGN_SET_IDENT
24872506
|| opcode == CBC_ASSIGN_PROP_LITERAL
24882507
|| opcode == CBC_ASSIGN_PROP_THIS_LITERAL
2489-
|| opcode == CBC_ASSIGN_LET_CONST);
2508+
|| opcode == CBC_ASSIGN_LET_CONST
2509+
|| opcode == CBC_INIT_ARG_OR_CATCH
2510+
|| opcode == CBC_INIT_LET
2511+
|| opcode == CBC_INIT_CONST);
24902512

24912513
index = parser_stack_pop_uint16 (context_p);
24922514
}
@@ -2601,7 +2623,7 @@ parser_pattern_get_target (parser_context_t *context_p, /**< context */
26012623
{
26022624
JERRY_ASSERT (flags & PARSER_PATTERN_TARGET_ON_STACK);
26032625

2604-
parser_emit_cbc_forward_branch (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_DEFAULT_INITIALIZER), &skip_init);
2626+
parser_emit_cbc_ext_forward_branch (context_p, CBC_EXT_DEFAULT_INITIALIZER, &skip_init);
26052627
}
26062628

26072629
if ((flags & (PARSER_PATTERN_TARGET_ON_STACK | PARSER_PATTERN_TARGET_DEFAULT)) != PARSER_PATTERN_TARGET_ON_STACK)
@@ -2707,8 +2729,7 @@ parser_pattern_form_assignment (parser_context_t *context_p, /**< context */
27072729
JERRY_UNUSED (ident_line_counter);
27082730

27092731
parser_stack_push_uint8 (context_p, LEXER_EXPRESSION_START);
2710-
bool is_lexical = (flags & (PARSER_PATTERN_LEXICAL | PARSER_PATTERN_LOCAL)) != 0;
2711-
uint8_t assign_opcode = parser_append_binary_single_assignment_token (context_p, is_lexical);
2732+
uint8_t assign_opcode = parser_append_binary_single_assignment_token (context_p, flags);
27122733

27132734
if (flags & PARSER_PATTERN_ARRAY)
27142735
{
@@ -2724,7 +2745,7 @@ parser_pattern_form_assignment (parser_context_t *context_p, /**< context */
27242745
{
27252746
parser_branch_t skip_init;
27262747
lexer_next_token (context_p);
2727-
parser_emit_cbc_forward_branch (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_DEFAULT_INITIALIZER), &skip_init);
2748+
parser_emit_cbc_ext_forward_branch (context_p, CBC_EXT_DEFAULT_INITIALIZER, &skip_init);
27282749

27292750
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
27302751
parser_set_branch_to_current_position (context_p, &skip_init);
@@ -2770,7 +2791,8 @@ parser_pattern_process_nested_pattern (parser_context_t *context_p, /**< context
27702791
parser_pattern_flags_t options = (PARSER_PATTERN_NESTED_PATTERN
27712792
| PARSER_PATTERN_TARGET_ON_STACK
27722793
| (flags & (PARSER_PATTERN_BINDING
2773-
| PARSER_PATTERN_LEXICAL
2794+
| PARSER_PATTERN_LET
2795+
| PARSER_PATTERN_CONST
27742796
| PARSER_PATTERN_LOCAL
27752797
| PARSER_PATTERN_REST_ELEMENT
27762798
| PARSER_PATTERN_ARGUMENTS)));
@@ -2821,7 +2843,7 @@ parser_pattern_process_assignment (parser_context_t *context_p, /**< context */
28212843

28222844
lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL);
28232845

2824-
if (flags & PARSER_PATTERN_LEXICAL
2846+
if (flags & (PARSER_PATTERN_LET | PARSER_PATTERN_CONST)
28252847
&& context_p->token.keyword_type == LEXER_KEYW_LET)
28262848
{
28272849
parser_raise_error (context_p, PARSER_ERR_LEXICAL_LET_BINDING);

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

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,12 @@ typedef enum
110110
PARSER_PATTERN_TARGET_ON_STACK = (1u << 1), /**< assignment target is the topmost element on the stack */
111111
PARSER_PATTERN_TARGET_DEFAULT = (1u << 2), /**< perform default value comparison for assignment target */
112112
PARSER_PATTERN_NESTED_PATTERN = (1u << 3), /**< parse patter inside a pattern */
113-
PARSER_PATTERN_LEXICAL = (1u << 4), /**< pattern is a lexical (let/const) declaration */
114-
PARSER_PATTERN_LOCAL = (1u << 5), /**< pattern is a local (catch parameter) declaration */
115-
PARSER_PATTERN_REST_ELEMENT = (1u << 6), /**< parse rest array initializer */
116-
PARSER_PATTERN_ARGUMENTS = (1u << 7), /**< parse arguments binding */
117-
PARSER_PATTERN_ARRAY = (1u << 8), /**< array pattern is being parsed */
113+
PARSER_PATTERN_LET = (1u << 4), /**< pattern is a let declaration */
114+
PARSER_PATTERN_CONST = (1u << 5), /**< pattern is a const declaration */
115+
PARSER_PATTERN_LOCAL = (1u << 6), /**< pattern is a local (catch parameter) declaration */
116+
PARSER_PATTERN_REST_ELEMENT = (1u << 7), /**< parse rest array initializer */
117+
PARSER_PATTERN_ARGUMENTS = (1u << 8), /**< parse arguments binding */
118+
PARSER_PATTERN_ARRAY = (1u << 9), /**< array pattern is being parsed */
118119
} parser_pattern_flags_t;
119120

120121
/**
@@ -395,12 +396,17 @@ typedef struct
395396
* Function statements with the name specified
396397
* in map_from should not be copied to global scope.
397398
*/
398-
#define PARSER_SCOPE_STACK_NO_FUNCTION_COPY 0x4000
399+
#define PARSER_SCOPE_STACK_NO_FUNCTION_COPY 0x8000
399400

400401
/**
401-
* The scope stack item represents a const declaration
402+
* The scope stack item represents a const binding stored in register
402403
*/
403-
#define PARSER_SCOPE_STACK_IS_CONST 0x8000
404+
#define PARSER_SCOPE_STACK_IS_CONST_REG 0x4000
405+
406+
/**
407+
* The scope stack item represents a binding which has already created with ECMA_VALUE_UNINITIALIZED
408+
*/
409+
#define PARSER_SCOPE_STACK_IS_LOCAL_CREATED (PARSER_SCOPE_STACK_IS_CONST_REG)
404410

405411
#endif /* ENABLED (JERRY_ES2015) */
406412

@@ -753,6 +759,7 @@ void scanner_set_location (parser_context_t *context_p, scanner_location_t *loca
753759
uint16_t scanner_decode_map_to (parser_scope_stack_t *stack_item_p);
754760
#if ENABLED (JERRY_ES2015)
755761
bool scanner_literal_is_const_reg (parser_context_t *context_p, uint16_t literal_index);
762+
bool scanner_literal_is_created (parser_context_t *context_p, uint16_t literal_index);
756763
#endif /* ENABLED (JERRY_ES2015) */
757764

758765
void scanner_scan_all (parser_context_t *context_p, const uint8_t *arg_list_p, const uint8_t *arg_list_end_p,

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

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -499,10 +499,15 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */
499499
{
500500
parser_pattern_flags_t flags = PARSER_PATTERN_BINDING;
501501

502-
if (declaration_type != LEXER_KEYW_VAR)
502+
if (declaration_type == LEXER_KEYW_LET)
503503
{
504-
flags |= PARSER_PATTERN_LEXICAL;
504+
flags |= PARSER_PATTERN_LET;
505505
}
506+
else if (declaration_type == LEXER_KEYW_CONST)
507+
{
508+
flags |= PARSER_PATTERN_CONST;
509+
}
510+
506511
parser_parse_initializer_by_next_char (context_p, flags);
507512
}
508513
else
@@ -569,7 +574,16 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */
569574
if (declaration_type != LEXER_KEYW_VAR
570575
&& (index < PARSER_REGISTER_START))
571576
{
572-
opcode = CBC_ASSIGN_LET_CONST;
577+
opcode = CBC_INIT_LET;
578+
579+
if (scanner_literal_is_created (context_p, index))
580+
{
581+
opcode = CBC_ASSIGN_LET_CONST;
582+
}
583+
else if (declaration_type == LEXER_KEYW_CONST)
584+
{
585+
opcode = CBC_INIT_CONST;
586+
}
573587
}
574588
#endif /* ENABLED (JERRY_ES2015) */
575589

@@ -581,9 +595,15 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */
581595
parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED);
582596

583597
uint16_t index = context_p->lit_object.index;
584-
parser_emit_cbc_literal (context_p,
585-
index >= PARSER_REGISTER_START ? CBC_MOV_IDENT : CBC_ASSIGN_LET_CONST,
586-
index);
598+
cbc_opcode_t opcode = CBC_MOV_IDENT;
599+
600+
if (index < PARSER_REGISTER_START)
601+
{
602+
opcode = (scanner_literal_is_created (context_p, index) ? CBC_ASSIGN_LET_CONST
603+
: CBC_INIT_LET);
604+
}
605+
606+
parser_emit_cbc_literal (context_p, (uint16_t) opcode, index);
587607
}
588608
else if (declaration_type == LEXER_KEYW_CONST)
589609
{
@@ -1289,8 +1309,6 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
12891309
#if ENABLED (JERRY_ES2015)
12901310
if (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE))
12911311
{
1292-
bool is_var = (token_type == LEXER_KEYW_VAR);
1293-
12941312
parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
12951313
: CBC_EXT_FOR_OF_GET_NEXT);
12961314

@@ -1303,9 +1321,13 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
13031321

13041322
parser_pattern_flags_t flags = (PARSER_PATTERN_BINDING | PARSER_PATTERN_TARGET_ON_STACK);
13051323

1306-
if (!is_var)
1324+
if (token_type == LEXER_KEYW_LET)
1325+
{
1326+
flags |= PARSER_PATTERN_LET;
1327+
}
1328+
else if (token_type == LEXER_KEYW_CONST)
13071329
{
1308-
flags |= PARSER_PATTERN_LEXICAL;
1330+
flags |= PARSER_PATTERN_CONST;
13091331
}
13101332

13111333
parser_parse_initializer_by_next_char (context_p, flags);
@@ -1347,9 +1369,12 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
13471369
}
13481370
#endif /* !JERRY_NDEBUG */
13491371

1350-
parser_emit_cbc_literal (context_p,
1351-
has_context ? CBC_ASSIGN_LET_CONST : CBC_ASSIGN_SET_IDENT,
1352-
literal_index);
1372+
JERRY_ASSERT (literal_index >= PARSER_REGISTER_START
1373+
|| !has_context
1374+
|| scanner_literal_is_created (context_p, literal_index));
1375+
1376+
uint16_t opcode = (has_context ? CBC_ASSIGN_LET_CONST : CBC_ASSIGN_SET_IDENT);
1377+
parser_emit_cbc_literal (context_p, opcode, literal_index);
13531378
#else /* !ENABLED (JERRY_ES2015) */
13541379
parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index);
13551380
#endif /* ENABLED (JERRY_ES2015) */
@@ -1928,7 +1953,7 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */
19281953
{
19291954
parser_pattern_flags_t flags = (PARSER_PATTERN_BINDING
19301955
| PARSER_PATTERN_TARGET_ON_STACK
1931-
| PARSER_PATTERN_LOCAL);
1956+
| PARSER_PATTERN_LET);
19321957

19331958
parser_parse_initializer_by_next_char (context_p, flags);
19341959
}

0 commit comments

Comments
 (0)