Skip to content

Commit d16e570

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 d16e570

File tree

16 files changed

+732
-216
lines changed

16 files changed

+732
-216
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: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -813,9 +813,19 @@ 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 = CBC_INIT_LET;
821+
822+
if (scanner_literal_is_created (context_p, class_ident_index))
823+
{
824+
opcode = CBC_ASSIGN_LET_CONST;
825+
}
826+
}
827+
828+
parser_emit_cbc_literal (context_p, (uint16_t) opcode, class_ident_index);
819829
}
820830

821831
parser_flush_cbc (context_p);
@@ -2251,9 +2261,9 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */
22512261
*/
22522262
static uint8_t
22532263
parser_append_binary_single_assignment_token (parser_context_t *context_p, /**< context */
2254-
bool is_lexical) /**< assign lexical declaration */
2264+
uint32_t pattern_flags) /**< pattern flags */
22552265
{
2256-
JERRY_UNUSED (is_lexical);
2266+
JERRY_UNUSED (pattern_flags);
22572267

22582268
/* Unlike other tokens, the whole byte code is saved for binary
22592269
* assignment, since it has multiple forms depending on the
@@ -2301,7 +2311,7 @@ parser_append_binary_single_assignment_token (parser_context_t *context_p, /**<
23012311
assign_opcode = CBC_ASSIGN_SET_IDENT;
23022312

23032313
#if ENABLED (JERRY_ES2015)
2304-
if (!is_lexical)
2314+
if (!(pattern_flags & (PARSER_PATTERN_LET | PARSER_PATTERN_CONST | PARSER_PATTERN_LOCAL)))
23052315
{
23062316
if (scanner_literal_is_const_reg (context_p, literal_index))
23072317
{
@@ -2310,7 +2320,20 @@ parser_append_binary_single_assignment_token (parser_context_t *context_p, /**<
23102320
}
23112321
else if (literal_index < PARSER_REGISTER_START)
23122322
{
2313-
assign_opcode = CBC_ASSIGN_LET_CONST;
2323+
assign_opcode = CBC_INIT_LET;
2324+
2325+
if (scanner_literal_is_created (context_p, literal_index))
2326+
{
2327+
assign_opcode = CBC_ASSIGN_LET_CONST;
2328+
}
2329+
else if (pattern_flags & PARSER_PATTERN_CONST)
2330+
{
2331+
assign_opcode = CBC_INIT_CONST;
2332+
}
2333+
else if (pattern_flags & PARSER_PATTERN_LOCAL)
2334+
{
2335+
assign_opcode = CBC_INIT_ARG_OR_CATCH;
2336+
}
23142337
}
23152338
#endif /* ENABLED (JERRY_ES2015) */
23162339

@@ -2395,7 +2418,7 @@ parser_append_binary_token (parser_context_t *context_p) /**< context */
23952418

23962419
if (context_p->token.type == LEXER_ASSIGN)
23972420
{
2398-
parser_append_binary_single_assignment_token (context_p, false);
2421+
parser_append_binary_single_assignment_token (context_p, 0);
23992422
return;
24002423
}
24012424

@@ -2486,7 +2509,10 @@ parser_process_binary_opcodes (parser_context_t *context_p, /**< context */
24862509
JERRY_ASSERT (opcode == CBC_ASSIGN_SET_IDENT
24872510
|| opcode == CBC_ASSIGN_PROP_LITERAL
24882511
|| opcode == CBC_ASSIGN_PROP_THIS_LITERAL
2489-
|| opcode == CBC_ASSIGN_LET_CONST);
2512+
|| opcode == CBC_ASSIGN_LET_CONST
2513+
|| opcode == CBC_INIT_ARG_OR_CATCH
2514+
|| opcode == CBC_INIT_LET
2515+
|| opcode == CBC_INIT_CONST);
24902516

24912517
index = parser_stack_pop_uint16 (context_p);
24922518
}
@@ -2601,7 +2627,7 @@ parser_pattern_get_target (parser_context_t *context_p, /**< context */
26012627
{
26022628
JERRY_ASSERT (flags & PARSER_PATTERN_TARGET_ON_STACK);
26032629

2604-
parser_emit_cbc_forward_branch (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_DEFAULT_INITIALIZER), &skip_init);
2630+
parser_emit_cbc_ext_forward_branch (context_p, CBC_EXT_DEFAULT_INITIALIZER, &skip_init);
26052631
}
26062632

26072633
if ((flags & (PARSER_PATTERN_TARGET_ON_STACK | PARSER_PATTERN_TARGET_DEFAULT)) != PARSER_PATTERN_TARGET_ON_STACK)
@@ -2707,8 +2733,7 @@ parser_pattern_form_assignment (parser_context_t *context_p, /**< context */
27072733
JERRY_UNUSED (ident_line_counter);
27082734

27092735
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);
2736+
uint8_t assign_opcode = parser_append_binary_single_assignment_token (context_p, flags);
27122737

27132738
if (flags & PARSER_PATTERN_ARRAY)
27142739
{
@@ -2724,7 +2749,7 @@ parser_pattern_form_assignment (parser_context_t *context_p, /**< context */
27242749
{
27252750
parser_branch_t skip_init;
27262751
lexer_next_token (context_p);
2727-
parser_emit_cbc_forward_branch (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_DEFAULT_INITIALIZER), &skip_init);
2752+
parser_emit_cbc_ext_forward_branch (context_p, CBC_EXT_DEFAULT_INITIALIZER, &skip_init);
27282753

27292754
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
27302755
parser_set_branch_to_current_position (context_p, &skip_init);
@@ -2770,7 +2795,8 @@ parser_pattern_process_nested_pattern (parser_context_t *context_p, /**< context
27702795
parser_pattern_flags_t options = (PARSER_PATTERN_NESTED_PATTERN
27712796
| PARSER_PATTERN_TARGET_ON_STACK
27722797
| (flags & (PARSER_PATTERN_BINDING
2773-
| PARSER_PATTERN_LEXICAL
2798+
| PARSER_PATTERN_LET
2799+
| PARSER_PATTERN_CONST
27742800
| PARSER_PATTERN_LOCAL
27752801
| PARSER_PATTERN_REST_ELEMENT
27762802
| PARSER_PATTERN_ARGUMENTS)));
@@ -2821,7 +2847,7 @@ parser_pattern_process_assignment (parser_context_t *context_p, /**< context */
28212847

28222848
lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL);
28232849

2824-
if (flags & PARSER_PATTERN_LEXICAL
2850+
if (flags & (PARSER_PATTERN_LET | PARSER_PATTERN_CONST)
28252851
&& context_p->token.keyword_type == LEXER_KEYW_LET)
28262852
{
28272853
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: 43 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,19 @@ 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 = CBC_INIT_LET;
603+
604+
if (scanner_literal_is_created (context_p, index))
605+
{
606+
opcode = CBC_ASSIGN_LET_CONST;
607+
}
608+
}
609+
610+
parser_emit_cbc_literal (context_p, (uint16_t) opcode, index);
587611
}
588612
else if (declaration_type == LEXER_KEYW_CONST)
589613
{
@@ -1289,8 +1313,6 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
12891313
#if ENABLED (JERRY_ES2015)
12901314
if (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE))
12911315
{
1292-
bool is_var = (token_type == LEXER_KEYW_VAR);
1293-
12941316
parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
12951317
: CBC_EXT_FOR_OF_GET_NEXT);
12961318

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

13041326
parser_pattern_flags_t flags = (PARSER_PATTERN_BINDING | PARSER_PATTERN_TARGET_ON_STACK);
13051327

1306-
if (!is_var)
1328+
if (token_type == LEXER_KEYW_LET)
13071329
{
1308-
flags |= PARSER_PATTERN_LEXICAL;
1330+
flags |= PARSER_PATTERN_LET;
1331+
}
1332+
else if (token_type == LEXER_KEYW_CONST)
1333+
{
1334+
flags |= PARSER_PATTERN_CONST;
13091335
}
13101336

13111337
parser_parse_initializer_by_next_char (context_p, flags);
@@ -1347,9 +1373,12 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
13471373
}
13481374
#endif /* !JERRY_NDEBUG */
13491375

1350-
parser_emit_cbc_literal (context_p,
1351-
has_context ? CBC_ASSIGN_LET_CONST : CBC_ASSIGN_SET_IDENT,
1352-
literal_index);
1376+
JERRY_ASSERT (literal_index >= PARSER_REGISTER_START
1377+
|| !has_context
1378+
|| scanner_literal_is_created (context_p, literal_index));
1379+
1380+
uint16_t opcode = (has_context ? CBC_ASSIGN_LET_CONST : CBC_ASSIGN_SET_IDENT);
1381+
parser_emit_cbc_literal (context_p, opcode, literal_index);
13531382
#else /* !ENABLED (JERRY_ES2015) */
13541383
parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index);
13551384
#endif /* ENABLED (JERRY_ES2015) */
@@ -1928,7 +1957,7 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */
19281957
{
19291958
parser_pattern_flags_t flags = (PARSER_PATTERN_BINDING
19301959
| PARSER_PATTERN_TARGET_ON_STACK
1931-
| PARSER_PATTERN_LOCAL);
1960+
| PARSER_PATTERN_LET);
19321961

19331962
parser_parse_initializer_by_next_char (context_p, flags);
19341963
}

0 commit comments

Comments
 (0)