Skip to content

Commit 2f99a0c

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 2f99a0c

File tree

15 files changed

+611
-177
lines changed

15 files changed

+611
-177
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: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2251,9 +2251,9 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */
22512251
*/
22522252
static uint8_t
22532253
parser_append_binary_single_assignment_token (parser_context_t *context_p, /**< context */
2254-
bool is_lexical) /**< assign lexical declaration */
2254+
uint32_t pattern_flags) /**< pattern flags */
22552255
{
2256-
JERRY_UNUSED (is_lexical);
2256+
JERRY_UNUSED (pattern_flags);
22572257

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

23032303
#if ENABLED (JERRY_ES2015)
2304-
if (!is_lexical)
2304+
if (!(pattern_flags & (PARSER_PATTERN_LET | PARSER_PATTERN_CONST | PARSER_PATTERN_LOCAL)))
23052305
{
23062306
if (scanner_literal_is_const_reg (context_p, literal_index))
23072307
{
@@ -2310,7 +2310,20 @@ parser_append_binary_single_assignment_token (parser_context_t *context_p, /**<
23102310
}
23112311
else if (literal_index < PARSER_REGISTER_START)
23122312
{
2313-
assign_opcode = CBC_ASSIGN_LET_CONST;
2313+
assign_opcode = CBC_INIT_LET;
2314+
2315+
if (scanner_literal_is_created (context_p, literal_index))
2316+
{
2317+
assign_opcode = CBC_ASSIGN_LET_CONST;
2318+
}
2319+
else if (pattern_flags & PARSER_PATTERN_CONST)
2320+
{
2321+
assign_opcode = CBC_INIT_CONST;
2322+
}
2323+
else if (pattern_flags & PARSER_PATTERN_LOCAL)
2324+
{
2325+
assign_opcode = CBC_INIT_ARG_OR_CATCH;
2326+
}
23142327
}
23152328
#endif /* ENABLED (JERRY_ES2015) */
23162329

@@ -2395,7 +2408,7 @@ parser_append_binary_token (parser_context_t *context_p) /**< context */
23952408

23962409
if (context_p->token.type == LEXER_ASSIGN)
23972410
{
2398-
parser_append_binary_single_assignment_token (context_p, false);
2411+
parser_append_binary_single_assignment_token (context_p, 0);
23992412
return;
24002413
}
24012414

@@ -2486,7 +2499,10 @@ parser_process_binary_opcodes (parser_context_t *context_p, /**< context */
24862499
JERRY_ASSERT (opcode == CBC_ASSIGN_SET_IDENT
24872500
|| opcode == CBC_ASSIGN_PROP_LITERAL
24882501
|| opcode == CBC_ASSIGN_PROP_THIS_LITERAL
2489-
|| opcode == CBC_ASSIGN_LET_CONST);
2502+
|| opcode == CBC_ASSIGN_LET_CONST
2503+
|| opcode == CBC_INIT_ARG_OR_CATCH
2504+
|| opcode == CBC_INIT_LET
2505+
|| opcode == CBC_INIT_CONST);
24902506

24912507
index = parser_stack_pop_uint16 (context_p);
24922508
}
@@ -2601,7 +2617,7 @@ parser_pattern_get_target (parser_context_t *context_p, /**< context */
26012617
{
26022618
JERRY_ASSERT (flags & PARSER_PATTERN_TARGET_ON_STACK);
26032619

2604-
parser_emit_cbc_forward_branch (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_DEFAULT_INITIALIZER), &skip_init);
2620+
parser_emit_cbc_ext_forward_branch (context_p, CBC_EXT_DEFAULT_INITIALIZER, &skip_init);
26052621
}
26062622

26072623
if ((flags & (PARSER_PATTERN_TARGET_ON_STACK | PARSER_PATTERN_TARGET_DEFAULT)) != PARSER_PATTERN_TARGET_ON_STACK)
@@ -2707,8 +2723,7 @@ parser_pattern_form_assignment (parser_context_t *context_p, /**< context */
27072723
JERRY_UNUSED (ident_line_counter);
27082724

27092725
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);
2726+
uint8_t assign_opcode = parser_append_binary_single_assignment_token (context_p, flags);
27122727

27132728
if (flags & PARSER_PATTERN_ARRAY)
27142729
{
@@ -2724,7 +2739,7 @@ parser_pattern_form_assignment (parser_context_t *context_p, /**< context */
27242739
{
27252740
parser_branch_t skip_init;
27262741
lexer_next_token (context_p);
2727-
parser_emit_cbc_forward_branch (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_DEFAULT_INITIALIZER), &skip_init);
2742+
parser_emit_cbc_ext_forward_branch (context_p, CBC_EXT_DEFAULT_INITIALIZER, &skip_init);
27282743

27292744
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
27302745
parser_set_branch_to_current_position (context_p, &skip_init);
@@ -2770,7 +2785,8 @@ parser_pattern_process_nested_pattern (parser_context_t *context_p, /**< context
27702785
parser_pattern_flags_t options = (PARSER_PATTERN_NESTED_PATTERN
27712786
| PARSER_PATTERN_TARGET_ON_STACK
27722787
| (flags & (PARSER_PATTERN_BINDING
2773-
| PARSER_PATTERN_LEXICAL
2788+
| PARSER_PATTERN_LET
2789+
| PARSER_PATTERN_CONST
27742790
| PARSER_PATTERN_LOCAL
27752791
| PARSER_PATTERN_REST_ELEMENT
27762792
| PARSER_PATTERN_ARGUMENTS)));
@@ -2821,7 +2837,7 @@ parser_pattern_process_assignment (parser_context_t *context_p, /**< context */
28212837

28222838
lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL);
28232839

2824-
if (flags & PARSER_PATTERN_LEXICAL
2840+
if (flags & (PARSER_PATTERN_LET | PARSER_PATTERN_CONST)
28252841
&& context_p->token.keyword_type == LEXER_KEYW_LET)
28262842
{
28272843
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: 42 additions & 10 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

@@ -1289,8 +1303,6 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
12891303
#if ENABLED (JERRY_ES2015)
12901304
if (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE))
12911305
{
1292-
bool is_var = (token_type == LEXER_KEYW_VAR);
1293-
12941306
parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
12951307
: CBC_EXT_FOR_OF_GET_NEXT);
12961308

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

13041316
parser_pattern_flags_t flags = (PARSER_PATTERN_BINDING | PARSER_PATTERN_TARGET_ON_STACK);
13051317

1306-
if (!is_var)
1318+
if (token_type == LEXER_KEYW_LET)
1319+
{
1320+
flags |= PARSER_PATTERN_LET;
1321+
}
1322+
else if (token_type == LEXER_KEYW_CONST)
13071323
{
1308-
flags |= PARSER_PATTERN_LEXICAL;
1324+
flags |= PARSER_PATTERN_CONST;
13091325
}
13101326

13111327
parser_parse_initializer_by_next_char (context_p, flags);
@@ -1347,9 +1363,25 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
13471363
}
13481364
#endif /* !JERRY_NDEBUG */
13491365

1350-
parser_emit_cbc_literal (context_p,
1351-
has_context ? CBC_ASSIGN_LET_CONST : CBC_ASSIGN_SET_IDENT,
1352-
literal_index);
1366+
uint16_t opcode = CBC_ASSIGN_SET_IDENT;
1367+
1368+
if (has_context && literal_index < PARSER_REGISTER_START)
1369+
{
1370+
JERRY_ASSERT (token_type == LEXER_KEYW_LET || token_type == LEXER_KEYW_CONST);
1371+
1372+
opcode = CBC_INIT_LET;
1373+
1374+
if (scanner_literal_is_created (context_p, literal_index))
1375+
{
1376+
opcode = CBC_ASSIGN_LET_CONST;
1377+
}
1378+
else if (token_type == LEXER_KEYW_CONST)
1379+
{
1380+
opcode = CBC_INIT_CONST;
1381+
}
1382+
}
1383+
1384+
parser_emit_cbc_literal (context_p, opcode, literal_index);
13531385
#else /* !ENABLED (JERRY_ES2015) */
13541386
parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index);
13551387
#endif /* ENABLED (JERRY_ES2015) */

0 commit comments

Comments
 (0)