From eee88ffdc2ca8823dd2abf805db208c91aa34281 Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Mon, 4 Aug 2014 17:09:02 +0400 Subject: [PATCH] Add basic support of 'break' and 'continue' statements (without identifiers) --- src/libjsparser/parser.c | 435 +++++++++++++++++------ src/libruntime/serializer.h | 3 +- src/libruntime/target/linux/serializer.c | 4 +- 3 files changed, 327 insertions(+), 115 deletions(-) diff --git a/src/libjsparser/parser.c b/src/libjsparser/parser.c index 082fb8f22..82a6b5f2e 100644 --- a/src/libjsparser/parser.c +++ b/src/libjsparser/parser.c @@ -19,14 +19,43 @@ #include "parser.h" #include "opcodes.h" #include "serializer.h" +#include "interpreter.h" #define MAX_OPCODES 10 +#define MAX_NESTINGS 10 #define INVALID_VALUE 255 +typedef enum +{ + REWRITABLE_CONTINUE = 0, + REWRITABLE_BREAK, + REWRITABLE_OPCODES_COUNT +} +rewritable_opcode_type; + +typedef struct +{ + uint8_t size; + uint8_t head; + opcode_counter_t *oc_stack; +} __packed +rewritable_opcode; + +#define NESTING_ITERATIONAL 1 +#define NESTING_SWITCH 2 +#define NESTING_FUNCTION 3 + static token tok; static OPCODE opcode; -static T_IDX opcode_counter = 0; +static opcode_counter_t opcode_counter = 0; static T_IDX temp_name_stack[MAX_OPCODES], temp_name_stack_head = 0, max_temp_name; +static uint8_t nestings[MAX_NESTINGS], nestings_head = 0; + +static rewritable_opcode rewritable_opcodes[REWRITABLE_OPCODES_COUNT] = +{ + [REWRITABLE_CONTINUE] = { .size = 0, .head = 0, .oc_stack = NULL }, + [REWRITABLE_BREAK] = { .size = 0, .head = 0, .oc_stack = NULL } +}; static T_IDX parse_expression (void); static void parse_statement (void); @@ -63,6 +92,47 @@ reset_temp_name (void) temp_name = min_temp_name; } +static void +push_nesting (uint8_t nesting_type) +{ + JERRY_ASSERT (nestings_head < MAX_NESTINGS); + + nestings[nestings_head++] = nesting_type; +} + +static void +pop_nesting (uint8_t nesting_type) +{ + JERRY_ASSERT (nestings_head > 0); + JERRY_ASSERT (nestings[nestings_head - 1] == nesting_type); + + nestings_head--; +} + +static void +must_be_inside_but_not_in (uint8_t inside[], uint8_t insides_count, uint8_t not_in) +{ + int8_t i; + + if (nestings_head == 0) + parser_fatal (ERR_PARSER); + + for (i = (int8_t) (nestings_head - 1); i >= 0; i--) + { + int8_t j; + if (nestings[i] == not_in) + parser_fatal (ERR_PARSER); + + for (j = 0; j < insides_count; j++) + { + if (nestings[i] == inside[j]) + return; + } + } + + parser_fatal (ERR_PARSER); +} + static void assert_keyword (keyword kw) { @@ -144,19 +214,68 @@ insert_semicolon (void) do { skip_newlines (); ID = parse_##TYPE (); } while (0) #define DUMP_VOID_OPCODE(GETOP) \ - do { opcode=getop_##GETOP (); serializer_dump_opcode (opcode); opcode_counter++; } while (0) + do { \ + opcode=getop_##GETOP (); \ + serializer_dump_opcode (opcode); \ + opcode_counter++; \ + } while (0) -#define DUMP_OPCODE(GETOP, ...) \ - do { opcode=getop_##GETOP (__VA_ARGS__); serializer_dump_opcode (opcode); opcode_counter++; } while (0) +#define DUMP_OPCODE_1(GETOP, OP1) \ + do { \ + JERRY_ASSERT (sizeof (OP1) == 1 || OP1 <= 255); \ + opcode=getop_##GETOP ((T_IDX) (OP1)); \ + serializer_dump_opcode (opcode); \ + opcode_counter++; \ + } while (0) -#define REWRITE_OPCODE(OC, GETOP, ...) \ - do { opcode=getop_##GETOP (__VA_ARGS__); serializer_rewrite_opcode (OC, opcode); } while (0) +#define DUMP_OPCODE_2(GETOP, OP1, OP2) \ + do { \ + JERRY_ASSERT (sizeof (OP1) == 1 || OP1 <= 255); \ + JERRY_ASSERT (sizeof (OP2) == 1 || OP2 <= 255); \ + opcode=getop_##GETOP ((T_IDX) (OP1), (T_IDX) (OP2)); \ + serializer_dump_opcode (opcode); \ + opcode_counter++; \ + } while (0) + +#define DUMP_OPCODE_3(GETOP, OP1, OP2, OP3) \ + do { \ + JERRY_ASSERT (sizeof (OP1) == 1 || OP1 <= 255); \ + JERRY_ASSERT (sizeof (OP2) == 1 || OP2 <= 255); \ + JERRY_ASSERT (sizeof (OP3) == 1 || OP3 <= 255); \ + opcode=getop_##GETOP ((T_IDX) (OP1), (T_IDX) (OP2), (T_IDX) (OP3)); \ + serializer_dump_opcode (opcode); \ + opcode_counter++; \ + } while (0) + +#define REWRITE_OPCODE_1(OC, GETOP, OP1) \ + do { \ + JERRY_ASSERT (sizeof (OP1) == 1 || OP1 <= 255); \ + opcode=getop_##GETOP ((T_IDX) (OP1)); \ + serializer_rewrite_opcode (OC, opcode); \ + } while (0) + +#define REWRITE_OPCODE_2(OC, GETOP, OP1, OP2) \ + do { \ + JERRY_ASSERT (sizeof (OP1) == 1 || OP1 <= 255); \ + JERRY_ASSERT (sizeof (OP2) == 1 || OP2 <= 255); \ + opcode=getop_##GETOP ((T_IDX) (OP1), (T_IDX) (OP2)); \ + serializer_rewrite_opcode (OC, opcode); \ + } while (0) + +#define REWRITE_OPCODE_3(OC, GETOP, OP1, OP2, OP3) \ + do { \ + JERRY_ASSERT (sizeof (OP1) == 1 || OP1 <= 255); \ + JERRY_ASSERT (sizeof (OP2) == 1 || OP2 <= 255); \ + JERRY_ASSERT (sizeof (OP3) == 1 || OP3 <= 255); \ + opcode=getop_##GETOP ((T_IDX) (OP1), (T_IDX) (OP2), (T_IDX) (OP3)); \ + serializer_rewrite_opcode (OC, opcode); \ + } while (0) static T_IDX integer_zero (void) { T_IDX lhs = next_temp_name (); - DUMP_OPCODE (assignment, lhs, OPCODE_ARG_TYPE_SMALLINT, 0); + DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_SMALLINT, 0); return lhs; } @@ -164,10 +283,66 @@ static T_IDX integer_one (void) { T_IDX lhs = next_temp_name (); - DUMP_OPCODE (assignment, lhs, OPCODE_ARG_TYPE_SMALLINT, 1); + DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_SMALLINT, 1); return lhs; } +static void +add_to_rewritable_opcodes (rewritable_opcode_type type, opcode_counter_t oc) +{ + rewritable_opcode op = rewritable_opcodes[type]; + if (op.oc_stack == NULL) + { + op.size = op.head = 1; + op.oc_stack = (opcode_counter_t *) mem_heap_alloc_block (sizeof (opcode_counter_t), MEM_HEAP_ALLOC_SHORT_TERM); + op.oc_stack[0] = oc; + return; + } + + if (op.head == op.size) + { + opcode_counter_t *temp = (opcode_counter_t *) mem_heap_alloc_block (sizeof (opcode_counter_t) * op.size * 2, + MEM_HEAP_ALLOC_SHORT_TERM); + __memcpy (temp, op.oc_stack, op.size * sizeof (opcode_counter_t)); + op.size = (uint8_t) (op.size * 2); + temp[op.head++] = oc; + mem_heap_free_block ((uint8_t *) op.oc_stack); + op.oc_stack = temp; + return; + } + + op.oc_stack[op.head++] = oc; +} + +static void +rewrite_rewritable_opcodes (rewritable_opcode_type type, opcode_counter_t oc) +{ + uint8_t i; + rewritable_opcode op = rewritable_opcodes[type]; + + for (i = 0; i < op.head; i++) + { + switch (type) + { + case REWRITABLE_CONTINUE: + REWRITE_OPCODE_1 (op.oc_stack[i], jmp_up, oc); + break; + case REWRITABLE_BREAK: + REWRITE_OPCODE_1 (op.oc_stack[i], jmp_down, oc); + break; + default: + JERRY_UNREACHABLE (); + } + } + + if (op.oc_stack) + { + mem_heap_free_block ((uint8_t *) op.oc_stack); + } + op.oc_stack = NULL; + op.head = op.size = 0; +} + /* property_name : Identifier | StringLiteral @@ -201,7 +376,7 @@ parse_property_name_and_value (void) token_after_newlines_must_be (TOK_COLON); NEXT (value, assignment_expression); - DUMP_OPCODE (prop, lhs, name, value); + DUMP_OPCODE_3 (prop, lhs, name, value); return lhs; } @@ -228,7 +403,7 @@ parse_property_assignment (void) token_after_newlines_must_be (TOK_CLOSE_PAREN); token_after_newlines_must_be (TOK_OPEN_BRACE); - DUMP_OPCODE (prop_get_decl, lhs, name); + DUMP_OPCODE_2 (prop_get_decl, lhs, name); skip_newlines (); parse_source_element_list (); @@ -248,7 +423,7 @@ parse_property_assignment (void) token_after_newlines_must_be (TOK_CLOSE_PAREN); token_after_newlines_must_be (TOK_OPEN_BRACE); - DUMP_OPCODE (prop_set_decl, lhs, name, arg); + DUMP_OPCODE_3 (prop_set_decl, lhs, name, arg); skip_newlines (); parse_source_element_list (); @@ -267,7 +442,7 @@ dump_varg_3 (T_IDX current_param, T_IDX params[3]) { if (current_param == 3) { - DUMP_OPCODE (varg_3, params[0], params[1], params[2]); + DUMP_OPCODE_3 (varg_3, params[0], params[1], params[2]); current_param = 0; } } @@ -278,15 +453,15 @@ dump_varg_end (T_IDX current_param, T_IDX params[3]) switch (current_param) { case 0: - DUMP_OPCODE (varg_1_end, params[0]); + DUMP_OPCODE_1 (varg_1_end, params[0]); break; case 1: - DUMP_OPCODE (varg_2_end, params[0], params[1]); + DUMP_OPCODE_2 (varg_2_end, params[0], params[1]); break; case 2: - DUMP_OPCODE (varg_3_end, params[0], params[1], params[2]); + DUMP_OPCODE_3 (varg_3_end, params[0], params[1], params[2]); break; default: @@ -367,27 +542,27 @@ parse_argument_list (argument_list_type alt, T_IDX obj) switch (alt) { case AL_FUNC_DECL: - DUMP_OPCODE (func_decl_n, obj, args[0], args[1]); + DUMP_OPCODE_3 (func_decl_n, obj, args[0], args[1]); break; case AL_FUNC_EXPR: - DUMP_OPCODE (func_expr_n, lhs, obj, args[0]); + DUMP_OPCODE_3 (func_expr_n, lhs, obj, args[0]); break; case AL_ARRAY_LIT: - DUMP_OPCODE (array_n, lhs, args[0], args[1]); + DUMP_OPCODE_3 (array_n, lhs, args[0], args[1]); break; case AL_OBJECT_LIT: - DUMP_OPCODE (obj_n, lhs, args[0], args[1]); + DUMP_OPCODE_3 (obj_n, lhs, args[0], args[1]); break; case AL_CONSTRUCT_EXPR: - DUMP_OPCODE (construct_n, lhs, obj, args[0]); + DUMP_OPCODE_3 (construct_n, lhs, obj, args[0]); break; case AL_CALL_EXPR: - DUMP_OPCODE (call_n, lhs, obj, args[0]); + DUMP_OPCODE_3 (call_n, lhs, obj, args[0]); break; default: @@ -440,27 +615,27 @@ parse_argument_list (argument_list_type alt, T_IDX obj) switch (alt) { case AL_FUNC_DECL: - DUMP_OPCODE (func_decl_1, obj, args[0]); + DUMP_OPCODE_2 (func_decl_1, obj, args[0]); break; case AL_FUNC_EXPR: - DUMP_OPCODE (func_expr_1, lhs, obj, args[0]); + DUMP_OPCODE_3 (func_expr_1, lhs, obj, args[0]); break; case AL_ARRAY_LIT: - DUMP_OPCODE (array_1, lhs, args[0]); + DUMP_OPCODE_2 (array_1, lhs, args[0]); break; case AL_OBJECT_LIT: - DUMP_OPCODE (obj_1, lhs, args[0]); + DUMP_OPCODE_2 (obj_1, lhs, args[0]); break; case AL_CONSTRUCT_EXPR: - DUMP_OPCODE (construct_1, lhs, obj, args[0]); + DUMP_OPCODE_3 (construct_1, lhs, obj, args[0]); break; case AL_CALL_EXPR: - DUMP_OPCODE (call_1, lhs, obj, args[0]); + DUMP_OPCODE_3 (call_1, lhs, obj, args[0]); break; default: @@ -472,15 +647,15 @@ parse_argument_list (argument_list_type alt, T_IDX obj) switch (alt) { case AL_FUNC_DECL: - DUMP_OPCODE (func_decl_2, obj, args[0], args[1]); + DUMP_OPCODE_3 (func_decl_2, obj, args[0], args[1]); break; case AL_ARRAY_LIT: - DUMP_OPCODE (array_2, lhs, args[0], args[1]); + DUMP_OPCODE_3 (array_2, lhs, args[0], args[1]); break; case AL_OBJECT_LIT: - DUMP_OPCODE (obj_2, lhs, args[0], args[1]); + DUMP_OPCODE_3 (obj_2, lhs, args[0], args[1]); break; default: @@ -498,27 +673,27 @@ parse_argument_list (argument_list_type alt, T_IDX obj) switch (alt) { case AL_FUNC_DECL: - DUMP_OPCODE (func_decl_0, obj); + DUMP_OPCODE_1 (func_decl_0, obj); break; case AL_FUNC_EXPR: - DUMP_OPCODE (func_expr_0, lhs, obj); + DUMP_OPCODE_2 (func_expr_0, lhs, obj); break; case AL_ARRAY_LIT: - DUMP_OPCODE (array_0, lhs); + DUMP_OPCODE_1 (array_0, lhs); break; case AL_OBJECT_LIT: - DUMP_OPCODE (obj_0, lhs); + DUMP_OPCODE_1 (obj_0, lhs); break; case AL_CONSTRUCT_EXPR: - DUMP_OPCODE (construct_0, lhs, obj); + DUMP_OPCODE_2 (construct_0, lhs, obj); break; case AL_CALL_EXPR: - DUMP_OPCODE (call_0, lhs, obj); + DUMP_OPCODE_2 (call_0, lhs, obj); break; default: @@ -539,7 +714,8 @@ parse_argument_list (argument_list_type alt, T_IDX obj) static void parse_function_declaration (void) { - T_IDX name, jmp_oc; + T_IDX name; + opcode_counter_t jmp_oc; assert_keyword (KW_FUNCTION); @@ -551,17 +727,19 @@ parse_function_declaration (void) parse_argument_list (AL_FUNC_DECL, name); jmp_oc = opcode_counter; - DUMP_OPCODE (jmp_down, INVALID_VALUE); + DUMP_OPCODE_1 (jmp_down, INVALID_VALUE); token_after_newlines_must_be (TOK_OPEN_BRACE); skip_newlines (); + push_nesting (NESTING_FUNCTION); parse_source_element_list (); + pop_nesting (NESTING_FUNCTION); next_token_must_be (TOK_CLOSE_BRACE); DUMP_VOID_OPCODE (ret); - REWRITE_OPCODE (jmp_oc, jmp_down, (uint8_t) (opcode_counter - jmp_oc)); + REWRITE_OPCODE_1 (jmp_oc, jmp_down, opcode_counter - jmp_oc); } /* function_expression @@ -570,7 +748,8 @@ parse_function_declaration (void) static T_IDX parse_function_expression (void) { - T_IDX name, lhs, jmp_oc; + T_IDX name, lhs; + opcode_counter_t jmp_oc; assert_keyword (KW_FUNCTION); @@ -587,17 +766,19 @@ parse_function_expression (void) lhs = parse_argument_list (AL_FUNC_EXPR, name); jmp_oc = opcode_counter; - DUMP_OPCODE (jmp_down, INVALID_VALUE); + DUMP_OPCODE_1 (jmp_down, INVALID_VALUE); token_after_newlines_must_be (TOK_OPEN_BRACE); skip_newlines (); + push_nesting (NESTING_FUNCTION); parse_source_element_list (); + pop_nesting (NESTING_FUNCTION); token_after_newlines_must_be (TOK_CLOSE_BRACE); DUMP_VOID_OPCODE (ret); - REWRITE_OPCODE (jmp_oc, jmp_down, (uint8_t) (opcode_counter - jmp_oc)); + REWRITE_OPCODE_1 (jmp_oc, jmp_down, opcode_counter - jmp_oc); return lhs; } @@ -629,23 +810,23 @@ parse_literal (void) { case TOK_NULL: lhs = next_temp_name (); - DUMP_OPCODE (assignment, lhs, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_NULL); + DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_NULL); return lhs; case TOK_BOOL: lhs = next_temp_name (); - DUMP_OPCODE (assignment, lhs, OPCODE_ARG_TYPE_SIMPLE, + DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_SIMPLE, tok.data.uid ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); return lhs; case TOK_INT: lhs = next_temp_name (); - DUMP_OPCODE (assignment, lhs, OPCODE_ARG_TYPE_NUMBER, tok.data.uid); + DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_NUMBER, tok.data.uid); return lhs; case TOK_STRING: lhs = next_temp_name (); - DUMP_OPCODE (assignment, lhs, OPCODE_ARG_TYPE_STRING, tok.data.uid); + DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_STRING, tok.data.uid); return lhs; default: @@ -669,7 +850,7 @@ parse_primary_expression (void) if (is_keyword (KW_THIS)) { lhs = next_temp_name (); - DUMP_OPCODE (this, lhs); + DUMP_OPCODE_1 (this, lhs); return lhs; } else if (tok.type == TOK_NAME) @@ -752,7 +933,7 @@ parse_member_expression (void) else JERRY_UNREACHABLE (); - DUMP_OPCODE (prop_access, lhs, obj, prop); + DUMP_OPCODE_3 (prop_access, lhs, obj, prop); obj = lhs; skip_newlines (); } @@ -807,7 +988,7 @@ parse_call_expression (void) NEXT (prop, expression); next_token_must_be (TOK_CLOSE_SQUARE); - DUMP_OPCODE (prop_access, lhs, obj, prop); + DUMP_OPCODE_3 (prop_access, lhs, obj, prop); obj = lhs; skip_newlines (); break; @@ -816,7 +997,7 @@ parse_call_expression (void) token_after_newlines_must_be (TOK_NAME); prop = tok.data.uid; - DUMP_OPCODE (prop_access, lhs, obj, prop); + DUMP_OPCODE_3 (prop_access, lhs, obj, prop); obj = lhs; skip_newlines (); break; @@ -852,12 +1033,12 @@ parse_postfix_expression (void) if (tok.type == TOK_DOUBLE_PLUS) { lhs = next_temp_name (); - DUMP_OPCODE (post_incr, lhs, expr); + DUMP_OPCODE_2 (post_incr, lhs, expr); } else if (tok.type == TOK_DOUBLE_MINUS) { lhs = next_temp_name (); - DUMP_OPCODE (post_decr, lhs, expr); + DUMP_OPCODE_2 (post_decr, lhs, expr); } else lexer_save_token (tok); @@ -879,37 +1060,37 @@ parse_unary_expression (void) case TOK_DOUBLE_PLUS: lhs = next_temp_name (); NEXT (expr, unary_expression); - DUMP_OPCODE (pre_incr, lhs, expr); + DUMP_OPCODE_2 (pre_incr, lhs, expr); return expr; case TOK_DOUBLE_MINUS: lhs = next_temp_name (); NEXT (expr, unary_expression); - DUMP_OPCODE (pre_decr, lhs, expr); + DUMP_OPCODE_2 (pre_decr, lhs, expr); return expr; case TOK_PLUS: lhs = next_temp_name (); NEXT (expr, unary_expression); - DUMP_OPCODE (addition, lhs, integer_zero (), expr); + DUMP_OPCODE_3 (addition, lhs, integer_zero (), expr); return lhs; case TOK_MINUS: lhs = next_temp_name (); NEXT (expr, unary_expression); - DUMP_OPCODE (substraction, lhs, integer_zero (), expr); + DUMP_OPCODE_3 (substraction, lhs, integer_zero (), expr); return lhs; case TOK_COMPL: lhs = next_temp_name (); NEXT (expr, unary_expression); - DUMP_OPCODE (b_not, lhs, expr); + DUMP_OPCODE_2 (b_not, lhs, expr); return lhs; case TOK_NOT: lhs = next_temp_name (); NEXT (expr, unary_expression); - DUMP_OPCODE (logical_not, lhs, expr); + DUMP_OPCODE_2 (logical_not, lhs, expr); return lhs; case TOK_KEYWORD: @@ -917,7 +1098,7 @@ parse_unary_expression (void) { lhs = next_temp_name (); NEXT (expr, unary_expression); - DUMP_OPCODE (delete, lhs, expr); + DUMP_OPCODE_2 (delete, lhs, expr); return lhs; } if (is_keyword (KW_VOID)) @@ -926,7 +1107,7 @@ parse_unary_expression (void) { lhs = next_temp_name (); NEXT (expr, unary_expression); - DUMP_OPCODE (typeof, lhs, expr); + DUMP_OPCODE_2 (typeof, lhs, expr); return lhs; } /* FALLTHRU. */ @@ -939,7 +1120,7 @@ parse_unary_expression (void) #define DUMP_OF(GETOP, EXPR) \ lhs = next_temp_name (); \ NEXT (expr2, EXPR);\ - DUMP_OPCODE (GETOP, lhs, expr1, expr2); \ + DUMP_OPCODE_3 (GETOP, lhs, expr1, expr2); \ expr1 = lhs; \ break; @@ -1146,23 +1327,24 @@ parse_conditional_expression (bool *was_conditional) skip_newlines (); if (tok.type == TOK_QUERY) { - T_IDX lhs, jmp_oc, res = next_temp_name (); + T_IDX lhs, res = next_temp_name (); + opcode_counter_t jmp_oc; - DUMP_OPCODE (is_true_jmp, expr, (uint8_t) (opcode_counter + 2)); + DUMP_OPCODE_2 (is_true_jmp, expr, opcode_counter + 2); jmp_oc = opcode_counter; - DUMP_OPCODE (jmp_down, INVALID_VALUE); + DUMP_OPCODE_1 (jmp_down, INVALID_VALUE); NEXT (lhs, assignment_expression); - DUMP_OPCODE (assignment, res, OPCODE_ARG_TYPE_VARIABLE, lhs); + DUMP_OPCODE_3 (assignment, res, OPCODE_ARG_TYPE_VARIABLE, lhs); token_after_newlines_must_be (TOK_COLON); - REWRITE_OPCODE (jmp_oc, jmp_down, (uint8_t) (opcode_counter - jmp_oc)); + REWRITE_OPCODE_1 (jmp_oc, jmp_down, opcode_counter - jmp_oc); jmp_oc = opcode_counter; - DUMP_OPCODE (jmp_down, INVALID_VALUE); + DUMP_OPCODE_1 (jmp_down, INVALID_VALUE); NEXT (lhs, assignment_expression); - DUMP_OPCODE (assignment, res, OPCODE_ARG_TYPE_VARIABLE, lhs); - REWRITE_OPCODE (jmp_oc, jmp_down, (uint8_t) (opcode_counter - jmp_oc)); + DUMP_OPCODE_3 (assignment, res, OPCODE_ARG_TYPE_VARIABLE, lhs); + REWRITE_OPCODE_1 (jmp_oc, jmp_down, opcode_counter - jmp_oc); *was_conditional = true; return res; @@ -1195,62 +1377,62 @@ parse_assignment_expression (void) { case TOK_EQ: NEXT (rhs, assignment_expression); - DUMP_OPCODE (assignment, lhs, OPCODE_ARG_TYPE_VARIABLE, rhs); + DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_VARIABLE, rhs); break; case TOK_MULT_EQ: NEXT (rhs, assignment_expression); - DUMP_OPCODE (multiplication, lhs, lhs, rhs); + DUMP_OPCODE_3 (multiplication, lhs, lhs, rhs); break; case TOK_DIV_EQ: NEXT (rhs, assignment_expression); - DUMP_OPCODE (division, lhs, lhs, rhs); + DUMP_OPCODE_3 (division, lhs, lhs, rhs); break; case TOK_MOD_EQ: NEXT (rhs, assignment_expression); - DUMP_OPCODE (remainder, lhs, lhs, rhs); + DUMP_OPCODE_3 (remainder, lhs, lhs, rhs); break; case TOK_PLUS_EQ: NEXT (rhs, assignment_expression); - DUMP_OPCODE (addition, lhs, lhs, rhs); + DUMP_OPCODE_3 (addition, lhs, lhs, rhs); break; case TOK_MINUS_EQ: NEXT (rhs, assignment_expression); - DUMP_OPCODE (substraction, lhs, lhs, rhs); + DUMP_OPCODE_3 (substraction, lhs, lhs, rhs); break; case TOK_LSHIFT_EQ: NEXT (rhs, assignment_expression); - DUMP_OPCODE (b_shift_left, lhs, lhs, rhs); + DUMP_OPCODE_3 (b_shift_left, lhs, lhs, rhs); break; case TOK_RSHIFT_EQ: NEXT (rhs, assignment_expression); - DUMP_OPCODE (b_shift_right, lhs, lhs, rhs); + DUMP_OPCODE_3 (b_shift_right, lhs, lhs, rhs); break; case TOK_RSHIFT_EX_EQ: NEXT (rhs, assignment_expression); - DUMP_OPCODE (b_shift_uright, lhs, lhs, rhs); + DUMP_OPCODE_3 (b_shift_uright, lhs, lhs, rhs); break; case TOK_AND_EQ: NEXT (rhs, assignment_expression); - DUMP_OPCODE (b_and, lhs, lhs, rhs); + DUMP_OPCODE_3 (b_and, lhs, lhs, rhs); break; case TOK_XOR_EQ: NEXT (rhs, assignment_expression); - DUMP_OPCODE (b_xor, lhs, lhs, rhs); + DUMP_OPCODE_3 (b_xor, lhs, lhs, rhs); break; case TOK_OR_EQ: NEXT (rhs, assignment_expression); - DUMP_OPCODE (b_or, lhs, lhs, rhs); + DUMP_OPCODE_3 (b_or, lhs, lhs, rhs); break; default: @@ -1295,13 +1477,13 @@ parse_variable_declaration (void) current_token_must_be (TOK_NAME); name = tok.data.uid; - DUMP_OPCODE (var_decl, name); + DUMP_OPCODE_1 (var_decl, name); skip_newlines (); if (tok.type == TOK_EQ) { NEXT (expr, assignment_expression); - DUMP_OPCODE (assignment, name, OPCODE_ARG_TYPE_VARIABLE, expr); + DUMP_OPCODE_3 (assignment, name, OPCODE_ARG_TYPE_VARIABLE, expr); } else lexer_save_token (tok); @@ -1354,7 +1536,8 @@ parse_variable_declaration_list (bool *several_decls) static void parse_for_or_for_in_statement (void) { - T_IDX stop, cond_oc, body_oc, step_oc, end_oc; + T_IDX stop; + opcode_counter_t cond_oc, body_oc, step_oc, end_oc; assert_keyword (KW_FOR); token_after_newlines_must_be (TOK_OPEN_PAREN); @@ -1438,10 +1621,10 @@ plain_for: stop = integer_one (); end_oc = opcode_counter; - DUMP_OPCODE (is_false_jmp, stop, INVALID_VALUE); + DUMP_OPCODE_2 (is_false_jmp, stop, INVALID_VALUE); body_oc = opcode_counter; - DUMP_OPCODE (jmp_down, INVALID_VALUE); + DUMP_OPCODE_1 (jmp_down, INVALID_VALUE); step_oc = opcode_counter; skip_newlines (); @@ -1450,14 +1633,19 @@ plain_for: parse_assignment_expression (); next_token_must_be (TOK_CLOSE_PAREN); } - DUMP_OPCODE (jmp_up, (uint8_t) (opcode_counter - cond_oc)); - REWRITE_OPCODE (body_oc, jmp_down, (uint8_t) (opcode_counter - body_oc)); + DUMP_OPCODE_1 (jmp_up, opcode_counter - cond_oc); + REWRITE_OPCODE_1 (body_oc, jmp_down, opcode_counter - body_oc); skip_newlines (); + push_nesting (NESTING_ITERATIONAL); parse_statement (); + pop_nesting (NESTING_ITERATIONAL); - DUMP_OPCODE (jmp_up, (uint8_t) (opcode_counter - step_oc)); - REWRITE_OPCODE (end_oc, is_false_jmp, stop, opcode_counter); + DUMP_OPCODE_1 (jmp_up, opcode_counter - step_oc); + REWRITE_OPCODE_2 (end_oc, is_false_jmp, stop, opcode_counter); + + rewrite_rewritable_opcodes (REWRITABLE_CONTINUE, step_oc); + rewrite_rewritable_opcodes (REWRITABLE_BREAK, opcode_counter); return; for_in: @@ -1485,14 +1673,16 @@ parse_statement_list (void) { parse_statement (); - tok = lexer_next_token (); - if (tok.type != TOK_NEWLINE && tok.type != TOK_SEMICOLON) + skip_newlines (); + while (tok.type == TOK_SEMICOLON) + { + skip_newlines (); + } + if (tok.type == TOK_CLOSE_BRACE) { lexer_save_token (tok); return; } - - skip_newlines (); } } @@ -1502,17 +1692,18 @@ parse_statement_list (void) static void parse_if_statement (void) { - T_IDX cond, cond_oc; + T_IDX cond; + opcode_counter_t cond_oc; assert_keyword (KW_IF); cond = parse_expression_inside_parens (); cond_oc = opcode_counter; - DUMP_OPCODE (is_false_jmp, cond, INVALID_VALUE); + DUMP_OPCODE_2 (is_false_jmp, cond, INVALID_VALUE); skip_newlines (); parse_statement (); - REWRITE_OPCODE (cond_oc, is_false_jmp, cond, opcode_counter); + REWRITE_OPCODE_2 (cond_oc, is_false_jmp, cond, opcode_counter); skip_newlines (); if (is_keyword (KW_ELSE)) @@ -1530,18 +1721,24 @@ parse_if_statement (void) static void parse_do_while_statement (void) { - T_IDX cond, loop_oc; + T_IDX cond; + opcode_counter_t loop_oc; assert_keyword (KW_DO); loop_oc = opcode_counter; skip_newlines (); + push_nesting (NESTING_ITERATIONAL); parse_statement (); + pop_nesting (NESTING_ITERATIONAL); token_after_newlines_must_be_keyword (KW_WHILE); cond = parse_expression_inside_parens (); - DUMP_OPCODE (is_true_jmp, cond, loop_oc); + DUMP_OPCODE_2 (is_true_jmp, cond, loop_oc); + + rewrite_rewritable_opcodes (REWRITABLE_CONTINUE, loop_oc); + rewrite_rewritable_opcodes (REWRITABLE_BREAK, opcode_counter); } /* while_statement @@ -1550,20 +1747,26 @@ parse_do_while_statement (void) static void parse_while_statement (void) { - T_IDX cond, cond_oc, jmp_oc; + T_IDX cond; + opcode_counter_t cond_oc, jmp_oc; assert_keyword (KW_WHILE); cond_oc = opcode_counter; cond = parse_expression_inside_parens (); jmp_oc = opcode_counter; - DUMP_OPCODE (is_false_jmp, cond, INVALID_VALUE); + DUMP_OPCODE_2 (is_false_jmp, cond, INVALID_VALUE); skip_newlines (); + push_nesting (NESTING_ITERATIONAL); parse_statement (); + pop_nesting (NESTING_ITERATIONAL); - DUMP_OPCODE (jmp_up, (uint8_t) (opcode_counter - cond_oc)); - REWRITE_OPCODE (jmp_oc, is_false_jmp, cond, opcode_counter); + DUMP_OPCODE_1 (jmp_up, opcode_counter - cond_oc); + REWRITE_OPCODE_2 (jmp_oc, is_false_jmp, cond, opcode_counter); + + rewrite_rewritable_opcodes (REWRITABLE_CONTINUE, cond_oc); + rewrite_rewritable_opcodes (REWRITABLE_BREAK, opcode_counter); } /* with_statement @@ -1576,7 +1779,7 @@ parse_with_statement (void) assert_keyword (KW_WITH); expr = parse_expression_inside_parens (); - DUMP_OPCODE (with, expr); + DUMP_OPCODE_1 (with, expr); skip_newlines (); parse_statement (); @@ -1725,11 +1928,19 @@ parse_statement (void) } if (is_keyword (KW_CONTINUE)) { - JERRY_UNIMPLEMENTED (); + must_be_inside_but_not_in ((uint8_t[]){NESTING_ITERATIONAL, NESTING_SWITCH}, 2, + NESTING_FUNCTION); + add_to_rewritable_opcodes (REWRITABLE_CONTINUE, opcode_counter); + DUMP_OPCODE_1 (jmp_up, INVALID_VALUE); + return; } if (is_keyword (KW_BREAK)) { - JERRY_UNIMPLEMENTED (); + must_be_inside_but_not_in ((uint8_t[]){NESTING_ITERATIONAL, NESTING_SWITCH}, 2, + NESTING_FUNCTION); + add_to_rewritable_opcodes (REWRITABLE_BREAK, opcode_counter); + DUMP_OPCODE_1 (jmp_down, INVALID_VALUE); + return; } if (is_keyword (KW_RETURN)) { @@ -1738,7 +1949,7 @@ parse_statement (void) if (tok.type != TOK_SEMICOLON) { expr = parse_expression (); - DUMP_OPCODE (retval, expr); + DUMP_OPCODE_1 (retval, expr); } else DUMP_VOID_OPCODE (ret); @@ -1806,11 +2017,11 @@ parse_source_element (void) static void parse_source_element_list (void) { - T_IDX reg_var_decl_loc; + opcode_counter_t reg_var_decl_loc; start_new_scope (); reg_var_decl_loc = opcode_counter; - DUMP_OPCODE (reg_var_decl, min_temp_name, INVALID_VALUE); + DUMP_OPCODE_2 (reg_var_decl, min_temp_name, INVALID_VALUE); while (tok.type != TOK_EOF && tok.type != TOK_CLOSE_BRACE) { @@ -1819,9 +2030,9 @@ parse_source_element_list (void) } lexer_save_token (tok); if (max_temp_name > min_temp_name) - REWRITE_OPCODE (reg_var_decl_loc, reg_var_decl, min_temp_name, (uint8_t) (max_temp_name - 1)); + REWRITE_OPCODE_2 (reg_var_decl_loc, reg_var_decl, min_temp_name, max_temp_name - 1); else if (max_temp_name == min_temp_name) - REWRITE_OPCODE (reg_var_decl_loc, reg_var_decl, min_temp_name, max_temp_name); + REWRITE_OPCODE_2 (reg_var_decl_loc, reg_var_decl, min_temp_name, max_temp_name); else JERRY_UNREACHABLE (); finish_scope (); @@ -1839,7 +2050,7 @@ parser_parse_program (void) skip_newlines (); JERRY_ASSERT (tok.type == TOK_EOF); - DUMP_OPCODE (exitval, 0); + DUMP_OPCODE_1 (exitval, 0); } void diff --git a/src/libruntime/serializer.h b/src/libruntime/serializer.h index ba8759df0..624016c2b 100644 --- a/src/libruntime/serializer.h +++ b/src/libruntime/serializer.h @@ -18,6 +18,7 @@ #include "globals.h" #include "opcodes.h" +#include "interpreter.h" void serializer_init (bool show_opcodes); @@ -27,7 +28,7 @@ void serializer_dump_nums (const int32_t *, uint8_t, uint16_t, uint8_t); void serializer_dump_opcode (OPCODE); -void serializer_rewrite_opcode (const uint8_t, OPCODE); +void serializer_rewrite_opcode (const opcode_counter_t, OPCODE); void serializer_print_opcodes (void); diff --git a/src/libruntime/target/linux/serializer.c b/src/libruntime/target/linux/serializer.c index c3a538264..1e67cfa56 100644 --- a/src/libruntime/target/linux/serializer.c +++ b/src/libruntime/target/linux/serializer.c @@ -128,7 +128,7 @@ serializer_dump_nums (const int32_t nums[], uint8_t size, uint16_t offset, uint8 #endif } -static int32_t opcode_counter = 0; +static opcode_counter_t opcode_counter = 0; void serializer_dump_opcode (OPCODE opcode) @@ -152,7 +152,7 @@ serializer_dump_opcode (OPCODE opcode) } void -serializer_rewrite_opcode (const uint8_t loc, OPCODE opcode) +serializer_rewrite_opcode (const opcode_counter_t loc, OPCODE opcode) { uint8_t i; uint8_t opcode_num = opcode.op_idx;