From e77bd4f4e5bd8f48ea9f334e26b0b7f78e911dbf Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Tue, 16 Sep 2014 21:22:11 +0400 Subject: [PATCH] Add try-catch-finally support: parse and generate opcodes for this construct Fix varg generation: generate *_n opcodes with parameters in following meta opcodes Add stack internal structure: dimanically allocated stack. Use dynamically allocated memory in parser: every local and global variables are stored in dinamically allocated stacks. Use dynamically allocated memory in serializer: opcodes are also stored in stack. Change is_true_jmp and is_false_jmp opcodes to relative. Change *jmp* opcodes to be able to store opcode_counter_t instead of idx_t. --- .gitignore | 1 + Makefile.mk | 8 +- src/config.h | 2 +- src/libcoreint/opcodes-agnostic.c | 122 +- src/libcoreint/opcodes.h | 11 +- src/libintstructs/stack.h | 180 ++ src/libjsparser/lexer.c | 116 +- src/libjsparser/lexer.h | 7 +- src/libjsparser/parser.c | 2104 ++++++++++------- src/libjsparser/parser.h | 1 + src/liboptimizer/bytecode-data.h | 22 +- src/liboptimizer/deserializer.c | 3 +- src/liboptimizer/optimizer-passes.c | 376 --- src/liboptimizer/optimizer-passes.h | 3 - src/liboptimizer/pretty-printer.c | 21 +- src/liboptimizer/serializer.c | 23 +- src/main.c | 1 + .../test_addition_opcode_number_operands.c | 1 + tests/unit/test_array_obj.c | 33 +- tests/unit/test_assignment_opcode.c | 24 +- tests/unit/test_obj_initializer.c | 14 +- tests/unit/test_optimizer_adjust_jumps.c | 94 - tests/unit/test_optimizer_for_loops.c | 98 - tests/unit/test_optimizer_reorder_scope.c | 75 - tests/unit/test_try_catch.c | 4 +- .../test_var_decl_opcode_in_decl_lex_env.c | 10 +- 26 files changed, 1644 insertions(+), 1710 deletions(-) create mode 100644 src/libintstructs/stack.h delete mode 100644 tests/unit/test_optimizer_adjust_jumps.c delete mode 100644 tests/unit/test_optimizer_for_loops.c delete mode 100644 tests/unit/test_optimizer_reorder_scope.c diff --git a/.gitignore b/.gitignore index 27ed1f973..0a33559ef 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ core vgcore.* **.orig **.directory +**.patch # ctags and ID database tags diff --git a/Makefile.mk b/Makefile.mk index f2a73ce08..35b6691b2 100644 --- a/Makefile.mk +++ b/Makefile.mk @@ -285,8 +285,9 @@ SOURCES_JERRY_H = \ $(wildcard ./src/libecmaoperations/*.h) \ $(wildcard ./src/liballocator/*.h) \ $(wildcard ./src/libcoreint/*.h) \ - $(wildcard ./src/liboptimizer/*.h) ) \ - $(wildcard ./src/libruntime/target/$(TARGET_SYSTEM)/*.h) + $(wildcard ./src/liboptimizer/*.h) \ + $(wildcard ./src/libintstructs/*.h) \ + $(wildcard ./src/libruntime/target/$(TARGET_SYSTEM)/*.h) ) SOURCES_JERRY_ASM = \ $(wildcard src/libruntime/target/$(TARGET_SYSTEM)/*.S) @@ -302,7 +303,8 @@ INCLUDES_JERRY = \ -I src/libecmaoperations \ -I src/liballocator \ -I src/liboptimizer \ - -I src/libcoreint + -I src/libcoreint \ + -I src/libintstructs # libc ifeq ($(OPTION_LIBC),musl) diff --git a/src/config.h b/src/config.h index e03cc7855..288339704 100644 --- a/src/config.h +++ b/src/config.h @@ -55,7 +55,7 @@ /** * Size of heap */ -#define CONFIG_MEM_HEAP_AREA_SIZE (2 * 1024 + 512) +#define CONFIG_MEM_HEAP_AREA_SIZE (4 * 1024 + 512) /** * Log2 of maximum possible offset in the heap diff --git a/src/libcoreint/opcodes-agnostic.c b/src/libcoreint/opcodes-agnostic.c index 7d2446238..f84b09ded 100644 --- a/src/libcoreint/opcodes-agnostic.c +++ b/src/libcoreint/opcodes-agnostic.c @@ -20,15 +20,16 @@ * 'Jump if true' opcode handler. * * Note: - * the opcode changes current opcode position to specified opcode index + * current opcode's position changes by adding specified offset * if argument evaluates to true. */ ecma_completion_value_t -opfunc_is_true_jmp (opcode_t opdata, /**< operation data */ - int_data_t *int_data) /**< interpreter context */ +opfunc_is_true_jmp_down (opcode_t opdata, /**< operation data */ + int_data_t *int_data) /**< interpreter context */ { - const idx_t cond_var_idx = opdata.data.is_true_jmp.value; - const idx_t dst_opcode_idx = opdata.data.is_true_jmp.opcode; + const idx_t cond_var_idx = opdata.data.is_true_jmp_down.value; + const opcode_counter_t offset = calc_opcode_counter_from_idx_idx (opdata.data.is_true_jmp_down.opcode_1, + opdata.data.is_true_jmp_down.opcode_2); ecma_completion_value_t ret_value; @@ -39,7 +40,8 @@ opfunc_is_true_jmp (opcode_t opdata, /**< operation data */ if (ecma_is_value_true (to_bool_completion.u.value)) { - int_data->pos = dst_opcode_idx; + JERRY_ASSERT (offset != 0); + int_data->pos = (opcode_counter_t) (int_data->pos + offset); } else { @@ -51,21 +53,55 @@ opfunc_is_true_jmp (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (cond_value); return ret_value; -} /* opfunc_is_true_jmp */ +} + +/* Likewise to opfunc_is_true_jmp_down, but jumps up. */ +ecma_completion_value_t +opfunc_is_true_jmp_up (opcode_t opdata, /**< operation data */ + int_data_t *int_data) /**< interpreter context */ +{ + const idx_t cond_var_idx = opdata.data.is_true_jmp_up.value; + const opcode_counter_t offset = calc_opcode_counter_from_idx_idx (opdata.data.is_true_jmp_up.opcode_1, + opdata.data.is_true_jmp_up.opcode_2); + + ecma_completion_value_t ret_value; + + ECMA_TRY_CATCH (cond_value, get_variable_value (int_data, cond_var_idx, false), ret_value); + + ecma_completion_value_t to_bool_completion = ecma_op_to_boolean (cond_value.u.value); + JERRY_ASSERT (ecma_is_completion_value_normal (to_bool_completion)); + + if (ecma_is_value_true (to_bool_completion.u.value)) + { + JERRY_ASSERT (offset != 0 && int_data->pos >= offset); + int_data->pos = (opcode_counter_t) (int_data->pos - offset); + } + else + { + int_data->pos++; + } + + ret_value = ecma_make_empty_completion_value (); + + ECMA_FINALIZE (cond_value); + + return ret_value; +} /** * 'Jump if false' opcode handler. * * Note: - * the opcode changes current opcode position to specified opcode index + * current opcode's position changes by adding specified offset * if argument evaluates to false. */ ecma_completion_value_t -opfunc_is_false_jmp (opcode_t opdata, /**< operation data */ - int_data_t *int_data) /**< interpreter context */ +opfunc_is_false_jmp_down (opcode_t opdata, /**< operation data */ + int_data_t *int_data) /**< interpreter context */ { - const idx_t cond_var_idx = opdata.data.is_false_jmp.value; - const idx_t dst_opcode_idx = opdata.data.is_false_jmp.opcode; + const idx_t cond_var_idx = opdata.data.is_false_jmp_down.value; + const opcode_counter_t offset = calc_opcode_counter_from_idx_idx (opdata.data.is_false_jmp_down.opcode_1, + opdata.data.is_false_jmp_down.opcode_2); ecma_completion_value_t ret_value; @@ -76,7 +112,8 @@ opfunc_is_false_jmp (opcode_t opdata, /**< operation data */ if (!ecma_is_value_true (to_bool_completion.u.value)) { - int_data->pos = dst_opcode_idx; + JERRY_ASSERT (offset != 0); + int_data->pos = (opcode_counter_t) (int_data->pos + offset); } else { @@ -88,22 +125,40 @@ opfunc_is_false_jmp (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (cond_value); return ret_value; -} /* opfunc_is_false_jmp */ +} -/** - * 'Jump' opcode handler. - * - * Note: - * the opcode changes current opcode position to specified opcode index - */ +/* Likewise to opfunc_is_false_jmp_down, but jumps up. */ ecma_completion_value_t -opfunc_jmp (opcode_t opdata, /**< operation data */ - int_data_t *int_data) /**< interpreter context */ +opfunc_is_false_jmp_up (opcode_t opdata, /**< operation data */ + int_data_t *int_data) /**< interpreter context */ { - int_data->pos = opdata.data.jmp.opcode_idx; + const idx_t cond_var_idx = opdata.data.is_false_jmp_up.value; + const opcode_counter_t offset = calc_opcode_counter_from_idx_idx (opdata.data.is_false_jmp_up.opcode_1, + opdata.data.is_false_jmp_up.opcode_2); - return ecma_make_empty_completion_value (); -} /* opfunc_jmp */ + ecma_completion_value_t ret_value; + + ECMA_TRY_CATCH (cond_value, get_variable_value (int_data, cond_var_idx, false), ret_value); + + ecma_completion_value_t to_bool_completion = ecma_op_to_boolean (cond_value.u.value); + JERRY_ASSERT (ecma_is_completion_value_normal (to_bool_completion)); + + if (!ecma_is_value_true (to_bool_completion.u.value)) + { + JERRY_ASSERT (offset != 0 && int_data->pos >= offset); + int_data->pos = (opcode_counter_t) (int_data->pos - offset); + } + else + { + int_data->pos++; + } + + ret_value = ecma_make_empty_completion_value (); + + ECMA_FINALIZE (cond_value); + + return ret_value; +} /** * 'Jump down' opcode handler. @@ -115,12 +170,15 @@ ecma_completion_value_t opfunc_jmp_down (opcode_t opdata, /**< operation data */ int_data_t *int_data) /**< interpreter context */ { - JERRY_ASSERT (int_data->pos <= int_data->pos + opdata.data.jmp_up.opcode_count); + const opcode_counter_t offset = calc_opcode_counter_from_idx_idx (opdata.data.jmp_down.opcode_1, + opdata.data.jmp_down.opcode_2); - int_data->pos = (opcode_counter_t) (int_data->pos + opdata.data.jmp_down.opcode_count); + JERRY_ASSERT (offset != 0); + + int_data->pos = (opcode_counter_t) (int_data->pos + offset); return ecma_make_empty_completion_value (); -} /* opfunc_jmp_down */ +} /** * 'Jump up' opcode handler. @@ -132,9 +190,11 @@ ecma_completion_value_t opfunc_jmp_up (opcode_t opdata, /**< operation data */ int_data_t *int_data) /**< interpreter context */ { - JERRY_ASSERT (int_data->pos >= opdata.data.jmp_up.opcode_count); + const opcode_counter_t offset = calc_opcode_counter_from_idx_idx (opdata.data.jmp_up.opcode_1, + opdata.data.jmp_up.opcode_2); + JERRY_ASSERT (offset != 0 && int_data->pos >= offset); - int_data->pos = (opcode_counter_t) (int_data->pos - opdata.data.jmp_down.opcode_count); + int_data->pos = (opcode_counter_t) (int_data->pos - offset); return ecma_make_empty_completion_value (); -} /* opfunc_jmp_up */ +} diff --git a/src/libcoreint/opcodes.h b/src/libcoreint/opcodes.h index 2aa42169f..f4ddaf344 100644 --- a/src/libcoreint/opcodes.h +++ b/src/libcoreint/opcodes.h @@ -165,12 +165,13 @@ opcode_counter_t read_meta_opcode_counter (opcode_meta_type expected_type, int_d p##_3 (a, remainder, dst, var_left, var_right) #define OP_JUMPS(p, a) \ - p##_1 (a, jmp, opcode_idx) \ - p##_1 (a, jmp_up, opcode_count) \ - p##_1 (a, jmp_down, opcode_count) \ + p##_2 (a, jmp_up, opcode_1, opcode_2) \ + p##_2 (a, jmp_down, opcode_1, opcode_2) \ p##_0 (a, nop) \ - p##_2 (a, is_true_jmp, value, opcode) \ - p##_2 (a, is_false_jmp, value, opcode) + p##_3 (a, is_true_jmp_up, value, opcode_1, opcode_2) \ + p##_3 (a, is_true_jmp_down, value, opcode_1, opcode_2) \ + p##_3 (a, is_false_jmp_up, value, opcode_1, opcode_2) \ + p##_3 (a, is_false_jmp_down, value, opcode_1, opcode_2) #define OP_LIST_FULL(p, a) \ OP_CALLS_AND_ARGS (p, a) \ diff --git a/src/libintstructs/stack.h b/src/libintstructs/stack.h new file mode 100644 index 000000000..ad3f5c25a --- /dev/null +++ b/src/libintstructs/stack.h @@ -0,0 +1,180 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + This file contains macros to define and use stacks. + Do define stack type use macro DEFINE_STACK_TYPE. + After definition of type use macro STACK to create stack variable and define all necessaty routines. + Also, define variable with name NAME##_global_size. If the variable more than 0, + first NAME##_global_size element will remain untouched during PUSH and POP operations. + Before using the stack, init it by calling INIT_STACK macro. + Use macros PUSH, POP, DROP, CLEAN and HEAD to manipulate the stack. + DO NOT FORGET to free stack memory by calling FREE_STACK macro. + For check usage of stack during a function, use DECLARE_USAGE and CHECK_USAGE macros. + + Example (parser.c): + + #ifndef UINT8_T_STACK_DEFINED + #define UINT8_T_STACK_DEFINED + DEFINE_STACK_TYPE (uint8_t) + #endif + + enum + { + temp_name, + min_temp_name, + max_temp_name, + temp_names_global_size + }; + STACK(uint8_t, temp_names) + + #define GLOBAL(NAME, VAR) \ + NAME.data[VAR] + + #define MAX_TEMP_NAME() \ + GLOBAL(temp_names, max_temp_name) + + #define MIN_TEMP_NAME() \ + GLOBAL(temp_names, min_temp_name) + + #define TEMP_NAME() \ + GLOBAL(temp_names, temp_name) + + void + parser_init (void) + { + INIT_STACK(uint8_t, temp_names) + } + + void + parser_free (void) + { + FREE_STACK(temp_names) + } +*/ +#ifndef STACK_H +#define STACK_H + +#define DEFINE_STACK_TYPE(DATA_TYPE, TYPE) \ +typedef struct \ +{ \ + DATA_TYPE length; \ + DATA_TYPE current; \ + TYPE *data; \ +} \ +__packed \ +TYPE##_stack; + +#define INIT_STACK(TYPE, NAME) \ +do { \ +size_t NAME##_size = mem_heap_recommend_allocation_size (sizeof (TYPE) * NAME##_global_size); \ +NAME.data = (TYPE *) mem_heap_alloc_block (NAME##_size, MEM_HEAP_ALLOC_SHORT_TERM); \ +NAME.current = NAME##_global_size; \ +NAME.length = (__typeof__ (NAME.length)) (NAME##_size / sizeof (TYPE)); \ +} while (0) + +#define FREE_STACK(NAME) \ +do { \ +mem_heap_free_block ((uint8_t *) NAME.data); \ +NAME.length = NAME.current = 0; \ +} while (0) + +/* In most cases (for example, in parser) default size of stack is enough. + However, in serializer, there is a need for reallocation of memory. + Do this in several steps: + 1) Allocate already allocated memory size twice. + 2) Copy used memory to the last. + 3) Dealocate first two chuncks. + 4) Allocate new memory. (It must point to the memory before increasing). + 5) Copy data back. + 6) Free temp buffer. */ +#define DEFINE_INCREASE_STACK_SIZE(TYPE, NAME) \ +static void increase_##NAME##_stack_size (__typeof__ (NAME.length)) __unused; \ +static void \ +increase_##NAME##_stack_size (__typeof__ (NAME.length) elements_count) { \ + if (NAME.current + elements_count >= NAME.length) \ + { \ + size_t old_size = NAME.length * sizeof (TYPE); \ + size_t temp1_size = mem_heap_recommend_allocation_size ( \ + (size_t) (elements_count * sizeof (TYPE))); \ + size_t new_size = mem_heap_recommend_allocation_size ( \ + (size_t) (temp1_size + old_size)); \ + TYPE *temp1 = (TYPE *) mem_heap_alloc_block (temp1_size, MEM_HEAP_ALLOC_SHORT_TERM); \ + TYPE *temp2 = (TYPE *) mem_heap_alloc_block (old_size, MEM_HEAP_ALLOC_SHORT_TERM); \ + if (temp2 == NULL) \ + { \ + mem_heap_print (true, false, true); \ + JERRY_UNREACHABLE (); \ + } \ + __memcpy (temp2, NAME.data, old_size); \ + mem_heap_free_block ((uint8_t *) NAME.data); \ + mem_heap_free_block ((uint8_t *) temp1); \ + NAME.data = (TYPE *) mem_heap_alloc_block (new_size, MEM_HEAP_ALLOC_SHORT_TERM); \ + __memcpy (NAME.data, temp2, old_size); \ + mem_heap_free_block ((uint8_t *) temp2); \ + NAME.length = (__typeof__ (NAME.length)) (new_size / sizeof (TYPE)); \ + } \ + NAME.current = (__typeof__ (NAME.current)) (NAME.current + elements_count); \ +} + +#define DEFINE_DECREASE_STACE_SIZE(NAME) \ +static void decrease_##NAME##_stack_size (uint8_t) __unused; \ +static void \ +decrease_##NAME##_stack_size (uint8_t elements_count) { \ + JERRY_ASSERT (NAME.current - elements_count >= NAME##_global_size); \ + NAME.current = (__typeof__ (NAME.current)) (NAME.current - elements_count); \ +} + +#define PUSH(NAME, VALUE) \ +increase_##NAME##_stack_size (1); \ +NAME.data[NAME.current - 1] = VALUE; + +#define POP(VALUE, NAME) \ +decrease_##NAME##_stack_size (1); \ +VALUE = NAME.data[NAME.current]; + +#define DROP(NAME, I) \ +decrease_##NAME##_stack_size (I); + +#define CLEAN(NAME) \ +DROP (NAME, NAME.current - NAME##_global_size); + +#define HEAD(NAME, I) \ +NAME.data[NAME.current - I] + +#define STACK_SIZE(NAME) \ +NAME.current + +#define STACK(TYPE, NAME) \ +TYPE##_stack NAME; \ +DEFINE_DECREASE_STACE_SIZE (NAME) \ +DEFINE_INCREASE_STACK_SIZE (TYPE, NAME) + +#define STATIC_STACK(TYPE, NAME) \ +static TYPE##_stack NAME; \ +DEFINE_DECREASE_STACE_SIZE (NAME) \ +DEFINE_INCREASE_STACK_SIZE (TYPE, NAME) + +#ifndef JERRY_NDEBUG +#define DECLARE_USAGE(NAME) \ +uint8_t NAME##_current = NAME.current; +#define CHECK_USAGE(NAME) \ +JERRY_ASSERT (NAME.current == NAME##_current); +#else +#define DECLARE_USAGE(NAME) ; +#define CHECK_USAGE(NAME) ; +#endif /* JERRY_NDEBUG */ + +#endif /* STACK_H */ diff --git a/src/libjsparser/lexer.c b/src/libjsparser/lexer.c index b55a4aa77..d0541d7a1 100644 --- a/src/libjsparser/lexer.c +++ b/src/libjsparser/lexer.c @@ -23,7 +23,7 @@ static token empty_token = { .type = TOK_EMPTY, - .data.uid = 0 + .uid = 0 }; static bool allow_dump_lines = false; @@ -148,7 +148,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_BREAK + .uid = KW_BREAK }; } if (current_token_equals_to ("case")) @@ -156,7 +156,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_CASE + .uid = KW_CASE }; } if (current_token_equals_to ("catch")) @@ -164,7 +164,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_CATCH + .uid = KW_CATCH }; } if (current_token_equals_to ("class")) @@ -172,7 +172,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } if (current_token_equals_to ("const")) @@ -180,7 +180,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } if (current_token_equals_to ("continue")) @@ -188,7 +188,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_CONTINUE + .uid = KW_CONTINUE }; } if (current_token_equals_to ("debugger")) @@ -196,7 +196,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_DEBUGGER + .uid = KW_DEBUGGER }; } if (current_token_equals_to ("default")) @@ -204,7 +204,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_DEFAULT + .uid = KW_DEFAULT }; } if (current_token_equals_to ("delete")) @@ -212,7 +212,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_DELETE + .uid = KW_DELETE }; } if (current_token_equals_to ("do")) @@ -220,7 +220,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_DO + .uid = KW_DO }; } if (current_token_equals_to ("else")) @@ -228,7 +228,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_ELSE + .uid = KW_ELSE }; } if (current_token_equals_to ("enum")) @@ -236,7 +236,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } if (current_token_equals_to ("export")) @@ -244,7 +244,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } if (current_token_equals_to ("extends")) @@ -252,7 +252,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } if (current_token_equals_to ("false")) @@ -260,7 +260,7 @@ decode_keyword (void) return (token) { .type = TOK_BOOL, - .data.uid = false + .uid = false }; } if (current_token_equals_to ("finally")) @@ -268,7 +268,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_FINALLY + .uid = KW_FINALLY }; } if (current_token_equals_to ("for")) @@ -276,7 +276,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_FOR + .uid = KW_FOR }; } if (current_token_equals_to ("function")) @@ -284,7 +284,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_FUNCTION + .uid = KW_FUNCTION }; } if (current_token_equals_to ("if")) @@ -292,7 +292,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_IF + .uid = KW_IF }; } if (current_token_equals_to ("instanceof")) @@ -300,7 +300,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_INSTANCEOF + .uid = KW_INSTANCEOF }; } if (current_token_equals_to ("interface")) @@ -308,7 +308,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } if (current_token_equals_to ("in")) @@ -316,7 +316,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_IN + .uid = KW_IN }; } if (current_token_equals_to ("import")) @@ -324,7 +324,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } if (current_token_equals_to ("implements")) @@ -332,7 +332,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } if (current_token_equals_to ("let")) @@ -340,7 +340,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } if (current_token_equals_to ("new")) @@ -348,7 +348,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_NEW + .uid = KW_NEW }; } if (current_token_equals_to ("null")) @@ -356,7 +356,7 @@ decode_keyword (void) return (token) { .type = TOK_NULL, - .data.uid = 0 + .uid = 0 }; } if (current_token_equals_to ("package")) @@ -364,7 +364,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } if (current_token_equals_to ("private")) @@ -372,7 +372,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } if (current_token_equals_to ("protected")) @@ -380,7 +380,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } if (current_token_equals_to ("public")) @@ -388,7 +388,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } if (current_token_equals_to ("return")) @@ -396,7 +396,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RETURN + .uid = KW_RETURN }; } if (current_token_equals_to ("static")) @@ -404,7 +404,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } if (current_token_equals_to ("super")) @@ -412,7 +412,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } if (current_token_equals_to ("switch")) @@ -420,7 +420,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_SWITCH + .uid = KW_SWITCH }; } if (current_token_equals_to ("this")) @@ -428,7 +428,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_THIS + .uid = KW_THIS }; } if (current_token_equals_to ("throw")) @@ -436,7 +436,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_THROW + .uid = KW_THROW }; } if (current_token_equals_to ("true")) @@ -444,7 +444,7 @@ decode_keyword (void) return (token) { .type = TOK_BOOL, - .data.uid = true + .uid = true }; } if (current_token_equals_to ("try")) @@ -452,7 +452,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_TRY + .uid = KW_TRY }; } if (current_token_equals_to ("typeof")) @@ -460,7 +460,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_TYPEOF + .uid = KW_TYPEOF }; } if (current_token_equals_to ("var")) @@ -468,7 +468,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_VAR + .uid = KW_VAR }; } if (current_token_equals_to ("void")) @@ -476,7 +476,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_VOID + .uid = KW_VOID }; } if (current_token_equals_to ("while")) @@ -484,7 +484,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_WHILE + .uid = KW_WHILE }; } if (current_token_equals_to ("with")) @@ -492,7 +492,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_WITH + .uid = KW_WITH }; } if (current_token_equals_to ("yield")) @@ -500,7 +500,7 @@ decode_keyword (void) return (token) { .type = TOK_KEYWORD, - .data.kw = KW_RESERVED + .uid = KW_RESERVED }; } return empty_token; @@ -522,7 +522,7 @@ convert_seen_name_to_token (token_type tt, const char *string) ret_val = (token) { .type = tt, - .data.uid = i + .uid = i }; break; @@ -574,7 +574,7 @@ add_token_to_seen_names (token_type tt, const char *string) ret_val = (token) { .type = tt, - .data.uid = seen_names_count++ + .uid = seen_names_count++ }; return ret_val; @@ -668,7 +668,7 @@ lexer_adjust_num_ids (void) for (i = 0; i < seen_nums_count; i++) { - seen_nums[i].tok.data.uid = (uint8_t) (seen_nums[i].tok.data.uid + seen_names_count); + seen_nums[i].tok.uid = (uint8_t) (seen_nums[i].tok.uid + seen_names_count); } } @@ -693,7 +693,7 @@ consume_char (void) return (token) \ { \ .type = TOK, \ - .data.uid = 0 \ + .uid = 0 \ }; \ } \ while (0) @@ -881,7 +881,7 @@ parse_number (void) return (token) { .type = TOK_SMALL_INT, - .data.uid = (uint8_t) res + .uid = (uint8_t) res }; } @@ -894,7 +894,7 @@ parse_number (void) known_token = (token) { .type = TOK_NUMBER, - .data.uid = seen_nums_count + .uid = seen_nums_count }; add_num_to_seen_tokens ( (num_and_token) @@ -981,7 +981,7 @@ parse_number (void) known_token = (token) { .type = TOK_NUMBER, - .data.uid = seen_nums_count + .uid = seen_nums_count }; add_num_to_seen_tokens ( (num_and_token) @@ -1006,7 +1006,7 @@ parse_number (void) return (token) { .type = TOK_SMALL_INT, - .data.uid = (uint8_t) res + .uid = (uint8_t) res }; } @@ -1019,7 +1019,7 @@ parse_number (void) known_token = (token) { .type = TOK_NUMBER, - .data.uid = seen_nums_count + .uid = seen_nums_count }; add_num_to_seen_tokens ( (num_and_token) @@ -1251,7 +1251,7 @@ lexer_next_token_private (void) return (token) { .type = TOK_NEWLINE, - .data.uid = 0 + .uid = 0 }; } @@ -1260,7 +1260,7 @@ lexer_next_token_private (void) return (token) { .type = TOK_EOF, - .data.uid = 0 + .uid = 0 }; } @@ -1282,7 +1282,7 @@ lexer_next_token_private (void) return (token) { .type = TOK_NEWLINE, - .data.uid = 0 + .uid = 0 }; } else diff --git a/src/libjsparser/lexer.h b/src/libjsparser/lexer.h index f6de2f7c0..127046ca2 100644 --- a/src/libjsparser/lexer.h +++ b/src/libjsparser/lexer.h @@ -138,12 +138,7 @@ typedef struct { token_type type; - union - { - keyword kw; - uint8_t uid; - } - data; + uint8_t uid; } __packed token; diff --git a/src/libjsparser/parser.c b/src/libjsparser/parser.c index 1cfc23efa..a291e01fb 100644 --- a/src/libjsparser/parser.c +++ b/src/libjsparser/parser.c @@ -20,9 +20,8 @@ #include "opcodes.h" #include "serializer.h" #include "interpreter.h" +#include "stack.h" -#define MAX_OPCODES 10 -#define MAX_NESTINGS 10 #define INVALID_VALUE 255 typedef enum @@ -33,120 +32,243 @@ typedef enum } 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_t opcode; -static opcode_counter_t opcode_counter = 0; -static idx_t temp_name_stack[MAX_OPCODES], temp_name_stack_head = 0, max_temp_name; -static uint8_t nestings[MAX_NESTINGS], nestings_head = 0; +#ifndef UINT8_T_STACK_DEFINED +#define UINT8_T_STACK_DEFINED +DEFINE_STACK_TYPE (uint8_t, uint8_t) +#endif -static rewritable_opcode rewritable_opcodes[REWRITABLE_OPCODES_COUNT] = +#ifndef UINT16_T_STACK_DEFINED +DEFINE_STACK_TYPE (uint8_t, uint16_t) +#define UINT16_T_STACK_DEFINED +#endif + +#ifndef TOKEN_STACK_DEFINED +DEFINE_STACK_TYPE (uint8_t, token) +#define TOKEN_STACK_DEFINED +#endif + +#ifndef OPCODE_T_STACK_DEFINED +DEFINE_STACK_TYPE (uint8_t, opcode_t) +#define OPCODE_T_STACK_DEFINED +#endif + +#define GLOBAL(NAME, VAR) \ +NAME.data[VAR] + +enum { - [REWRITABLE_CONTINUE] = { .size = 0, .head = 0, .oc_stack = NULL }, - [REWRITABLE_BREAK] = { .size = 0, .head = 0, .oc_stack = NULL } + U8_global_size }; +STATIC_STACK (uint8_t, U8) -static idx_t parse_expression (void); +enum +{ + IDX_global_size +}; +STATIC_STACK (uint8_t, IDX) + +enum +{ + nestings_global_size +}; +STATIC_STACK (uint8_t, nestings) + +enum +{ + temp_name, + min_temp_name, + max_temp_name, + temp_names_global_size +}; +STATIC_STACK (uint8_t, temp_names) + +#define MAX_TEMP_NAME() \ +GLOBAL(temp_names, max_temp_name) + +#define MIN_TEMP_NAME() \ +GLOBAL(temp_names, min_temp_name) + +#define TEMP_NAME() \ +GLOBAL(temp_names, temp_name) + +enum +{ + tok = 0, + toks_global_size +}; +STATIC_STACK (token, toks) + +#define TOK() \ +GLOBAL(toks, tok) + +enum +{ + opcode = 0, + ops_global_size +}; +STATIC_STACK (opcode_t, ops) + +#define OPCODE() \ +GLOBAL(ops, opcode) + +enum +{ + opcode_counter = 0, + U16_global_size +}; +STATIC_STACK (uint16_t, U16) + +#define OPCODE_COUNTER() \ +GLOBAL(U16, opcode_counter) + +enum +{ + rewritable_continue_global_size +}; +STATIC_STACK (uint16_t, rewritable_continue) + +enum +{ + rewritable_break_global_size +}; +STATIC_STACK (uint16_t, rewritable_break) + +#ifndef JERRY_NDEBUG +#define CHECK_USAGE_LHS() \ +JERRY_ASSERT (IDX.current == IDX_current + 1); +#else +#define CHECK_USAGE_LHS() ; +#endif + +JERRY_STATIC_ASSERT (sizeof (idx_t) == sizeof (uint8_t)); + +JERRY_STATIC_ASSERT (sizeof (opcode_counter_t) == sizeof (uint16_t)); + +typedef enum +{ + AL_FUNC_DECL, + AL_FUNC_EXPR, + AL_ARRAY_DECL, + AL_OBJ_DECL, + AL_CONSTRUCT_EXPR, + AL_CALL_EXPR +} +argument_list_type; + +static void parse_expression (void); static void parse_statement (void); -static idx_t parse_assignment_expression (void); +static void parse_assignment_expression (void); static void parse_source_element_list (void); - -static idx_t temp_name, min_temp_name; +static void parse_argument_list (argument_list_type, idx_t); static idx_t next_temp_name (void) { - return temp_name++; + return TEMP_NAME()++; } static void start_new_scope (void) { - JERRY_ASSERT (temp_name_stack_head < MAX_OPCODES); - temp_name_stack[temp_name_stack_head++] = max_temp_name; - max_temp_name = min_temp_name; + PUSH (temp_names, MAX_TEMP_NAME()); + MAX_TEMP_NAME() = MIN_TEMP_NAME(); } static void finish_scope (void) { - temp_name = temp_name_stack[--temp_name_stack_head]; - max_temp_name = temp_name; + POP (TEMP_NAME(), temp_names); + MAX_TEMP_NAME() = TEMP_NAME(); } static void reset_temp_name (void) { - if (max_temp_name < temp_name) + if (MAX_TEMP_NAME() < TEMP_NAME()) { - max_temp_name = temp_name; + MAX_TEMP_NAME() = TEMP_NAME(); } - temp_name = min_temp_name; + TEMP_NAME() = MIN_TEMP_NAME(); } static void push_nesting (uint8_t nesting_type) { - JERRY_ASSERT (nestings_head < MAX_NESTINGS); - - nestings[nestings_head++] = nesting_type; + PUSH (nestings, 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--; + JERRY_ASSERT (HEAD (nestings, 1) == nesting_type); + DROP (nestings, 1); } static void -must_be_inside_but_not_in (uint8_t inside[], uint8_t insides_count, uint8_t not_in) +must_be_inside_but_not_in (uint8_t *inside, uint8_t insides_count, uint8_t not_in) { - int8_t i; + DECLARE_USAGE (U8) // i, j + PUSH (U8, 0) + PUSH (U8, 0) +#define I() HEAD (U8, 2) +#define J() HEAD (U8, 1) - if (nestings_head == 0) + if (STACK_SIZE(nestings) == 0) { parser_fatal (ERR_PARSER); } - for (i = (int8_t) (nestings_head - 1); i >= 0; i--) + for (I() = (uint8_t) (STACK_SIZE(nestings)); I() != 0; I()--) { - int8_t j; - if (nestings[i] == not_in) + if (nestings.data[I() - 1] == not_in) { parser_fatal (ERR_PARSER); } - for (j = 0; j < insides_count; j++) + for (J() = 0; J() < insides_count; J()++) { - if (nestings[i] == inside[j]) + if (nestings.data[I() - 1] == inside[J()]) { - return; + goto cleanup; } } } parser_fatal (ERR_PARSER); + +cleanup: + DROP (U8, 2) +#undef I +#undef J + CHECK_USAGE (U8) +} + +static bool +token_is (token_type tt) +{ + return TOK ().type == tt; +} + +static uint8_t +token_data (void) +{ + return TOK ().uid; +} + +static void +skip_token (void) +{ + TOK() = lexer_next_token (); } static void assert_keyword (keyword kw) { - if (tok.type != TOK_KEYWORD || tok.data.kw != kw) + if (!token_is (TOK_KEYWORD) || token_data () != kw) { #ifdef __TARGET_HOST_x64 __printf ("assert_keyword: %d\n", kw); @@ -158,13 +280,13 @@ assert_keyword (keyword kw) static bool is_keyword (keyword kw) { - return tok.type == TOK_KEYWORD && tok.data.kw == kw; + return token_is (TOK_KEYWORD) && token_data () == kw; } static void current_token_must_be (token_type tt) { - if (tok.type != tt) + if (!token_is (tt)) { #ifdef __TARGET_HOST_x64 __printf ("current_token_must_be: %d\n", tt); @@ -176,18 +298,18 @@ current_token_must_be (token_type tt) static void skip_newlines (void) { - tok = lexer_next_token (); - while (tok.type == TOK_NEWLINE) + do { - tok = lexer_next_token (); + skip_token (); } + while (token_is (TOK_NEWLINE)); } static void next_token_must_be (token_type tt) { - tok = lexer_next_token (); - if (tok.type != tt) + skip_token (); + if (!token_is (tt)) { #ifdef __TARGET_HOST_x64 __printf ("next_token_must_be: %d\n", tt); @@ -200,7 +322,7 @@ static void token_after_newlines_must_be (token_type tt) { skip_newlines (); - if (tok.type != tt) + if (!token_is (tt)) { parser_fatal (ERR_PARSER); } @@ -216,44 +338,31 @@ token_after_newlines_must_be_keyword (keyword kw) } } -#if 0 - -static void -insert_semicolon (void) -{ - tok = lexer_next_token (); - if (tok.type != TOK_NEWLINE && tok.type != TOK_SEMICOLON) - { - parser_fatal (ERR_PARSER); - } -} -#endif - -#define NEXT(ID, TYPE) \ - do { skip_newlines (); ID = parse_##TYPE (); } while (0) +#define NEXT(TYPE) \ + do { skip_newlines (); parse_##TYPE (); } while (0) #define DUMP_VOID_OPCODE(GETOP) \ do { \ - opcode=getop_##GETOP (); \ - serializer_dump_opcode (opcode); \ - opcode_counter++; \ + OPCODE()=getop_##GETOP (); \ + serializer_dump_opcode (OPCODE()); \ + OPCODE_COUNTER()++; \ } while (0) #define DUMP_OPCODE_1(GETOP, OP1) \ do { \ JERRY_ASSERT (0+OP1 <= 255); \ - opcode=getop_##GETOP ((idx_t) (OP1)); \ - serializer_dump_opcode (opcode); \ - opcode_counter++; \ + OPCODE()=getop_##GETOP ((idx_t) (OP1)); \ + serializer_dump_opcode (OPCODE()); \ + OPCODE_COUNTER()++; \ } while (0) #define DUMP_OPCODE_2(GETOP, OP1, OP2) \ do { \ JERRY_ASSERT (0+OP1 <= 255); \ JERRY_ASSERT (0+OP2 <= 255); \ - opcode=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2)); \ - serializer_dump_opcode (opcode); \ - opcode_counter++; \ + OPCODE()=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2)); \ + serializer_dump_opcode (OPCODE()); \ + OPCODE_COUNTER()++; \ } while (0) #define DUMP_OPCODE_3(GETOP, OP1, OP2, OP3) \ @@ -261,24 +370,24 @@ insert_semicolon (void) JERRY_ASSERT (0+OP1 <= 255); \ JERRY_ASSERT (0+OP2 <= 255); \ JERRY_ASSERT (0+OP3 <= 255); \ - opcode=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2), (idx_t) (OP3)); \ - serializer_dump_opcode (opcode); \ - opcode_counter++; \ + OPCODE()=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2), (idx_t) (OP3)); \ + serializer_dump_opcode (OPCODE()); \ + OPCODE_COUNTER()++; \ } while (0) #define REWRITE_OPCODE_1(OC, GETOP, OP1) \ do { \ JERRY_ASSERT (0+OP1 <= 255); \ - opcode=getop_##GETOP ((idx_t) (OP1)); \ - serializer_rewrite_opcode (OC, opcode); \ + OPCODE()=getop_##GETOP ((idx_t) (OP1)); \ + serializer_rewrite_opcode (OC, OPCODE()); \ } while (0) #define REWRITE_OPCODE_2(OC, GETOP, OP1, OP2) \ do { \ JERRY_ASSERT (0+OP1 <= 255); \ JERRY_ASSERT (0+OP2 <= 255); \ - opcode=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2)); \ - serializer_rewrite_opcode (OC, opcode); \ + OPCODE()=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2)); \ + serializer_rewrite_opcode (OC, OPCODE()); \ } while (0) #define REWRITE_OPCODE_3(OC, GETOP, OP1, OP2, OP3) \ @@ -286,86 +395,106 @@ insert_semicolon (void) JERRY_ASSERT (0+OP1 <= 255); \ JERRY_ASSERT (0+OP2 <= 255); \ JERRY_ASSERT (0+OP3 <= 255); \ - opcode=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2), (idx_t) (OP3)); \ - serializer_rewrite_opcode (OC, opcode); \ + OPCODE()=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2), (idx_t) (OP3)); \ + serializer_rewrite_opcode (OC, OPCODE()); \ } while (0) -static idx_t +#define REWRITE_COND_JMP(OC, GETOP, DIFF) \ + do { \ + JERRY_ASSERT (0+DIFF <= 256*256 - 1); \ + DECLARE_USAGE (IDX) \ + JERRY_STATIC_ASSERT (sizeof (idx_t) == 1); \ + PUSH (IDX, (idx_t) ((DIFF) >> JERRY_BITSINBYTE)); \ + PUSH (IDX, (idx_t) ((DIFF) & ((1 << JERRY_BITSINBYTE) - 1))); \ + JERRY_ASSERT ((DIFF) == calc_opcode_counter_from_idx_idx (HEAD (IDX, 2), HEAD (IDX, 1))); \ + OPCODE()=getop_##GETOP (HEAD (IDX, 3), HEAD (IDX, 2), HEAD (IDX, 1)); \ + serializer_rewrite_opcode (OC, OPCODE()); \ + DROP (IDX, 2); \ + CHECK_USAGE (IDX) \ + } while (0) + +#define REWRITE_JMP(OC, GETOP, DIFF) \ + do { \ + JERRY_ASSERT (0+DIFF <= 256*256 - 1); \ + DECLARE_USAGE (IDX) \ + JERRY_STATIC_ASSERT (sizeof (idx_t) == 1); \ + PUSH (IDX, (idx_t) ((DIFF) >> JERRY_BITSINBYTE)); \ + PUSH (IDX, (idx_t) ((DIFF) & ((1 << JERRY_BITSINBYTE) - 1))); \ + JERRY_ASSERT ((DIFF) == calc_opcode_counter_from_idx_idx (HEAD (IDX, 2), HEAD (IDX, 1))); \ + OPCODE()=getop_##GETOP (HEAD (IDX, 2), HEAD (IDX, 1)); \ + serializer_rewrite_opcode (OC, OPCODE()); \ + DROP (IDX, 2); \ + CHECK_USAGE (IDX) \ + } while (0) + +static void integer_zero (void) { - idx_t lhs = next_temp_name (); - DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_SMALLINT, 0); - return lhs; + DECLARE_USAGE (IDX) + + PUSH (IDX, next_temp_name ()); + DUMP_OPCODE_3 (assignment, HEAD (IDX, 1), OPCODE_ARG_TYPE_SMALLINT, 0); + + CHECK_USAGE_LHS () } -static idx_t +static void boolean_true (void) { - idx_t lhs = next_temp_name (); - DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_TRUE); - return lhs; + DECLARE_USAGE (IDX) + + PUSH (IDX, next_temp_name ()); + DUMP_OPCODE_3 (assignment, HEAD (IDX, 1), OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_TRUE); + + CHECK_USAGE_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) + switch (type) { - 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; + case REWRITABLE_BREAK: PUSH (rewritable_break, oc); break; + case REWRITABLE_CONTINUE: PUSH (rewritable_continue, oc); break; + default: JERRY_UNREACHABLE (); } - - 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]; + DECLARE_USAGE (U8) - for (i = 0; i < op.head; i++) + PUSH (U8, 0) + + switch (type) { - switch (type) + case REWRITABLE_BREAK: { - case REWRITABLE_CONTINUE: + for (HEAD (U8, 1) = 0; HEAD (U8, 1) < STACK_SIZE (rewritable_break); HEAD (U8, 1)++) { - 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 (); + REWRITE_JMP (rewritable_break.data[HEAD (U8, 1)], jmp_down, + oc - rewritable_break.data[HEAD (U8, 1)]); } + CLEAN (rewritable_break); + break; } + case REWRITABLE_CONTINUE: + { + for (HEAD (U8, 1) = 0; HEAD (U8, 1) < STACK_SIZE (rewritable_continue); HEAD (U8, 1)++) + { + REWRITE_JMP (rewritable_continue.data[HEAD (U8, 1)], jmp_up, + rewritable_continue.data[HEAD (U8, 1)] - oc); + } + CLEAN (rewritable_continue); + 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; + DROP (U8, 1) + + CHECK_USAGE (U8) } static int8_t @@ -385,21 +514,32 @@ is_intrinsic (idx_t obj) /* Every literal is represented by assignment to tmp. so if result of parse_primary_expression less then strings count, it is identifier, check for intrinsics. */ - uint8_t strings_count = lexer_get_strings (NULL); - if (obj < strings_count) + // U8 strs + bool result = false; + + DECLARE_USAGE (U8) + + PUSH (U8, lexer_get_strings (NULL)); + if (obj < HEAD (U8, 1)) { const char *string = lexer_get_string_by_id (obj); - return intrinsic_argument_count (string) >= 0; + result = intrinsic_argument_count (string) >= 0; } - return false; + DROP (U8, 1); + + CHECK_USAGE (U8) + return result; } static void -dump_intrinsic (idx_t obj, idx_t args[3]) +dump_intrinsic (idx_t obj, idx_t arg) { - uint8_t strings_count = lexer_get_strings (NULL); - if (obj < strings_count) + // U8 strs + DECLARE_USAGE (U8) + + PUSH (U8, lexer_get_strings (NULL)); + if (obj < HEAD (U8, 1)) { const char *string = lexer_get_string_by_id (obj); if (!__strcmp (string, "assert")) @@ -408,65 +548,93 @@ dump_intrinsic (idx_t obj, idx_t args[3]) is_true_jmp arg, +2 exitval 1 */ - DUMP_OPCODE_2 (is_true_jmp, args[0], opcode_counter + 2); + DUMP_OPCODE_3 (is_true_jmp_down, arg, 0, 2); DUMP_OPCODE_1 (exitval, 1); - return; + goto cleanup; } } JERRY_UNREACHABLE (); + +cleanup: + DROP (U8, 1); + + CHECK_USAGE (U8) } + /* property_name : Identifier | StringLiteral | NumericLiteral ; */ -static idx_t +static void parse_property_name (void) { - idx_t lhs; + DECLARE_USAGE (IDX) - switch (tok.type) + switch (TOK ().type) { case TOK_NAME: case TOK_STRING: case TOK_NUMBER: { - return tok.data.uid; + PUSH (IDX, token_data ()) + break; } case TOK_SMALL_INT: { - lhs = next_temp_name (); - DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_SMALLINT, tok.data.uid); - return lhs; + PUSH (IDX, next_temp_name ()); + DUMP_OPCODE_3 (assignment, HEAD (IDX, 1), OPCODE_ARG_TYPE_SMALLINT, token_data ()); + break; } default: { JERRY_UNREACHABLE (); } } + + CHECK_USAGE_LHS () } /* property_name_and_value : property_name LT!* ':' LT!* assignment_expression ; */ -static idx_t +static void parse_property_name_and_value (void) { - idx_t lhs, name, value; + // IDX lhs, name, expr + DECLARE_USAGE (IDX) + + PUSH (IDX, next_temp_name ()) + parse_property_name (); // push name - lhs = next_temp_name (); - name = parse_property_name (); token_after_newlines_must_be (TOK_COLON); - NEXT (value, assignment_expression); + NEXT (assignment_expression); // push expr - TODO (Change to dumping meta opcode); - // DUMP_OPCODE_3 (prop, lhs, name, value); - // to - // DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_VARG_PROP_DATA, name, value); - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS (name, value); + DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_VARG_PROP_DATA, HEAD(IDX, 1), HEAD(IDX, 2)); - return lhs; + DROP (IDX, 2); + CHECK_USAGE_LHS () +} + +static void +rewrite_meta_opcode_counter (opcode_counter_t meta_oc, opcode_meta_type type) +{ + // IDX oc_idx_1, oc_idx_2 + DECLARE_USAGE (IDX) + + JERRY_STATIC_ASSERT (sizeof (idx_t) == 1); + + PUSH (IDX, (idx_t) (OPCODE_COUNTER () >> JERRY_BITSINBYTE)); + PUSH (IDX, (idx_t) (OPCODE_COUNTER () & ((1 << JERRY_BITSINBYTE) - 1))); + + JERRY_ASSERT (OPCODE_COUNTER () == calc_opcode_counter_from_idx_idx (HEAD (IDX, 2), HEAD (IDX, 1))); + + REWRITE_OPCODE_3 (meta_oc, meta, type, HEAD (IDX, 2), HEAD (IDX, 1)); + + DROP (IDX, 2); + + CHECK_USAGE (IDX) } /* property_assignment @@ -474,175 +642,139 @@ parse_property_name_and_value (void) | get LT!* property_name LT!* '(' LT!* ')' LT!* '{' LT!* function_body LT!* '}' | set LT!* property_name LT!* '(' identifier ')' LT!* '{' LT!* function_body LT!* '}' ; */ -static idx_t +static void parse_property_assignment (void) { - idx_t lhs, name, arg; + DECLARE_USAGE (IDX) + DECLARE_USAGE (U16) current_token_must_be (TOK_NAME); - lhs = next_temp_name (); - - if (!__strcmp ("get", lexer_get_string_by_id (tok.data.uid))) + if (!__strcmp ("get", lexer_get_string_by_id (token_data ()))) { - NEXT (name, property_name); - - token_after_newlines_must_be (TOK_OPEN_PAREN); - token_after_newlines_must_be (TOK_CLOSE_PAREN); - token_after_newlines_must_be (TOK_OPEN_BRACE); - - TODO (Change to dumping meta opcode); - // DUMP_OPCODE_2 (prop_get_decl, lhs, name); - // to - // DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_VARG_PROP_GETTER, name, result_of_func_expression); - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS (name); + // name, lhs + NEXT (property_name); // push name + skip_newlines (); + parse_argument_list (AL_FUNC_EXPR, next_temp_name ()); // push lhs + + PUSH (U16, opcode_counter); + DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_FUNCTION_END, INVALID_VALUE, INVALID_VALUE); + + token_after_newlines_must_be (TOK_OPEN_BRACE); skip_newlines (); parse_source_element_list (); - token_after_newlines_must_be (TOK_CLOSE_BRACE); - DUMP_VOID_OPCODE (ret); - return lhs; + DUMP_VOID_OPCODE (ret); + rewrite_meta_opcode_counter (HEAD (U16, 1), OPCODE_META_TYPE_FUNCTION_END); + DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_VARG_PROP_GETTER, HEAD (IDX, 2), HEAD (IDX, 1)); + + HEAD (IDX, 2) = HEAD (IDX, 1); + DROP (IDX, 1); + DROP (U16, 1); } - else if (!__strcmp ("set", lexer_get_string_by_id (tok.data.uid))) + else if (!__strcmp ("set", lexer_get_string_by_id (token_data ()))) { - NEXT (name, property_name); - - token_after_newlines_must_be (TOK_OPEN_PAREN); - token_after_newlines_must_be (TOK_NAME); - arg = tok.data.uid; - token_after_newlines_must_be (TOK_CLOSE_PAREN); - token_after_newlines_must_be (TOK_OPEN_BRACE); - - TODO (Change to dumping meta opcode); - // DUMP_OPCODE_3 (prop_set_decl, lhs, name, arg); - // to - // DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_VARG_PROP_SETTER, name, result_of_func_expression); - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS (name, arg); + // name, lhs + NEXT (property_name); // push name + skip_newlines (); + parse_argument_list (AL_FUNC_EXPR, next_temp_name ()); // push lhs + + PUSH (U16, opcode_counter); + DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_FUNCTION_END, INVALID_VALUE, INVALID_VALUE); + + token_after_newlines_must_be (TOK_OPEN_BRACE); skip_newlines (); parse_source_element_list (); - token_after_newlines_must_be (TOK_CLOSE_BRACE); - DUMP_VOID_OPCODE (ret); - return lhs; + DUMP_VOID_OPCODE (ret); + rewrite_meta_opcode_counter (HEAD (U16, 1), OPCODE_META_TYPE_FUNCTION_END); + DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_VARG_PROP_SETTER, HEAD (IDX, 2), HEAD (IDX, 1)); + + HEAD (IDX, 2) = HEAD (IDX, 1); + DROP (IDX, 1); + DROP (U16, 1); } else { - return parse_property_name_and_value (); + parse_property_name_and_value (); } -} -static void -dump_varg_3 (idx_t current_param, idx_t params[3] __unused) -{ - if (current_param == 3) - { - TODO(Refine to match new opcodes) - //DUMP_OPCODE_3 (varg_3, params[0], params[1], params[2]); - current_param = 0; - } + CHECK_USAGE (U16) + CHECK_USAGE_LHS () } -static void -dump_varg_end (idx_t current_param, idx_t params[3] __unused) -{ - switch (current_param) - { - case 0: - { - TODO(Refine to match new opcodes) - //DUMP_OPCODE_1 (varg_1_end, params[0]); - break; - } - case 1: - { - TODO(Refine to match new opcodes) - //DUMP_OPCODE_2 (varg_2_end, params[0], params[1]); - break; - } - case 2: - { - TODO(Refine to match new opcodes) - //DUMP_OPCODE_3 (varg_3_end, params[0], params[1], params[2]); - break; - } - default: - { - JERRY_UNREACHABLE (); - } - } -} - -typedef enum -{ - AL_FUNC_DECL, - AL_FUNC_EXPR, - AL_ARRAY_LIT, - AL_OBJECT_LIT, - AL_CONSTRUCT_EXPR, - AL_CALL_EXPR -} -argument_list_type; - /** Parse list of identifiers, assigment expressions or properties, splitted by comma. For each ALT dumps appropriate bytecode. Uses OBJ during dump if neccesary. Returns temp var if expression has lhs, or 0 otherwise. */ -static idx_t +static void parse_argument_list (argument_list_type alt, idx_t obj) { - token_type open_tt, close_tt; - idx_t first_opcode_args_count; - idx_t lhs = 0; - idx_t args[3 + 1/* +1 for stack protector */]; - idx_t current_arg = 0; + // U8 open_tt, close_tt, args_count + // IDX lhs, current_arg + // U16 oc + DECLARE_USAGE (U8) + DECLARE_USAGE (U16) + DECLARE_USAGE (IDX) + PUSH (U16, OPCODE_COUNTER ()); switch (alt) { case AL_FUNC_DECL: { - open_tt = TOK_OPEN_PAREN; // Openning token - close_tt = TOK_CLOSE_PAREN; // Ending token - first_opcode_args_count = 2; // Maximum number of arguments in first opcode + PUSH (U8, TOK_OPEN_PAREN); // Openning token + PUSH (U8, TOK_CLOSE_PAREN); // Ending token + DUMP_OPCODE_2 (func_decl_n, obj, INVALID_VALUE); break; } case AL_FUNC_EXPR: + { + PUSH (U8, TOK_OPEN_PAREN); + PUSH (U8, TOK_CLOSE_PAREN); + PUSH (IDX, next_temp_name ()); + DUMP_OPCODE_3 (func_expr_n, HEAD (IDX, 1), obj, INVALID_VALUE); + break; + } case AL_CONSTRUCT_EXPR: { - open_tt = TOK_OPEN_PAREN; - close_tt = TOK_CLOSE_PAREN; - first_opcode_args_count = 1; - lhs = next_temp_name (); + PUSH (U8, TOK_OPEN_PAREN); + PUSH (U8, TOK_CLOSE_PAREN); + PUSH (IDX, next_temp_name ()); + DUMP_OPCODE_3 (construct_n, HEAD (IDX, 1), obj, INVALID_VALUE); break; } case AL_CALL_EXPR: { - open_tt = TOK_OPEN_PAREN; - close_tt = TOK_CLOSE_PAREN; - first_opcode_args_count = 1; + PUSH (U8, TOK_OPEN_PAREN); + PUSH (U8, TOK_CLOSE_PAREN); if (is_intrinsic (obj)) { break; } - lhs = next_temp_name (); + else + { + PUSH (IDX, next_temp_name ()); + DUMP_OPCODE_3 (call_n, HEAD (IDX, 1), obj, INVALID_VALUE); + } break; } - case AL_ARRAY_LIT: + case AL_ARRAY_DECL: { - open_tt = TOK_OPEN_SQUARE; - close_tt = TOK_CLOSE_SQUARE; - first_opcode_args_count = 2; - lhs = next_temp_name (); + PUSH (U8, TOK_OPEN_SQUARE); + PUSH (U8, TOK_CLOSE_SQUARE); + PUSH (IDX, next_temp_name ()); + DUMP_OPCODE_2 (array_decl, HEAD (IDX, 1), INVALID_VALUE); break; } - case AL_OBJECT_LIT: + case AL_OBJ_DECL: { - open_tt = TOK_OPEN_BRACE; - close_tt = TOK_CLOSE_BRACE; - first_opcode_args_count = 2; - lhs = next_temp_name (); + PUSH (U8, TOK_OPEN_BRACE); + PUSH (U8, TOK_CLOSE_BRACE); + PUSH (IDX, next_temp_name ()); + DUMP_OPCODE_2 (obj_decl, HEAD (IDX, 1), INVALID_VALUE); break; } default: @@ -651,237 +783,37 @@ parse_argument_list (argument_list_type alt, idx_t obj) } } - current_token_must_be (open_tt); + PUSH (U8, 0); + + current_token_must_be (HEAD (U8, 3)); skip_newlines (); - if (tok.type != close_tt) - { - bool is_first_opcode = true; - while (true) - { - if (is_first_opcode) - { - if (current_arg == first_opcode_args_count) - { - switch (alt) - { - case AL_FUNC_DECL: - { - TODO(Refine to match new opcodes) - // DUMP_OPCODE_3 (func_decl_n, obj, args[0], args[1]); - break; - } - case AL_FUNC_EXPR: - { - TODO(Refine to match new opcodes) - //DUMP_OPCODE_3 (func_expr_n, lhs, obj, args[0]); - break; - } - case AL_ARRAY_LIT: - { - TODO(Refine to match new opcodes) - //DUMP_OPCODE_3 (array_n, lhs, args[0], args[1]); - break; - } - case AL_OBJECT_LIT: - { - TODO(Refine to match new opcodes) - //DUMP_OPCODE_3 (obj_n, lhs, args[0], args[1]); - break; - } - case AL_CONSTRUCT_EXPR: - { - TODO(Refine to match new opcodes) - //DUMP_OPCODE_3 (construct_n, lhs, obj, args[0]); - break; - } - case AL_CALL_EXPR: - { - if (is_intrinsic (obj)) - { - parser_fatal (ERR_PARSER); - } - DUMP_OPCODE_3 (call_n, lhs, obj, args[0]); - break; - } - default: - { - JERRY_UNREACHABLE (); - } - } - current_arg = 0; - is_first_opcode = false; - } - } - else - { - dump_varg_3 (current_arg, args); - } - - switch (alt) - { - case AL_FUNC_DECL: - { - current_token_must_be (TOK_NAME); - args[current_arg] = tok.data.uid; - break; - } - case AL_FUNC_EXPR: - case AL_ARRAY_LIT: - case AL_CONSTRUCT_EXPR: - case AL_CALL_EXPR: - { - args[current_arg] = parse_assignment_expression (); - break; - } - case AL_OBJECT_LIT: - { - args[current_arg] = parse_property_assignment (); - break; - } - default: - { - JERRY_UNREACHABLE (); - } - } - - skip_newlines (); - if (tok.type != TOK_COMMA) - { - current_token_must_be (close_tt); - break; - } - - skip_newlines (); - current_arg++; - } - - if (is_first_opcode) - { - if (current_arg == 0) - { - switch (alt) - { - case AL_FUNC_DECL: - { - DUMP_OPCODE_2 (func_decl_1, obj, args[0]); - break; - } - case AL_FUNC_EXPR: - { - TODO(Refine to match new opcodes) - //DUMP_OPCODE_3 (func_expr_1, lhs, obj, args[0]); - break; - } - case AL_ARRAY_LIT: - { - TODO(Refine to match new opcodes) - //DUMP_OPCODE_2 (array_1, lhs, args[0]); - break; - } - case AL_OBJECT_LIT: - { - TODO (Refine to match new opcodes) - //DUMP_OPCODE_2 (obj_1, lhs, args[0]); - break; - } - case AL_CONSTRUCT_EXPR: - { - TODO(Refine to match new opcodes) - //DUMP_OPCODE_3 (construct_1, lhs, obj, args[0]); - break; - } - case AL_CALL_EXPR: - { - if (is_intrinsic (obj)) - { - dump_intrinsic (obj, args); - } - else - { - DUMP_OPCODE_3 (call_1, lhs, obj, args[0]); - } - break; - } - default: - { - JERRY_UNREACHABLE (); - } - } - } - else if (current_arg == 1) - { - switch (alt) - { - case AL_FUNC_DECL: - { - DUMP_OPCODE_3 (func_decl_2, obj, args[0], args[1]); - break; - } - case AL_ARRAY_LIT: - { - TODO(Refine to match new opcodes) - //DUMP_OPCODE_3 (array_2, lhs, args[0], args[1]); - break; - } - case AL_OBJECT_LIT: - { - TODO (Refine to match new opcodes) - //DUMP_OPCODE_3 (obj_2, lhs, args[0], args[1]); - break; - } - default: - { - JERRY_UNREACHABLE (); - } - } - } - else - { - JERRY_UNREACHABLE (); - } - } - else - { - dump_varg_end (current_arg, args); - } - } - else + while (!token_is (HEAD (U8, 2))) { switch (alt) { case AL_FUNC_DECL: { - DUMP_OPCODE_1 (func_decl_0, obj); + current_token_must_be (TOK_NAME); + PUSH (IDX, token_data ()) break; } case AL_FUNC_EXPR: - { - TODO(Refine to match new opcodes) - //DUMP_OPCODE_2 (func_expr_0, lhs, obj); - break; - } - case AL_ARRAY_LIT: - { - TODO(Refine to match new opcodes) - //DUMP_OPCODE_1 (array_0, lhs); - break; - } - case AL_OBJECT_LIT: - { - TODO (Refine to match new opcodes) - //DUMP_OPCODE_1 (obj_0, lhs); - break; - } + case AL_ARRAY_DECL: case AL_CONSTRUCT_EXPR: - { - TODO(Refine to match new opcodes) - //DUMP_OPCODE_2 (construct_0, lhs, obj); - break; - } case AL_CALL_EXPR: { - DUMP_OPCODE_2 (call_0, lhs, obj); + parse_assignment_expression (); + if (is_intrinsic (obj)) + { + dump_intrinsic (obj, HEAD (IDX, 1)); + goto next; + } + break; + } + case AL_OBJ_DECL: + { + parse_property_assignment (); break; } default: @@ -889,24 +821,84 @@ parse_argument_list (argument_list_type alt, idx_t obj) JERRY_UNREACHABLE (); } } + + DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_VARG, HEAD (IDX, 1), INVALID_VALUE); + HEAD(U8, 1)++; + + DROP (IDX, 1); + +next: + skip_newlines (); + if (!token_is (TOK_COMMA)) + { + current_token_must_be (HEAD (U8, 2)); + break; + } + + skip_newlines (); } - return lhs; -} + switch (alt) + { + case AL_FUNC_DECL: + { + REWRITE_OPCODE_2 (HEAD (U16, 1), func_decl_n, obj, HEAD (U8, 1)); + break; + } + case AL_FUNC_EXPR: + { + REWRITE_OPCODE_3 (HEAD (U16, 1), func_expr_n, HEAD (IDX, 1), obj, HEAD (U8, 1)); + break; + } + case AL_CONSTRUCT_EXPR: + { + REWRITE_OPCODE_3 (HEAD (U16, 1), construct_n, HEAD (IDX, 1), obj, HEAD (U8, 1)); + break; + } + case AL_CALL_EXPR: + { + if (is_intrinsic (obj)) + { + break; + } + else + { + REWRITE_OPCODE_3 (HEAD (U16, 1), call_n, HEAD (IDX, 1), obj, HEAD (U8, 1)); + } + break; + } + case AL_ARRAY_DECL: + { + REWRITE_OPCODE_2 (HEAD (U16, 1), array_decl, HEAD (IDX, 1), HEAD (U8, 1)); + break; + } + case AL_OBJ_DECL: + { + REWRITE_OPCODE_2 (HEAD (U16, 1), obj_decl, HEAD (IDX, 1), HEAD (U8, 1)); + break; + } + default: + { + JERRY_UNREACHABLE (); + } + } -static void -rewrite_meta_opcode_counter (opcode_meta_type type, - opcode_counter_t meta_oc, - opcode_counter_t new_value) -{ - JERRY_STATIC_ASSERT (sizeof (idx_t) == 1); + DROP (U8, 3); + DROP (U16, 1); - const idx_t oc_idx_1 = (idx_t) (new_value >> JERRY_BITSINBYTE); - const idx_t oc_idx_2 = (idx_t) (new_value & ((1 << JERRY_BITSINBYTE) - 1)); + CHECK_USAGE (U8) + CHECK_USAGE (U16) - JERRY_ASSERT (new_value == calc_opcode_counter_from_idx_idx (oc_idx_1, oc_idx_2)); - - REWRITE_OPCODE_3 (meta_oc, meta, type, oc_idx_1, oc_idx_2); +#ifndef JERRY_NDEBUG + if (alt == AL_FUNC_DECL) + { + CHECK_USAGE (IDX) + } + else + { + CHECK_USAGE_LHS () + } +#endif } /* function_declaration @@ -919,19 +911,22 @@ rewrite_meta_opcode_counter (opcode_meta_type type, static void parse_function_declaration (void) { - idx_t name; - opcode_counter_t meta_oc; + // IDX name + // U16 meta_oc + DECLARE_USAGE (IDX) + DECLARE_USAGE (U16) + DECLARE_USAGE (nestings) assert_keyword (KW_FUNCTION); token_after_newlines_must_be (TOK_NAME); - name = tok.data.uid; + PUSH (IDX, token_data ()); skip_newlines (); - parse_argument_list (AL_FUNC_DECL, name); + parse_argument_list (AL_FUNC_DECL, HEAD (IDX, 1)); - meta_oc = opcode_counter; + PUSH (U16, OPCODE_COUNTER ()); DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_UNDEFINED, INVALID_VALUE, INVALID_VALUE); token_after_newlines_must_be (TOK_OPEN_BRACE); @@ -945,35 +940,45 @@ parse_function_declaration (void) DUMP_VOID_OPCODE (ret); - rewrite_meta_opcode_counter (OPCODE_META_TYPE_FUNCTION_END, meta_oc, opcode_counter); + rewrite_meta_opcode_counter (HEAD (U16, 1), OPCODE_META_TYPE_FUNCTION_END); + + DROP (U16, 1); + DROP (IDX, 1); + + CHECK_USAGE (IDX) + CHECK_USAGE (U16) + CHECK_USAGE (nestings) } /* function_expression : 'function' LT!* Identifier? LT!* '(' formal_parameter_list? LT!* ')' LT!* function_body ; */ -static idx_t +static void parse_function_expression (void) { - idx_t name, lhs; - opcode_counter_t meta_oc; + // IDX lhs, name + // U16 meta_oc + DECLARE_USAGE (IDX) + DECLARE_USAGE (U16) + DECLARE_USAGE (nestings) assert_keyword (KW_FUNCTION); skip_newlines (); - if (tok.type == TOK_NAME) + if (token_is (TOK_NAME)) { - name = tok.data.uid; + PUSH (IDX, token_data ()); } else { - lexer_save_token (tok); - name = next_temp_name (); + lexer_save_token (TOK()); + PUSH (IDX, next_temp_name ()); } skip_newlines (); - lhs = parse_argument_list (AL_FUNC_EXPR, name); + parse_argument_list (AL_FUNC_EXPR, HEAD (IDX, 1)); // push lhs - meta_oc = opcode_counter; + PUSH (U16, OPCODE_COUNTER ()); DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_UNDEFINED, INVALID_VALUE, INVALID_VALUE); token_after_newlines_must_be (TOK_OPEN_BRACE); @@ -986,72 +991,89 @@ parse_function_expression (void) token_after_newlines_must_be (TOK_CLOSE_BRACE); DUMP_VOID_OPCODE (ret); - rewrite_meta_opcode_counter (OPCODE_META_TYPE_FUNCTION_END, meta_oc, opcode_counter); + rewrite_meta_opcode_counter (HEAD (U16, 1), OPCODE_META_TYPE_FUNCTION_END); - return lhs; + HEAD (IDX, 2) = HEAD (IDX, 1); + DROP (IDX, 1); + DROP (U16, 1); + + CHECK_USAGE (U16) + CHECK_USAGE_LHS () + CHECK_USAGE (nestings) } /* array_literal : '[' LT!* assignment_expression? (LT!* ',' (LT!* assignment_expression)?)* LT!* ']' LT!* ; */ -static idx_t +static void parse_array_literal (void) { - return parse_argument_list (AL_ARRAY_LIT, 0); + DECLARE_USAGE (IDX) + + parse_argument_list (AL_ARRAY_DECL, 0); + + CHECK_USAGE_LHS () } /* object_literal : '{' LT!* property_assignment (LT!* ',' LT!* property_assignment)* LT!* '}' ; */ -static idx_t +static void parse_object_literal (void) { - return parse_argument_list (AL_OBJECT_LIT, 0); + DECLARE_USAGE (IDX) + + parse_argument_list (AL_OBJ_DECL, 0); + + CHECK_USAGE_LHS (); } -static idx_t +static void parse_literal (void) { - idx_t lhs; + // IDX lhs; + DECLARE_USAGE (IDX) - switch (tok.type) + switch (TOK ().type) { case TOK_NULL: { - lhs = next_temp_name (); - DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_NULL); - return lhs; + PUSH (IDX, next_temp_name ()); + DUMP_OPCODE_3 (assignment, HEAD (IDX, 1), OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_NULL); + break; } case TOK_BOOL: { - lhs = next_temp_name (); - DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_SIMPLE, - tok.data.uid ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); - return lhs; + PUSH (IDX, next_temp_name ()); + DUMP_OPCODE_3 (assignment, HEAD (IDX, 1), OPCODE_ARG_TYPE_SIMPLE, + token_data () ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); + break; } case TOK_NUMBER: { - lhs = next_temp_name (); - DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_NUMBER, tok.data.uid); - return lhs; + PUSH (IDX, next_temp_name ()); + DUMP_OPCODE_3 (assignment, HEAD (IDX, 1), OPCODE_ARG_TYPE_NUMBER, token_data ()); + break; } case TOK_SMALL_INT: { - lhs = next_temp_name (); - DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_SMALLINT, tok.data.uid); - return lhs; + PUSH (IDX, next_temp_name ()); + DUMP_OPCODE_3 (assignment, HEAD (IDX, 1), OPCODE_ARG_TYPE_SMALLINT, token_data ()); + break; } case TOK_STRING: { - lhs = next_temp_name (); - DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_STRING, tok.data.uid); - return lhs; + PUSH (IDX, next_temp_name ()); + DUMP_OPCODE_3 (assignment, HEAD (IDX, 1), OPCODE_ARG_TYPE_STRING, token_data ()); + break; } default: { JERRY_UNREACHABLE (); } } + + CHECK_USAGE_LHS () } /* primary_expression @@ -1062,23 +1084,25 @@ parse_literal (void) | '{' LT!* object_literal LT!* '}' | '(' LT!* expression LT!* ')' ; */ -static idx_t +static void parse_primary_expression (void) { - idx_t lhs; + // IDX lhs; + DECLARE_USAGE (IDX) if (is_keyword (KW_THIS)) { - lhs = next_temp_name (); - DUMP_OPCODE_1 (this, lhs); - return lhs; + PUSH (IDX, next_temp_name ()); + DUMP_OPCODE_1 (this, HEAD (IDX, 1)); + goto cleanup; } - switch (tok.type) + switch (TOK ().type) { case TOK_NAME: { - return tok.data.uid; + PUSH (IDX, token_data ()); + break; } case TOK_NULL: case TOK_BOOL: @@ -1086,24 +1110,27 @@ parse_primary_expression (void) case TOK_NUMBER: case TOK_STRING: { - return parse_literal (); + parse_literal (); + goto cleanup; } case TOK_OPEN_SQUARE: { - return parse_array_literal (); + parse_array_literal (); + goto cleanup; } case TOK_OPEN_BRACE: { - return parse_object_literal (); + parse_object_literal (); + goto cleanup; } case TOK_OPEN_PAREN: { skip_newlines (); - if (tok.type != TOK_CLOSE_PAREN) + if (!token_is (TOK_CLOSE_PAREN)) { - lhs = parse_expression (); + parse_expression (); token_after_newlines_must_be (TOK_CLOSE_PAREN); - return lhs; + goto cleanup; } /* FALLTHRU */ } @@ -1112,6 +1139,9 @@ parse_primary_expression (void) JERRY_UNREACHABLE (); } } + +cleanup: + CHECK_USAGE_LHS () } /* member_expression @@ -1135,59 +1165,64 @@ parse_primary_expression (void) property_reference_suffix : '.' LT!* Identifier ; */ -static idx_t +static void parse_member_expression (void) { - idx_t lhs, obj, prop; + // IDX obj, lhs, prop; + DECLARE_USAGE (IDX) + if (is_keyword (KW_FUNCTION)) { - obj = parse_function_expression (); + parse_function_expression (); } else if (is_keyword (KW_NEW)) { - idx_t member; + NEXT (member_expression); // push member - NEXT (member, member_expression); + parse_argument_list (AL_CONSTRUCT_EXPR, HEAD (IDX, 1)); // push obj - obj = parse_argument_list (AL_CONSTRUCT_EXPR, member); + HEAD (IDX, 2) = HEAD (IDX, 1); + DROP (IDX, 1) } else { - obj = parse_primary_expression (); + parse_primary_expression (); } skip_newlines (); - while (tok.type == TOK_OPEN_SQUARE || tok.type == TOK_DOT) + while (token_is (TOK_OPEN_SQUARE) || token_is (TOK_DOT)) { - lhs = next_temp_name (); + PUSH (IDX, next_temp_name ()); - if (tok.type == TOK_OPEN_SQUARE) + if (token_is (TOK_OPEN_SQUARE)) { - NEXT (prop, expression); + NEXT (expression); // push prop next_token_must_be (TOK_CLOSE_SQUARE); } - else if (tok.type == TOK_DOT) + else if (token_is (TOK_DOT)) { skip_newlines (); - if (tok.type != TOK_NAME) + if (!token_is (TOK_NAME)) { parser_fatal (ERR_PARSER); } - prop = tok.data.uid; + PUSH (IDX, token_data ()); } else { JERRY_UNREACHABLE (); } - DUMP_OPCODE_3 (prop_getter, lhs, obj, prop); - obj = lhs; + DUMP_OPCODE_3 (prop_getter, HEAD (IDX, 2), HEAD (IDX, 3), HEAD (IDX, 1)); + HEAD (IDX, 3) = HEAD (IDX, 2); skip_newlines (); + + DROP (IDX, 2) } - lexer_save_token (tok); + lexer_save_token (TOK ()); - return obj; + CHECK_USAGE_LHS () } /* call_expression @@ -1203,52 +1238,56 @@ parse_member_expression (void) arguments : '(' LT!* assignment_expression LT!* (',' LT!* assignment_expression * LT!*)* ')' ; */ -static idx_t +static void parse_call_expression (void) { - idx_t lhs, obj, prop; + // IDX obj, lhs, prop; + DECLARE_USAGE (IDX) - obj = parse_member_expression (); + parse_member_expression (); skip_newlines (); - if (tok.type != TOK_OPEN_PAREN) + if (!token_is (TOK_OPEN_PAREN)) { - lexer_save_token (tok); - return obj; + lexer_save_token (TOK ()); + goto cleanup; } - lhs = parse_argument_list (AL_CALL_EXPR, obj); - obj = lhs; + parse_argument_list (AL_CALL_EXPR, HEAD (IDX, 1)); // push lhs + HEAD (IDX, 2) = HEAD (IDX, 1); skip_newlines (); - while (tok.type == TOK_OPEN_PAREN || tok.type == TOK_OPEN_SQUARE - || tok.type == TOK_DOT) + while (token_is (TOK_OPEN_PAREN) || token_is (TOK_OPEN_SQUARE) + || token_is (TOK_DOT)) { - switch (tok.type) + switch (TOK ().type) { case TOK_OPEN_PAREN: { - lhs = parse_argument_list (AL_CALL_EXPR, obj); + DROP (IDX, 1) + parse_argument_list (AL_CALL_EXPR, HEAD (IDX, 1)); // push lhs skip_newlines (); break; } case TOK_OPEN_SQUARE: { - NEXT (prop, expression); + NEXT (expression); // push prop next_token_must_be (TOK_CLOSE_SQUARE); - DUMP_OPCODE_3 (prop_getter, lhs, obj, prop); - obj = lhs; + DUMP_OPCODE_3 (prop_getter, HEAD (IDX, 2), HEAD (IDX, 3), HEAD (IDX, 1)); + DROP (IDX, 1) + HEAD (IDX, 2) = HEAD (IDX, 1); skip_newlines (); break; } case TOK_DOT: { token_after_newlines_must_be (TOK_NAME); - prop = tok.data.uid; + PUSH (IDX, token_data ()); - DUMP_OPCODE_3 (prop_getter, lhs, obj, prop); - obj = lhs; + DUMP_OPCODE_3 (prop_getter, HEAD (IDX, 2), HEAD (IDX, 3), HEAD (IDX, 1)); + DROP (IDX, 1) + HEAD (IDX, 2) = HEAD (IDX, 1); skip_newlines (); break; } @@ -1258,114 +1297,123 @@ parse_call_expression (void) } } } - lexer_save_token (tok); + lexer_save_token (TOK ()); - return obj; + DROP (IDX, 1) + +cleanup: + CHECK_USAGE_LHS () } /* left_hand_side_expression : call_expression | new_expression ; */ -static idx_t +static void parse_left_hand_side_expression (void) { - return parse_call_expression (); + DECLARE_USAGE (IDX) + + parse_call_expression (); + + CHECK_USAGE_LHS () } /* postfix_expression : left_hand_side_expression ('++' | '--')? ; */ -static idx_t +static void parse_postfix_expression (void) { - idx_t expr = parse_left_hand_side_expression (), lhs; + // IDX expr, lhs + DECLARE_USAGE (IDX) - tok = lexer_next_token (); - if (tok.type == TOK_DOUBLE_PLUS) + parse_left_hand_side_expression (); // push expr + + skip_token (); + if (token_is (TOK_DOUBLE_PLUS)) { - lhs = next_temp_name (); - DUMP_OPCODE_2 (post_incr, lhs, expr); + DUMP_OPCODE_2 (post_incr, next_temp_name (), HEAD (IDX, 1)); } - else if (tok.type == TOK_DOUBLE_MINUS) + else if (token_is (TOK_DOUBLE_MINUS)) { - lhs = next_temp_name (); - DUMP_OPCODE_2 (post_decr, lhs, expr); + DUMP_OPCODE_2 (post_decr, next_temp_name (), HEAD (IDX, 1)); } else { - lexer_save_token (tok); + lexer_save_token (TOK ()); } - return expr; + CHECK_USAGE_LHS () } /* unary_expression : postfix_expression | ('delete' | 'void' | 'typeof' | '++' | '--' | '+' | '-' | '~' | '!') unary_expression ; */ -static idx_t +static void parse_unary_expression (void) { - idx_t expr, lhs; + // IDX expr, lhs; + DECLARE_USAGE (IDX) - switch (tok.type) + switch (TOK ().type) { case TOK_DOUBLE_PLUS: { - lhs = next_temp_name (); - NEXT (expr, unary_expression); - DUMP_OPCODE_2 (pre_incr, lhs, expr); - return expr; + NEXT (unary_expression); + DUMP_OPCODE_2 (pre_incr, next_temp_name (), HEAD (IDX, 1)); + break; } case TOK_DOUBLE_MINUS: { - lhs = next_temp_name (); - NEXT (expr, unary_expression); - DUMP_OPCODE_2 (pre_decr, lhs, expr); - return expr; + NEXT (unary_expression); + DUMP_OPCODE_2 (pre_decr, next_temp_name (), HEAD (IDX, 1)); + break; } case TOK_PLUS: { - lhs = next_temp_name (); - NEXT (expr, unary_expression); - DUMP_OPCODE_3 (addition, lhs, integer_zero (), expr); - return lhs; + PUSH (IDX, next_temp_name ()); + NEXT (unary_expression); + integer_zero (); + DUMP_OPCODE_3 (addition, HEAD (IDX, 3), HEAD (IDX, 1), HEAD (IDX, 2)); + DROP (IDX, 2) + break; } case TOK_MINUS: { - lhs = next_temp_name (); - NEXT (expr, unary_expression); - DUMP_OPCODE_3 (substraction, lhs, integer_zero (), expr); - return lhs; + PUSH (IDX, next_temp_name ()); + NEXT (unary_expression); + integer_zero (); + DUMP_OPCODE_3 (substraction, HEAD (IDX, 3), HEAD (IDX, 1), HEAD (IDX, 2)); + DROP (IDX, 2) + break; } case TOK_COMPL: { - lhs = next_temp_name (); - NEXT (expr, unary_expression); - DUMP_OPCODE_2 (b_not, lhs, expr); - return lhs; + PUSH (IDX, next_temp_name ()); + NEXT (unary_expression); + DUMP_OPCODE_2 (b_not, HEAD (IDX, 2), HEAD (IDX, 1)); + DROP (IDX, 1) + break; } case TOK_NOT: { - lhs = next_temp_name (); - NEXT (expr, unary_expression); - DUMP_OPCODE_2 (logical_not, lhs, expr); - return lhs; + PUSH (IDX, next_temp_name ()); + NEXT (unary_expression); + DUMP_OPCODE_2 (logical_not, HEAD (IDX, 2), HEAD (IDX, 1)); + DROP (IDX, 1) + break; } case TOK_KEYWORD: { if (is_keyword (KW_DELETE)) { - lhs = next_temp_name (); - NEXT (expr, unary_expression); TODO (/* lhs = delete_var for delete, applied to expression, that is evaluating to Identifier; lhs = delete_prop for 'delete expr[expr]'; lhs = true - otherwise; */); - // DUMP_OPCODE_2 (delete, lhs, expr); JERRY_UNIMPLEMENTED (); - return lhs; } if (is_keyword (KW_VOID)) { @@ -1373,126 +1421,131 @@ parse_unary_expression (void) } if (is_keyword (KW_TYPEOF)) { - lhs = next_temp_name (); - NEXT (expr, unary_expression); - DUMP_OPCODE_2 (typeof, lhs, expr); - return lhs; + PUSH (IDX, next_temp_name ()); + NEXT (unary_expression); + DUMP_OPCODE_2 (typeof, HEAD (IDX, 2), HEAD (IDX, 1)); + DROP (IDX, 1) + break; } /* FALLTHRU. */ } default: { - return parse_postfix_expression (); + parse_postfix_expression (); } } + + CHECK_USAGE_LHS () } #define DUMP_OF(GETOP, EXPR) \ - lhs = next_temp_name (); \ - NEXT (expr2, EXPR);\ - DUMP_OPCODE_3 (GETOP, lhs, expr1, expr2); \ - expr1 = lhs + PUSH (IDX, next_temp_name ()); \ + NEXT (EXPR);\ + DUMP_OPCODE_3 (GETOP, HEAD (IDX, 2), HEAD (IDX, 3), HEAD (IDX, 1)); \ + HEAD (IDX, 3) = HEAD (IDX, 2); \ + DROP (IDX, 2) /* multiplicative_expression : unary_expression (LT!* ('*' | '/' | '%') LT!* unary_expression)* ; */ -static idx_t +static void parse_multiplicative_expression (void) { - idx_t lhs, expr1, expr2; + // IDX expr1, lhs, expr2; + DECLARE_USAGE (IDX) - expr1 = parse_unary_expression (); + parse_unary_expression (); skip_newlines (); while (true) { - switch (tok.type) + switch (TOK ().type) { case TOK_MULT: DUMP_OF (multiplication, unary_expression); break; case TOK_DIV: DUMP_OF (division, unary_expression); break; case TOK_MOD: DUMP_OF (remainder, unary_expression); break; - default: - { - lexer_save_token (tok); - return expr1; - } + default: lexer_save_token (TOK ()); goto cleanup; } skip_newlines (); } + +cleanup: + CHECK_USAGE_LHS () } /* additive_expression : multiplicative_expression (LT!* ('+' | '-') LT!* multiplicative_expression)* ; */ -static idx_t +static void parse_additive_expression (void) { - idx_t lhs, expr1, expr2; + // IDX expr1, lhs, expr2; + DECLARE_USAGE (IDX) - expr1 = parse_multiplicative_expression (); + parse_multiplicative_expression (); skip_newlines (); while (true) { - switch (tok.type) + switch (TOK ().type) { case TOK_PLUS: DUMP_OF (addition, multiplicative_expression); break; case TOK_MINUS: DUMP_OF (substraction, multiplicative_expression); break; - default: - { - lexer_save_token (tok); - return expr1; - } + default: lexer_save_token (TOK ()); goto cleanup; } skip_newlines (); } + +cleanup: + CHECK_USAGE_LHS () } /* shift_expression : additive_expression (LT!* ('<<' | '>>' | '>>>') LT!* additive_expression)* ; */ -static idx_t +static void parse_shift_expression (void) { - idx_t lhs, expr1, expr2; + // IDX expr1, lhs, expr2; + DECLARE_USAGE (IDX) - expr1 = parse_additive_expression (); + parse_additive_expression (); skip_newlines (); while (true) { - switch (tok.type) + switch (TOK ().type) { case TOK_LSHIFT: DUMP_OF (b_shift_left, additive_expression); break; case TOK_RSHIFT: DUMP_OF (b_shift_right, additive_expression); break; case TOK_RSHIFT_EX: DUMP_OF (b_shift_uright, additive_expression); break; - default: - { - lexer_save_token (tok); - return expr1; - } + default: lexer_save_token (TOK ()); goto cleanup; } skip_newlines (); } + +cleanup: + CHECK_USAGE_LHS () } /* relational_expression : shift_expression (LT!* ('<' | '>' | '<=' | '>=' | 'instanceof' | 'in') LT!* shift_expression)* ; */ -static idx_t +static void parse_relational_expression (void) { - idx_t lhs, expr1, expr2; + // IDX expr1, lhs, expr2; + DECLARE_USAGE (IDX) - expr1 = parse_shift_expression (); + parse_shift_expression (); skip_newlines (); while (true) { - switch (tok.type) + switch (TOK ().type) { case TOK_LESS: DUMP_OF (less_than, shift_expression); break; case TOK_GREATER: DUMP_OF (greater_than, shift_expression); break; @@ -1514,29 +1567,33 @@ parse_relational_expression (void) } default: { - lexer_save_token (tok); - return expr1; + lexer_save_token (TOK ()); + goto cleanup; } } skip_newlines (); } + +cleanup: + CHECK_USAGE_LHS () } /* equality_expression : relational_expression (LT!* ('==' | '!=' | '===' | '!==') LT!* relational_expression)* ; */ -static idx_t +static void parse_equality_expression (void) { - idx_t lhs, expr1, expr2; + // IDX expr1, lhs, expr2; + DECLARE_USAGE (IDX) - expr1 = parse_relational_expression (); + parse_relational_expression (); skip_newlines (); while (true) { - switch (tok.type) + switch (TOK ().type) { case TOK_DOUBLE_EQ: DUMP_OF (equal_value, relational_expression); break; case TOK_NOT_EQ: DUMP_OF (not_equal_value, relational_expression); break; @@ -1544,29 +1601,34 @@ parse_equality_expression (void) case TOK_NOT_DOUBLE_EQ: DUMP_OF (not_equal_value_type, relational_expression); break; default: { - lexer_save_token (tok); - return expr1; + lexer_save_token (TOK ()); + goto cleanup; } } skip_newlines (); } + +cleanup: + CHECK_USAGE_LHS () } #define PARSE_OF(FUNC, EXPR, TOK_TYPE, GETOP) \ -static idx_t parse_##FUNC (void) { \ - idx_t lhs, expr1, expr2; \ - expr1 = parse_##EXPR (); \ +static void parse_##FUNC (void) { \ + DECLARE_USAGE (IDX) \ + parse_##EXPR (); \ skip_newlines (); \ while (true) \ { \ - switch (tok.type) \ + switch (TOK ().type) \ { \ case TOK_##TOK_TYPE: DUMP_OF (GETOP, EXPR); break; \ - default: lexer_save_token (tok); return expr1; \ + default: lexer_save_token (TOK ()); goto cleanup; \ } \ skip_newlines (); \ } \ +cleanup: \ + CHECK_USAGE_LHS () \ } /* bitwise_and_expression @@ -1597,165 +1659,183 @@ PARSE_OF (logical_or_expression, logical_and_expression, DOUBLE_OR, logical_or) /* conditional_expression : logical_or_expression (LT!* '?' LT!* assignment_expression LT!* ':' LT!* assignment_expression)? ; */ -static idx_t +static void parse_conditional_expression (bool *was_conditional) { - idx_t expr = parse_logical_or_expression (); + // IDX expr, res, lhs + DECLARE_USAGE (IDX) + DECLARE_USAGE (U16) + + parse_logical_or_expression (); skip_newlines (); - if (tok.type == TOK_QUERY) + if (token_is (TOK_QUERY)) { - idx_t lhs, res = next_temp_name (); - opcode_counter_t jmp_oc; + DUMP_OPCODE_3 (is_true_jmp_down, HEAD (IDX, 1), 0, 2); + PUSH (IDX, next_temp_name ()) + PUSH (U16, OPCODE_COUNTER ()) + DUMP_OPCODE_2 (jmp_down, INVALID_VALUE, INVALID_VALUE); - DUMP_OPCODE_2 (is_true_jmp, expr, opcode_counter + 2); - jmp_oc = opcode_counter; - DUMP_OPCODE_1 (jmp_down, INVALID_VALUE); - - NEXT (lhs, assignment_expression); - DUMP_OPCODE_3 (assignment, res, OPCODE_ARG_TYPE_VARIABLE, lhs); + NEXT (assignment_expression); + DUMP_OPCODE_3 (assignment, HEAD (IDX, 2), OPCODE_ARG_TYPE_VARIABLE, HEAD (IDX, 1)); token_after_newlines_must_be (TOK_COLON); - REWRITE_OPCODE_1 (jmp_oc, jmp_down, opcode_counter - jmp_oc); - jmp_oc = opcode_counter; - DUMP_OPCODE_1 (jmp_down, INVALID_VALUE); + REWRITE_JMP (HEAD (U16, 1), jmp_down, OPCODE_COUNTER () - HEAD (U16, 1)); + HEAD (U16, 1) = OPCODE_COUNTER (); + DUMP_OPCODE_2 (jmp_down, INVALID_VALUE, INVALID_VALUE); - NEXT (lhs, assignment_expression); - DUMP_OPCODE_3 (assignment, res, OPCODE_ARG_TYPE_VARIABLE, lhs); - REWRITE_OPCODE_1 (jmp_oc, jmp_down, opcode_counter - jmp_oc); + DROP (IDX, 1) + NEXT (assignment_expression); + DUMP_OPCODE_3 (assignment, HEAD (IDX, 2), OPCODE_ARG_TYPE_VARIABLE, HEAD (IDX, 1)); + REWRITE_JMP (HEAD (U16, 1), jmp_down, OPCODE_COUNTER () - HEAD (U16, 1)); *was_conditional = true; - return res; + HEAD (IDX, 3) = HEAD (IDX, 2); + DROP (IDX, 2) } else { - lexer_save_token (tok); - return expr; + lexer_save_token (TOK ()); } + + CHECK_USAGE (U16) + CHECK_USAGE_LHS () } /* assignment_expression : conditional_expression | left_hand_side_expression LT!* assignment_operator LT!* assignment_expression ; */ -static idx_t +static void parse_assignment_expression (void) { - idx_t lhs, rhs; + // IDX lhs, rhs; + DECLARE_USAGE (IDX) bool was_conditional = false; - lhs = parse_conditional_expression (&was_conditional); + parse_conditional_expression (&was_conditional); if (was_conditional) { - return lhs; + goto cleanup; } skip_newlines (); - switch (tok.type) + switch (TOK ().type) { case TOK_EQ: { - NEXT (rhs, assignment_expression); - DUMP_OPCODE_3 (assignment, lhs, OPCODE_ARG_TYPE_VARIABLE, rhs); + NEXT (assignment_expression); + DUMP_OPCODE_3 (assignment, HEAD (IDX, 2), OPCODE_ARG_TYPE_VARIABLE, HEAD (IDX, 1)); break; } case TOK_MULT_EQ: { - NEXT (rhs, assignment_expression); - DUMP_OPCODE_3 (multiplication, lhs, lhs, rhs); + NEXT (assignment_expression); + DUMP_OPCODE_3 (multiplication, HEAD (IDX, 2), HEAD (IDX, 2), HEAD (IDX, 1)); break; } case TOK_DIV_EQ: { - NEXT (rhs, assignment_expression); - DUMP_OPCODE_3 (division, lhs, lhs, rhs); + NEXT (assignment_expression); + DUMP_OPCODE_3 (division, HEAD (IDX, 2), HEAD (IDX, 2), HEAD (IDX, 1)); break; } case TOK_MOD_EQ: { - NEXT (rhs, assignment_expression); - DUMP_OPCODE_3 (remainder, lhs, lhs, rhs); + NEXT (assignment_expression); + DUMP_OPCODE_3 (remainder, HEAD (IDX, 2), HEAD (IDX, 2), HEAD (IDX, 1)); break; } case TOK_PLUS_EQ: { - NEXT (rhs, assignment_expression); - DUMP_OPCODE_3 (addition, lhs, lhs, rhs); + NEXT (assignment_expression); + DUMP_OPCODE_3 (addition, HEAD (IDX, 2), HEAD (IDX, 2), HEAD (IDX, 1)); break; } case TOK_MINUS_EQ: { - NEXT (rhs, assignment_expression); - DUMP_OPCODE_3 (substraction, lhs, lhs, rhs); + NEXT (assignment_expression); + DUMP_OPCODE_3 (substraction, HEAD (IDX, 2), HEAD (IDX, 2), HEAD (IDX, 1)); break; } case TOK_LSHIFT_EQ: { - NEXT (rhs, assignment_expression); - DUMP_OPCODE_3 (b_shift_left, lhs, lhs, rhs); + NEXT (assignment_expression); + DUMP_OPCODE_3 (b_shift_left, HEAD (IDX, 2), HEAD (IDX, 2), HEAD (IDX, 1)); break; } case TOK_RSHIFT_EQ: { - NEXT (rhs, assignment_expression); - DUMP_OPCODE_3 (b_shift_right, lhs, lhs, rhs); + NEXT (assignment_expression); + DUMP_OPCODE_3 (b_shift_right, HEAD (IDX, 2), HEAD (IDX, 2), HEAD (IDX, 1)); break; } case TOK_RSHIFT_EX_EQ: { - NEXT (rhs, assignment_expression); - DUMP_OPCODE_3 (b_shift_uright, lhs, lhs, rhs); + NEXT (assignment_expression); + DUMP_OPCODE_3 (b_shift_uright, HEAD (IDX, 2), HEAD (IDX, 2), HEAD (IDX, 1)); break; } case TOK_AND_EQ: { - NEXT (rhs, assignment_expression); - DUMP_OPCODE_3 (b_and, lhs, lhs, rhs); + NEXT (assignment_expression); + DUMP_OPCODE_3 (b_and, HEAD (IDX, 2), HEAD (IDX, 2), HEAD (IDX, 1)); break; } case TOK_XOR_EQ: { - NEXT (rhs, assignment_expression); - DUMP_OPCODE_3 (b_xor, lhs, lhs, rhs); + NEXT (assignment_expression); + DUMP_OPCODE_3 (b_xor, HEAD (IDX, 2), HEAD (IDX, 2), HEAD (IDX, 1)); break; } case TOK_OR_EQ: { - NEXT (rhs, assignment_expression); - DUMP_OPCODE_3 (b_or, lhs, lhs, rhs); + NEXT (assignment_expression); + DUMP_OPCODE_3 (b_or, HEAD (IDX, 2), HEAD (IDX, 2), HEAD (IDX, 1)); break; } default: { - lexer_save_token (tok); + lexer_save_token (TOK ()); + goto cleanup; } } - return lhs; + DROP (IDX, 1) + +cleanup: + CHECK_USAGE_LHS () } /* expression : assignment_expression (LT!* ',' LT!* assignment_expression)* ; */ -static idx_t +static void parse_expression (void) { - idx_t expr = parse_assignment_expression (); + // IDX expr + DECLARE_USAGE (IDX) + + parse_assignment_expression (); while (true) { skip_newlines (); - if (tok.type == TOK_COMMA) + if (token_is (TOK_COMMA)) { - NEXT (expr, assignment_expression); + NEXT (assignment_expression); + HEAD (IDX, 2) = HEAD (IDX, 1); + DROP (IDX, 1) } else { - lexer_save_token (tok); - return expr; + lexer_save_token (TOK ()); + break; } } + + CHECK_USAGE_LHS () } /* variable_declaration @@ -1767,22 +1847,29 @@ parse_expression (void) static void parse_variable_declaration (void) { - idx_t name, expr; + //IDX name, expr; + + DECLARE_USAGE (IDX) current_token_must_be (TOK_NAME); - name = tok.data.uid; - DUMP_OPCODE_1 (var_decl, name); + PUSH (IDX, token_data ()); + DUMP_OPCODE_1 (var_decl, HEAD (IDX, 1)); skip_newlines (); - if (tok.type == TOK_EQ) + if (token_is (TOK_EQ)) { - NEXT (expr, assignment_expression); - DUMP_OPCODE_3 (assignment, name, OPCODE_ARG_TYPE_VARIABLE, expr); + NEXT (assignment_expression); + DUMP_OPCODE_3 (assignment, HEAD (IDX, 2), OPCODE_ARG_TYPE_VARIABLE, HEAD (IDX, 1)); + DROP (IDX, 1) } else { - lexer_save_token (tok); + lexer_save_token (TOK ()); } + + DROP (IDX, 1) + + CHECK_USAGE (IDX) } /* variable_declaration_list @@ -1792,14 +1879,16 @@ parse_variable_declaration (void) static void parse_variable_declaration_list (bool *several_decls) { + DECLARE_USAGE (IDX) + while (true) { parse_variable_declaration (); skip_newlines (); - if (tok.type != TOK_COMMA) + if (!token_is (TOK_COMMA)) { - lexer_save_token (tok); + lexer_save_token (TOK ()); return; } @@ -1809,6 +1898,8 @@ parse_variable_declaration_list (bool *several_decls) *several_decls = true; } } + + CHECK_USAGE (IDX) } /* for_statement @@ -1834,14 +1925,17 @@ parse_variable_declaration_list (bool *several_decls) static void parse_for_or_for_in_statement (void) { - idx_t stop; - opcode_counter_t cond_oc, body_oc, step_oc, end_oc; + // IDX stop; + // U16 cond_oc, body_oc, step_oc, end_oc; + DECLARE_USAGE (IDX) + DECLARE_USAGE (U16) + DECLARE_USAGE (nestings) assert_keyword (KW_FOR); token_after_newlines_must_be (TOK_OPEN_PAREN); skip_newlines (); - if (tok.type == TOK_SEMICOLON) + if (token_is (TOK_SEMICOLON)) { goto plain_for; } @@ -1860,7 +1954,7 @@ parse_for_or_for_in_statement (void) else { skip_newlines (); - if (tok.type == TOK_SEMICOLON) + if (token_is (TOK_SEMICOLON)) { goto plain_for; } @@ -1877,9 +1971,10 @@ parse_for_or_for_in_statement (void) /* expression contains left_hand_side_expression. */ parse_expression (); + DROP (IDX, 1) skip_newlines (); - if (tok.type == TOK_SEMICOLON) + if (token_is (TOK_SEMICOLON)) { goto plain_for; } @@ -1908,7 +2003,7 @@ plain_for: 12 tmp1 = #10; 13 tmp2 = i < tmp1; end_oc: - 14 is_false_jmp tmp2, 8 // end of loop + 14 is_false_jmp_down tmp2, +8 // end of loop body_oc: 15 jmp_down 5 // body step_oc: @@ -1922,58 +2017,71 @@ plain_for: 21 jmp_up 5; // step_oc; 22 ... */ - cond_oc = opcode_counter; + PUSH (U16, OPCODE_COUNTER ()) // cond_oc skip_newlines (); - if (tok.type != TOK_SEMICOLON) + if (!token_is (TOK_SEMICOLON)) { - stop = parse_assignment_expression (); + parse_assignment_expression (); next_token_must_be (TOK_SEMICOLON); } else { - stop = boolean_true (); + boolean_true (); } - end_oc = opcode_counter; - DUMP_OPCODE_2 (is_false_jmp, stop, INVALID_VALUE); + PUSH (U16, OPCODE_COUNTER ()) // end_oc + DUMP_OPCODE_3 (is_false_jmp_down, INVALID_VALUE, INVALID_VALUE, INVALID_VALUE); - body_oc = opcode_counter; - DUMP_OPCODE_1 (jmp_down, INVALID_VALUE); + PUSH (U16, OPCODE_COUNTER ()) // body_oc + DUMP_OPCODE_2 (jmp_down, INVALID_VALUE, INVALID_VALUE); - step_oc = opcode_counter; + PUSH (U16, OPCODE_COUNTER ()) // step_oc skip_newlines (); - if (tok.type != TOK_CLOSE_PAREN) + if (!token_is (TOK_CLOSE_PAREN)) { parse_assignment_expression (); + DROP (IDX, 1) next_token_must_be (TOK_CLOSE_PAREN); } - DUMP_OPCODE_1 (jmp_up, opcode_counter - cond_oc); - REWRITE_OPCODE_1 (body_oc, jmp_down, opcode_counter - body_oc); + DUMP_OPCODE_2 (jmp_up, 0, OPCODE_COUNTER () - HEAD (U16, 4)); + REWRITE_JMP (HEAD (U16, 2), jmp_down, OPCODE_COUNTER () - HEAD (U16, 2)); skip_newlines (); push_nesting (NESTING_ITERATIONAL); parse_statement (); pop_nesting (NESTING_ITERATIONAL); - DUMP_OPCODE_1 (jmp_up, opcode_counter - step_oc); - REWRITE_OPCODE_2 (end_oc, is_false_jmp, stop, opcode_counter); + DUMP_OPCODE_2 (jmp_up, 0, OPCODE_COUNTER () - HEAD (U16, 1)); + REWRITE_COND_JMP (HEAD (U16, 3), is_false_jmp_down, OPCODE_COUNTER () - HEAD (U16, 3)); - rewrite_rewritable_opcodes (REWRITABLE_CONTINUE, step_oc); - rewrite_rewritable_opcodes (REWRITABLE_BREAK, opcode_counter); - return; + rewrite_rewritable_opcodes (REWRITABLE_CONTINUE, HEAD (U16, 1)); + rewrite_rewritable_opcodes (REWRITABLE_BREAK, OPCODE_COUNTER ()); + + DROP (IDX, 1) + DROP (U16, 4) + + goto cleanup; for_in: JERRY_UNIMPLEMENTED (); + +cleanup: + CHECK_USAGE (IDX) + CHECK_USAGE (U16) + CHECK_USAGE (nestings) } -static idx_t +static void parse_expression_inside_parens (void) { - idx_t expr; + // IDX expr; + DECLARE_USAGE (IDX) + token_after_newlines_must_be (TOK_OPEN_PAREN); - NEXT (expr, expression); + NEXT (expression); token_after_newlines_must_be (TOK_CLOSE_PAREN); - return expr; + + CHECK_USAGE_LHS () } /* statement_list @@ -1982,21 +2090,25 @@ parse_expression_inside_parens (void) static void parse_statement_list (void) { + DECLARE_USAGE (IDX) + while (true) { parse_statement (); skip_newlines (); - while (tok.type == TOK_SEMICOLON) + while (token_is (TOK_SEMICOLON)) { skip_newlines (); } - if (tok.type == TOK_CLOSE_BRACE) + if (token_is (TOK_CLOSE_BRACE)) { - lexer_save_token (tok); + lexer_save_token (TOK ()); return; } } + + CHECK_USAGE (IDX) } /* if_statement @@ -2005,18 +2117,21 @@ parse_statement_list (void) static void parse_if_statement (void) { - idx_t cond; - opcode_counter_t cond_oc; + // IDX cond; + // U16 cond_oc; + DECLARE_USAGE (IDX) + DECLARE_USAGE (U16) + assert_keyword (KW_IF); - cond = parse_expression_inside_parens (); - cond_oc = opcode_counter; - DUMP_OPCODE_2 (is_false_jmp, cond, INVALID_VALUE); + parse_expression_inside_parens (); + PUSH (U16, OPCODE_COUNTER ()) + DUMP_OPCODE_3 (is_false_jmp_down, INVALID_VALUE, INVALID_VALUE, INVALID_VALUE); skip_newlines (); parse_statement (); - REWRITE_OPCODE_2 (cond_oc, is_false_jmp, cond, opcode_counter); + REWRITE_COND_JMP (HEAD (U16, 1), is_false_jmp_down, OPCODE_COUNTER () - HEAD (U16, 1)); skip_newlines (); if (is_keyword (KW_ELSE)) @@ -2026,8 +2141,14 @@ parse_if_statement (void) } else { - lexer_save_token (tok); + lexer_save_token (TOK ()); } + + DROP (U16, 1) + DROP (IDX, 1) + + CHECK_USAGE (U16) + CHECK_USAGE (IDX) } /* do_while_statement @@ -2036,12 +2157,15 @@ parse_if_statement (void) static void parse_do_while_statement (void) { - idx_t cond; - opcode_counter_t loop_oc; + // IDX cond; + // U16 loop_oc; + DECLARE_USAGE (IDX) + DECLARE_USAGE (U16) + DECLARE_USAGE (nestings) assert_keyword (KW_DO); - loop_oc = opcode_counter; + PUSH (U16, OPCODE_COUNTER ()) skip_newlines (); push_nesting (NESTING_ITERATIONAL); @@ -2049,11 +2173,20 @@ parse_do_while_statement (void) pop_nesting (NESTING_ITERATIONAL); token_after_newlines_must_be_keyword (KW_WHILE); - cond = parse_expression_inside_parens (); - DUMP_OPCODE_2 (is_true_jmp, cond, loop_oc); + parse_expression_inside_parens (); + PUSH (U16, OPCODE_COUNTER ()) + DUMP_OPCODE_3 (is_true_jmp_up, INVALID_VALUE, INVALID_VALUE, INVALID_VALUE); + REWRITE_COND_JMP (HEAD(U16, 1), is_true_jmp_up, OPCODE_COUNTER () - HEAD (U16, 2)); - rewrite_rewritable_opcodes (REWRITABLE_CONTINUE, loop_oc); - rewrite_rewritable_opcodes (REWRITABLE_BREAK, opcode_counter); + rewrite_rewritable_opcodes (REWRITABLE_CONTINUE, HEAD (U16, 2)); + rewrite_rewritable_opcodes (REWRITABLE_BREAK, OPCODE_COUNTER ()); + + DROP (IDX, 1) + DROP (U16, 2) + + CHECK_USAGE (U16) + CHECK_USAGE (IDX) + CHECK_USAGE (nestings) } /* while_statement @@ -2062,26 +2195,38 @@ parse_do_while_statement (void) static void parse_while_statement (void) { - idx_t cond; - opcode_counter_t cond_oc, jmp_oc; + // IDX cond; + // U16 cond_oc, jmp_oc; + DECLARE_USAGE (IDX) + DECLARE_USAGE (U16) + DECLARE_USAGE (nestings) assert_keyword (KW_WHILE); - cond_oc = opcode_counter; - cond = parse_expression_inside_parens (); - jmp_oc = opcode_counter; - DUMP_OPCODE_2 (is_false_jmp, cond, INVALID_VALUE); + PUSH (U16, OPCODE_COUNTER ()) // cond_oc + parse_expression_inside_parens (); + PUSH (U16, OPCODE_COUNTER ()) // jmp_oc + DUMP_OPCODE_3 (is_false_jmp_down, INVALID_VALUE, INVALID_VALUE, INVALID_VALUE); skip_newlines (); push_nesting (NESTING_ITERATIONAL); parse_statement (); pop_nesting (NESTING_ITERATIONAL); - DUMP_OPCODE_1 (jmp_up, opcode_counter - cond_oc); - REWRITE_OPCODE_2 (jmp_oc, is_false_jmp, cond, opcode_counter); + PUSH (U16, OPCODE_COUNTER ()) + DUMP_OPCODE_2 (jmp_up, INVALID_VALUE, INVALID_VALUE); + REWRITE_JMP (HEAD (U16, 1), jmp_up, OPCODE_COUNTER () - HEAD (U16, 3)); + REWRITE_COND_JMP (HEAD (U16, 2), is_false_jmp_down, OPCODE_COUNTER () - HEAD (U16, 2)); - rewrite_rewritable_opcodes (REWRITABLE_CONTINUE, cond_oc); - rewrite_rewritable_opcodes (REWRITABLE_BREAK, opcode_counter); + rewrite_rewritable_opcodes (REWRITABLE_CONTINUE, HEAD (U16, 3)); + rewrite_rewritable_opcodes (REWRITABLE_BREAK, OPCODE_COUNTER ()); + + DROP (IDX, 1) + DROP (U16, 3) + + CHECK_USAGE (U16) + CHECK_USAGE (IDX) + CHECK_USAGE (nestings) } /* with_statement @@ -2090,18 +2235,34 @@ parse_while_statement (void) static void parse_with_statement (void) { - idx_t expr; - assert_keyword (KW_WITH); - expr = parse_expression_inside_parens (); + // IDX expr; + DECLARE_USAGE (IDX) - DUMP_OPCODE_1 (with, expr); + assert_keyword (KW_WITH); + parse_expression_inside_parens (); + + DUMP_OPCODE_1 (with, HEAD (IDX, 1)); skip_newlines (); parse_statement (); DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_END_WITH, INVALID_VALUE, INVALID_VALUE); + + DROP (IDX, 1) + + CHECK_USAGE (IDX) } +/* case_block + : '{' LT!* case_clause* LT!* '}' + | '{' LT!* case_clause* LT!* default_clause LT!* case_clause* LT!* '}' + ; + case_clause + : 'case' LT!* expression LT!* ':' LT!* statement* + ; + default_clause + : 'default' LT!* ':' LT!* statement* + ; */ /* switch_statement : 'switch' LT!* '(' LT!* expression LT!* ')' LT!* '{' LT!* case_block LT!* '}' ; */ @@ -2111,21 +2272,122 @@ parse_switch_statement (void) JERRY_UNIMPLEMENTED (); } +/* catch_clause + : 'catch' LT!* '(' LT!* Identifier LT!* ')' LT!* '{' LT!* statement_list LT!* '}' + ; */ +static void +parse_catch_clause (void) +{ + // IDX ex_name; + // U16 catch_oc; + DECLARE_USAGE (IDX) + DECLARE_USAGE (U16) + + assert_keyword (KW_CATCH); + + token_after_newlines_must_be (TOK_OPEN_PAREN); + token_after_newlines_must_be (TOK_NAME); + PUSH (IDX, token_data ()); + token_after_newlines_must_be (TOK_CLOSE_PAREN); + + PUSH (U16, OPCODE_COUNTER ()); + DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_CATCH, INVALID_VALUE, INVALID_VALUE); + DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER, HEAD (IDX, 1), INVALID_VALUE); + + token_after_newlines_must_be (TOK_OPEN_BRACE); + parse_statement_list (); + next_token_must_be (TOK_CLOSE_BRACE); + + rewrite_meta_opcode_counter (HEAD (U16, 1), OPCODE_META_TYPE_CATCH); + + DROP (U16, 1); + DROP (IDX, 1); + + CHECK_USAGE (IDX) + CHECK_USAGE (U16) +} + +/* finally_clause + : 'finally' LT!* '{' LT!* statement_list LT!* '}' + ; */ +static void +parse_finally_clause (void) +{ + // U16 finally_oc; + DECLARE_USAGE (U16) + + assert_keyword (KW_FINALLY); + + PUSH (U16, OPCODE_COUNTER ()); + DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_FINALLY, INVALID_VALUE, INVALID_VALUE); + + token_after_newlines_must_be (TOK_OPEN_BRACE); + parse_statement_list (); + next_token_must_be (TOK_CLOSE_BRACE); + + rewrite_meta_opcode_counter (HEAD (U16, 1), OPCODE_META_TYPE_FINALLY); + + DROP (U16, 1) + + CHECK_USAGE (U16) +} + /* try_statement : 'try' LT!* '{' LT!* statement_list LT!* '}' LT!* (finally_clause | catch_clause (LT!* finally_clause)?) - ; - - catch_clause - : 'catch' LT!* '(' LT!* Identifier LT!* ')' LT!* '{' LT!* statement_list LT!* '}' - ; - - finally_clause - : 'finally' LT!* '{' LT!* statement_list LT!* '}' - ;*/ + ; */ static void parse_try_statement (void) { - JERRY_UNIMPLEMENTED (); + // U16 try_oc; + DECLARE_USAGE (U16) + + assert_keyword (KW_TRY); + + PUSH (U16, OPCODE_COUNTER ()) + DUMP_OPCODE_2 (try, HEAD (U16, 1) + 1, INVALID_VALUE); + + token_after_newlines_must_be (TOK_OPEN_BRACE); + parse_statement_list (); + next_token_must_be (TOK_CLOSE_BRACE); + + REWRITE_OPCODE_2 (HEAD (U16, 1), try, HEAD (U16, 1) + 1, opcode_counter); + + token_after_newlines_must_be (TOK_KEYWORD); + if (is_keyword (KW_CATCH)) + { + parse_catch_clause (); + + skip_newlines (); + if (is_keyword (KW_FINALLY)) + { + parse_finally_clause (); + } + else + { + lexer_save_token (TOK ()); + } + } + else if (is_keyword (KW_FINALLY)) + { + parse_finally_clause (); + } + else + { + parser_fatal (ERR_PARSER); + } + + DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_END_TRY_CATCH_FINALLY, INVALID_VALUE, INVALID_VALUE); + + DROP (U16, 1) + + CHECK_USAGE (U16) +} + +static void +insert_semicolon (void) +{ + skip_token (); + JERRY_ASSERT (token_is (TOK_SEMICOLON) || token_is (TOK_NEWLINE)); } /* statement @@ -2196,131 +2458,144 @@ parse_statement (void) { reset_temp_name (); - if (tok.type == TOK_CLOSE_BRACE) + DECLARE_USAGE (IDX) + DECLARE_USAGE (toks) + + if (token_is (TOK_CLOSE_BRACE)) { - lexer_save_token (tok); - return; + lexer_save_token (TOK ()); + goto cleanup; } - if (tok.type == TOK_OPEN_BRACE) + if (token_is (TOK_OPEN_BRACE)) { skip_newlines (); - if (tok.type != TOK_CLOSE_BRACE) + if (!token_is (TOK_CLOSE_BRACE)) { parse_statement_list (); next_token_must_be (TOK_CLOSE_BRACE); } - return; + goto cleanup; } if (is_keyword (KW_VAR)) { skip_newlines (); parse_variable_declaration_list (NULL); - return; + goto cleanup; } - if (tok.type == TOK_SEMICOLON) + if (token_is (TOK_SEMICOLON)) { - return; + goto cleanup; } if (is_keyword (KW_IF)) { parse_if_statement (); - return; + goto cleanup; } if (is_keyword (KW_DO)) { parse_do_while_statement (); - return; + goto cleanup; } if (is_keyword (KW_WHILE)) { parse_while_statement (); - return; + goto cleanup; } if (is_keyword (KW_FOR)) { parse_for_or_for_in_statement (); - return; + goto cleanup; } if (is_keyword (KW_CONTINUE)) { - - 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; + uint8_t *temp = mem_heap_alloc_block (1, MEM_HEAP_ALLOC_SHORT_TERM); + temp[0] = NESTING_ITERATIONAL; + must_be_inside_but_not_in (temp, 1, NESTING_FUNCTION); + add_to_rewritable_opcodes (REWRITABLE_CONTINUE, OPCODE_COUNTER ()); + mem_heap_free_block (temp); + DUMP_OPCODE_2 (jmp_up, INVALID_VALUE, INVALID_VALUE); + goto cleanup; } if (is_keyword (KW_BREAK)) { - - must_be_inside_but_not_in ((uint8_t[]) - { - NESTING_ITERATIONAL, NESTING_SWITCH - }, 2, - NESTING_FUNCTION); + uint8_t *temp = mem_heap_alloc_block (2, MEM_HEAP_ALLOC_SHORT_TERM); + temp[0] = NESTING_ITERATIONAL; + temp[1] = NESTING_SWITCH; + must_be_inside_but_not_in (temp, 2, NESTING_FUNCTION); add_to_rewritable_opcodes (REWRITABLE_BREAK, opcode_counter); - DUMP_OPCODE_1 (jmp_down, INVALID_VALUE); - return; + mem_heap_free_block (temp); + DUMP_OPCODE_2 (jmp_down, INVALID_VALUE, INVALID_VALUE); + goto cleanup; } if (is_keyword (KW_RETURN)) { - idx_t expr; - tok = lexer_next_token (); - if (tok.type != TOK_SEMICOLON) + skip_token (); + if (!token_is (TOK_SEMICOLON) && !token_is (TOK_NEWLINE)) { - expr = parse_expression (); - DUMP_OPCODE_1 (retval, expr); + parse_expression (); + DUMP_OPCODE_1 (retval, HEAD (IDX, 1)); + DROP (IDX, 1) + insert_semicolon (); + goto cleanup; } else { DUMP_VOID_OPCODE (ret); + goto cleanup; } - return; } if (is_keyword (KW_WITH)) { parse_with_statement (); - return; + goto cleanup; } if (is_keyword (KW_SWITCH)) { parse_switch_statement (); - return; + goto cleanup; } if (is_keyword (KW_THROW)) { - JERRY_UNIMPLEMENTED (); + skip_token (); + parse_expression (); + insert_semicolon (); + + DUMP_OPCODE_1 (throw, HEAD (IDX, 1)); + goto cleanup; } if (is_keyword (KW_TRY)) { parse_try_statement (); - return; + goto cleanup; } - if (tok.type == TOK_NAME) + if (token_is (TOK_NAME)) { - token saved = tok; + PUSH (toks, TOK ()) skip_newlines (); - if (tok.type == TOK_COLON) + if (token_is (TOK_COLON)) { // STMT_LABELLED; JERRY_UNIMPLEMENTED (); } else { - lexer_save_token (tok); - tok = saved; + lexer_save_token (TOK ()); + POP (TOK(), toks) parse_expression (); - return; + DROP (IDX, 1) + goto cleanup; } } else { parse_expression (); - return; + DROP (IDX, 1) + goto cleanup; } + +cleanup: + CHECK_USAGE (IDX) + CHECK_USAGE (toks) } /* source_element @@ -2330,6 +2605,8 @@ parse_statement (void) static void parse_source_element (void) { + DECLARE_USAGE (IDX) + if (is_keyword (KW_FUNCTION)) { parse_function_declaration (); @@ -2338,6 +2615,8 @@ parse_source_element (void) { parse_statement (); } + + CHECK_USAGE (IDX) } /* source_element_list @@ -2346,32 +2625,40 @@ parse_source_element (void) static void parse_source_element_list (void) { - opcode_counter_t reg_var_decl_loc; + // U16 reg_var_decl_loc; + DECLARE_USAGE (U16) + DECLARE_USAGE (IDX) + DECLARE_USAGE (temp_names) start_new_scope (); - reg_var_decl_loc = opcode_counter; - DUMP_OPCODE_2 (reg_var_decl, min_temp_name, INVALID_VALUE); + PUSH (U16, OPCODE_COUNTER ()) + DUMP_OPCODE_2 (reg_var_decl, MIN_TEMP_NAME (), INVALID_VALUE); - while (tok.type != TOK_EOF && tok.type != TOK_CLOSE_BRACE) + while (!token_is (TOK_EOF) && !token_is (TOK_CLOSE_BRACE)) { parse_source_element (); skip_newlines (); } - lexer_save_token (tok); - if (max_temp_name > min_temp_name) + lexer_save_token (TOK ()); + if (MAX_TEMP_NAME () > MIN_TEMP_NAME ()) { - REWRITE_OPCODE_2 (reg_var_decl_loc, reg_var_decl, min_temp_name, max_temp_name - 1); + REWRITE_OPCODE_2 (HEAD (U16, 1), reg_var_decl, MIN_TEMP_NAME (), MAX_TEMP_NAME () - 1); } - else if (max_temp_name == min_temp_name) + else if (MAX_TEMP_NAME () == MIN_TEMP_NAME ()) { - REWRITE_OPCODE_2 (reg_var_decl_loc, reg_var_decl, min_temp_name, max_temp_name); + REWRITE_OPCODE_2 (HEAD (U16, 1), reg_var_decl, MIN_TEMP_NAME (), MAX_TEMP_NAME ()); } else { JERRY_UNREACHABLE (); } finish_scope (); - optimizer_reorder_scope ((uint16_t) (reg_var_decl_loc + 1), opcode_counter); + + DROP (U16, 1) + + CHECK_USAGE (U16) + CHECK_USAGE (IDX) + CHECK_USAGE (temp_names) } /* program @@ -2380,18 +2667,47 @@ parse_source_element_list (void) void parser_parse_program (void) { + DECLARE_USAGE (IDX) + skip_newlines (); parse_source_element_list (); skip_newlines (); - JERRY_ASSERT (tok.type == TOK_EOF); + JERRY_ASSERT (token_is (TOK_EOF)); DUMP_OPCODE_1 (exitval, 0); + + CHECK_USAGE (IDX) } void parser_init (void) { - max_temp_name = temp_name = min_temp_name = lexer_get_reserved_ids_count (); + INIT_STACK(uint8_t, U8); + INIT_STACK(uint8_t, IDX); + INIT_STACK(uint8_t, nestings); + INIT_STACK(uint8_t, temp_names); + INIT_STACK(token, toks); + INIT_STACK(opcode_t, ops); + INIT_STACK(uint16_t, U16); + INIT_STACK(opcode_counter_t, rewritable_continue); + INIT_STACK(opcode_counter_t, rewritable_break); + + MAX_TEMP_NAME () = TEMP_NAME () = MIN_TEMP_NAME () = lexer_get_reserved_ids_count (); + OPCODE_COUNTER () = 0; +} + +void +parser_free (void) +{ + FREE_STACK(U8); + FREE_STACK(IDX); + FREE_STACK(nestings); + FREE_STACK(temp_names); + FREE_STACK(toks); + FREE_STACK(ops); + FREE_STACK(U16); + FREE_STACK(rewritable_continue); + FREE_STACK(rewritable_break); } void diff --git a/src/libjsparser/parser.h b/src/libjsparser/parser.h index 7dcfbf274..7f36c864e 100644 --- a/src/libjsparser/parser.h +++ b/src/libjsparser/parser.h @@ -20,6 +20,7 @@ void parser_init (void); void parser_parse_program (void); +void parser_free (void); void parser_fatal (jerry_status_t code); diff --git a/src/liboptimizer/bytecode-data.h b/src/liboptimizer/bytecode-data.h index 444ae8884..355c1ba5d 100644 --- a/src/liboptimizer/bytecode-data.h +++ b/src/liboptimizer/bytecode-data.h @@ -13,12 +13,19 @@ * limitations under the License. */ -#ifndef BYTECODE_LINUX_H -#define BYTECODE_LINUX_H +#ifndef BYTECODE_DATA_H +#define BYTECODE_DATA_H #include "opcodes.h" +#include "stack.h" +#include "jerry-libc.h" -#define MAX_OPCODES 255 +#define MAX_OPCODES (256*256 - 1) + +#ifndef OPCODE_T_STACK_DEFINED +DEFINE_STACK_TYPE (opcode_counter_t, opcode_t) +#define OPCODE_T_STACK_DEFINED +#endif /* bytecode_data contains identifiers, string and num literals. Memory map if the following. @@ -32,6 +39,11 @@ U32 nums[nums_count]; } */ extern uint8_t *bytecode_data; -opcode_t bytecode_opcodes[MAX_OPCODES]; -#endif // BYTECODE_LINUX_H +enum +{ + bytecode_opcodes_global_size +}; +STACK (opcode_t, bytecode_opcodes) + +#endif // BYTECODE_DATA_H diff --git a/src/liboptimizer/deserializer.c b/src/liboptimizer/deserializer.c index 2c4e64077..9c440d1cd 100644 --- a/src/liboptimizer/deserializer.c +++ b/src/liboptimizer/deserializer.c @@ -85,7 +85,8 @@ deserialize_num_by_id (uint8_t id) const void * deserialize_bytecode (void) { - return bytecode_opcodes; + JERRY_ASSERT (STACK_SIZE (bytecode_opcodes) > 0); + return bytecode_opcodes.data; } uint8_t diff --git a/src/liboptimizer/optimizer-passes.c b/src/liboptimizer/optimizer-passes.c index f237097ad..97036685d 100644 --- a/src/liboptimizer/optimizer-passes.c +++ b/src/liboptimizer/optimizer-passes.c @@ -52,382 +52,6 @@ optimize_calls (opcode_t *opcodes) } } -/* Move NUMBER opcodes from FROM to TO and adjust opcodes beetwen FROM and TO. */ -void -optimizer_move_opcodes (opcode_t *from, opcode_t *to, uint16_t number) -{ - opcode_t temp[number], *current_opcode; - uint16_t i; - - if (to == from) - { - return; - } - - for (i = 0; i < number; i++) - { - temp[i] = from[i]; - } - - if (to > from) - { - if (number <= to - from) - { - // Adjust opcodes up - for (current_opcode = from; current_opcode != to; current_opcode++) - { - *current_opcode = *(current_opcode + number); - } - } - else - { - optimizer_move_opcodes (from + number, from, (uint16_t) (to - from)); - } - } - else - { - if (number <= from - to) - { - // Adjust opcodes down - for (current_opcode = from; current_opcode != to; current_opcode--) - { - *current_opcode = *(current_opcode - number); - } - } - else - { - optimizer_move_opcodes (to, to + number, (uint16_t) (from - to)); - } - } - - for (i = 0; i < number; i++) - { - to[i] = temp[i]; - } -} - -static uint16_t -opcode_to_counter (opcode_t *opcode) -{ - JERRY_ASSERT (opcode > (opcode_t *) deserialize_bytecode ()); - return (uint16_t) (opcode - (opcode_t *) deserialize_bytecode ()); -} - -void -optimizer_adjust_jumps (opcode_t *first_opcode, opcode_t *last_opcode, int16_t value) -{ - opcode_t *current_opcode; - - JERRY_ASSERT (first_opcode <= last_opcode); - - for (current_opcode = first_opcode; current_opcode != last_opcode; current_opcode++) - { - if (current_opcode->op_idx == NAME_TO_ID (is_true_jmp)) - { - /* 19: is_true_jmp 2 - 20: var_decl ... - - becomes - - 19: var_decl ... - 20: is_true_jmp 2 - */ - if (current_opcode->data.is_true_jmp.opcode >= opcode_to_counter (last_opcode) - || current_opcode->data.is_true_jmp.opcode < opcode_to_counter (first_opcode) - value) - { - continue; - } - - /* 19: is_true_jmp 20 - 20: assignment - 21: var_decl - - becomes - - 19: var_decl - 20: is_true_jmp 21 - 21: assignment - */ - if (current_opcode->data.is_true_jmp.opcode >= opcode_to_counter (first_opcode) - && current_opcode->data.is_true_jmp.opcode <= opcode_to_counter (last_opcode) - value) - { - current_opcode->data.is_true_jmp.opcode = (idx_t) (current_opcode->data.is_true_jmp.opcode + value); - continue; - } - - /* 19: is_true_jmp 22 - 20: assignment - 21: var_decl - 22: var_decl - - becomes - - 19: var_decl - 20: var_decl - 21: is_true_jmp 23 - 22: assignment - */ - if (current_opcode->data.is_true_jmp.opcode < opcode_to_counter (last_opcode)) - { - current_opcode->data.is_true_jmp.opcode = (idx_t) opcode_to_counter (last_opcode); - continue; - } - - JERRY_UNREACHABLE (); - } - - if (current_opcode->op_idx == NAME_TO_ID (is_false_jmp)) - { - /* 19: is_false_jmp 2 - 20: var_decl ... - - becomes - - 19: var_decl ... - 20: is_false_jmp 2 - */ - if (current_opcode->data.is_false_jmp.opcode >= opcode_to_counter (last_opcode) - || current_opcode->data.is_false_jmp.opcode < opcode_to_counter (first_opcode) - value) - { - continue; - } - - /* 19: is_false_jmp 20 - 20: assignment - 21: var_decl - - becomes - - 19: var_decl - 20: is_false_jmp 21 - 21: assignment - */ - if (current_opcode->data.is_false_jmp.opcode >= opcode_to_counter (first_opcode) - && current_opcode->data.is_false_jmp.opcode <= opcode_to_counter (last_opcode) - value) - { - current_opcode->data.is_false_jmp.opcode = (idx_t) (current_opcode->data.is_false_jmp.opcode + value); - continue; - } - - /* 19: is_false_jmp 22 - 20: assignment - 21: var_decl - 22: var_decl - - becomes - - 19: var_decl - 20: var_decl - 21: is_false_jmp 23 - 22: assignment - */ - if (current_opcode->data.is_false_jmp.opcode < opcode_to_counter (last_opcode)) - { - current_opcode->data.is_false_jmp.opcode = (idx_t) opcode_to_counter (last_opcode); - continue; - } - - JERRY_UNREACHABLE (); - } - - if (current_opcode->op_idx == NAME_TO_ID (jmp_down)) - { - /* 19: jmp_down 1 - 20: assignment - 21: var_decl ... - - becomes - - 19: var_decl ... - 20: jmp_down 1 - 21: assignment - */ - if (current_opcode->data.jmp_down.opcode_count < last_opcode - current_opcode) - { - continue; - } - - /* 19: jmp_down 3 - 20: assignment - 21: var_decl - - becomes - - 19: var_decl - 20: jmp_down 2 - 21: assignment - */ - if (current_opcode->data.jmp_down.opcode_count >= last_opcode - current_opcode + value) - { - current_opcode->data.jmp_down.opcode_count = (idx_t) (current_opcode->data.jmp_down.opcode_count - value); - continue; - } - - /* 19: jmp_down 3 - 20: assignment - 21: var_decl - 22: var_decl - - becomes - - 19: var_decl - 20: var_decl - 21: jmp_down 2 - 22: assignment - */ - if (current_opcode->data.jmp_down.opcode_count >= last_opcode - current_opcode - && current_opcode->data.jmp_down.opcode_count < last_opcode - current_opcode + value) - { - current_opcode->data.jmp_down.opcode_count = (idx_t) (last_opcode - current_opcode); - continue; - } - - JERRY_UNREACHABLE (); - } - - if (current_opcode->op_idx == NAME_TO_ID (jmp_up)) - { - /* 19: assignment - 20: jmp_up 1 - 21: var_decl ... - - becomes - - 19: var_decl ... - 20: assignment - 21: jmp_up 1 - */ - if (current_opcode->data.jmp_up.opcode_count < current_opcode - first_opcode) - { - continue; - } - - /* 19: jmp_up 1 - 20: assignment - 21: var_decl - - becomes - - 19: var_decl - 20: jmp_up 2 - 21: assignment - */ - if (current_opcode->data.jmp_up.opcode_count >= current_opcode - first_opcode) - { - current_opcode->data.jmp_up.opcode_count = (idx_t) (current_opcode->data.jmp_up.opcode_count + value); - continue; - } - - JERRY_UNREACHABLE (); - } - } -} - -/* Reorder scope like - "use strict" - func_decl - var_decl - other opcodes - */ -void -optimizer_reorder_scope (uint16_t scope_start, uint16_t scope_end) -{ - opcode_t *opcodes = (opcode_t *) deserialize_bytecode (); - opcode_t *first_opcode = opcodes + scope_start; - opcode_t *last_opcode = opcodes + scope_end; - opcode_t *current_opcode, *processed_opcode = first_opcode; - opcode_t *var_decls_start; - - for (current_opcode = processed_opcode; current_opcode != last_opcode; current_opcode++) - { - if (current_opcode->op_idx == NAME_TO_ID (assignment) - && current_opcode->data.assignment.type_value_right == OPCODE_ARG_TYPE_STRING - && !__strcmp ("use strict", (char *) deserialize_string_by_id (current_opcode->data.assignment.value_right))) - { - optimizer_move_opcodes (current_opcode, processed_opcode, 1); - optimizer_adjust_jumps (processed_opcode + 1, current_opcode + 1, 1); - processed_opcode++; - break; - } - } - - for (current_opcode = processed_opcode; current_opcode != last_opcode;) - { - if (current_opcode->op_idx == NAME_TO_ID (func_decl_0) - || current_opcode->op_idx == NAME_TO_ID (func_decl_1) - || current_opcode->op_idx == NAME_TO_ID (func_decl_2) - || current_opcode->op_idx == NAME_TO_ID (func_decl_n)) - { - opcode_t *fun_opcode; - int16_t value, jmp_offset = 0; - for (fun_opcode = current_opcode + 1; fun_opcode != last_opcode; fun_opcode++) - { - if (fun_opcode->op_idx == NAME_TO_ID (jmp_down)) - { - jmp_offset = (int16_t) (fun_opcode - current_opcode); - fun_opcode += fun_opcode->data.jmp_down.opcode_count; - break; - } - } - JERRY_ASSERT (fun_opcode <= last_opcode); - - value = (int16_t) (fun_opcode - current_opcode); - optimizer_move_opcodes (current_opcode, processed_opcode, (uint16_t) value); - // Adjust jumps inside func_decl except end's jmp_down - optimizer_adjust_jumps (processed_opcode + jmp_offset + 1, - processed_opcode + value, - (int16_t) (processed_opcode - current_opcode)); - optimizer_adjust_jumps (processed_opcode + value, - fun_opcode, - value); - processed_opcode += value; - current_opcode = fun_opcode; - continue; - } - else - { - current_opcode++; - } - } - - var_decls_start = processed_opcode; - for (current_opcode = processed_opcode; current_opcode != last_opcode; current_opcode++) - { - if (current_opcode->op_idx == NAME_TO_ID (var_decl)) - { - // If variable already declared, replace it with nop - bool was_decl = false; - if (var_decls_start->op_idx == NAME_TO_ID (var_decl) && var_decls_start != current_opcode) - { - opcode_t *var_decls_iterator; - for (var_decls_iterator = var_decls_start; - var_decls_iterator != processed_opcode; - var_decls_iterator++) - { - JERRY_ASSERT (var_decls_iterator->op_idx == NAME_TO_ID (var_decl)); - if (var_decls_iterator->data.var_decl.variable_name - == current_opcode->data.var_decl.variable_name) - { - was_decl = true; - break; - } - } - } - - if (was_decl) - { - current_opcode->op_idx = NAME_TO_ID (nop); - } - else - { - optimizer_move_opcodes (current_opcode, processed_opcode, 1); - optimizer_adjust_jumps (processed_opcode + 1, current_opcode + 1, 1); - processed_opcode++; - } - } - } -} - void optimizer_run_passes (opcode_t *opcodes) { diff --git a/src/liboptimizer/optimizer-passes.h b/src/liboptimizer/optimizer-passes.h index 338990f83..8534ab214 100644 --- a/src/liboptimizer/optimizer-passes.h +++ b/src/liboptimizer/optimizer-passes.h @@ -19,9 +19,6 @@ #include "globals.h" #include "opcodes.h" -void optimizer_move_opcodes (opcode_t *, opcode_t *, uint16_t); -void optimizer_adjust_jumps (opcode_t *, opcode_t *, int16_t); -void optimizer_reorder_scope (uint16_t, uint16_t); void optimizer_run_passes (opcode_t *); #endif // OPTIMIZER_PASSES_H diff --git a/src/liboptimizer/pretty-printer.c b/src/liboptimizer/pretty-printer.c index f5206c8e2..af27417a9 100644 --- a/src/liboptimizer/pretty-printer.c +++ b/src/liboptimizer/pretty-printer.c @@ -91,18 +91,20 @@ dump_variable (idx_t id) } } -#define CASE_CONDITIONAL_JUMP(op, string1, field1, string2, field2) \ +#define CASE_CONDITIONAL_JUMP(op, string1, field1, string2, oc, sign, field2, field3) \ case NAME_TO_ID (op): \ __printf (string1); \ dump_variable (opcode.data.op.field1); \ __printf (string2); \ - __printf (" %d;", opcode.data.op.field2); \ + __printf (" %d;", oc sign ((opcode.data.op.field2 << JERRY_BITSINBYTE) \ + + opcode.data.op.field3)); \ break; -#define CASE_UNCONDITIONAL_JUMP(op, string, oc, oper, field) \ +#define CASE_UNCONDITIONAL_JUMP(op, string, oc, sign, field2, field3) \ case NAME_TO_ID (op): \ __printf (string); \ - __printf (" %d;", oc oper opcode.data.op.field); \ + __printf (" %d;", oc sign ((opcode.data.op.field2 << JERRY_BITSINBYTE) \ + + opcode.data.op.field3)); \ break; #define CASE_TRIPLE_ADDRESS(op, lhs, equals, op1, oper, op2) \ @@ -366,12 +368,13 @@ pp_opcode (opcode_counter_t oc, opcode_t opcode, bool is_rewrite) switch (opcode_num) { - CASE_CONDITIONAL_JUMP (is_true_jmp, "if (", value, ") goto", opcode) - CASE_CONDITIONAL_JUMP (is_false_jmp, "if (", value, " == false) goto", opcode) + CASE_CONDITIONAL_JUMP (is_true_jmp_up, "if (", value, ") goto", oc, -, opcode_1, opcode_2) + CASE_CONDITIONAL_JUMP (is_false_jmp_up, "if (", value, " == false) goto", oc, -, opcode_1, opcode_2) + CASE_CONDITIONAL_JUMP (is_true_jmp_down, "if (", value, ") goto", oc, +, opcode_1, opcode_2) + CASE_CONDITIONAL_JUMP (is_false_jmp_down, "if (", value, " == false) goto", oc, +, opcode_1, opcode_2) - CASE_UNCONDITIONAL_JUMP (jmp, "goto", 0, +, opcode_idx) - CASE_UNCONDITIONAL_JUMP (jmp_up, "goto", oc, -, opcode_count) - CASE_UNCONDITIONAL_JUMP (jmp_down, "goto", oc, +, opcode_count) + CASE_UNCONDITIONAL_JUMP (jmp_up, "goto", oc, -, opcode_1, opcode_2) + CASE_UNCONDITIONAL_JUMP (jmp_down, "goto", oc, +, opcode_1, opcode_2) CASE_TRIPLE_ADDRESS (addition, dst, "=", var_left, "+", var_right) CASE_TRIPLE_ADDRESS (substraction, dst, "=", var_left, "-", var_right) diff --git a/src/liboptimizer/serializer.c b/src/liboptimizer/serializer.c index d0321c341..613114045 100644 --- a/src/liboptimizer/serializer.c +++ b/src/liboptimizer/serializer.c @@ -28,6 +28,7 @@ void serializer_init (bool show_opcodes) { print_opcodes = show_opcodes; + INIT_STACK (opcode_t, bytecode_opcodes); } uint16_t @@ -111,25 +112,24 @@ serializer_dump_nums (const ecma_number_t nums[], uint8_t size, uint16_t offset, #endif } -static opcode_counter_t opcode_counter = 0; - void serializer_dump_opcode (opcode_t opcode) { + JERRY_ASSERT (STACK_SIZE (bytecode_opcodes) < MAX_OPCODES); + if (print_opcodes) { - pp_opcode (opcode_counter, opcode, false); + pp_opcode (STACK_SIZE (bytecode_opcodes), opcode, false); } - JERRY_ASSERT (opcode_counter < MAX_OPCODES); - bytecode_opcodes[opcode_counter++] = opcode; + PUSH (bytecode_opcodes, opcode) } void serializer_rewrite_opcode (const opcode_counter_t loc, opcode_t opcode) { - JERRY_ASSERT (loc < MAX_OPCODES); - bytecode_opcodes[loc] = opcode; + JERRY_ASSERT (loc < STACK_SIZE (bytecode_opcodes)); + bytecode_opcodes.data[loc] = opcode; if (print_opcodes) { @@ -149,9 +149,9 @@ serializer_print_opcodes (void) __printf ("AFTER OPTIMIZER:\n"); - for (loc = 0; (*(uint32_t *) (bytecode_opcodes + loc) != 0x0); loc++) + for (loc = 0; loc < STACK_SIZE (bytecode_opcodes); loc++) { - pp_opcode (loc, bytecode_opcodes[loc], false); + pp_opcode (loc, bytecode_opcodes.data[loc], false); } } @@ -160,4 +160,9 @@ serializer_free (void) { mem_heap_free_block (bytecode_data); bytecode_data = NULL; + + if (bytecode_opcodes.data) + { + FREE_STACK (bytecode_opcodes); + } } diff --git a/src/main.c b/src/main.c index 6ef58afb2..929ea5ccf 100644 --- a/src/main.c +++ b/src/main.c @@ -56,6 +56,7 @@ parser_run (const char *script_source, size_t script_source_size, bool is_show_o parser_parse_program (); lexer_free (); + parser_free (); opcodes = deserialize_bytecode (); diff --git a/tests/unit/test_addition_opcode_number_operands.c b/tests/unit/test_addition_opcode_number_operands.c index 109cf7f66..3649daeba 100644 --- a/tests/unit/test_addition_opcode_number_operands.c +++ b/tests/unit/test_addition_opcode_number_operands.c @@ -37,6 +37,7 @@ main( int __unused argc, }; mem_init(); + serializer_init (false); const char *strings[] = { "a", "b" }; diff --git a/tests/unit/test_array_obj.c b/tests/unit/test_array_obj.c index c70a5e730..904746467 100644 --- a/tests/unit/test_array_obj.c +++ b/tests/unit/test_array_obj.c @@ -28,7 +28,7 @@ main( int __unused argc, { const opcode_t test_program[] = { [ 0] = getop_reg_var_decl (240, 255), - [ 1] = getop_jmp_down (2), + [ 1] = getop_jmp_down (0, 2), [ 2] = getop_exitval (1), /* var a, b; */ @@ -52,35 +52,35 @@ main( int __unused argc, [14] = getop_prop_getter (240, 0, 240), [15] = getop_assignment (241, OPCODE_ARG_TYPE_SMALLINT, 3), [16] = getop_equal_value_type (240, 240, 241), - [17] = getop_is_false_jmp (240, 2), + [17] = getop_is_false_jmp_up (240, 0, 15), /* assert (a[0] === 12.0); */ [18] = getop_assignment (240, OPCODE_ARG_TYPE_SMALLINT, 0), [19] = getop_prop_getter (240, 0, 240), [20] = getop_assignment (241, OPCODE_ARG_TYPE_NUMBER, 5), [21] = getop_equal_value_type (240, 240, 241), - [22] = getop_is_false_jmp (240, 2), + [22] = getop_is_false_jmp_up (240, 0, 20), /* assert (a['1'] === 'length'); */ [23] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 3), [24] = getop_prop_getter (240, 0, 240), [25] = getop_assignment (241, OPCODE_ARG_TYPE_STRING, 2), [26] = getop_equal_value_type (240, 240, 241), - [27] = getop_is_false_jmp (240, 2), + [27] = getop_is_false_jmp_up (240, 0, 25), /* assert (a[2.0] === null); */ [28] = getop_assignment (240, OPCODE_ARG_TYPE_NUMBER, 4), [29] = getop_prop_getter (240, 0, 240), [30] = getop_assignment (241, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_NULL), [31] = getop_equal_value_type (240, 240, 241), - [32] = getop_is_false_jmp (240, 2), + [32] = getop_is_false_jmp_up (240, 0, 30), /* assert (a[2.5] === undefined); */ [33] = getop_assignment (240, OPCODE_ARG_TYPE_NUMBER, 6), [34] = getop_prop_getter (240, 0, 240), [35] = getop_assignment (241, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_UNDEFINED), [36] = getop_equal_value_type (240, 240, 241), - [37] = getop_is_false_jmp (240, 2), + [37] = getop_is_false_jmp_up (240, 0, 35), /* a.length = 1; */ [38] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 2), @@ -92,27 +92,27 @@ main( int __unused argc, [42] = getop_prop_getter (240, 0, 240), [43] = getop_assignment (241, OPCODE_ARG_TYPE_SMALLINT, 1), [44] = getop_equal_value_type (240, 240, 241), - [45] = getop_is_false_jmp (240, 2), + [45] = getop_is_false_jmp_up (240, 0, 43), /* assert (a[0] === 12.0); */ [46] = getop_assignment (240, OPCODE_ARG_TYPE_SMALLINT, 0), [47] = getop_prop_getter (240, 0, 240), [48] = getop_assignment (241, OPCODE_ARG_TYPE_NUMBER, 5), [49] = getop_equal_value_type (240, 240, 241), - [50] = getop_is_false_jmp (240, 2), + [50] = getop_is_false_jmp_up (240, 0, 48), /* assert (a['1'] === undefined); */ [51] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 3), [52] = getop_prop_getter (240, 0, 240), [53] = getop_assignment (241, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_UNDEFINED), [54] = getop_equal_value_type (240, 240, 241), - [55] = getop_is_false_jmp (240, 2), + [55] = getop_is_false_jmp_up (240, 0, 53), /* assert (a[2.0] === undefined); */ [56] = getop_assignment (240, OPCODE_ARG_TYPE_NUMBER, 4), [57] = getop_prop_getter (240, 0, 240), [58] = getop_equal_value_type (240, 240, 241), - [59] = getop_is_false_jmp (240, 2), + [59] = getop_is_false_jmp_up (240, 0, 57), /* a.length = 8; */ [60] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 2), @@ -124,7 +124,7 @@ main( int __unused argc, [64] = getop_prop_getter (240, 0, 240), [65] = getop_assignment (241, OPCODE_ARG_TYPE_SMALLINT, 8), [66] = getop_equal_value_type (240, 240, 241), - [67] = getop_is_false_jmp (240, 2), + [67] = getop_is_false_jmp_up (240, 0, 65), /* a[10] = true; */ [68] = getop_assignment (240, OPCODE_ARG_TYPE_SMALLINT, 10), @@ -136,34 +136,34 @@ main( int __unused argc, [72] = getop_prop_getter (240, 0, 240), [73] = getop_assignment (241, OPCODE_ARG_TYPE_SMALLINT, 11), [74] = getop_equal_value_type (240, 240, 241), - [75] = getop_is_false_jmp (240, 2), + [75] = getop_is_false_jmp_up (240, 0, 73), /* assert (a[0] === 12.0); */ [76] = getop_assignment (240, OPCODE_ARG_TYPE_SMALLINT, 0), [77] = getop_prop_getter (240, 0, 240), [78] = getop_assignment (241, OPCODE_ARG_TYPE_NUMBER, 5), [79] = getop_equal_value_type (240, 240, 241), - [80] = getop_is_false_jmp (240, 2), + [80] = getop_is_false_jmp_up (240, 0, 78), /* assert (a['1'] === undefined); */ [81] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 3), [82] = getop_prop_getter (240, 0, 240), [83] = getop_assignment (241, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_UNDEFINED), [84] = getop_equal_value_type (240, 240, 241), - [85] = getop_is_false_jmp (240, 2), + [85] = getop_is_false_jmp_up (240, 0, 83), /* assert (a[2.0] === undefined); */ [86] = getop_assignment (240, OPCODE_ARG_TYPE_NUMBER, 4), [87] = getop_prop_getter (240, 0, 240), [88] = getop_equal_value_type (240, 240, 241), - [89] = getop_is_false_jmp (240, 2), + [89] = getop_is_false_jmp_up (240, 0, 87), /* assert (a[17] === true); */ [90] = getop_assignment (240, OPCODE_ARG_TYPE_SMALLINT, 10), [91] = getop_prop_getter (240, 0, 240), [92] = getop_assignment (241, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_TRUE), [93] = getop_equal_value_type (240, 240, 241), - [94] = getop_is_false_jmp (240, 2), + [94] = getop_is_false_jmp_up (240, 0, 92), [95] = getop_exitval (0), }; @@ -186,6 +186,7 @@ main( int __unused argc, bool status = run_int(); serializer_free (); + mem_heap_print (true, false, true); mem_finalize (false); return (status ? 0 : 1); diff --git a/tests/unit/test_assignment_opcode.c b/tests/unit/test_assignment_opcode.c index f381b9691..cf02c4715 100644 --- a/tests/unit/test_assignment_opcode.c +++ b/tests/unit/test_assignment_opcode.c @@ -27,18 +27,18 @@ main( int __unused argc, char __unused **argv) { const opcode_t test_program[] = { - /* 0: */ getop_reg_var_decl( 255, 255), - /* 1: */ getop_var_decl( 0), - /* 2: */ getop_var_decl( 1), - /* 3: */ getop_assignment( 0, OPCODE_ARG_TYPE_STRING, 1), - /* 4: */ getop_assignment( 1, OPCODE_ARG_TYPE_VARIABLE, 0), - /* 5: */ getop_is_true_jmp( 1, 7), - /* 6: */ getop_jmp_down( 5), - /* 7: */ getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253), - /* 8: */ getop_assignment( 1, OPCODE_ARG_TYPE_NUMBER, 2), - /* 9: */ getop_is_false_jmp( 1, 11), - /* 10: */ getop_exitval( 0), - /* 11: */ getop_exitval( 1) + [ 0] = getop_reg_var_decl (255, 255), + [ 1] = getop_var_decl (0), + [ 2] = getop_var_decl (1), + [ 3] = getop_assignment (0, OPCODE_ARG_TYPE_STRING, 1), + [ 4] = getop_assignment (1, OPCODE_ARG_TYPE_VARIABLE, 0), + [ 5] = getop_is_true_jmp_down (1, 0, 2), + [ 6] = getop_jmp_down (0, 5), + [ 7] = getop_assignment (0, OPCODE_ARG_TYPE_SMALLINT, 253), + [ 8] = getop_assignment (1, OPCODE_ARG_TYPE_NUMBER, 2), + [ 9] = getop_is_false_jmp_down (1, 0, 2), + [10] = getop_exitval (0), + [11] = getop_exitval (1) }; mem_init(); diff --git a/tests/unit/test_obj_initializer.c b/tests/unit/test_obj_initializer.c index 07fccaf82..4854a337f 100644 --- a/tests/unit/test_obj_initializer.c +++ b/tests/unit/test_obj_initializer.c @@ -28,7 +28,7 @@ main( int __unused argc, { const opcode_t test_program[] = { [ 0] = getop_reg_var_decl (240, 255), - [ 1] = getop_jmp_down (2), + [ 1] = getop_jmp_down (0, 2), [ 2] = getop_exitval (1), /* var a, b; */ @@ -82,14 +82,14 @@ main( int __unused argc, [36] = getop_prop_getter (240, 0, 240), [37] = getop_assignment (241, OPCODE_ARG_TYPE_STRING, 5), [38] = getop_equal_value_type (240, 240, 241), - [39] = getop_is_false_jmp (240, 2), + [39] = getop_is_false_jmp_up (240, 0, 37), /* assert (a.property2 === 1); */ [40] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 3), [41] = getop_prop_getter (240, 0, 240), [42] = getop_assignment (241, OPCODE_ARG_TYPE_SMALLINT, 1), [43] = getop_equal_value_type (240, 240, 241), - [44] = getop_is_false_jmp (240, 2), + [44] = getop_is_false_jmp_up (240, 0, 42), /* a.property3 = 'value2'; */ [45] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 4), @@ -101,7 +101,7 @@ main( int __unused argc, [49] = getop_prop_getter (240, 0, 240), [50] = getop_assignment (241, OPCODE_ARG_TYPE_STRING, 6), [51] = getop_equal_value_type (240, 240, 241), - [52] = getop_is_false_jmp (240, 2), + [52] = getop_is_false_jmp_up (240, 0, 50), /* a.property2 = 2.5; */ [53] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 3), @@ -113,7 +113,7 @@ main( int __unused argc, [57] = getop_prop_getter (240, 0, 240), [58] = getop_assignment (241, OPCODE_ARG_TYPE_SMALLINT, 25), [59] = getop_equal_value_type (240, 240, 241), - [60] = getop_is_false_jmp (240, 2), + [60] = getop_is_false_jmp_up (240, 0, 58), /* b = delete a[b]; */ [61] = getop_delete_prop (1, 0, 1), @@ -121,14 +121,14 @@ main( int __unused argc, /* assert (b === true); */ [62] = getop_assignment (240, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_TRUE), [63] = getop_equal_value_type (240, 240, 1), - [64] = getop_is_false_jmp (240, 2), + [64] = getop_is_false_jmp_up (240, 0, 62), /* assert (a.property1 === undefined); */ [65] = getop_assignment (240, OPCODE_ARG_TYPE_STRING, 2), [66] = getop_prop_getter (240, 0, 240), [67] = getop_assignment (241, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_UNDEFINED), [68] = getop_equal_value_type (240, 240, 241), - [69] = getop_is_false_jmp (240, 2), + [69] = getop_is_false_jmp_up (240, 0, 67), [70] = getop_exitval (0) }; diff --git a/tests/unit/test_optimizer_adjust_jumps.c b/tests/unit/test_optimizer_adjust_jumps.c deleted file mode 100644 index 738c84dd5..000000000 --- a/tests/unit/test_optimizer_adjust_jumps.c +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright 2014 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "globals.h" -#include "interpreter.h" -#include "mem-allocator.h" -#include "opcodes.h" -#include "serializer.h" -#include "optimizer-passes.h" -#include "jerry-libc.h" -#include "deserializer.h" -#include "common.h" - -/** - * Unit test's main function. - */ -int -main( int __unused argc, - char __unused **argv) -{ - opcode_t test_program[] = { - [0] = getop_assignment( 0, OPCODE_ARG_TYPE_STRING, 1), - [1] = getop_assignment( 1, OPCODE_ARG_TYPE_VARIABLE, 0), - [2] = getop_is_false_jmp (0, 10), - [3] = getop_is_true_jmp (0, 6), - [4] = getop_jmp_up (1), - [5] = getop_jmp_up (4), - [6] = getop_jmp_down (1), - [7] = getop_jmp_down (2), - [8] = getop_jmp_down (2), - [9] = getop_assignment (0, OPCODE_ARG_TYPE_SMALLINT, 253), - [10] = getop_exitval (0) - }; - - mem_init(); - - const char *strings[] = { "a", - "b" }; - ecma_number_t nums [] = { 2 }; - serializer_init (true); - uint16_t offset = serializer_dump_strings (strings, 2); - serializer_dump_nums (nums, 1, offset, 2); - - for (int i = 0; i < 11; i++) - serializer_dump_opcode (test_program[i]); - - opcode_t * opcodes = (opcode_t *) deserialize_bytecode (); - - optimizer_move_opcodes (opcodes + 9, opcodes + 2, 1); - if (!opcodes_equal (opcodes, (opcode_t[]) { - [0] = getop_assignment( 0, OPCODE_ARG_TYPE_STRING, 1), - [1] = getop_assignment( 1, OPCODE_ARG_TYPE_VARIABLE, 0), - [2] = getop_assignment (0, OPCODE_ARG_TYPE_SMALLINT, 253), - [3] = getop_is_false_jmp (0, 10), - [4] = getop_is_true_jmp (0, 6), - [5] = getop_jmp_up (1), - [6] = getop_jmp_up (4), - [7] = getop_jmp_down (1), - [8] = getop_jmp_down (2), - [9] = getop_jmp_down (2), - [10] = getop_exitval (0) - }, 11)) - return 1; - - optimizer_adjust_jumps (opcodes + 3, opcodes + 10, 1); - if (!opcodes_equal (opcodes, (opcode_t[]) { - [0] = getop_assignment( 0, OPCODE_ARG_TYPE_STRING, 1), - [1] = getop_assignment( 1, OPCODE_ARG_TYPE_VARIABLE, 0), - [2] = getop_assignment (0, OPCODE_ARG_TYPE_SMALLINT, 253), - [3] = getop_is_false_jmp (0, 10), - [4] = getop_is_true_jmp (0, 7), - [5] = getop_jmp_up (1), - [6] = getop_jmp_up (5), - [7] = getop_jmp_down (1), - [8] = getop_jmp_down (2), - [9] = getop_jmp_down (1), - [10] = getop_exitval (0) - }, 11)) - return 1; - - return 0; -} diff --git a/tests/unit/test_optimizer_for_loops.c b/tests/unit/test_optimizer_for_loops.c deleted file mode 100644 index d640748d3..000000000 --- a/tests/unit/test_optimizer_for_loops.c +++ /dev/null @@ -1,98 +0,0 @@ -/* Copyright 2014 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "globals.h" -#include "serializer.h" -#include "optimizer-passes.h" -#include "jerry-libc.h" -#include "deserializer.h" -#include "common.h" -#include "lexer.h" -#include "parser.h" -#include "mem-allocator.h" -#include "opcodes.h" - -#define MAX_STRINGS 100 -#define MAX_NUMS 25 -/** - * Unit test's main function. - */ -int -main( int __unused argc, - char __unused **argv) -{ - const char *strings[MAX_STRINGS]; - ecma_number_t nums[MAX_NUMS]; - uint8_t strings_num, nums_count; - uint16_t offset; - const opcode_t *opcodes; - const char *source = "for (var i = 0; i < 10; i++) {\n" - " var j = 10;\n" - "}\n" - "for (var i = 0; i < 10; i++) {\n" - " var j = 10;\n" - "}"; - - mem_init (); - serializer_init (true); - lexer_init (source, __strlen (source), true); - lexer_run_first_pass(); - - strings_num = lexer_get_strings (strings); - nums_count = lexer_get_nums (nums); - lexer_adjust_num_ids (); - - offset = serializer_dump_strings (strings, strings_num); - serializer_dump_nums (nums, nums_count, offset, strings_num); - - parser_init (); - parser_parse_program (); - - opcodes = deserialize_bytecode (); - serializer_print_opcodes (); - if (!opcodes_equal (opcodes, (opcode_t[]) { - [0] = getop_reg_var_decl (2, 5), // var tmp2 .. tmp5; - [1] = getop_var_decl (0), // var i; - [2] = getop_var_decl (1), // var j; - [3] = getop_assignment (2, 1, 0), // tmp2 = 0; - [4] = getop_assignment (0, 4, 2), // i = tmp2; - [5] = getop_assignment (4, 1, 10),// tmp4 = 10; - [6] = getop_less_than (3, 0, 4), // tmp3 = i < tmp4; - [7] = getop_is_false_jmp (3, 14), // if (!tmp3) goto 14; - [8] = getop_jmp_down (3), // goto 11; - [9] = getop_post_incr (5, 0), // tmp5 = i ++; - [10] = getop_jmp_up (5), // goto 5; - [11] = getop_assignment (2, 1, 10),// tmp2 = 10; - [12] = getop_assignment (1, 4, 2), // j = tmp2; - [13] = getop_jmp_up (5), // goto 8; - [14] = getop_nop (), // ; - [15] = getop_assignment (2, 1, 0), // tmp2 = 0; - [16] = getop_assignment (0, 4, 2), // i = tmp2; - [17] = getop_assignment (4, 1, 10),// tmp7 = 10; - [18] = getop_less_than (3, 0, 4), // tmp3 = i < tmp7; - [19] = getop_is_false_jmp (3, 27), // if (!tmp3) goto 27; - [20] = getop_jmp_down (3), // goto 23; - [21] = getop_post_incr (5, 0), // tmp5 = i ++; - [22] = getop_jmp_up (5), // goto 17; - [23] = getop_nop (), // ; - [24] = getop_assignment (2, 1, 10),// tmp2 = 10; - [25] = getop_assignment (1, 4, 5), // j = tmp2; - [26] = getop_jmp_up (5), // goto 21; - [27] = getop_exitval (0) // exit 0; - }, 28)) - return 1; - - return 0; -} diff --git a/tests/unit/test_optimizer_reorder_scope.c b/tests/unit/test_optimizer_reorder_scope.c deleted file mode 100644 index f0da2b658..000000000 --- a/tests/unit/test_optimizer_reorder_scope.c +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright 2014 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "globals.h" -#include "interpreter.h" -#include "mem-allocator.h" -#include "opcodes.h" -#include "serializer.h" -#include "optimizer-passes.h" -#include "jerry-libc.h" -#include "deserializer.h" -#include "common.h" - -/** - * Unit test's main function. - */ -int -main( int __unused argc, - char __unused **argv) -{ - // Honestly, after RETVAL there must be RET - opcode_t test_program[] = { - [0] = getop_reg_var_decl (5, 5), // tmp6 - [1] = getop_assignment (0, OPCODE_ARG_TYPE_STRING, 1), // a = "b" - [2] = getop_var_decl (1), // var b - [3] = getop_func_decl_0 (2), // function c() - [4] = getop_jmp_down (3), // { - [5] = getop_var_decl (1), // var b - [6] = getop_retval (1), // return b; } - [7] = getop_assignment (5, OPCODE_ARG_TYPE_STRING, 3), // "use strict" - [8] = getop_exitval (0) - }; - - mem_init(); - - const char *strings[] = { "a", "b", "c", "use strict" }; - ecma_number_t nums [] = { 2 }; - serializer_init (true); - uint16_t offset = serializer_dump_strings (strings, 4); - serializer_dump_nums (nums, 1, offset, 4); - - for (int i = 0; i < 9; i++) - serializer_dump_opcode (test_program[i]); - - opcode_t * opcodes = (opcode_t *) deserialize_bytecode (); - - optimizer_reorder_scope (1, 8); - if (!opcodes_equal (opcodes, (opcode_t[]) { - [0] = getop_reg_var_decl (5, 5), // tmp6 - [1] = getop_assignment (5, OPCODE_ARG_TYPE_STRING, 3), // "use strict" - [2] = getop_func_decl_0 (2), // function c() - [3] = getop_jmp_down (3), // { - [4] = getop_var_decl (1), // var b - [5] = getop_retval (1), // return b; } - [6] = getop_var_decl (1), // var b - [7] = getop_assignment (0, OPCODE_ARG_TYPE_STRING, 1), // a = "b" - [8] = getop_exitval (0) - }, 9)) - return 1; - - - return 0; -} diff --git a/tests/unit/test_try_catch.c b/tests/unit/test_try_catch.c index 789957a43..d0adf27e1 100644 --- a/tests/unit/test_try_catch.c +++ b/tests/unit/test_try_catch.c @@ -38,11 +38,11 @@ main( int __unused argc, [ 8] = getop_meta (OPCODE_META_TYPE_CATCH, 0, 14), [ 9] = getop_meta (OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER, 2, 255), [10] = getop_equal_value_type (0, 1, 2), - [11] = getop_is_true_jmp (0, 14), + [11] = getop_is_true_jmp_down (0, 0, 3), [12] = getop_exitval (1), [13] = getop_assignment (0, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_FALSE), [14] = getop_meta (OPCODE_META_TYPE_FINALLY, 0, 18), - [15] = getop_is_false_jmp (0, 17), + [15] = getop_is_false_jmp_down (0, 0, 2), [16] = getop_exitval (0), [17] = getop_exitval (1), [18] = getop_meta (OPCODE_META_TYPE_END_TRY_CATCH_FINALLY, 255, 255), diff --git a/tests/unit/test_var_decl_opcode_in_decl_lex_env.c b/tests/unit/test_var_decl_opcode_in_decl_lex_env.c index 661a66286..dcee81890 100644 --- a/tests/unit/test_var_decl_opcode_in_decl_lex_env.c +++ b/tests/unit/test_var_decl_opcode_in_decl_lex_env.c @@ -27,11 +27,11 @@ main( int __unused argc, char __unused **argv) { const opcode_t test_program[] = { - /* 0: */ getop_reg_var_decl( 255, 255), - /* 1: */ getop_var_decl( 0), - /* 2: */ getop_is_true_jmp( 0, 4), - /* 3: */ getop_exitval( 0), - /* 4: */ getop_exitval( 1) + [0] = getop_reg_var_decl( 255, 255), + [1] = getop_var_decl( 0), + [2] = getop_is_true_jmp_down( 0, 0, 2), + [3] = getop_exitval( 0), + [4] = getop_exitval( 1) }; mem_init();