From dc8ab279006be14befec9e880fcc9cf6b2833394 Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Wed, 10 Dec 2014 18:31:59 +0300 Subject: [PATCH] Split parser into parser itself, opcodes dumper and syntax errors checker. Add internal hash map of literal indexes: In this hash map key is pair of block number and literal's unique identifier in the block, and the value is a literal index that unique in the whole program. Block is a continues array of opcodes. So, bytecode is splitted into blocks. Each block has its own uid counter. To get literal index the interpreter looks up it in the hash map. Thus, now JS program is able to have more than 255 identifiers/string literals. The first 128 (0-127) uids are reserved for block's uid counter, the other 128 (128-255) are reserved for tmp variables. --- src/config.h | 5 + src/liballocator/mem-heap.c | 2 + src/libcoreint/opcodes-ecma-arithmetics.c | 36 +- src/libcoreint/opcodes-ecma-bitwise.c | 30 +- src/libcoreint/opcodes-ecma-equality.c | 34 +- src/libcoreint/opcodes-ecma-relational.c | 36 +- src/libcoreint/opcodes-ecma-support.h | 3 +- .../opcodes-ecma-try-catch-finally.c | 7 +- src/libcoreint/opcodes-helpers-variables.c | 9 +- src/libcoreint/opcodes-varg.c | 2 +- src/libcoreint/opcodes.c | 218 +- src/libcoreint/opcodes.h | 9 +- src/libecmaobjects/ecma-globals.h | 2 +- src/libecmaobjects/ecma-helpers-string.c | 12 +- src/libintstructs/linked-list.c | 66 +- src/libintstructs/linked-list.h | 17 +- src/libintstructs/literal.c | 4 +- src/libintstructs/literal.h | 2 + src/libintstructs/stack.h | 135 +- src/libjsparser/lexer.c | 83 +- src/libjsparser/lexer.h | 12 +- src/libjsparser/opcodes-dumper.c | 2446 ++++++++++++ src/libjsparser/opcodes-dumper.h | 233 ++ src/libjsparser/parser.c | 3424 +++++------------ src/libjsparser/parser.h | 1 - src/libjsparser/scopes-tree.c | 340 +- src/libjsparser/scopes-tree.h | 20 +- src/libjsparser/syntax-errors.c | 223 ++ .../{parse-error.h => syntax-errors.h} | 33 +- src/liboptimizer/bytecode-data.h | 22 +- src/liboptimizer/deserializer.c | 58 +- src/liboptimizer/deserializer.h | 5 +- src/liboptimizer/pretty-printer.c | 493 ++- src/liboptimizer/pretty-printer.h | 4 +- src/liboptimizer/serializer.c | 52 +- src/liboptimizer/serializer.h | 9 +- tests/unit/test_preparser.c | 14 +- 37 files changed, 5015 insertions(+), 3086 deletions(-) create mode 100644 src/libjsparser/opcodes-dumper.c create mode 100644 src/libjsparser/opcodes-dumper.h create mode 100644 src/libjsparser/syntax-errors.c rename src/libjsparser/{parse-error.h => syntax-errors.h} (74%) diff --git a/src/config.h b/src/config.h index d4a4852f7..299a0bd6d 100644 --- a/src/config.h +++ b/src/config.h @@ -71,6 +71,11 @@ */ #define CONFIG_MEM_HEAP_OFFSET_LOG 16 +/** + * Number of lower bits in key of literal hash table. + */ +#define CONFIG_LITERAL_HASH_TABLE_KEY_BITS 7 + /** * Width of fields used for holding counter of references to ecma-strings and ecma-objects * diff --git a/src/liballocator/mem-heap.c b/src/liballocator/mem-heap.c index 9969c202b..f02258138 100644 --- a/src/liballocator/mem-heap.c +++ b/src/liballocator/mem-heap.c @@ -428,6 +428,8 @@ mem_heap_alloc_block (size_t size_in_bytes, /**< size of region to all } else { + JERRY_ASSERT (alloc_term == MEM_HEAP_ALLOC_SHORT_TERM); + block_p = mem_heap.last_block_p; direction = MEM_DIRECTION_PREV; } diff --git a/src/libcoreint/opcodes-ecma-arithmetics.c b/src/libcoreint/opcodes-ecma-arithmetics.c index 24443e872..f52e10d77 100644 --- a/src/libcoreint/opcodes-ecma-arithmetics.c +++ b/src/libcoreint/opcodes-ecma-arithmetics.c @@ -88,7 +88,7 @@ do_number_arithmetic (int_data_t *int_data, /**< interpreter context */ } } - ret_value = set_variable_value (int_data, + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, ecma_make_number_value (res_p)); @@ -114,8 +114,6 @@ opfunc_addition (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.addition.var_left; const idx_t right_var_idx = opdata.data.addition.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -140,7 +138,7 @@ opfunc_addition (opcode_t opdata, /**< operation data */ ecma_string_t *concat_str_p = ecma_concat_ecma_strings (string1_p, string2_p); - ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_string_value (concat_str_p)); + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, ecma_make_string_value (concat_str_p)); ecma_deref_ecma_string (concat_str_p); @@ -161,6 +159,8 @@ opfunc_addition (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_addition */ @@ -180,8 +180,6 @@ opfunc_substraction (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.substraction.var_left; const idx_t right_var_idx = opdata.data.substraction.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -196,6 +194,8 @@ opfunc_substraction (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_substraction */ @@ -215,8 +215,6 @@ opfunc_multiplication (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.multiplication.var_left; const idx_t right_var_idx = opdata.data.multiplication.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -231,6 +229,8 @@ opfunc_multiplication (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_multiplication */ @@ -250,8 +250,6 @@ opfunc_division (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.division.var_left; const idx_t right_var_idx = opdata.data.division.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -266,6 +264,8 @@ opfunc_division (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_division */ @@ -285,8 +285,6 @@ opfunc_remainder (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.remainder.var_left; const idx_t right_var_idx = opdata.data.remainder.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -301,6 +299,8 @@ opfunc_remainder (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_remainder */ @@ -319,21 +319,21 @@ opfunc_unary_plus (opcode_t opdata, /**< operation data */ const idx_t dst_var_idx = opdata.data.remainder.dst; const idx_t var_idx = opdata.data.remainder.var_left; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (var_value, get_variable_value (int_data, var_idx, false), ret_value); ECMA_TRY_CATCH (num_value, ecma_op_to_number (ecma_get_completion_value_value (var_value)), ret_value); ecma_number_t *var_p = ecma_get_number_from_completion_value (num_value); - ret_value = set_variable_value (int_data, + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, ecma_make_number_value (var_p)); ECMA_FINALIZE (num_value); ECMA_FINALIZE (var_value); + int_data->pos++; + return ret_value; } /* opfunc_unary_plus */ @@ -352,8 +352,6 @@ opfunc_unary_minus (opcode_t opdata, /**< operation data */ const idx_t dst_var_idx = opdata.data.remainder.dst; const idx_t var_idx = opdata.data.remainder.var_left; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (var_value, get_variable_value (int_data, var_idx, false), ret_value); @@ -365,12 +363,14 @@ opfunc_unary_minus (opcode_t opdata, /**< operation data */ res_p = int_data->tmp_num_p; *res_p = ecma_number_negate (*var_p); - ret_value = set_variable_value (int_data, + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, ecma_make_number_value (res_p)); ECMA_FINALIZE (num_value); ECMA_FINALIZE (var_value); + int_data->pos++; + return ret_value; } /* opfunc_unary_minus */ diff --git a/src/libcoreint/opcodes-ecma-bitwise.c b/src/libcoreint/opcodes-ecma-bitwise.c index e249c3055..e15dab15b 100644 --- a/src/libcoreint/opcodes-ecma-bitwise.c +++ b/src/libcoreint/opcodes-ecma-bitwise.c @@ -104,7 +104,7 @@ do_number_bitwise_logic (int_data_t *int_data, /**< interpreter context */ } } - ret_value = set_variable_value (int_data, + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, ecma_make_number_value (res_p)); @@ -130,8 +130,6 @@ opfunc_b_and (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.b_and.var_left; const idx_t right_var_idx = opdata.data.b_and.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -146,6 +144,8 @@ opfunc_b_and (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_b_and */ @@ -165,8 +165,6 @@ opfunc_b_or (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.b_or.var_left; const idx_t right_var_idx = opdata.data.b_or.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -181,6 +179,8 @@ opfunc_b_or (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_b_or */ @@ -200,8 +200,6 @@ opfunc_b_xor (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.b_xor.var_left; const idx_t right_var_idx = opdata.data.b_xor.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -216,6 +214,8 @@ opfunc_b_xor (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_b_xor */ @@ -235,8 +235,6 @@ opfunc_b_shift_left (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.b_shift_left.var_left; const idx_t right_var_idx = opdata.data.b_shift_left.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -251,6 +249,8 @@ opfunc_b_shift_left (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_b_shift_left */ @@ -270,8 +270,6 @@ opfunc_b_shift_right (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.b_shift_right.var_left; const idx_t right_var_idx = opdata.data.b_shift_right.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -286,6 +284,8 @@ opfunc_b_shift_right (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_b_shift_right */ @@ -305,8 +305,6 @@ opfunc_b_shift_uright (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.b_shift_uright.var_left; const idx_t right_var_idx = opdata.data.b_shift_uright.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -321,6 +319,8 @@ opfunc_b_shift_uright (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_b_shift_uright */ @@ -339,8 +339,6 @@ opfunc_b_not (opcode_t opdata, /**< operation data */ const idx_t dst_var_idx = opdata.data.b_not.dst; const idx_t right_var_idx = opdata.data.b_not.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (right_value, get_variable_value (int_data, right_var_idx, false), ret_value); @@ -353,5 +351,7 @@ opfunc_b_not (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (right_value); + int_data->pos++; + return ret_value; } /* opfunc_b_not */ diff --git a/src/libcoreint/opcodes-ecma-equality.c b/src/libcoreint/opcodes-ecma-equality.c index 96bbbbd6b..1a1c30385 100644 --- a/src/libcoreint/opcodes-ecma-equality.c +++ b/src/libcoreint/opcodes-ecma-equality.c @@ -32,8 +32,6 @@ opfunc_equal_value (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.equal_value.var_left; const idx_t right_var_idx = opdata.data.equal_value.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -46,12 +44,15 @@ opfunc_equal_value (opcode_t opdata, /**< operation data */ JERRY_ASSERT (ecma_is_completion_value_normal_true (compare_result) || ecma_is_completion_value_normal_false (compare_result)); - ret_value = set_variable_value (int_data, dst_var_idx, ecma_get_completion_value_value (compare_result)); + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, + ecma_get_completion_value_value (compare_result)); ECMA_FINALIZE (compare_result); ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_equal_value */ @@ -71,8 +72,6 @@ opfunc_not_equal_value (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.not_equal_value.var_left; const idx_t right_var_idx = opdata.data.not_equal_value.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -87,13 +86,16 @@ opfunc_not_equal_value (opcode_t opdata, /**< operation data */ bool is_equal = ecma_is_completion_value_normal_true (compare_result); - ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE - : ECMA_SIMPLE_VALUE_TRUE)); + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, + ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE + : ECMA_SIMPLE_VALUE_TRUE)); ECMA_FINALIZE (compare_result); ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_not_equal_value */ @@ -113,8 +115,6 @@ opfunc_equal_value_type (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.equal_value_type.var_left; const idx_t right_var_idx = opdata.data.equal_value_type.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -123,12 +123,15 @@ opfunc_equal_value_type (opcode_t opdata, /**< operation data */ bool is_equal = ecma_op_strict_equality_compare (ecma_get_completion_value_value (left_value), ecma_get_completion_value_value (right_value)); - ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE - : ECMA_SIMPLE_VALUE_FALSE)); + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, + ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE + : ECMA_SIMPLE_VALUE_FALSE)); ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_equal_value_type */ @@ -148,8 +151,6 @@ opfunc_not_equal_value_type (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.not_equal_value_type.var_left; const idx_t right_var_idx = opdata.data.not_equal_value_type.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -158,12 +159,15 @@ opfunc_not_equal_value_type (opcode_t opdata, /**< operation data */ bool is_equal = ecma_op_strict_equality_compare (ecma_get_completion_value_value (left_value), ecma_get_completion_value_value (right_value)); - ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE - : ECMA_SIMPLE_VALUE_TRUE)); + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, + ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE + : ECMA_SIMPLE_VALUE_TRUE)); ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_not_equal_value_type */ diff --git a/src/libcoreint/opcodes-ecma-relational.c b/src/libcoreint/opcodes-ecma-relational.c index af4fd35b4..57761ebe9 100644 --- a/src/libcoreint/opcodes-ecma-relational.c +++ b/src/libcoreint/opcodes-ecma-relational.c @@ -32,8 +32,6 @@ opfunc_less_than (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.less_than.var_left; const idx_t right_var_idx = opdata.data.less_than.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -57,12 +55,14 @@ opfunc_less_than (opcode_t opdata, /**< operation data */ res = (ecma_is_completion_value_normal_true (compare_result) ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } - ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_simple_value (res)); + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, ecma_make_simple_value (res)); ECMA_FINALIZE (compare_result); ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_less_than */ @@ -82,8 +82,6 @@ opfunc_greater_than (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.greater_than.var_left; const idx_t right_var_idx = opdata.data.greater_than.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -107,12 +105,14 @@ opfunc_greater_than (opcode_t opdata, /**< operation data */ res = (ecma_is_completion_value_normal_true (compare_result) ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } - ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_simple_value (res)); + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, ecma_make_simple_value (res)); ECMA_FINALIZE (compare_result); ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_greater_than */ @@ -132,8 +132,6 @@ opfunc_less_or_equal_than (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.less_or_equal_than.var_left; const idx_t right_var_idx = opdata.data.less_or_equal_than.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -164,12 +162,14 @@ opfunc_less_or_equal_than (opcode_t opdata, /**< operation data */ } } - ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_simple_value (res)); + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, ecma_make_simple_value (res)); ECMA_FINALIZE (compare_result); ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_less_or_equal_than */ @@ -189,8 +189,6 @@ opfunc_greater_or_equal_than (opcode_t opdata, /**< operation data */ const idx_t left_var_idx = opdata.data.greater_or_equal_than.var_left; const idx_t right_var_idx = opdata.data.greater_or_equal_than.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -221,12 +219,14 @@ opfunc_greater_or_equal_than (opcode_t opdata, /**< operation data */ } } - ret_value = set_variable_value (int_data, dst_var_idx, ecma_make_simple_value (res)); + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, ecma_make_simple_value (res)); ECMA_FINALIZE (compare_result); ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_greater_or_equal_than */ @@ -246,8 +246,6 @@ opfunc_instanceof (opcode_t opdata __unused, /**< operation data */ const idx_t left_var_idx = opdata.data.instanceof.var_left; const idx_t right_var_idx = opdata.data.instanceof.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -266,7 +264,7 @@ opfunc_instanceof (opcode_t opdata __unused, /**< operation data */ ecma_get_completion_value_value (left_value)), ret_value); - ret_value = set_variable_value (int_data, dst_idx, ecma_get_completion_value_value (is_instance_of)); + ret_value = set_variable_value (int_data, int_data->pos, dst_idx, ecma_get_completion_value_value (is_instance_of)); ECMA_FINALIZE (is_instance_of); } @@ -274,6 +272,8 @@ opfunc_instanceof (opcode_t opdata __unused, /**< operation data */ ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_instanceof */ @@ -293,8 +293,6 @@ opfunc_in (opcode_t opdata __unused, /**< operation data */ const idx_t left_var_idx = opdata.data.in.var_left; const idx_t right_var_idx = opdata.data.in.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); @@ -321,7 +319,7 @@ opfunc_in (opcode_t opdata __unused, /**< operation data */ is_in = ECMA_SIMPLE_VALUE_FALSE; } - ret_value = set_variable_value (int_data, + ret_value = set_variable_value (int_data, int_data->pos, dst_idx, ecma_make_simple_value (is_in)); @@ -331,5 +329,7 @@ opfunc_in (opcode_t opdata __unused, /**< operation data */ ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); + int_data->pos++; + return ret_value; } /* opfunc_in */ diff --git a/src/libcoreint/opcodes-ecma-support.h b/src/libcoreint/opcodes-ecma-support.h index 53429404b..99d989f24 100644 --- a/src/libcoreint/opcodes-ecma-support.h +++ b/src/libcoreint/opcodes-ecma-support.h @@ -31,10 +31,11 @@ #include "ecma-operations.h" #include "ecma-reference.h" #include "ecma-try-catch-macro.h" +#include "deserializer.h" bool is_reg_variable (int_data_t *int_data, idx_t var_idx); ecma_completion_value_t get_variable_value (int_data_t *, idx_t, bool); -ecma_completion_value_t set_variable_value (int_data_t *, idx_t, ecma_value_t); +ecma_completion_value_t set_variable_value (int_data_t *, opcode_counter_t, idx_t, ecma_value_t); ecma_completion_value_t fill_varg_list (int_data_t *int_data, ecma_length_t args_number, ecma_value_t args_values[], diff --git a/src/libcoreint/opcodes-ecma-try-catch-finally.c b/src/libcoreint/opcodes-ecma-try-catch-finally.c index 4f97b6213..f96012fb2 100644 --- a/src/libcoreint/opcodes-ecma-try-catch-finally.c +++ b/src/libcoreint/opcodes-ecma-try-catch-finally.c @@ -58,11 +58,14 @@ opfunc_try (opcode_t opdata, /**< operation data */ if (ecma_is_completion_value_throw (try_completion)) { - next_opcode = read_opcode (int_data->pos++); + next_opcode = read_opcode (int_data->pos); JERRY_ASSERT (next_opcode.op_idx == __op__idx_meta); JERRY_ASSERT (next_opcode.data.meta.type == OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER); - const idx_t catch_exc_val_var_name_lit_idx = next_opcode.data.meta.data_1; + const literal_index_t catch_exc_val_var_name_lit_idx = deserialize_lit_id_by_uid (next_opcode.data.meta.data_1, + int_data->pos); + int_data->pos++; + ecma_string_t *catch_exc_var_name_str_p = ecma_new_ecma_string_from_lit_index (catch_exc_val_var_name_lit_idx); ecma_object_t *old_env_p = int_data->lex_env_p; diff --git a/src/libcoreint/opcodes-helpers-variables.c b/src/libcoreint/opcodes-helpers-variables.c index 1420dac57..dd74ca9d7 100644 --- a/src/libcoreint/opcodes-helpers-variables.c +++ b/src/libcoreint/opcodes-helpers-variables.c @@ -90,7 +90,9 @@ get_variable_value (int_data_t *int_data, /**< interpreter context */ else { ecma_string_t var_name_string; - ecma_new_ecma_string_on_stack_from_lit_index (&var_name_string, var_idx); + const literal_index_t lit_id = deserialize_lit_id_by_uid (var_idx, int_data->pos); + JERRY_ASSERT (lit_id != INVALID_LITERAL); + ecma_new_ecma_string_on_stack_from_lit_index (&var_name_string, lit_id); ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (int_data->lex_env_p, &var_name_string); @@ -122,6 +124,7 @@ get_variable_value (int_data_t *int_data, /**< interpreter context */ */ ecma_completion_value_t set_variable_value (int_data_t *int_data, /**< interpreter context */ + opcode_counter_t lit_oc, /**< opcode counter for literal */ idx_t var_idx, /**< variable identifier */ ecma_value_t value) /**< value to set */ { @@ -143,7 +146,9 @@ set_variable_value (int_data_t *int_data, /**< interpreter context */ else { ecma_string_t var_name_string; - ecma_new_ecma_string_on_stack_from_lit_index (&var_name_string, var_idx); + const literal_index_t lit_id = deserialize_lit_id_by_uid (var_idx, lit_oc); + JERRY_ASSERT (lit_id != INVALID_LITERAL); + ecma_new_ecma_string_on_stack_from_lit_index (&var_name_string, lit_id); ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (int_data->lex_env_p, &var_name_string); diff --git a/src/libcoreint/opcodes-varg.c b/src/libcoreint/opcodes-varg.c index 2c909bb1c..aa807b623 100644 --- a/src/libcoreint/opcodes-varg.c +++ b/src/libcoreint/opcodes-varg.c @@ -96,7 +96,7 @@ fill_params_list (int_data_t *int_data, /**< interpreter context */ JERRY_ASSERT (next_opcode.op_idx == __op__idx_meta); JERRY_ASSERT (next_opcode.data.meta.type == OPCODE_META_TYPE_VARG); - const idx_t param_name_lit_idx = next_opcode.data.meta.data_1; + const literal_index_t param_name_lit_idx = deserialize_lit_id_by_uid (next_opcode.data.meta.data_1, int_data->pos); params_names [param_index] = ecma_new_ecma_string_from_lit_index (param_name_lit_idx); diff --git a/src/libcoreint/opcodes.c b/src/libcoreint/opcodes.c index ef686e4a9..df3bac2cf 100644 --- a/src/libcoreint/opcodes.c +++ b/src/libcoreint/opcodes.c @@ -87,30 +87,29 @@ opfunc_assignment (opcode_t opdata, /**< operation data */ const opcode_arg_type_operand type_value_right = opdata.data.assignment.type_value_right; const idx_t src_val_descr = opdata.data.assignment.value_right; - int_data->pos++; + ecma_completion_value_t ret_value; if (type_value_right == OPCODE_ARG_TYPE_SIMPLE) { - return set_variable_value (int_data, - dst_var_idx, - ecma_make_simple_value (src_val_descr)); + ret_value = set_variable_value (int_data, + int_data->pos, + dst_var_idx, + ecma_make_simple_value (src_val_descr)); } else if (type_value_right == OPCODE_ARG_TYPE_STRING) { - ecma_string_t *string_p = ecma_new_ecma_string_from_lit_index (src_val_descr); + const literal_index_t lit_id = deserialize_lit_id_by_uid (src_val_descr, int_data->pos); + ecma_string_t *string_p = ecma_new_ecma_string_from_lit_index (lit_id); - ecma_completion_value_t completion = set_variable_value (int_data, - dst_var_idx, - ecma_make_string_value (string_p)); + ret_value = set_variable_value (int_data, + int_data->pos, + dst_var_idx, + ecma_make_string_value (string_p)); ecma_deref_ecma_string (string_p); - - return completion; } else if (type_value_right == OPCODE_ARG_TYPE_VARIABLE) { - ecma_completion_value_t ret_value; - ECMA_TRY_CATCH (get_value_completion, get_variable_value (int_data, src_val_descr, @@ -118,33 +117,69 @@ opfunc_assignment (opcode_t opdata, /**< operation data */ ret_value); ret_value = set_variable_value (int_data, + int_data->pos, dst_var_idx, ecma_get_completion_value_value (get_value_completion)); ECMA_FINALIZE (get_value_completion); - - return ret_value; } else if (type_value_right == OPCODE_ARG_TYPE_NUMBER) { ecma_number_t *num_p = int_data->tmp_num_p; - const literal lit = deserialize_literal_by_id (src_val_descr); + const literal_index_t lit_id = deserialize_lit_id_by_uid (src_val_descr, int_data->pos); + const literal lit = deserialize_literal_by_id (lit_id); JERRY_ASSERT (lit.type == LIT_NUMBER); *num_p = lit.data.num; - return set_variable_value (int_data, dst_var_idx, ecma_make_number_value (num_p)); + ret_value = set_variable_value (int_data, + int_data->pos, + dst_var_idx, + ecma_make_number_value (num_p)); } - else + else if (type_value_right == OPCODE_ARG_TYPE_NUMBER_NEGATE) + { + ecma_number_t *num_p = int_data->tmp_num_p; + + const literal_index_t lit_id = deserialize_lit_id_by_uid (src_val_descr, int_data->pos); + const literal lit = deserialize_literal_by_id (lit_id); + JERRY_ASSERT (lit.type == LIT_NUMBER); + + *num_p = ecma_number_negate (lit.data.num); + + ret_value = set_variable_value (int_data, + int_data->pos, + dst_var_idx, + ecma_make_number_value (num_p)); + } + else if (type_value_right == OPCODE_ARG_TYPE_SMALLINT) { - JERRY_ASSERT (type_value_right == OPCODE_ARG_TYPE_SMALLINT); ecma_number_t *num_p = int_data->tmp_num_p; *num_p = src_val_descr; - return set_variable_value (int_data, dst_var_idx, ecma_make_number_value (num_p)); + ret_value = set_variable_value (int_data, + int_data->pos, + dst_var_idx, + ecma_make_number_value (num_p)); } + else + { + JERRY_ASSERT (type_value_right == OPCODE_ARG_TYPE_SMALLINT_NEGATE); + ecma_number_t *num_p = int_data->tmp_num_p; + + *num_p = ecma_number_negate (src_val_descr); + + ret_value = set_variable_value (int_data, + int_data->pos, + dst_var_idx, + ecma_make_number_value (num_p)); + } + + int_data->pos++; + + return ret_value; } /* opfunc_assignment */ /** @@ -162,8 +197,6 @@ opfunc_pre_incr (opcode_t opdata, /**< operation data */ const idx_t dst_var_idx = opdata.data.pre_incr.dst; const idx_t incr_var_idx = opdata.data.pre_incr.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; // 1., 2., 3. @@ -179,12 +212,12 @@ opfunc_pre_incr (opcode_t opdata, /**< operation data */ ecma_value_t new_num_value = ecma_make_number_value (new_num_p); // 5. - ret_value = set_variable_value (int_data, + ret_value = set_variable_value (int_data, int_data->pos, incr_var_idx, new_num_value); // assignment of operator result to register variable - ecma_completion_value_t reg_assignment_res = set_variable_value (int_data, + ecma_completion_value_t reg_assignment_res = set_variable_value (int_data, int_data->pos, dst_var_idx, new_num_value); JERRY_ASSERT (ecma_is_completion_value_empty (reg_assignment_res)); @@ -192,6 +225,8 @@ opfunc_pre_incr (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (old_num_value); ECMA_FINALIZE (old_value); + int_data->pos++; + return ret_value; } /* opfunc_pre_incr */ @@ -210,8 +245,6 @@ opfunc_pre_decr (opcode_t opdata, /**< operation data */ const idx_t dst_var_idx = opdata.data.pre_decr.dst; const idx_t decr_var_idx = opdata.data.pre_decr.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; // 1., 2., 3. @@ -227,12 +260,12 @@ opfunc_pre_decr (opcode_t opdata, /**< operation data */ ecma_value_t new_num_value = ecma_make_number_value (new_num_p); // 5. - ret_value = set_variable_value (int_data, + ret_value = set_variable_value (int_data, int_data->pos, decr_var_idx, new_num_value); // assignment of operator result to register variable - ecma_completion_value_t reg_assignment_res = set_variable_value (int_data, + ecma_completion_value_t reg_assignment_res = set_variable_value (int_data, int_data->pos, dst_var_idx, new_num_value); JERRY_ASSERT (ecma_is_completion_value_empty (reg_assignment_res)); @@ -240,6 +273,8 @@ opfunc_pre_decr (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (old_num_value); ECMA_FINALIZE (old_value); + int_data->pos++; + return ret_value; } /* opfunc_pre_decr */ @@ -258,8 +293,6 @@ opfunc_post_incr (opcode_t opdata, /**< operation data */ const idx_t dst_var_idx = opdata.data.post_incr.dst; const idx_t incr_var_idx = opdata.data.post_incr.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; // 1., 2., 3. @@ -273,12 +306,12 @@ opfunc_post_incr (opcode_t opdata, /**< operation data */ *new_num_p = ecma_number_add (*old_num_p, ECMA_NUMBER_ONE); // 5. - ret_value = set_variable_value (int_data, + ret_value = set_variable_value (int_data, int_data->pos, incr_var_idx, ecma_make_number_value (new_num_p)); // assignment of operator result to register variable - ecma_completion_value_t reg_assignment_res = set_variable_value (int_data, + ecma_completion_value_t reg_assignment_res = set_variable_value (int_data, int_data->pos, dst_var_idx, ecma_get_completion_value_value (old_num_value)); JERRY_ASSERT (ecma_is_completion_value_empty (reg_assignment_res)); @@ -286,6 +319,8 @@ opfunc_post_incr (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (old_num_value); ECMA_FINALIZE (old_value); + int_data->pos++; + return ret_value; } /* opfunc_post_incr */ @@ -304,8 +339,6 @@ opfunc_post_decr (opcode_t opdata, /**< operation data */ const idx_t dst_var_idx = opdata.data.post_decr.dst; const idx_t decr_var_idx = opdata.data.post_decr.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; // 1., 2., 3. @@ -319,12 +352,12 @@ opfunc_post_decr (opcode_t opdata, /**< operation data */ *new_num_p = ecma_number_substract (*old_num_p, ECMA_NUMBER_ONE); // 5. - ret_value = set_variable_value (int_data, + ret_value = set_variable_value (int_data, int_data->pos, decr_var_idx, ecma_make_number_value (new_num_p)); // assignment of operator result to register variable - ecma_completion_value_t reg_assignment_res = set_variable_value (int_data, + ecma_completion_value_t reg_assignment_res = set_variable_value (int_data, int_data->pos, dst_var_idx, ecma_get_completion_value_value (old_num_value)); JERRY_ASSERT (ecma_is_completion_value_empty (reg_assignment_res)); @@ -332,6 +365,8 @@ opfunc_post_decr (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (old_num_value); ECMA_FINALIZE (old_value); + int_data->pos++; + return ret_value; } /* opfunc_post_decr */ @@ -360,7 +395,11 @@ ecma_completion_value_t opfunc_var_decl (opcode_t opdata, /**< operation data */ int_data_t *int_data) /**< interpreter context */ { - ecma_string_t *var_name_string_p = ecma_new_ecma_string_from_lit_index (opdata.data.var_decl.variable_name); + const literal_index_t lit_id = deserialize_lit_id_by_uid (opdata.data.var_decl.variable_name, + int_data->pos); + JERRY_ASSERT (lit_id != INVALID_LITERAL); + + ecma_string_t *var_name_string_p = ecma_new_ecma_string_from_lit_index (lit_id); if (!ecma_op_has_binding (int_data->lex_env_p, var_name_string_p)) { @@ -396,7 +435,8 @@ opfunc_var_decl (opcode_t opdata, /**< operation data */ */ static ecma_completion_value_t function_declaration (int_data_t *int_data, /**< interpreter context */ - idx_t function_name_lit_idx, /**< identifier of literal with function name */ + literal_index_t function_name_lit_id, /**< index of literal + with function name */ ecma_string_t* args_names[], /**< names of arguments */ ecma_length_t args_number) /**< number of arguments */ { @@ -416,7 +456,7 @@ function_declaration (int_data_t *int_data, /**< interpreter context */ int_data->pos++; } - ecma_string_t *function_name_string_p = ecma_new_ecma_string_from_lit_index (function_name_lit_idx); + ecma_string_t *function_name_string_p = ecma_new_ecma_string_from_lit_index (function_name_lit_id); ecma_completion_value_t ret_value = ecma_op_function_declaration (int_data->lex_env_p, function_name_string_p, @@ -442,16 +482,19 @@ ecma_completion_value_t opfunc_func_decl_n (opcode_t opdata, /**< operation data */ int_data_t *int_data) /**< interpreter context */ { - int_data->pos++; - const idx_t function_name_idx = opdata.data.func_decl_n.name_lit_idx; const ecma_length_t params_number = opdata.data.func_decl_n.arg_list; + literal_index_t function_name_lit_id = deserialize_lit_id_by_uid (function_name_idx, + int_data->pos); + + int_data->pos++; + ecma_string_t *params_names[params_number + 1 /* length of array should not be zero */]; fill_params_list (int_data, params_number, params_names); ecma_completion_value_t ret_value = function_declaration (int_data, - function_name_idx, + function_name_lit_id, params_names, params_number); @@ -475,12 +518,14 @@ ecma_completion_value_t opfunc_func_expr_n (opcode_t opdata, /**< operation data */ int_data_t *int_data) /**< interpreter context */ { + const opcode_counter_t lit_oc = int_data->pos; + int_data->pos++; const idx_t dst_var_idx = opdata.data.func_expr_n.lhs; const idx_t function_name_lit_idx = opdata.data.func_expr_n.name_lit_idx; const ecma_length_t params_number = opdata.data.func_expr_n.arg_list; - const bool is_named_func_expr = (!is_reg_variable (int_data, function_name_lit_idx)); + const bool is_named_func_expr = (function_name_lit_idx != INVALID_VALUE); ecma_string_t *params_names[params_number + 1 /* length of array should not be zero */]; fill_params_list (int_data, params_number, params_names); @@ -505,7 +550,11 @@ opfunc_func_expr_n (opcode_t opdata, /**< operation data */ if (is_named_func_expr) { scope_p = ecma_create_decl_lex_env (int_data->lex_env_p); - function_name_string_p = ecma_new_ecma_string_from_lit_index (function_name_lit_idx); + + const literal_index_t lit_id = deserialize_lit_id_by_uid (function_name_lit_idx, lit_oc); + JERRY_ASSERT (lit_id != INVALID_LITERAL); + + function_name_string_p = ecma_new_ecma_string_from_lit_index (lit_id); ecma_op_create_immutable_binding (scope_p, function_name_string_p); } @@ -521,7 +570,7 @@ opfunc_func_expr_n (opcode_t opdata, /**< operation data */ is_strict, int_data->pos); - ecma_completion_value_t ret_value = set_variable_value (int_data, + ecma_completion_value_t ret_value = set_variable_value (int_data, lit_oc, dst_var_idx, ecma_make_object_value (func_obj_p)); @@ -563,13 +612,14 @@ opfunc_call_n (opcode_t opdata, /**< operation data */ const idx_t lhs_var_idx = opdata.data.call_n.lhs; const idx_t func_name_lit_idx = opdata.data.call_n.name_lit_idx; const idx_t args_number_idx = opdata.data.call_n.arg_list; - - int_data->pos++; + const opcode_counter_t lit_oc = int_data->pos; ecma_completion_value_t ret_value; ECMA_TRY_CATCH (func_value, get_variable_value (int_data, func_name_lit_idx, false), ret_value); + int_data->pos++; + bool this_arg_var_idx_set = false; idx_t this_arg_var_idx; idx_t args_number; @@ -632,7 +682,7 @@ opfunc_call_n (opcode_t opdata, /**< operation data */ args_number), ret_value); - ret_value = set_variable_value (int_data, + ret_value = set_variable_value (int_data, lit_oc, lhs_var_idx, ecma_get_completion_value_value (call_completion)); @@ -676,14 +726,17 @@ opfunc_construct_n (opcode_t opdata, /**< operation data */ const idx_t lhs_var_idx = opdata.data.construct_n.lhs; const idx_t constructor_name_lit_idx = opdata.data.construct_n.name_lit_idx; const idx_t args_number = opdata.data.construct_n.arg_list; - - int_data->pos++; + const opcode_counter_t lit_oc = int_data->pos; ecma_completion_value_t ret_value; - ECMA_TRY_CATCH (constructor_value, get_variable_value (int_data, constructor_name_lit_idx, false), ret_value); + ECMA_TRY_CATCH (constructor_value, + get_variable_value (int_data, constructor_name_lit_idx, false), + ret_value); ecma_value_t arg_values[args_number + 1 /* length of array should not be zero */]; + int_data->pos++; + ecma_length_t args_read; ecma_completion_value_t get_arg_completion = fill_varg_list (int_data, args_number, @@ -708,7 +761,8 @@ opfunc_construct_n (opcode_t opdata, /**< operation data */ args_number), ret_value); - ret_value = set_variable_value (int_data, lhs_var_idx, ecma_get_completion_value_value (construction_completion)); + ret_value = set_variable_value (int_data, lit_oc, lhs_var_idx, + ecma_get_completion_value_value (construction_completion)); ECMA_FINALIZE (construction_completion); } @@ -746,6 +800,7 @@ opfunc_array_decl (opcode_t opdata, /**< operation data */ { const idx_t lhs_var_idx = opdata.data.array_decl.lhs; const idx_t args_number = opdata.data.array_decl.list; + const opcode_counter_t lit_oc = int_data->pos; int_data->pos++; @@ -769,7 +824,7 @@ opfunc_array_decl (opcode_t opdata, /**< operation data */ false), ret_value); - ret_value = set_variable_value (int_data, + ret_value = set_variable_value (int_data, lit_oc, lhs_var_idx, ecma_get_completion_value_value (array_obj_value)); @@ -806,6 +861,7 @@ opfunc_obj_decl (opcode_t opdata, /**< operation data */ { const idx_t lhs_var_idx = opdata.data.obj_decl.lhs; const idx_t args_number = opdata.data.obj_decl.list; + const opcode_counter_t obj_lit_oc = int_data->pos; int_data->pos++; @@ -948,7 +1004,7 @@ opfunc_obj_decl (opcode_t opdata, /**< operation data */ if (ecma_is_completion_value_empty (completion)) { - ret_value = set_variable_value (int_data, lhs_var_idx, ecma_make_object_value (obj_p)); + ret_value = set_variable_value (int_data, obj_lit_oc, lhs_var_idx, ecma_make_object_value (obj_p)); } else { @@ -1016,8 +1072,6 @@ opfunc_prop_getter (opcode_t opdata __unused, /**< operation data */ const idx_t base_var_idx = opdata.data.prop_getter.obj; const idx_t prop_name_var_idx = opdata.data.prop_getter.prop; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (base_value, @@ -1040,7 +1094,7 @@ opfunc_prop_getter (opcode_t opdata __unused, /**< operation data */ ECMA_TRY_CATCH (prop_value, ecma_op_get_value_object_base (ref), ret_value); - ret_value = set_variable_value (int_data, lhs_var_idx, ecma_get_completion_value_value (prop_value)); + ret_value = set_variable_value (int_data, int_data->pos, lhs_var_idx, ecma_get_completion_value_value (prop_value)); ECMA_FINALIZE (prop_value); @@ -1051,6 +1105,8 @@ opfunc_prop_getter (opcode_t opdata __unused, /**< operation data */ ECMA_FINALIZE (prop_name_value); ECMA_FINALIZE (base_value); + int_data->pos++; + return ret_value; } /* opfunc_prop_getter */ @@ -1071,8 +1127,6 @@ opfunc_prop_setter (opcode_t opdata __unused, /**< operation data */ const idx_t prop_name_var_idx = opdata.data.prop_setter.prop; const idx_t rhs_var_idx = opdata.data.prop_setter.rhs; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (base_value, @@ -1104,6 +1158,8 @@ opfunc_prop_setter (opcode_t opdata __unused, /**< operation data */ ECMA_FINALIZE (prop_name_value); ECMA_FINALIZE (base_value); + int_data->pos++; + return ret_value; } /* opfunc_prop_setter */ @@ -1145,8 +1201,6 @@ opfunc_logical_not (opcode_t opdata, /**< operation data */ const idx_t dst_var_idx = opdata.data.logical_not.dst; const idx_t right_var_idx = opdata.data.logical_not.var_right; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (right_value, get_variable_value (int_data, right_var_idx, false), ret_value); @@ -1159,12 +1213,14 @@ opfunc_logical_not (opcode_t opdata, /**< operation data */ old_value = ECMA_SIMPLE_VALUE_FALSE; } - ret_value = set_variable_value (int_data, + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, ecma_make_simple_value (old_value)); ECMA_FINALIZE (right_value); + int_data->pos++; + return ret_value; } /* opfunc_logical_not */ @@ -1181,12 +1237,13 @@ opfunc_this (opcode_t opdata, /**< operation data */ int_data_t *int_data) /**< interpreter context */ { const idx_t dst_var_idx = opdata.data.this.lhs; + const opcode_counter_t lit_oc = int_data->pos; int_data->pos++; ecma_completion_value_t ret_value; - ret_value = set_variable_value (int_data, + ret_value = set_variable_value (int_data, lit_oc, dst_var_idx, int_data->this_binding); @@ -1207,8 +1264,6 @@ opfunc_with (opcode_t opdata, /**< operation data */ { const idx_t expr_var_idx = opdata.data.with.expr; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (expr_value, @@ -1220,6 +1275,8 @@ opfunc_with (opcode_t opdata, /**< operation data */ ecma_op_to_object (ecma_get_completion_value_value (expr_value)), ret_value); + int_data->pos++; + ecma_object_t *obj_p = ecma_get_object_from_completion_value (obj_expr_value); ecma_object_t *old_env_p = int_data->lex_env_p; @@ -1271,8 +1328,6 @@ opfunc_throw (opcode_t opdata, /**< operation data */ { const idx_t var_idx = opdata.data.throw.var; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (var_value, @@ -1285,6 +1340,8 @@ opfunc_throw (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (var_value); + int_data->pos++; + return ret_value; } /* opfunc_throw */ @@ -1312,7 +1369,10 @@ evaluate_arg_for_typeof (int_data_t *int_data, /**< interpreter context */ } else { - ecma_string_t *var_name_string_p = ecma_new_ecma_string_from_lit_index (var_idx); + const literal_index_t lit_id = deserialize_lit_id_by_uid (var_idx, int_data->pos); + JERRY_ASSERT (lit_id != INVALID_LITERAL); + + ecma_string_t *var_name_string_p = ecma_new_ecma_string_from_lit_index (lit_id); ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (int_data->lex_env_p, var_name_string_p); @@ -1348,8 +1408,6 @@ opfunc_typeof (opcode_t opdata, /**< operation data */ const idx_t dst_var_idx = opdata.data.typeof.lhs; const idx_t obj_var_idx = opdata.data.typeof.obj; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (typeof_evaluate_arg_completion, @@ -1395,7 +1453,7 @@ opfunc_typeof (opcode_t opdata, /**< operation data */ } } - ret_value = set_variable_value (int_data, + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, ecma_make_string_value (type_str_p)); @@ -1403,6 +1461,8 @@ opfunc_typeof (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (typeof_evaluate_arg_completion); + int_data->pos++; + return ret_value; } /* opfunc_typeof */ @@ -1420,12 +1480,16 @@ opfunc_delete_var (opcode_t opdata, /**< operation data */ { const idx_t dst_var_idx = opdata.data.delete_var.lhs; const idx_t name_lit_idx = opdata.data.delete_var.name; + const opcode_counter_t lit_oc = int_data->pos; int_data->pos++; ecma_completion_value_t ret_value; - ecma_string_t *name_string_p = ecma_new_ecma_string_from_lit_index (name_lit_idx); + const literal_index_t lit_id = deserialize_lit_id_by_uid (name_lit_idx, lit_oc); + JERRY_ASSERT (lit_id != INVALID_LITERAL); + + ecma_string_t *name_string_p = ecma_new_ecma_string_from_lit_index (lit_id); ecma_reference_t ref = ecma_op_get_identifier_reference (int_data->lex_env_p, name_string_p, @@ -1440,7 +1504,7 @@ opfunc_delete_var (opcode_t opdata, /**< operation data */ { if (ecma_is_value_undefined (ref.base)) { - ret_value = set_variable_value (int_data, + ret_value = set_variable_value (int_data, lit_oc, dst_var_idx, ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE)); } @@ -1454,7 +1518,8 @@ opfunc_delete_var (opcode_t opdata, /**< operation data */ ECMA_GET_NON_NULL_POINTER (ref.referenced_name_cp)), ret_value); - ret_value = set_variable_value (int_data, dst_var_idx, ecma_get_completion_value_value (delete_completion)); + ret_value = set_variable_value (int_data, lit_oc, dst_var_idx, + ecma_get_completion_value_value (delete_completion)); ECMA_FINALIZE (delete_completion); } @@ -1484,8 +1549,6 @@ opfunc_delete_prop (opcode_t opdata, /**< operation data */ const idx_t base_var_idx = opdata.data.delete_prop.base; const idx_t name_var_idx = opdata.data.delete_prop.name; - int_data->pos++; - ecma_completion_value_t ret_value; ECMA_TRY_CATCH (base_value, @@ -1528,7 +1591,8 @@ opfunc_delete_prop (opcode_t opdata, /**< operation data */ ecma_op_object_delete (obj_p, name_string_p, int_data->is_strict), ret_value); - ret_value = set_variable_value (int_data, dst_var_idx, ecma_get_completion_value_value (delete_op_completion)); + ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, + ecma_get_completion_value_value (delete_op_completion)); ECMA_FINALIZE (delete_op_completion); ECMA_FINALIZE (obj_value); @@ -1539,6 +1603,8 @@ opfunc_delete_prop (opcode_t opdata, /**< operation data */ ECMA_FINALIZE (name_value); ECMA_FINALIZE (base_value); + int_data->pos++; + return ret_value; } /* opfunc_delete_prop */ diff --git a/src/libcoreint/opcodes.h b/src/libcoreint/opcodes.h index ccf12fbb6..a87cafed0 100644 --- a/src/libcoreint/opcodes.h +++ b/src/libcoreint/opcodes.h @@ -44,8 +44,10 @@ typedef uint8_t idx_t; /** index values */ typedef enum { OPCODE_ARG_TYPE_SIMPLE, /**< ecma_simple_value_t */ - OPCODE_ARG_TYPE_SMALLINT, /**< small integer: from -128 to 127 */ + OPCODE_ARG_TYPE_SMALLINT, /**< small integer: from 0 to 255 */ + OPCODE_ARG_TYPE_SMALLINT_NEGATE, /**< small integer: from -255 to -0 */ OPCODE_ARG_TYPE_NUMBER, /**< index of number literal */ + OPCODE_ARG_TYPE_NUMBER_NEGATE, /**< index of number literal with negation */ OPCODE_ARG_TYPE_STRING, /**< index of string literal */ OPCODE_ARG_TYPE_VARIABLE /**< index of variable name */ } opcode_arg_type_operand; @@ -270,5 +272,10 @@ OP_ARGS_LIST (GETOP_DECL) #undef GETOP_DECL_2 #undef GETOP_DECL_3 +typedef struct +{ + uint8_t uids[4]; +} +raw_opcode; #endif /* OPCODES_H */ diff --git a/src/libecmaobjects/ecma-globals.h b/src/libecmaobjects/ecma-globals.h index 5fa0e8188..c65b23f30 100644 --- a/src/libecmaobjects/ecma-globals.h +++ b/src/libecmaobjects/ecma-globals.h @@ -721,7 +721,7 @@ typedef enum ECMA_STRING_CONTAINER_MAGIC_STRING /**< the ecma-string is equal to one of ECMA magic strings */ } ecma_string_container_t; -FIXME (Move to library that should define the type (libserializer /* ? */)) +FIXME (Move to library that should define the type (literal.h /* ? */)) /** * Index in literal table */ diff --git a/src/libecmaobjects/ecma-helpers-string.c b/src/libecmaobjects/ecma-helpers-string.c index a0e3cd92b..631f0ad5c 100644 --- a/src/libecmaobjects/ecma-helpers-string.c +++ b/src/libecmaobjects/ecma-helpers-string.c @@ -291,7 +291,7 @@ ecma_init_ecma_string_from_lit_index (ecma_string_t *string_p, /**< descriptor t JERRY_ASSERT (is_stack_var == (!mem_is_heap_pointer (string_p))); #endif /* !JERRY_NDEBUG */ - const literal lit = deserialize_literal_by_id ((idx_t) lit_index); + const literal lit = deserialize_literal_by_id (lit_index); if (lit.type == LIT_MAGIC_STR) { ecma_init_ecma_string_from_magic_string_id (string_p, @@ -878,7 +878,7 @@ ecma_string_to_zt_string (const ecma_string_t *string_desc_p, /**< ecma-string d } case ECMA_STRING_CONTAINER_LIT_TABLE: { - const literal lit = deserialize_literal_by_id ((idx_t) string_desc_p->u.lit_index); + const literal lit = deserialize_literal_by_id (string_desc_p->u.lit_index); JERRY_ASSERT (lit.type == LIT_STR); const ecma_char_t *str_p = literal_to_zt (lit); JERRY_ASSERT (str_p != NULL); @@ -1159,8 +1159,7 @@ ecma_compare_ecma_strings_relational (const ecma_string_t *string1_p, /**< ecma- if (string1_p->container == ECMA_STRING_CONTAINER_LIT_TABLE) { - FIXME (uint8_t -> literal_index_t); - const literal lit = deserialize_literal_by_id ((uint8_t) string1_p->u.lit_index); + const literal lit = deserialize_literal_by_id (string1_p->u.lit_index); JERRY_ASSERT (lit.type == LIT_STR); zt_string1_p = literal_to_zt (lit); } @@ -1195,8 +1194,7 @@ ecma_compare_ecma_strings_relational (const ecma_string_t *string1_p, /**< ecma- if (string2_p->container == ECMA_STRING_CONTAINER_LIT_TABLE) { - FIXME (uint8_t -> literal_index_t); - const literal lit = deserialize_literal_by_id ((uint8_t) string2_p->u.lit_index); + const literal lit = deserialize_literal_by_id (string2_p->u.lit_index); JERRY_ASSERT (lit.type == LIT_STR); zt_string2_p = literal_to_zt (lit); } @@ -1258,7 +1256,7 @@ ecma_string_get_length (const ecma_string_t *string_p) /**< ecma-string */ if (container == ECMA_STRING_CONTAINER_LIT_TABLE) { - const literal lit = deserialize_literal_by_id ((idx_t) string_p->u.lit_index); + const literal lit = deserialize_literal_by_id (string_p->u.lit_index); return lit.data.lp.length; } diff --git a/src/libintstructs/linked-list.c b/src/libintstructs/linked-list.c index 20ca78f36..21e3b1913 100644 --- a/src/libintstructs/linked-list.c +++ b/src/libintstructs/linked-list.c @@ -19,6 +19,18 @@ #include "mem-heap.h" #include "lp-string.h" +#define LINKED_LIST_MAGIC 0x42 + +typedef struct linked_list_header +{ + struct linked_list_header *next; + struct linked_list_header *prev; + uint16_t block_size; + uint16_t element_size; + uint8_t magic; +} +linked_list_header; + #define ASSERT_LIST(list) \ do { \ linked_list_header *header = (linked_list_header *) list; \ @@ -27,7 +39,7 @@ do { \ } while (0); linked_list -linked_list_init (size_t element_size) +linked_list_init (uint16_t element_size) { size_t size = mem_heap_recommend_allocation_size (element_size); linked_list list = mem_heap_alloc_block (size, MEM_HEAP_ALLOC_SHORT_TERM); @@ -40,6 +52,7 @@ linked_list_init (size_t element_size) linked_list_header* header = (linked_list_header *) list; header->magic = LINKED_LIST_MAGIC; header->prev = header->next = null_list; + header->element_size = element_size; header->block_size = (uint8_t) (size - sizeof (linked_list_header)); return list; } @@ -57,42 +70,42 @@ linked_list_free (linked_list list) } void * -linked_list_element (linked_list list, size_t element_size, size_t element_num) +linked_list_element (linked_list list, uint16_t element_num) { ASSERT_LIST (list); linked_list_header *header = (linked_list_header *) list; linked_list raw = list + sizeof (linked_list_header); - if (header->block_size < element_size * (element_num + 1)) + if (header->block_size < header->element_size * (element_num + 1)) { if (header->next) { - return linked_list_element ((linked_list) header->next, element_size, - element_num - (header->block_size / element_size)); + return linked_list_element ((linked_list) header->next, + (uint16_t) (element_num - (header->block_size / header->element_size))); } else { return NULL; } } - raw += element_size * element_num; + raw += header->element_size * element_num; return raw; } void -linked_list_set_element (linked_list list, size_t element_size, size_t element_num, void *element) +linked_list_set_element (linked_list list, uint16_t element_num, void *element) { ASSERT_LIST (list); linked_list_header *header = (linked_list_header *) list; - linked_list raw = list + sizeof (linked_list_header); - if (header->block_size < element_size * (element_num + 1)) + uint8_t *raw = (uint8_t *) (header + 1); + if (header->block_size < header->element_size * (element_num + 1)) { if (header->next == null_list) { - header->next = (linked_list_header *) linked_list_init (element_size); + header->next = (linked_list_header *) linked_list_init (header->element_size); header->next->prev = header; } - linked_list_set_element ((linked_list) header->next, element_size, - element_num - (header->block_size / element_size), + linked_list_set_element ((linked_list) header->next, + (uint16_t) (element_num - (header->block_size / header->element_size)), element); return; } @@ -100,32 +113,5 @@ linked_list_set_element (linked_list list, size_t element_size, size_t element_n { return; } - switch (element_size) - { - case 1: - { - ((uint8_t *) raw)[element_num] = *((uint8_t *) element); - break; - } - case 2: - { - ((uint16_t *) raw)[element_num] = *((uint16_t *) element); - break; - } - case 4: - { - ((uint32_t *) raw)[element_num] = *((uint32_t *) element); - break; - } - case 8: - { - ((uint64_t *) raw)[element_num] = *((uint64_t *) element); - break; - } - default: - { - __memcpy ((uint8_t*) raw + element_num * element_size, element, element_size); - break; - } - } + __memcpy (raw + element_num * header->element_size, element, header->element_size); } diff --git a/src/libintstructs/linked-list.h b/src/libintstructs/linked-list.h index fcc3beffc..2bde37e5f 100644 --- a/src/libintstructs/linked-list.h +++ b/src/libintstructs/linked-list.h @@ -18,23 +18,12 @@ #include "globals.h" -#define LINKED_LIST_MAGIC 0x42 - -typedef struct linked_list_header -{ - struct linked_list_header *next; - struct linked_list_header *prev; - uint8_t magic; - uint8_t block_size; -} -linked_list_header; - typedef uint8_t* linked_list; #define null_list NULL -linked_list linked_list_init (size_t); +linked_list linked_list_init (uint16_t); void linked_list_free (linked_list); -void *linked_list_element (linked_list, size_t, size_t); -void linked_list_set_element (linked_list, size_t, size_t, void *); +void *linked_list_element (linked_list, uint16_t); +void linked_list_set_element (linked_list, uint16_t, void *); #endif /* LINKED_LIST_H */ diff --git a/src/libintstructs/literal.c b/src/libintstructs/literal.c index 97f3eb607..9d8034a24 100644 --- a/src/libintstructs/literal.c +++ b/src/libintstructs/literal.c @@ -164,9 +164,7 @@ literal_equal (literal lit1, literal lit2) } case LIT_NUMBER: { - ecma_char_t buff[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; - ecma_number_to_zt_string (lit2.data.num, buff, ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER); - return literal_equal_zt (lit1, buff); + return literal_equal_num (lit1, lit2.data.num); } default: { diff --git a/src/libintstructs/literal.h b/src/libintstructs/literal.h index e94c386f8..ef43401ef 100644 --- a/src/libintstructs/literal.h +++ b/src/libintstructs/literal.h @@ -42,6 +42,8 @@ typedef struct } literal; +#define LITERAL_TO_REWRITE (INVALID_VALUE - 1) + literal create_empty_literal (void); literal create_literal_from_num (ecma_number_t); literal create_literal_from_str (const char *, ecma_length_t); diff --git a/src/libintstructs/stack.h b/src/libintstructs/stack.h index 4ff0449a5..3e87121b4 100644 --- a/src/libintstructs/stack.h +++ b/src/libintstructs/stack.h @@ -66,104 +66,73 @@ #ifndef STACK_H #define STACK_H -#include "linked-list.h" +#include "array-list.h" -#define DEFINE_STACK_TYPE(NAME, DATA_TYPE, TYPE) \ +#define DEFINE_STACK_TYPE(NAME, TYPE) \ typedef TYPE NAME##_stack_value_type; \ -typedef DATA_TYPE NAME##_stack_data_type; \ typedef struct \ { \ - linked_list blocks; \ - DATA_TYPE length; \ - DATA_TYPE current; \ - DATA_TYPE block_len; \ + array_list data; \ } \ NAME##_stack; #define STACK_INIT(NAME) \ do { \ - NAME.blocks = linked_list_init (sizeof (NAME##_stack_value_type)); \ - NAME.current = NAME##_global_size; \ - NAME.length = NAME.block_len = ((linked_list_header *) NAME.blocks)->block_size / sizeof (NAME##_stack_value_type); \ + NAME.data = array_list_init (sizeof (NAME##_stack_value_type)); \ } while (0) #define STACK_FREE(NAME) \ do { \ - linked_list_free (NAME.blocks); \ - NAME.length = NAME.current = 0; \ - NAME.blocks = NULL; \ + array_list_free (NAME.data); \ + NAME.data = null_list; \ } while (0) -#define DEFINE_INCREASE_STACK_SIZE(NAME, TYPE) \ -static void increase_##NAME##_stack_size (void) __unused; \ -static void \ -increase_##NAME##_stack_size (void) { \ - linked_list_set_element (NAME.blocks, sizeof (TYPE), NAME.current, NULL); \ - if (NAME.current >= NAME.length) \ - { \ - NAME.length = (NAME##_stack_data_type) (NAME.length + NAME.block_len); \ - } \ - NAME.current = (NAME##_stack_data_type) (NAME.current + 1); \ -} - -#define DEFINE_DECREASE_STACE_SIZE(NAME, TYPE) \ -static void decrease_##NAME##_stack_size (void) __unused; \ -static void \ -decrease_##NAME##_stack_size (void) { \ - JERRY_ASSERT (NAME.current > NAME##_global_size); \ - NAME.current = (NAME##_stack_data_type) (NAME.current - 1); \ -} - #define DEFINE_STACK_ELEMENT(NAME, TYPE) \ -static TYPE NAME##_stack_element (NAME##_stack_data_type) __unused; \ -static TYPE NAME##_stack_element (NAME##_stack_data_type elem) { \ - JERRY_ASSERT (elem < NAME.current); \ - return *((TYPE *) linked_list_element (NAME.blocks, sizeof (TYPE), elem)); \ +static TYPE NAME##_stack_element (size_t) __unused; \ +static TYPE NAME##_stack_element (size_t elem) { \ + return *((TYPE *) array_list_element (NAME.data, elem)); \ } #define DEFINE_SET_STACK_ELEMENT(NAME, TYPE) \ -static void set_##NAME##_stack_element (NAME##_stack_data_type, TYPE) __unused; \ -static void set_##NAME##_stack_element (NAME##_stack_data_type elem, TYPE value) { \ - JERRY_ASSERT (elem < NAME.current); \ - linked_list_set_element (NAME.blocks, sizeof (TYPE), elem, &value); \ +static void set_##NAME##_stack_element (size_t, TYPE) __unused; \ +static void set_##NAME##_stack_element (size_t elem, TYPE value) { \ + array_list_set_element (NAME.data, elem, &value); \ } #define DEFINE_STACK_HEAD(NAME, TYPE) \ -static TYPE NAME##_stack_head (NAME##_stack_data_type) __unused; \ -static TYPE NAME##_stack_head (NAME##_stack_data_type elem) { \ - JERRY_ASSERT (elem <= NAME.current); \ - return *((TYPE *) linked_list_element (NAME.blocks, sizeof (TYPE), (size_t) (NAME.current - elem))); \ +static TYPE NAME##_stack_head (size_t) __unused; \ +static TYPE NAME##_stack_head (size_t elem) { \ + return *((TYPE *) array_list_last_element (NAME.data, elem)); \ } -#define DEFINE_SET_STACK_HEAD(NAME, DATA_TYPE, TYPE) \ -static void set_##NAME##_stack_head (DATA_TYPE, TYPE) __unused; \ -static void set_##NAME##_stack_head (DATA_TYPE elem, TYPE value) { \ - JERRY_ASSERT (elem <= NAME.current); \ - linked_list_set_element (NAME.blocks, sizeof (TYPE), (size_t) (NAME.current - elem), &value); \ +#define DEFINE_SET_STACK_HEAD(NAME, TYPE) \ +static void set_##NAME##_stack_head (size_t, TYPE) __unused; \ +static void set_##NAME##_stack_head (size_t elem, TYPE value) { \ + array_list_set_last_element (NAME.data, elem, &value); \ } #define DEFINE_STACK_PUSH(NAME, TYPE) \ static void NAME##_stack_push (TYPE) __unused; \ static void NAME##_stack_push (TYPE value) { \ - linked_list_set_element (NAME.blocks, sizeof (TYPE), NAME.current, &value); \ - increase_##NAME##_stack_size (); \ + NAME.data = array_list_append (NAME.data, &value); \ } #define DEFINE_CONVERT_TO_RAW_DATA(NAME, TYPE) \ static TYPE *convert_##NAME##_to_raw_data (void) __unused; \ static TYPE *convert_##NAME##_to_raw_data (void) { \ + if (array_list_len (NAME.data) == 0) \ + { \ + return NULL; \ + } \ size_t size = mem_heap_recommend_allocation_size ( \ - ((size_t) (NAME.current + 1) * sizeof (NAME##_stack_value_type))); \ + array_list_len (NAME.data) * sizeof (NAME##_stack_value_type)); \ TYPE *DATA = (TYPE *) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_LONG_TERM); \ if (DATA == NULL) \ { \ __printf ("Out of memory\n"); \ JERRY_UNREACHABLE (); \ } \ - __memset (DATA, 0, size); \ - for (NAME##_stack_data_type i = 0; i < NAME.current; i++) { \ - DATA[i] = STACK_ELEMENT (NAME, i); \ - } \ + __memcpy (DATA, array_list_element (NAME.data, 0), array_list_len (NAME.data) * sizeof (NAME##_stack_value_type)); \ return DATA; \ } @@ -173,16 +142,16 @@ do { NAME##_stack_push (VALUE); } while (0) #define STACK_DROP(NAME, I) \ do { \ for (size_t i = 0, till = (size_t) (I); i < till; i++) { \ - decrease_##NAME##_stack_size (); } } while (0) + array_list_drop_last (NAME.data); } } while (0) #define STACK_CLEAN(NAME) \ STACK_DROP (NAME, NAME.current - NAME##_global_size); #define STACK_HEAD(NAME, I) \ -NAME##_stack_head ((NAME##_stack_data_type) (I)) +NAME##_stack_head ((size_t) (I)) #define STACK_SET_HEAD(NAME, I, VALUE) \ -do { set_##NAME##_stack_head ((NAME##_stack_data_type) (I), VALUE); } while (0) +do { set_##NAME##_stack_head ((size_t) (I), VALUE); } while (0) #define STACK_INCR_HEAD(NAME, I) \ do { STACK_SET_HEAD (NAME, I, (NAME##_stack_value_type) (STACK_HEAD (NAME, I) + 1)); } while (0) @@ -201,13 +170,13 @@ do { \ } while (0) #define STACK_SIZE(NAME) \ -NAME.current +array_list_len (NAME.data) #define STACK_ELEMENT(NAME, I) \ -NAME##_stack_element ((NAME##_stack_data_type) (I)) +NAME##_stack_element ((size_t) (I)) #define STACK_SET_ELEMENT(NAME, I, VALUE) \ -do { set_##NAME##_stack_element ((NAME##_stack_data_type) I, VALUE); } while (0) +do { set_##NAME##_stack_element ((size_t) I, VALUE); } while (0) #define STACK_CONVERT_TO_RAW_DATA(NAME, DATA) \ do { DATA = convert_##NAME##_to_raw_data (); } while (0) @@ -218,52 +187,48 @@ do { STACK_SET_ELEMENT (NAME, I, (NAME##_stack_value_type) (STACK_ELEMENT(NAME, #define STACK_DECR_ELEMENT(NAME, I) \ do { STACK_SET_ELEMENT (NAME, I, (NAME##_stack_value_type) (STACK_ELEMENT(NAME, I) - 1)); } while (0) -#define STACK_ITERATE(NAME, FUNC, FROM) \ -do { for (NAME##_stack_data_type i = FROM; i < NAME.current; i++) { \ - FUNC (STACK_ELEMENT (NAME, i)); \ -} } while (0) +#define STACK_ITERATE(NAME, VAL, FROM) \ +for (size_t NAME##_i = FROM; \ + NAME##_i < array_list_len (NAME.data); \ + NAME##_i++) \ +{ \ + NAME##_stack_value_type VAL = STACK_ELEMENT (NAME, NAME##_i); -#define STACK_ITERATE_VARG(NAME, FUNC, FROM, ...) \ -do { for (NAME##_stack_data_type i = FROM; i < NAME.current; i++) { \ - FUNC (STACK_ELEMENT (NAME, i), __VA_ARGS__); \ -} } while (0) +#define STACK_ITERATE_END() \ +} #define STACK_ITERATE_VARG_SET(NAME, FUNC, FROM, ...) \ -do { for (NAME##_stack_data_type i = FROM; i < NAME.current; i++) { \ +do { for (size_t i = FROM; i < array_list_len (NAME.data); i++) { \ STACK_SET_ELEMENT (NAME, i, FUNC (STACK_ELEMENT (NAME, i), __VA_ARGS__)); \ } } while (0) -#define STACK(NAME, DATA_TYPE, TYPE) \ -DEFINE_STACK_TYPE(NAME, DATA_TYPE, TYPE) \ +#define STACK(NAME, TYPE) \ +DEFINE_STACK_TYPE(NAME, TYPE) \ NAME##_stack NAME; \ -DEFINE_DECREASE_STACE_SIZE (NAME, TYPE) \ -DEFINE_INCREASE_STACK_SIZE (NAME, TYPE) \ DEFINE_STACK_ELEMENT(NAME, TYPE) \ DEFINE_SET_STACK_ELEMENT(NAME, TYPE) \ DEFINE_STACK_HEAD(NAME, TYPE) \ DEFINE_CONVERT_TO_RAW_DATA(NAME, TYPE) \ -DEFINE_SET_STACK_HEAD(NAME, DATA_TYPE, TYPE) \ +DEFINE_SET_STACK_HEAD(NAME, TYPE) \ DEFINE_STACK_PUSH(NAME, TYPE) -#define STATIC_STACK(NAME, DATA_TYPE, TYPE) \ -DEFINE_STACK_TYPE(NAME, DATA_TYPE, TYPE) \ +#define STATIC_STACK(NAME, TYPE) \ +DEFINE_STACK_TYPE(NAME, TYPE) \ static NAME##_stack NAME; \ -DEFINE_DECREASE_STACE_SIZE (NAME, TYPE) \ -DEFINE_INCREASE_STACK_SIZE (NAME, TYPE) \ DEFINE_STACK_ELEMENT(NAME, TYPE) \ DEFINE_SET_STACK_ELEMENT(NAME, TYPE) \ DEFINE_STACK_HEAD(NAME, TYPE) \ DEFINE_CONVERT_TO_RAW_DATA(NAME, TYPE) \ -DEFINE_SET_STACK_HEAD(NAME, DATA_TYPE, TYPE) \ +DEFINE_SET_STACK_HEAD(NAME, TYPE) \ DEFINE_STACK_PUSH(NAME, TYPE) #ifndef JERRY_NDEBUG #define STACK_DECLARE_USAGE(NAME) \ -NAME##_stack_data_type NAME##_current = NAME.current; +size_t NAME##_current = array_list_len (NAME.data); #define STACK_CHECK_USAGE(NAME) \ do { \ - JERRY_ASSERT (NAME.current == NAME##_current); \ -} while (0); + JERRY_ASSERT (array_list_len (NAME.data) == NAME##_current); \ +} while (0) #else #define STACK_DECLARE_USAGE(NAME) ; #define STACK_CHECK_USAGE(NAME) ; diff --git a/src/libjsparser/lexer.c b/src/libjsparser/lexer.c index b8a568ad9..62b4e192a 100644 --- a/src/libjsparser/lexer.c +++ b/src/libjsparser/lexer.c @@ -19,7 +19,7 @@ #include "parser.h" #include "stack.h" #include "opcodes.h" -#include "parse-error.h" +#include "syntax-errors.h" #include "parser.h" #include "ecma-helpers.h" @@ -31,7 +31,7 @@ static token empty_token = .loc = 0 }; -static bool allow_dump_lines = false; +static bool allow_dump_lines = false, strict_mode; static size_t buffer_size = 0; /* Represents the contents of a script. */ @@ -48,7 +48,7 @@ enum { literals_global_size }; -STATIC_STACK (literals, uint8_t, literal) +STATIC_STACK (literals, literal) static bool is_empty (token tok) @@ -61,7 +61,7 @@ current_locus (void) { if (token_start == NULL) { - return (locus) (buffer - buffer_start - 1); + return (locus) (buffer - buffer_start); } else { @@ -99,7 +99,7 @@ dump_current_line (void) } static token -create_token (token_type type, uint8_t uid) +create_token (token_type type, literal_index_t uid) { return (token) { @@ -140,7 +140,7 @@ current_token_equals_to_literal (literal lit) else if (lit.type == LIT_MAGIC_STR) { const char *str = (const char *) ecma_get_magic_string_zt (lit.data.magic_str_id); - if (__strlen (str) != /* Fucking [-Werror=sign-compare] */ (size_t) (buffer - token_start)) + if (__strlen (str) != (size_t) (buffer - token_start)) { return false; } @@ -201,26 +201,13 @@ convert_current_token_to_token (token_type tt) { JERRY_ASSERT (token_start); - for (uint8_t i = 0; i < STACK_SIZE (literals); i++) + for (literal_index_t i = 0; i < STACK_SIZE (literals); i++) { const literal lit = STACK_ELEMENT (literals, i); if ((lit.type == LIT_STR || lit.type == LIT_MAGIC_STR) && current_token_equals_to_literal (lit)) { - if (tt == TOK_STRING) - { - // locus must point to the first '"' - return (token) - { - .type = tt, - .loc = current_locus () - 1, - .uid = i - }; - } - else - { - return create_token (tt, i); - } + return create_token (tt, i); } } @@ -233,7 +220,7 @@ convert_current_token_to_token (token_type tt) STACK_PUSH (literals, lit); - return create_token (tt, (idx_t) (STACK_SIZE (literals) - 1)); + return create_token (tt, (literal_index_t) (STACK_SIZE (literals) - 1)); } /* If TOKEN represents a keyword, return decoded keyword, @@ -328,7 +315,7 @@ decode_keyword (void) } if (current_token_equals_to ("interface")) { - if (parser_strict_mode ()) + if (strict_mode) { return create_token (TOK_KEYWORD, KW_INTERFACE); } @@ -343,7 +330,7 @@ decode_keyword (void) } if (current_token_equals_to ("implements")) { - if (parser_strict_mode ()) + if (strict_mode) { return create_token (TOK_KEYWORD, KW_IMPLEMENTS); } @@ -354,7 +341,7 @@ decode_keyword (void) } if (current_token_equals_to ("let")) { - if (parser_strict_mode ()) + if (strict_mode) { return create_token (TOK_KEYWORD, KW_LET); } @@ -373,7 +360,7 @@ decode_keyword (void) } if (current_token_equals_to ("package")) { - if (parser_strict_mode ()) + if (strict_mode) { return create_token (TOK_KEYWORD, KW_PACKAGE); } @@ -384,7 +371,7 @@ decode_keyword (void) } if (current_token_equals_to ("private")) { - if (parser_strict_mode ()) + if (strict_mode) { return create_token (TOK_KEYWORD, KW_PRIVATE); } @@ -395,7 +382,7 @@ decode_keyword (void) } if (current_token_equals_to ("protected")) { - if (parser_strict_mode ()) + if (strict_mode) { return create_token (TOK_KEYWORD, KW_PROTECTED); } @@ -406,7 +393,7 @@ decode_keyword (void) } if (current_token_equals_to ("public")) { - if (parser_strict_mode ()) + if (strict_mode) { return create_token (TOK_KEYWORD, KW_PUBLIC); } @@ -421,7 +408,7 @@ decode_keyword (void) } if (current_token_equals_to ("static")) { - if (parser_strict_mode ()) + if (strict_mode) { return create_token (TOK_KEYWORD, KW_STATIC); } @@ -476,7 +463,7 @@ decode_keyword (void) } if (current_token_equals_to ("yield")) { - if (parser_strict_mode ()) + if (strict_mode) { return create_token (TOK_KEYWORD, KW_YIELD); } @@ -491,7 +478,7 @@ decode_keyword (void) static token convert_seen_num_to_token (ecma_number_t num) { - for (uint8_t i = 0; i < STACK_SIZE (literals); i++) + for (literal_index_t i = 0; i < STACK_SIZE (literals); i++) { const literal lit = STACK_ELEMENT (literals, i); if (lit.type != LIT_NUMBER) @@ -506,27 +493,30 @@ convert_seen_num_to_token (ecma_number_t num) STACK_PUSH (literals, create_literal_from_num (num)); - return create_token (TOK_NUMBER, (idx_t) (STACK_SIZE (literals) - 1)); + return create_token (TOK_NUMBER, (literal_index_t) (STACK_SIZE (literals) - 1)); } const literal * lexer_get_literals (void) { literal *data = NULL; - STACK_CONVERT_TO_RAW_DATA (literals, data); + if (STACK_SIZE (literals) > 0) + { + STACK_CONVERT_TO_RAW_DATA (literals, data); + } return data; } -uint8_t +literal_index_t lexer_get_literals_count (void) { - return STACK_SIZE (literals); + return (literal_index_t) STACK_SIZE (literals); } -idx_t +literal_index_t lexer_lookup_literal_uid (literal lit) { - for (uint8_t i = 0; i < STACK_SIZE (literals); i++) + for (literal_index_t i = 0; i < STACK_SIZE (literals); i++) { if (literal_equal_type (STACK_ELEMENT (literals, i), lit)) { @@ -537,8 +527,9 @@ lexer_lookup_literal_uid (literal lit) } literal -lexer_get_literal_by_id (uint8_t id) +lexer_get_literal_by_id (literal_index_t id) { + JERRY_ASSERT (id != INVALID_LITERAL); JERRY_ASSERT (id < STACK_SIZE (literals)); return STACK_ELEMENT (literals, id); } @@ -552,7 +543,7 @@ lexer_get_strings_cache (void) void lexer_add_literal_if_not_present (literal lit) { - for (uint8_t i = 0; i < STACK_SIZE (literals); i++) + for (literal_index_t i = 0; i < STACK_SIZE (literals); i++) { if (literal_equal_type (STACK_ELEMENT (literals, i), lit)) { @@ -579,8 +570,9 @@ consume_char (void) #define RETURN_PUNC_EX(TOK, NUM) \ do \ { \ + token tok = create_token (TOK, 0); \ buffer += NUM; \ - return create_token (TOK, 0); \ + return tok; \ } \ while (0) @@ -865,7 +857,7 @@ parse_number (void) if (*token_start == '0' && tok_length != 1) { - if (parser_strict_mode ()) + if (strict_mode) { PARSE_ERROR ("Octal tnteger literals are not allowed in strict mode", token_start - buffer_start); } @@ -1430,6 +1422,12 @@ lexer_token_type_to_string (token_type tt) } } +void +lexer_set_strict_mode (bool is_strict) +{ + strict_mode = is_strict; +} + void lexer_init (const char *source, size_t source_size, bool show_opcodes) { @@ -1439,6 +1437,7 @@ lexer_init (const char *source, size_t source_size, bool show_opcodes) lexer_set_source (source); strings_cache = NULL; strings_cache_used_size = strings_cache_size = 0; + lexer_set_strict_mode (false); STACK_INIT (literals); } diff --git a/src/libjsparser/lexer.h b/src/libjsparser/lexer.h index 4bb7ab13a..3dcf3816c 100644 --- a/src/libjsparser/lexer.h +++ b/src/libjsparser/lexer.h @@ -22,6 +22,8 @@ #include "opcodes.h" #define INVALID_VALUE 255 +#define INVALID_LITERAL UINT32_MAX + /* Keywords. */ typedef enum { @@ -163,7 +165,7 @@ typedef struct { locus loc; token_type type; - idx_t uid; + literal_index_t uid; } token; @@ -177,9 +179,9 @@ token lexer_prev_token (void); const literal *lexer_get_literals (void); const ecma_char_t *lexer_get_strings_cache (void); void lexer_add_literal_if_not_present (literal); -uint8_t lexer_get_literals_count (void); -literal lexer_get_literal_by_id (uint8_t); -idx_t lexer_lookup_literal_uid (literal lit); +literal_index_t lexer_get_literals_count (void); +literal lexer_get_literal_by_id (literal_index_t); +literal_index_t lexer_lookup_literal_uid (literal lit); void lexer_seek (locus); void lexer_locus_to_line_and_column (locus, size_t *, size_t *); @@ -187,4 +189,6 @@ void lexer_dump_line (size_t); const char *lexer_keyword_to_string (keyword); const char *lexer_token_type_to_string (token_type); +void lexer_set_strict_mode (bool); + #endif diff --git a/src/libjsparser/opcodes-dumper.c b/src/libjsparser/opcodes-dumper.c new file mode 100644 index 000000000..89ef90aa3 --- /dev/null +++ b/src/libjsparser/opcodes-dumper.c @@ -0,0 +1,2446 @@ +/* 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 "opcodes-dumper.h" +#include "serializer.h" +#include "deserializer.h" +#include "globals.h" +#include "lexer.h" +#include "stack.h" +#include "syntax-errors.h" +#include "jerry-libc.h" +#include "opcodes-native-call.h" + +#define MIN_TEMP_NAME 128 +static idx_t temp_name, max_temp_name; + +#define OPCODE(name) (__op__idx_##name) + +enum +{ + U8_global_size +}; +STATIC_STACK (U8, uint8_t) + +enum +{ + varg_headers_global_size +}; +STATIC_STACK (varg_headers, opcode_counter_t) + +enum +{ + function_ends_global_size +}; +STATIC_STACK (function_ends, opcode_counter_t) + +enum +{ + logical_and_checks_global_size +}; +STATIC_STACK (logical_and_checks, opcode_counter_t) + +enum +{ + logical_or_checks_global_size +}; +STATIC_STACK (logical_or_checks, opcode_counter_t) + +enum +{ + conditional_checks_global_size +}; +STATIC_STACK (conditional_checks, opcode_counter_t) + +enum +{ + jumps_to_end_global_size +}; +STATIC_STACK (jumps_to_end, opcode_counter_t) + +enum +{ + prop_getters_global_size +}; +STATIC_STACK (prop_getters, op_meta) + +enum +{ + breaks_global_size +}; +STATIC_STACK (breaks, opcode_counter_t) + +enum +{ + break_targets_global_size +}; +STATIC_STACK (break_targets, opcode_counter_t) + +enum +{ + continues_global_size +}; +STATIC_STACK (continues, opcode_counter_t) + +enum +{ + continue_targets_global_size +}; +STATIC_STACK (continue_targets, opcode_counter_t) + +enum +{ + next_iterations_global_size +}; +STATIC_STACK (next_iterations, opcode_counter_t) + +enum +{ + case_clauses_global_size +}; +STATIC_STACK (case_clauses, opcode_counter_t) + +enum +{ + tries_global_size +}; +STATIC_STACK (tries, opcode_counter_t) + +enum +{ + catches_global_size +}; +STATIC_STACK (catches, opcode_counter_t) + +enum +{ + finallies_global_size +}; +STATIC_STACK (finallies, opcode_counter_t) + +enum +{ + temp_names_global_size +}; +STATIC_STACK (temp_names, idx_t) + +enum +{ + reg_var_decls_global_size +}; +STATIC_STACK (reg_var_decls, opcode_counter_t) + +static void +reset_temp_name (void) +{ + temp_name = MIN_TEMP_NAME; +} + +static idx_t +next_temp_name (void) +{ + temp_name++; + if (max_temp_name < temp_name) + { + max_temp_name = temp_name; + } + return temp_name; +} + +static op_meta +create_op_meta (opcode_t op, literal_index_t lit_id1, literal_index_t lit_id2, literal_index_t lit_id3) +{ + return (op_meta) + { + .op = op, + .lit_id[0] = lit_id1, + .lit_id[1] = lit_id2, + .lit_id[2] = lit_id3 + }; +} + +static op_meta +create_op_meta_000 (opcode_t op) +{ + return create_op_meta (op, NOT_A_LITERAL, NOT_A_LITERAL, NOT_A_LITERAL); +} + +static op_meta +create_op_meta_001 (opcode_t op, literal_index_t lit_id) +{ + return create_op_meta (op, NOT_A_LITERAL, NOT_A_LITERAL, lit_id); +} + +static op_meta +create_op_meta_010 (opcode_t op, literal_index_t lit_id) +{ + return create_op_meta (op, NOT_A_LITERAL, lit_id, NOT_A_LITERAL); +} + +static op_meta +create_op_meta_011 (opcode_t op, literal_index_t lit_id2, literal_index_t lit_id3) +{ + return create_op_meta (op, NOT_A_LITERAL, lit_id2, lit_id3); +} + +static op_meta +create_op_meta_100 (opcode_t op, literal_index_t lit_id) +{ + return create_op_meta (op, lit_id, NOT_A_LITERAL, NOT_A_LITERAL); +} + +static op_meta +create_op_meta_101 (opcode_t op, literal_index_t lit_id1, literal_index_t lit_id3) +{ + return create_op_meta (op, lit_id1, NOT_A_LITERAL, lit_id3); +} + +static op_meta +create_op_meta_110 (opcode_t op, literal_index_t lit_id1, literal_index_t lit_id2) +{ + return create_op_meta (op, lit_id1, lit_id2, NOT_A_LITERAL); +} + +static op_meta +create_op_meta_111 (opcode_t op, literal_index_t lit_id1, literal_index_t lit_id2, literal_index_t lit_id3) +{ + return create_op_meta (op, lit_id1, lit_id2, lit_id3); +} + +static operand +tmp_operand (void) +{ + return (operand) + { + .type = OPERAND_TMP, + .data.uid = next_temp_name () + }; +} + +static uint8_t +name_to_native_call_id (operand obj) +{ + if (obj.type != OPERAND_LITERAL) + { + return OPCODE_NATIVE_CALL__COUNT; + } + if (literal_equal_type_s (lexer_get_literal_by_id (obj.data.lit_id), "LEDToggle")) + { + return OPCODE_NATIVE_CALL_LED_TOGGLE; + } + else if (literal_equal_type_s (lexer_get_literal_by_id (obj.data.lit_id), "LEDOn")) + { + return OPCODE_NATIVE_CALL_LED_ON; + } + else if (literal_equal_type_s (lexer_get_literal_by_id (obj.data.lit_id), "LEDOff")) + { + return OPCODE_NATIVE_CALL_LED_OFF; + } + else if (literal_equal_type_s (lexer_get_literal_by_id (obj.data.lit_id), "LEDOnce")) + { + return OPCODE_NATIVE_CALL_LED_ONCE; + } + else if (literal_equal_type_s (lexer_get_literal_by_id (obj.data.lit_id), "wait")) + { + return OPCODE_NATIVE_CALL_WAIT; + } + else if (literal_equal_type_s (lexer_get_literal_by_id (obj.data.lit_id), "print")) + { + return OPCODE_NATIVE_CALL_PRINT; + } + return OPCODE_NATIVE_CALL__COUNT; +} + +static bool +is_native_call (operand obj) +{ + return name_to_native_call_id (obj) < OPCODE_NATIVE_CALL__COUNT; +} + +static op_meta +create_op_meta_for_res_and_obj (opcode_t (*getop) (idx_t, idx_t, idx_t), operand *res, operand *obj) +{ + JERRY_ASSERT (obj != NULL); + JERRY_ASSERT (res != NULL); + op_meta ret; + switch (obj->type) + { + case OPERAND_TMP: + { + switch (res->type) + { + case OPERAND_TMP: + { + const opcode_t opcode = getop (res->data.uid, obj->data.uid, INVALID_VALUE); + ret = create_op_meta_000 (opcode); + break; + } + case OPERAND_LITERAL: + { + const opcode_t opcode = getop (LITERAL_TO_REWRITE, obj->data.uid, INVALID_VALUE); + ret = create_op_meta_100 (opcode, res->data.lit_id); + break; + } + } + break; + } + case OPERAND_LITERAL: + { + switch (res->type) + { + case OPERAND_TMP: + { + const opcode_t opcode = getop (res->data.uid, LITERAL_TO_REWRITE, INVALID_VALUE); + ret = create_op_meta_010 (opcode, obj->data.lit_id); + break; + } + case OPERAND_LITERAL: + { + const opcode_t opcode = getop (LITERAL_TO_REWRITE, LITERAL_TO_REWRITE, INVALID_VALUE); + ret = create_op_meta_110 (opcode, res->data.lit_id, obj->data.lit_id); + break; + } + } + break; + } + } + return ret; +} + +static op_meta +create_op_meta_for_obj (opcode_t (*getop) (idx_t, idx_t), operand *obj) +{ + JERRY_ASSERT (obj != NULL); + op_meta res; + switch (obj->type) + { + case OPERAND_TMP: + { + const opcode_t opcode = getop (obj->data.uid, INVALID_VALUE); + res = create_op_meta_000 (opcode); + break; + } + case OPERAND_LITERAL: + { + const opcode_t opcode = getop (LITERAL_TO_REWRITE, INVALID_VALUE); + res = create_op_meta_100 (opcode, obj->data.lit_id); + break; + } + } + return res; +} + +static op_meta +create_op_meta_for_vlt (varg_list_type vlt, operand *res, operand *obj) +{ + op_meta ret; + switch (vlt) + { + case VARG_FUNC_EXPR: ret = create_op_meta_for_res_and_obj (getop_func_expr_n, res, obj); break; + case VARG_CONSTRUCT_EXPR: ret = create_op_meta_for_res_and_obj (getop_construct_n, res, obj); break; + case VARG_CALL_EXPR: + { + JERRY_ASSERT (obj != NULL); + if (is_native_call (*obj)) + { + ret = create_op_meta_for_res_and_obj (getop_native_call, res, obj); + } + else + { + ret = create_op_meta_for_res_and_obj (getop_call_n, res, obj); + } + break; + } + case VARG_FUNC_DECL: + { + JERRY_ASSERT (res == NULL); + ret = create_op_meta_for_obj (getop_func_decl_n, obj); + break; + } + case VARG_ARRAY_DECL: + { + JERRY_ASSERT (obj == NULL); + ret = create_op_meta_for_obj (getop_array_decl, res); + break; + } + case VARG_OBJ_DECL: + { + JERRY_ASSERT (obj == NULL); + ret = create_op_meta_for_obj (getop_obj_decl, res); + break; + } + } + return ret; +} + +static void +dump_assert (operand op) +{ + switch (op.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_is_true_jmp_down (LITERAL_TO_REWRITE, 0, 2); + serializer_dump_op_meta (create_op_meta_100 (opcode, op.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_is_true_jmp_down (op.data.uid, 0, 2); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + break; + } + } + const opcode_t opcode = getop_exitval (1); + serializer_dump_op_meta (create_op_meta_000 (opcode)); +} + +static void +split_opcode_counter (opcode_counter_t oc, idx_t *id1, idx_t *id2) +{ + JERRY_ASSERT (id1 != NULL); + JERRY_ASSERT (id2 != NULL); + *id1 = (idx_t) (oc >> JERRY_BITSINBYTE); + *id2 = (idx_t) (oc & ((1 << JERRY_BITSINBYTE) - 1)); + JERRY_ASSERT (oc == calc_opcode_counter_from_idx_idx (*id1, *id2)); +} + +static op_meta +last_dumped_op_meta (void) +{ + return deserialize_op_meta ((opcode_counter_t) (serializer_get_current_opcode_counter () - 1)); +} + +static void +dump_single_address (opcode_t (*getop) (idx_t), operand op) +{ + switch (op.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop (LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_100 (opcode, op.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop (op.data.uid); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + break; + } + } +} + +static void +dump_double_address (opcode_t (*getop) (idx_t, idx_t), operand res, operand obj) +{ + switch (res.type) + { + case OPERAND_LITERAL: + { + switch (obj.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop (LITERAL_TO_REWRITE, LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_110 (opcode, res.data.lit_id, obj.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop (LITERAL_TO_REWRITE, obj.data.uid); + serializer_dump_op_meta (create_op_meta_100 (opcode, res.data.lit_id)); + break; + } + } + break; + } + case OPERAND_TMP: + { + switch (obj.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop (res.data.uid, LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_010 (opcode, obj.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop (res.data.uid, obj.data.uid); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + break; + } + } + break; + } + } +} + +static void +dump_triple_address (opcode_t (*getop) (idx_t, idx_t, idx_t), operand res, operand lhs, operand rhs) +{ + switch (res.type) + { + case OPERAND_LITERAL: + { + switch (lhs.type) + { + case OPERAND_LITERAL: + { + switch (rhs.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop (LITERAL_TO_REWRITE, LITERAL_TO_REWRITE, LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_111 (opcode, res.data.lit_id, lhs.data.lit_id, rhs.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop (LITERAL_TO_REWRITE, LITERAL_TO_REWRITE, rhs.data.uid); + serializer_dump_op_meta (create_op_meta_110 (opcode, res.data.lit_id, lhs.data.lit_id)); + break; + } + } + break; + } + case OPERAND_TMP: + { + switch (rhs.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop (LITERAL_TO_REWRITE, lhs.data.uid, LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_101 (opcode, res.data.lit_id, rhs.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop (LITERAL_TO_REWRITE, lhs.data.uid, rhs.data.uid); + serializer_dump_op_meta (create_op_meta_100 (opcode, res.data.lit_id)); + break; + } + } + break; + } + } + break; + } + case OPERAND_TMP: + { + switch (lhs.type) + { + case OPERAND_LITERAL: + { + switch (rhs.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop (res.data.uid, LITERAL_TO_REWRITE, LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_011 (opcode, lhs.data.lit_id, rhs.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop (res.data.uid, LITERAL_TO_REWRITE, rhs.data.uid); + serializer_dump_op_meta (create_op_meta_010 (opcode, lhs.data.lit_id)); + break; + } + } + break; + } + case OPERAND_TMP: + { + switch (rhs.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop (res.data.uid, lhs.data.uid, LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_001 (opcode, rhs.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop (res.data.uid, lhs.data.uid, rhs.data.uid); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + break; + } + } + break; + } + } + break; + } + } +} + +static void +dump_prop_setter_op_meta (op_meta last, operand op) +{ + JERRY_ASSERT (last.op.op_idx == OPCODE (prop_getter)); + switch (op.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_prop_setter (last.op.data.prop_getter.obj, + last.op.data.prop_getter.prop, + LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_111 (opcode, last.lit_id[1], last.lit_id[2], op.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_prop_setter (last.op.data.prop_getter.obj, + last.op.data.prop_getter.prop, + op.data.uid); + serializer_dump_op_meta (create_op_meta_110 (opcode, last.lit_id[1], last.lit_id[2])); + break; + } + } +} + +static operand +create_operand_from_tmp_and_lit (idx_t tmp, literal_index_t lit_id) +{ + if (tmp != LITERAL_TO_REWRITE) + { + JERRY_ASSERT (lit_id != NOT_A_LITERAL); + return (operand) + { + .type = OPERAND_TMP, + .data.uid = tmp + }; + } + else + { + JERRY_ASSERT (lit_id == NOT_A_LITERAL); + return (operand) + { + .type = OPERAND_LITERAL, + .data.lit_id = lit_id + }; + } +} + +static operand +dump_triple_address_and_prop_setter_res (void (*dumper) (operand, operand, operand), + op_meta last, operand op) +{ + JERRY_ASSERT (last.op.op_idx == OPCODE (prop_getter)); + const operand obj = create_operand_from_tmp_and_lit (last.op.data.prop_getter.obj, last.lit_id[1]); + const operand prop = create_operand_from_tmp_and_lit (last.op.data.prop_getter.prop, last.lit_id[2]); + const operand tmp = dump_prop_getter_res (obj, prop); + dumper (tmp, tmp, op); + dump_prop_setter (obj, prop, tmp); + return tmp; +} + +static operand +dump_prop_setter_or_triple_address_res (void (*dumper) (operand, operand, operand), + operand res, operand op) +{ + const op_meta last = STACK_TOP (prop_getters); + if (last.op.op_idx == OPCODE (prop_getter)) + { + res = dump_triple_address_and_prop_setter_res (dumper, last, op); + } + else + { + dumper (res, res, op); + } + STACK_DROP (prop_getters, 1); + return res; +} + +static opcode_counter_t +get_diff_from (opcode_counter_t oc) +{ + return (opcode_counter_t) (serializer_get_current_opcode_counter () - oc); +} + +operand +empty_operand (void) +{ + return (operand) + { + .type = OPERAND_TMP, + .data.uid = INVALID_VALUE + }; +} + +operand +literal_operand (literal_index_t lit_id) +{ + return (operand) + { + .type = OPERAND_LITERAL, + .data.lit_id = lit_id + }; +} + +bool +operand_is_empty (operand op) +{ + return op.type == OPERAND_TMP && op.data.uid == INVALID_VALUE; +} + +void +dumper_new_statement (void) +{ + reset_temp_name (); +} + +void +dumper_new_scope (void) +{ + STACK_PUSH (temp_names, temp_name); + STACK_PUSH (temp_names, max_temp_name); + reset_temp_name (); + max_temp_name = temp_name; +} + +void +dumper_finish_scope (void) +{ + max_temp_name = STACK_TOP (temp_names); + STACK_DROP (temp_names, 1); + temp_name = STACK_TOP (temp_names); + STACK_DROP (temp_names, 1); +} + +bool +dumper_is_intrinsic (operand obj) +{ + if (obj.type == OPERAND_LITERAL) + { + if (literal_equal_type_s (lexer_get_literal_by_id (obj.data.lit_id), "assert")) + { + return true; + } + } + return false; +} + +operand +dump_intrinsic (operand obj, operand arg) +{ + JERRY_ASSERT (obj.type == OPERAND_LITERAL); + TODO (/* Rewrite when there will be more intrinsics. */) + JERRY_ASSERT (literal_equal_type_s (lexer_get_literal_by_id (obj.data.lit_id), "assert")); + dump_assert (arg); + return dump_undefined_assignment_res (); +} + +void +dump_boolean_assignment (operand op, bool is_true) +{ + switch (op.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_assignment (LITERAL_TO_REWRITE, + OPCODE_ARG_TYPE_SIMPLE, + is_true ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); + const op_meta om = create_op_meta_100 (opcode, op.data.lit_id); + serializer_dump_op_meta (om); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_assignment (op.data.uid, + OPCODE_ARG_TYPE_SIMPLE, + is_true ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); + const op_meta om = create_op_meta_000 (opcode); + serializer_dump_op_meta (om); + break; + } + } +} + +operand +dump_boolean_assignment_res (bool is_true) +{ + operand op = tmp_operand (); + dump_boolean_assignment (op, is_true); + return op; +} + +void +dump_string_assignment (operand op, literal_index_t lit_id) +{ + switch (op.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_assignment (LITERAL_TO_REWRITE, OPCODE_ARG_TYPE_STRING, LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_101 (opcode, op.data.lit_id, lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_assignment (op.data.uid, OPCODE_ARG_TYPE_STRING, LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_001 (opcode, lit_id)); + break; + } + } +} + +operand +dump_string_assignment_res (literal_index_t lit_id) +{ + operand op = tmp_operand (); + dump_string_assignment (op, lit_id); + return op; +} + +void +dump_number_assignment (operand op, literal_index_t lit_id) +{ + switch (op.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_assignment (LITERAL_TO_REWRITE, OPCODE_ARG_TYPE_NUMBER, LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_101 (opcode, op.data.lit_id, lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_assignment (op.data.uid, OPCODE_ARG_TYPE_NUMBER, LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_001 (opcode, lit_id)); + break; + } + } +} + +operand +dump_number_assignment_res (literal_index_t lit_id) +{ + operand op = tmp_operand (); + dump_number_assignment (op, lit_id); + return op; +} + +void +dump_smallint_assignment (operand op, idx_t uid) +{ + switch (op.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_assignment (LITERAL_TO_REWRITE, OPCODE_ARG_TYPE_SMALLINT, uid); + serializer_dump_op_meta (create_op_meta_100 (opcode, op.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_assignment (op.data.uid, OPCODE_ARG_TYPE_SMALLINT, uid); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + break; + } + } +} + +operand +dump_smallint_assignment_res (idx_t uid) +{ + operand op = tmp_operand (); + dump_smallint_assignment (op, uid); + return op; +} + +void +dump_undefined_assignment (operand op) +{ + switch (op.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_assignment (LITERAL_TO_REWRITE, + OPCODE_ARG_TYPE_SIMPLE, + ECMA_SIMPLE_VALUE_UNDEFINED); + serializer_dump_op_meta (create_op_meta_100 (opcode, op.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_assignment (op.data.uid, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_UNDEFINED); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + break; + } + } +} + +operand +dump_undefined_assignment_res (void) +{ + operand op = tmp_operand (); + dump_undefined_assignment (op); + return op; +} + +void +dump_null_assignment (operand op) +{ + switch (op.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_assignment (LITERAL_TO_REWRITE, + OPCODE_ARG_TYPE_SIMPLE, + ECMA_SIMPLE_VALUE_NULL); + serializer_dump_op_meta (create_op_meta_100 (opcode, op.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_assignment (op.data.uid, + OPCODE_ARG_TYPE_SIMPLE, + ECMA_SIMPLE_VALUE_NULL); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + break; + } + } +} + +operand +dump_null_assignment_res (void) +{ + operand op = tmp_operand (); + dump_null_assignment (op); + return op; +} + +void +dump_variable_assignment (operand res, operand var) +{ + switch (res.type) + { + case OPERAND_LITERAL: + { + switch (var.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_assignment (LITERAL_TO_REWRITE, + OPCODE_ARG_TYPE_VARIABLE, + LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_101 (opcode, res.data.lit_id, var.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_assignment (LITERAL_TO_REWRITE, + OPCODE_ARG_TYPE_VARIABLE, + var.data.uid); + serializer_dump_op_meta (create_op_meta_100 (opcode, res.data.lit_id)); + break; + } + } + break; + } + case OPERAND_TMP: + { + switch (var.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_assignment (res.data.uid, + OPCODE_ARG_TYPE_VARIABLE, + LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_001 (opcode, var.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_assignment (res.data.uid, + OPCODE_ARG_TYPE_VARIABLE, + var.data.uid); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + break; + } + } + break; + } + } +} + +operand +dump_variable_assignment_res (operand var) +{ + operand op = tmp_operand (); + dump_variable_assignment (op, var); + return op; +} + +void +dump_varg_header_for_rewrite (varg_list_type vlt, operand obj) +{ + STACK_PUSH (varg_headers, serializer_get_current_opcode_counter ()); + switch (vlt) + { + case VARG_FUNC_EXPR: + case VARG_CONSTRUCT_EXPR: + case VARG_CALL_EXPR: + { + operand res = empty_operand (); + serializer_dump_op_meta (create_op_meta_for_vlt (vlt, &res, &obj)); + break; + } + case VARG_FUNC_DECL: + { + serializer_dump_op_meta (create_op_meta_for_vlt (vlt, NULL, &obj)); + break; + } + case VARG_ARRAY_DECL: + case VARG_OBJ_DECL: + { + operand res = empty_operand (); + serializer_dump_op_meta (create_op_meta_for_vlt (vlt, &res, NULL)); + break; + } + } +} + +operand +rewrite_varg_header_set_args_count (uint8_t args_count) +{ + op_meta om = deserialize_op_meta (STACK_TOP (varg_headers)); + switch (om.op.op_idx) + { + case OPCODE (func_expr_n): + case OPCODE (construct_n): + case OPCODE (call_n): + case OPCODE (native_call): + { + const operand res = tmp_operand (); + om.op.data.func_expr_n.arg_list = args_count; + om.op.data.func_expr_n.lhs = res.data.uid; + serializer_rewrite_op_meta (STACK_TOP (varg_headers), om); + STACK_DROP (varg_headers, 1); + return res; + } + case OPCODE (func_decl_n): + { + om.op.data.func_decl_n.arg_list = args_count; + serializer_rewrite_op_meta (STACK_TOP (varg_headers), om); + STACK_DROP (varg_headers, 1); + return empty_operand (); + } + case OPCODE (array_decl): + case OPCODE (obj_decl): + { + const operand res = tmp_operand (); + om.op.data.obj_decl.list = args_count; + om.op.data.obj_decl.lhs = res.data.uid; + serializer_rewrite_op_meta (STACK_TOP (varg_headers), om); + STACK_DROP (varg_headers, 1); + return res; + } + default: + { + JERRY_UNREACHABLE (); + } + } +} + +void +dump_this_arg (operand this_arg) +{ + JERRY_ASSERT (this_arg.type == OPERAND_TMP); + const opcode_t opcode = getop_meta (OPCODE_META_TYPE_THIS_ARG, this_arg.data.uid, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + return; +} + +void +dump_varg (operand op) +{ + switch (op.type) + { + case OPERAND_TMP: + { + const opcode_t opcode = getop_meta (OPCODE_META_TYPE_VARG, op.data.uid, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + return; + } + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_meta (OPCODE_META_TYPE_VARG, LITERAL_TO_REWRITE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_010 (opcode, op.data.lit_id)); + return; + } + } +} + +void +dump_prop_name_and_value (operand name, operand value) +{ + JERRY_ASSERT (name.type == OPERAND_LITERAL); + const literal lit = lexer_get_literal_by_id (name.data.lit_id); + operand tmp; + if (lit.type == LIT_STR || lit.type == LIT_MAGIC_STR) + { + tmp = dump_string_assignment_res (name.data.lit_id); + } + else + { + JERRY_ASSERT (lit.type == LIT_NUMBER); + tmp = dump_number_assignment_res (name.data.lit_id); + } + switch (value.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_meta (OPCODE_META_TYPE_VARG_PROP_DATA, tmp.data.uid, LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_001 (opcode, value.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_meta (OPCODE_META_TYPE_VARG_PROP_DATA, tmp.data.uid, value.data.uid); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + break; + } + } +} + +void +dump_prop_getter_decl (operand name, operand func) +{ + JERRY_ASSERT (name.type == OPERAND_LITERAL); + JERRY_ASSERT (func.type == OPERAND_TMP); + const literal lit = lexer_get_literal_by_id (name.data.lit_id); + operand tmp; + if (lit.type == LIT_STR || lit.type == LIT_MAGIC_STR) + { + tmp = dump_string_assignment_res (name.data.lit_id); + } + else + { + JERRY_ASSERT (lit.type == LIT_NUMBER); + tmp = dump_number_assignment_res (name.data.lit_id); + } + const opcode_t opcode = getop_meta (OPCODE_META_TYPE_VARG_PROP_GETTER, tmp.data.uid, func.data.uid); + serializer_dump_op_meta (create_op_meta_000 (opcode)); +} + +void +dump_prop_setter_decl (operand name, operand func) +{ + JERRY_ASSERT (name.type == OPERAND_LITERAL); + JERRY_ASSERT (func.type == OPERAND_TMP); + const literal lit = lexer_get_literal_by_id (name.data.lit_id); + operand tmp; + if (lit.type == LIT_STR || lit.type == LIT_MAGIC_STR) + { + tmp = dump_string_assignment_res (name.data.lit_id); + } + else + { + JERRY_ASSERT (lit.type == LIT_NUMBER); + tmp = dump_number_assignment_res (name.data.lit_id); + } + const opcode_t opcode = getop_meta (OPCODE_META_TYPE_VARG_PROP_SETTER, tmp.data.uid, func.data.uid); + serializer_dump_op_meta (create_op_meta_000 (opcode)); +} + +void +dump_prop_getter (operand res, operand obj, operand prop) +{ + dump_triple_address (getop_prop_getter, res, obj, prop); +} + +operand +dump_prop_getter_res (operand obj, operand prop) +{ + const operand res = tmp_operand (); + dump_prop_getter (res, obj, prop); + return res; +} + +void +dump_prop_setter (operand res, operand obj, operand prop) +{ + dump_triple_address (getop_prop_setter, res, obj, prop); +} + +void +dump_function_end_for_rewrite (void) +{ + STACK_PUSH (function_ends, serializer_get_current_opcode_counter ()); + const opcode_t opcode = getop_meta (OPCODE_META_TYPE_FUNCTION_END, INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); +} + +void +rewrite_function_end (varg_list_type vlt) +{ + opcode_counter_t oc; + if (vlt == VARG_FUNC_DECL) + { + oc = (opcode_counter_t) (get_diff_from (STACK_TOP (function_ends)) + + serializer_count_opcodes_in_subscopes ()); + } + else + { + JERRY_ASSERT (vlt == VARG_FUNC_EXPR); + oc = (opcode_counter_t) (get_diff_from (STACK_TOP (function_ends))); + } + idx_t id1, id2; + split_opcode_counter (oc, &id1, &id2); + const opcode_t opcode = getop_meta (OPCODE_META_TYPE_FUNCTION_END, id1, id2); + serializer_rewrite_op_meta (STACK_TOP (function_ends), create_op_meta_000 (opcode)); + STACK_DROP (function_ends, 1); +} + +void +dump_this (operand op) +{ + dump_single_address (getop_this, op); +} + +operand +dump_this_res (void) +{ + const operand res = tmp_operand (); + dump_this (res); + return res; +} + +void +dump_post_increment (operand res, operand obj) +{ + dump_double_address (getop_post_incr, res, obj); +} + +operand +dump_post_increment_res (operand op) +{ + const operand res = tmp_operand (); + dump_post_increment (res, op); + return res; +} + +void +dump_post_decrement (operand res, operand obj) +{ + dump_double_address (getop_post_decr, res, obj); +} + +operand +dump_post_decrement_res (operand op) +{ + const operand res = tmp_operand (); + dump_post_decrement (res, op); + return res; +} + +void +dump_pre_increment (operand res, operand obj) +{ + dump_double_address (getop_pre_incr, res, obj); +} + +operand +dump_pre_increment_res (operand op) +{ + const operand res = tmp_operand (); + dump_pre_increment (res, op); + return res; +} + +void +dump_pre_decrement (operand res, operand obj) +{ + dump_double_address (getop_pre_decr, res, obj); +} + +operand +dump_pre_decrement_res (operand op) +{ + const operand res = tmp_operand (); + dump_pre_decrement (res, op); + return res; +} + +void +dump_unary_plus (operand res, operand obj) +{ + dump_double_address (getop_unary_plus, res, obj); +} + +operand +dump_unary_plus_res (operand op) +{ + const operand res = tmp_operand (); + dump_unary_plus (res, op); + return res; +} + +void +dump_unary_minus (operand res, operand obj) +{ + dump_double_address (getop_unary_minus, res, obj); +} + +operand +dump_unary_minus_res (operand op) +{ + const operand res = tmp_operand (); + dump_unary_minus (res, op); + return res; +} + +void +dump_bitwise_not (operand res, operand obj) +{ + dump_double_address (getop_b_not, res, obj); +} + +operand +dump_bitwise_not_res (operand op) +{ + const operand res = tmp_operand (); + dump_bitwise_not (res, op); + return res; +} + +void +dump_logical_not (operand res, operand obj) +{ + dump_double_address (getop_logical_not, res, obj); +} + +operand +dump_logical_not_res (operand op) +{ + const operand res = tmp_operand (); + dump_logical_not (res, op); + return res; +} + +void +dump_delete (operand res, operand op, bool is_strict, locus loc) +{ + switch (op.type) + { + case OPERAND_LITERAL: + { + const literal lit = lexer_get_literal_by_id (op.data.lit_id); + if (lit.type == LIT_MAGIC_STR || lit.type == LIT_STR) + { + syntax_check_delete (is_strict, loc); + switch (res.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_delete_var (LITERAL_TO_REWRITE, LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_110 (opcode, res.data.lit_id, op.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_delete_var (res.data.uid, LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_010 (opcode, op.data.lit_id)); + break; + } + } + break; + } + else if (lit.type == LIT_NUMBER) + { + dump_boolean_assignment (res, true); + } + break; + } + case OPERAND_TMP: + { + const op_meta last_op_meta = last_dumped_op_meta (); + switch (last_op_meta.op.op_idx) + { + case OPCODE (assignment): + { + if (last_op_meta.op.data.assignment.value_right == LITERAL_TO_REWRITE) + { + const operand var_op = literal_operand (last_op_meta.lit_id[2]); + syntax_check_delete (is_strict, loc); + switch (res.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_delete_var (LITERAL_TO_REWRITE, LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_110 (opcode, res.data.lit_id, var_op.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_delete_var (res.data.uid, LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_010 (opcode, var_op.data.lit_id)); + break; + } + } + } + else + { + dump_boolean_assignment (res, true); + } + break; + } + case OPCODE (prop_getter): + { + const opcode_counter_t oc = (opcode_counter_t) (serializer_get_current_opcode_counter () - 1); + serializer_set_writing_position (oc); + switch (res.type) + { + case OPERAND_LITERAL: + { + if (last_op_meta.op.data.prop_getter.obj == LITERAL_TO_REWRITE) + { + if (last_op_meta.op.data.prop_getter.prop == LITERAL_TO_REWRITE) + { + const opcode_t opcode = getop_delete_prop (LITERAL_TO_REWRITE, + LITERAL_TO_REWRITE, + LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_111 (opcode, res.data.lit_id, + last_op_meta.lit_id[1], + last_op_meta.lit_id[2])); + } + else + { + const opcode_t opcode = getop_delete_prop (LITERAL_TO_REWRITE, + LITERAL_TO_REWRITE, + last_op_meta.op.data.prop_getter.prop); + serializer_dump_op_meta (create_op_meta_110 (opcode, res.data.lit_id, + last_op_meta.lit_id[1])); + } + } + else + { + if (last_op_meta.op.data.prop_getter.prop == LITERAL_TO_REWRITE) + { + const opcode_t opcode = getop_delete_prop (LITERAL_TO_REWRITE, + last_op_meta.op.data.prop_getter.obj, + LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_101 (opcode, res.data.lit_id, + last_op_meta.lit_id[2])); + } + else + { + const opcode_t opcode = getop_delete_prop (LITERAL_TO_REWRITE, + last_op_meta.op.data.prop_getter.obj, + last_op_meta.op.data.prop_getter.prop); + serializer_dump_op_meta (create_op_meta_100 (opcode, res.data.lit_id)); + } + } + break; + } + case OPERAND_TMP: + { + if (last_op_meta.op.data.prop_getter.obj == LITERAL_TO_REWRITE) + { + if (last_op_meta.op.data.prop_getter.prop == LITERAL_TO_REWRITE) + { + const opcode_t opcode = getop_delete_prop (res.data.uid, + LITERAL_TO_REWRITE, + LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_011 (opcode, last_op_meta.lit_id[1], + last_op_meta.lit_id[2])); + } + else + { + const opcode_t opcode = getop_delete_prop (res.data.uid, + LITERAL_TO_REWRITE, + last_op_meta.op.data.prop_getter.prop); + serializer_dump_op_meta (create_op_meta_010 (opcode, last_op_meta.lit_id[1])); + } + } + else + { + if (last_op_meta.op.data.prop_getter.prop == LITERAL_TO_REWRITE) + { + const opcode_t opcode = getop_delete_prop (res.data.uid, + last_op_meta.op.data.prop_getter.obj, + LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_001 (opcode, last_op_meta.lit_id[2])); + } + else + { + const opcode_t opcode = getop_delete_prop (res.data.uid, + last_op_meta.op.data.prop_getter.obj, + last_op_meta.op.data.prop_getter.prop); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + } + } + break; + } + } + break; + } + } + break; + } + } +} + +operand +dump_delete_res (operand op, bool is_strict, locus loc) +{ + const operand res = tmp_operand (); + dump_delete (res, op, is_strict, loc); + return res; +} + +void +dump_typeof (operand res, operand op) +{ + dump_double_address (getop_typeof, res, op); +} + +operand +dump_typeof_res (operand op) +{ + const operand res = tmp_operand (); + dump_typeof (res, op); + return res; +} + +void +dump_multiplication (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_multiplication, res, lhs, rhs); +} + +operand +dump_multiplication_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_multiplication (res, lhs, rhs); + return res; +} + +void +dump_division (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_division, res, lhs, rhs); +} + +operand +dump_division_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_division (res, lhs, rhs); + return res; +} + +void +dump_remainder (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_remainder, res, lhs, rhs); +} + +operand +dump_remainder_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_remainder (res, lhs, rhs); + return res; +} + +void +dump_addition (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_addition, res, lhs, rhs); +} + +operand +dump_addition_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_addition (res, lhs, rhs); + return res; +} + +void +dump_substraction (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_substraction, res, lhs, rhs); +} + +operand +dump_substraction_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_substraction (res, lhs, rhs); + return res; +} + +void +dump_left_shift (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_b_shift_left, res, lhs, rhs); +} + +operand +dump_left_shift_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_left_shift (res, lhs, rhs); + return res; +} + +void +dump_right_shift (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_b_shift_right, res, lhs, rhs); +} + +operand +dump_right_shift_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_right_shift (res, lhs, rhs); + return res; +} + +void +dump_right_shift_ex (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_b_shift_uright, res, lhs, rhs); +} + +operand +dump_right_shift_ex_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_right_shift_ex (res, lhs, rhs); + return res; +} + +void +dump_less_than (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_less_than, res, lhs, rhs); +} + +operand +dump_less_than_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_less_than (res, lhs, rhs); + return res; +} + +void +dump_greater_than (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_greater_than, res, lhs, rhs); +} + +operand +dump_greater_than_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_greater_than (res, lhs, rhs); + return res; +} + +void +dump_less_or_equal_than (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_less_or_equal_than, res, lhs, rhs); +} + +operand +dump_less_or_equal_than_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_less_or_equal_than (res, lhs, rhs); + return res; +} + +void +dump_greater_or_equal_than (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_greater_or_equal_than, res, lhs, rhs); +} + +operand +dump_greater_or_equal_than_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_greater_or_equal_than (res, lhs, rhs); + return res; +} + +void +dump_instanceof (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_instanceof, res, lhs, rhs); +} + +operand +dump_instanceof_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_instanceof (res, lhs, rhs); + return res; +} + +void +dump_in (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_in, res, lhs, rhs); +} + +operand +dump_in_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_in (res, lhs, rhs); + return res; +} + +void +dump_equal_value (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_equal_value, res, lhs, rhs); +} + +operand +dump_equal_value_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_equal_value (res, lhs, rhs); + return res; +} + +void +dump_not_equal_value (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_not_equal_value, res, lhs, rhs); +} + +operand +dump_not_equal_value_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_not_equal_value (res, lhs, rhs); + return res; +} + +void +dump_equal_value_type (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_equal_value_type, res, lhs, rhs); +} + +operand +dump_equal_value_type_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_equal_value_type (res, lhs, rhs); + return res; +} + +void +dump_not_equal_value_type (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_not_equal_value_type, res, lhs, rhs); +} + +operand +dump_not_equal_value_type_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_not_equal_value_type (res, lhs, rhs); + return res; +} + +void +dump_bitwise_and (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_b_and, res, lhs, rhs); +} + +operand +dump_bitwise_and_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_bitwise_and (res, lhs, rhs); + return res; +} + +void +dump_bitwise_xor (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_b_xor, res, lhs, rhs); +} + +operand +dump_bitwise_xor_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_bitwise_xor (res, lhs, rhs); + return res; +} + +void +dump_bitwise_or (operand res, operand lhs, operand rhs) +{ + dump_triple_address (getop_b_or, res, lhs, rhs); +} + +operand +dump_bitwise_or_res (operand lhs, operand rhs) +{ + const operand res = tmp_operand (); + dump_bitwise_or (res, lhs, rhs); + return res; +} + +void +start_dumping_logical_and_checks (void) +{ + STACK_PUSH (U8, (uint8_t) STACK_SIZE (logical_and_checks)); +} + +void +dump_logical_and_check_for_rewrite (operand op) +{ + STACK_PUSH (logical_and_checks, serializer_get_current_opcode_counter ()); + switch (op.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_is_false_jmp_down (LITERAL_TO_REWRITE, INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_100 (opcode, op.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_is_false_jmp_down (op.data.uid, INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + break; + } + } +} + +void +rewrite_logical_and_checks (void) +{ + for (uint8_t i = STACK_TOP (U8); i < STACK_SIZE (logical_and_checks); i++) + { + op_meta jmp_op_meta = deserialize_op_meta (STACK_ELEMENT (logical_and_checks, i)); + JERRY_ASSERT (jmp_op_meta.op.op_idx == OPCODE (is_false_jmp_down)); + idx_t id1, id2; + split_opcode_counter (get_diff_from (STACK_ELEMENT (logical_and_checks, i)), &id1, &id2); + jmp_op_meta.op.data.is_false_jmp_down.opcode_1 = id1; + jmp_op_meta.op.data.is_false_jmp_down.opcode_2 = id2; + serializer_rewrite_op_meta (STACK_ELEMENT (logical_and_checks, i), jmp_op_meta); + } + STACK_DROP (logical_and_checks, STACK_SIZE (logical_and_checks) - STACK_TOP (U8)); + STACK_DROP (U8, 1); +} + +void +start_dumping_logical_or_checks (void) +{ + STACK_PUSH (U8, (uint8_t) STACK_SIZE (logical_or_checks)); +} + +void +dump_logical_or_check_for_rewrite (operand op) +{ + STACK_PUSH (logical_or_checks, serializer_get_current_opcode_counter ()); + switch (op.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_is_true_jmp_down (LITERAL_TO_REWRITE, INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_100 (opcode, op.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_is_true_jmp_down (op.data.uid, INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + break; + } + } +} + +void +rewrite_logical_or_checks (void) +{ + for (uint8_t i = STACK_TOP (U8); i < STACK_SIZE (logical_or_checks); i++) + { + op_meta jmp_op_meta = deserialize_op_meta (STACK_ELEMENT (logical_or_checks, i)); + JERRY_ASSERT (jmp_op_meta.op.op_idx == OPCODE (is_true_jmp_down)); + idx_t id1, id2; + split_opcode_counter (get_diff_from (STACK_ELEMENT (logical_or_checks, i)), &id1, &id2); + jmp_op_meta.op.data.is_true_jmp_down.opcode_1 = id1; + jmp_op_meta.op.data.is_true_jmp_down.opcode_2 = id2; + serializer_rewrite_op_meta (STACK_ELEMENT (logical_or_checks, i), jmp_op_meta); + } + STACK_DROP (logical_or_checks, STACK_SIZE (logical_or_checks) - STACK_TOP (U8)); + STACK_DROP (U8, 1); +} + +void +dump_conditional_check_for_rewrite (operand op) +{ + STACK_PUSH (conditional_checks, serializer_get_current_opcode_counter ()); + switch (op.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_is_false_jmp_down (LITERAL_TO_REWRITE, INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_100 (opcode, op.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_is_false_jmp_down (op.data.uid, INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + break; + } + } +} + +void +rewrite_conditional_check (void) +{ + op_meta jmp_op_meta = deserialize_op_meta (STACK_TOP (conditional_checks)); + JERRY_ASSERT (jmp_op_meta.op.op_idx == OPCODE (is_false_jmp_down)); + idx_t id1, id2; + split_opcode_counter (get_diff_from (STACK_TOP (conditional_checks)), &id1, &id2); + jmp_op_meta.op.data.is_false_jmp_down.opcode_1 = id1; + jmp_op_meta.op.data.is_false_jmp_down.opcode_2 = id2; + serializer_rewrite_op_meta (STACK_TOP (conditional_checks), jmp_op_meta); + STACK_DROP (conditional_checks, 1); +} + +void +dump_jump_to_end_for_rewrite (void) +{ + STACK_PUSH (jumps_to_end, serializer_get_current_opcode_counter ()); + const opcode_t opcode = getop_jmp_down (INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); +} + +void +rewrite_jump_to_end (void) +{ + op_meta jmp_op_meta = deserialize_op_meta (STACK_TOP (jumps_to_end)); + JERRY_ASSERT (jmp_op_meta.op.op_idx == OPCODE (jmp_down)); + idx_t id1, id2; + split_opcode_counter (get_diff_from (STACK_TOP (jumps_to_end)), &id1, &id2); + jmp_op_meta.op.data.jmp_down.opcode_1 = id1; + jmp_op_meta.op.data.jmp_down.opcode_2 = id2; + serializer_rewrite_op_meta (STACK_TOP (jumps_to_end), jmp_op_meta); + STACK_DROP (jumps_to_end, 1); +} + +void +start_dumping_assignment_expression (void) +{ + const op_meta last = last_dumped_op_meta (); + if (last.op.op_idx == OPCODE (prop_getter)) + { + serializer_set_writing_position ((opcode_counter_t) (serializer_get_current_opcode_counter () - 1)); + } + STACK_PUSH (prop_getters, last); +} + +operand +dump_prop_setter_or_variable_assignment_res (operand res, operand op) +{ + const op_meta last = STACK_TOP (prop_getters); + if (last.op.op_idx == OPCODE (prop_getter)) + { + dump_prop_setter_op_meta (last, op); + } + else + { + dump_variable_assignment (res, op); + } + STACK_DROP (prop_getters, 1); + return op; +} + +operand +dump_prop_setter_or_addition_res (operand res, operand op) +{ + return dump_prop_setter_or_triple_address_res (dump_addition, res, op); +} + +operand +dump_prop_setter_or_multiplication_res (operand res, operand op) +{ + return dump_prop_setter_or_triple_address_res (dump_multiplication, res, op); +} + +operand +dump_prop_setter_or_division_res (operand res, operand op) +{ + return dump_prop_setter_or_triple_address_res (dump_division, res, op); +} + +operand +dump_prop_setter_or_remainder_res (operand res, operand op) +{ + return dump_prop_setter_or_triple_address_res (dump_remainder, res, op); +} + +operand +dump_prop_setter_or_substraction_res (operand res, operand op) +{ + return dump_prop_setter_or_triple_address_res (dump_substraction, res, op); +} + +operand +dump_prop_setter_or_left_shift_res (operand res, operand op) +{ + return dump_prop_setter_or_triple_address_res (dump_left_shift, res, op); +} + +operand +dump_prop_setter_or_right_shift_res (operand res, operand op) +{ + return dump_prop_setter_or_triple_address_res (dump_right_shift, res, op); +} + +operand +dump_prop_setter_or_right_shift_ex_res (operand res, operand op) +{ + return dump_prop_setter_or_triple_address_res (dump_right_shift_ex, res, op); +} + +operand +dump_prop_setter_or_bitwise_and_res (operand res, operand op) +{ + return dump_prop_setter_or_triple_address_res (dump_bitwise_and, res, op); +} + +operand +dump_prop_setter_or_bitwise_xor_res (operand res, operand op) +{ + return dump_prop_setter_or_triple_address_res (dump_bitwise_xor, res, op); +} + +operand +dump_prop_setter_or_bitwise_or_res (operand res, operand op) +{ + return dump_prop_setter_or_triple_address_res (dump_bitwise_or, res, op); +} + +void +start_collecting_breaks (void) +{ + STACK_PUSH (U8, (uint8_t) STACK_SIZE (breaks)); +} + +void +start_collecting_continues (void) +{ + STACK_PUSH (U8, (uint8_t) STACK_SIZE (continues)); +} + +void +dumper_set_break_target (void) +{ + STACK_PUSH (break_targets, serializer_get_current_opcode_counter ()); +} + +void +dumper_set_continue_target (void) +{ + STACK_PUSH (continue_targets, serializer_get_current_opcode_counter ()); +} + +void +dumper_set_next_interation_target (void) +{ + STACK_PUSH (next_iterations, serializer_get_current_opcode_counter ()); +} + +void +dump_continue_iterations_check (operand op) +{ + const opcode_counter_t next_iteration_target_diff = (opcode_counter_t) (serializer_get_current_opcode_counter () + - STACK_TOP (next_iterations)); + idx_t id1, id2; + split_opcode_counter (next_iteration_target_diff, &id1, &id2); + if (operand_is_empty (op)) + { + const opcode_t opcode = getop_jmp_up (id1, id2); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + } + else + { + switch (op.type) + { + case OPERAND_LITERAL: + { + const opcode_t opcode = getop_is_true_jmp_up (LITERAL_TO_REWRITE, id1, id2); + serializer_dump_op_meta (create_op_meta_100 (opcode, op.data.lit_id)); + break; + } + case OPERAND_TMP: + { + const opcode_t opcode = getop_is_true_jmp_up (op.data.uid, id1, id2); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + break; + } + } + } + STACK_DROP (next_iterations, 1); +} + +void +dump_continue_for_rewrite (void) +{ + STACK_PUSH (continues, serializer_get_current_opcode_counter ()); + const opcode_t opcode = getop_jmp_down (INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); +} + +void +dump_break_for_rewrite (void) +{ + STACK_PUSH (breaks, serializer_get_current_opcode_counter ()); + const opcode_t opcode = getop_jmp_down (INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); +} + +void +rewrite_breaks (void) +{ + const opcode_counter_t break_target = STACK_TOP (break_targets); + + STACK_ITERATE (breaks, break_oc, STACK_TOP (U8)) + { + idx_t id1, id2; + split_opcode_counter ((opcode_counter_t) (break_target - break_oc), &id1, &id2); + op_meta break_op_meta = deserialize_op_meta (break_oc); + JERRY_ASSERT (break_op_meta.op.op_idx == OPCODE (jmp_down)); + break_op_meta.op.data.jmp_down.opcode_1 = id1; + break_op_meta.op.data.jmp_down.opcode_2 = id2; + serializer_rewrite_op_meta (break_oc, break_op_meta); + } + STACK_ITERATE_END(); + + STACK_DROP (break_targets, 1); + STACK_DROP (breaks, STACK_SIZE (breaks) - STACK_TOP (U8)); + STACK_DROP (U8, 1); +} + +void +rewrite_continues (void) +{ + const opcode_counter_t continue_target = STACK_TOP (continue_targets); + + STACK_ITERATE (continues, continue_oc, STACK_TOP (U8)) + { + idx_t id1, id2; + split_opcode_counter ((opcode_counter_t) (continue_target - continue_oc), &id1, &id2); + op_meta continue_op_meta = deserialize_op_meta (continue_oc); + JERRY_ASSERT (continue_op_meta.op.op_idx == OPCODE (jmp_down)); + continue_op_meta.op.data.jmp_down.opcode_1 = id1; + continue_op_meta.op.data.jmp_down.opcode_2 = id2; + serializer_rewrite_op_meta (continue_oc, continue_op_meta); + } + STACK_ITERATE_END(); + + STACK_DROP (continue_targets, 1); + STACK_DROP (continues, STACK_SIZE (continues) - STACK_TOP (U8)); + STACK_DROP (U8, 1); +} + +void +start_dumping_case_clauses (void) +{ + STACK_PUSH (U8, (uint8_t) STACK_SIZE (case_clauses)); + STACK_PUSH (U8, (uint8_t) STACK_SIZE (case_clauses)); +} + +void +dump_case_clause_check_for_rewrite (operand switch_expr, operand case_expr) +{ + const operand res = tmp_operand (); + dump_triple_address (getop_equal_value_type, res, switch_expr, case_expr); + STACK_PUSH (case_clauses, serializer_get_current_opcode_counter ()); + const opcode_t opcode = getop_is_true_jmp_down (res.data.uid, INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); +} + +void +dump_default_clause_check_for_rewrite (void) +{ + STACK_PUSH (case_clauses, serializer_get_current_opcode_counter ()); + const opcode_t opcode = getop_jmp_down (INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); +} + +void +rewrite_case_clause (void) +{ + const opcode_counter_t jmp_oc = STACK_ELEMENT (case_clauses, STACK_HEAD (U8, 2)); + idx_t id1, id2; + split_opcode_counter (get_diff_from (jmp_oc), &id1, &id2); + op_meta jmp_op_meta = deserialize_op_meta (jmp_oc); + JERRY_ASSERT (jmp_op_meta.op.op_idx == OPCODE (is_true_jmp_down)); + jmp_op_meta.op.data.is_true_jmp_down.opcode_1 = id1; + jmp_op_meta.op.data.is_true_jmp_down.opcode_2 = id2; + serializer_rewrite_op_meta (jmp_oc, jmp_op_meta); + STACK_INCR_HEAD (U8, 2); +} + +void +rewrite_default_clause (void) +{ + const opcode_counter_t jmp_oc = STACK_TOP (case_clauses); + idx_t id1, id2; + split_opcode_counter (get_diff_from (jmp_oc), &id1, &id2); + op_meta jmp_op_meta = deserialize_op_meta (jmp_oc); + JERRY_ASSERT (jmp_op_meta.op.op_idx == OPCODE (jmp_down)); + jmp_op_meta.op.data.jmp_down.opcode_1 = id1; + jmp_op_meta.op.data.jmp_down.opcode_2 = id2; + serializer_rewrite_op_meta (jmp_oc, jmp_op_meta); +} + +void +finish_dumping_case_clauses (void) +{ + STACK_DROP (U8, 1); + STACK_DROP (case_clauses, STACK_SIZE (case_clauses) - STACK_TOP (U8)); + STACK_DROP (U8, 1); +} + +void +dump_with (operand op) +{ + dump_single_address (getop_with, op); +} + +void +dump_with_end (void) +{ + const opcode_t opcode = getop_meta (OPCODE_META_TYPE_END_WITH, INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); +} + +void +dump_try_for_rewrite (void) +{ + STACK_PUSH (tries, serializer_get_current_opcode_counter ()); + const opcode_t opcode = getop_try (INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); +} + +void +rewrite_try (void) +{ + op_meta try_op_meta = deserialize_op_meta (STACK_TOP (tries)); + JERRY_ASSERT (try_op_meta.op.op_idx == OPCODE (try)); + idx_t id1, id2; + split_opcode_counter (get_diff_from (STACK_TOP (tries)), &id1, &id2); + try_op_meta.op.data.try.oc_idx_1 = id1; + try_op_meta.op.data.try.oc_idx_2 = id2; + serializer_rewrite_op_meta (STACK_TOP (tries), try_op_meta); + STACK_DROP (tries, 1); +} + +void +dump_catch_for_rewrite (operand op) +{ + JERRY_ASSERT (op.type == OPERAND_LITERAL); + STACK_PUSH (catches, serializer_get_current_opcode_counter ()); + opcode_t opcode = getop_meta (OPCODE_META_TYPE_CATCH, INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + opcode = getop_meta (OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER, LITERAL_TO_REWRITE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_010 (opcode, op.data.lit_id)); +} + +void +rewrite_catch (void) +{ + op_meta catch_op_meta = deserialize_op_meta (STACK_TOP (catches)); + JERRY_ASSERT (catch_op_meta.op.op_idx == OPCODE (meta) + && catch_op_meta.op.data.meta.type == OPCODE_META_TYPE_CATCH); + idx_t id1, id2; + split_opcode_counter (get_diff_from (STACK_TOP (catches)), &id1, &id2); + catch_op_meta.op.data.meta.data_1 = id1; + catch_op_meta.op.data.meta.data_2 = id2; + serializer_rewrite_op_meta (STACK_TOP (catches), catch_op_meta); + STACK_DROP (catches, 1); +} + +void +dump_finally_for_rewrite (void) +{ + STACK_PUSH (finallies, serializer_get_current_opcode_counter ()); + const opcode_t opcode = getop_meta (OPCODE_META_TYPE_FINALLY, INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); +} + +void +rewrite_finally (void) +{ + op_meta finally_op_meta = deserialize_op_meta (STACK_TOP (finallies)); + JERRY_ASSERT (finally_op_meta.op.op_idx == OPCODE (meta) + && finally_op_meta.op.data.meta.type == OPCODE_META_TYPE_FINALLY); + idx_t id1, id2; + split_opcode_counter (get_diff_from (STACK_TOP (finallies)), &id1, &id2); + finally_op_meta.op.data.meta.data_1 = id1; + finally_op_meta.op.data.meta.data_2 = id2; + serializer_rewrite_op_meta (STACK_TOP (finallies), finally_op_meta); + STACK_DROP (finallies, 1); +} + +void +dump_end_try_catch_finally (void) +{ + const opcode_t opcode = getop_meta (OPCODE_META_TYPE_END_TRY_CATCH_FINALLY, + INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); +} + +void +dump_throw (operand op) +{ + dump_single_address (getop_throw, op); +} + +bool +dumper_variable_declaration_exists (literal_index_t lit_id) +{ + for (opcode_counter_t oc = (opcode_counter_t) (serializer_get_current_opcode_counter () - 1); + oc > 0; oc--) + { + const op_meta var_decl_op_meta = deserialize_op_meta (oc); + if (var_decl_op_meta.op.op_idx != OPCODE (var_decl)) + { + break; + } + if (var_decl_op_meta.lit_id[0] == lit_id) + { + return true; + } + } + return false; +} + +void +dump_variable_declaration (literal_index_t lit_id) +{ + const opcode_t opcode = getop_var_decl (LITERAL_TO_REWRITE); + serializer_dump_op_meta (create_op_meta_100 (opcode, lit_id)); +} + +void +dump_strict_mode_header (void) +{ + const opcode_t opcode = getop_meta (OPCODE_META_TYPE_STRICT_CODE, INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); +} + +void +dump_ret (void) +{ + serializer_dump_op_meta (create_op_meta_000 (getop_ret ())); +} + +void +dump_reg_var_decl_for_rewrite (void) +{ + STACK_PUSH (reg_var_decls, serializer_get_current_opcode_counter ()); + serializer_dump_op_meta (create_op_meta_000 (getop_reg_var_decl (MIN_TEMP_NAME, INVALID_VALUE))); +} + +void +rewrite_reg_var_decl (void) +{ + opcode_counter_t reg_var_decl_oc = STACK_TOP (reg_var_decls); + op_meta opm = deserialize_op_meta (reg_var_decl_oc); + JERRY_ASSERT (opm.op.op_idx == OPCODE (reg_var_decl)); + opm.op.data.reg_var_decl.max = max_temp_name; + serializer_rewrite_op_meta (reg_var_decl_oc, opm); + STACK_DROP (reg_var_decls, 1); +} + +void +dump_retval (operand op) +{ + dump_single_address (getop_retval, op); +} + +void +dump_exit (void) +{ + serializer_dump_op_meta (create_op_meta_000 (getop_exitval (0))); +} + +void +dumper_init (void) +{ + max_temp_name = 0; + reset_temp_name (); + STACK_INIT (U8); + STACK_INIT (varg_headers); + STACK_INIT (function_ends); + STACK_INIT (logical_and_checks); + STACK_INIT (logical_or_checks); + STACK_INIT (conditional_checks); + STACK_INIT (jumps_to_end); + STACK_INIT (prop_getters); + STACK_INIT (breaks); + STACK_INIT (continues); + STACK_INIT (break_targets); + STACK_INIT (continue_targets); + STACK_INIT (next_iterations); + STACK_INIT (case_clauses); + STACK_INIT (catches); + STACK_INIT (finallies); + STACK_INIT (tries); + STACK_INIT (temp_names); + STACK_INIT (reg_var_decls); +} + +void +dumper_free (void) +{ + STACK_FREE (U8); + STACK_FREE (varg_headers); + STACK_FREE (function_ends); + STACK_FREE (logical_and_checks); + STACK_FREE (logical_or_checks); + STACK_FREE (conditional_checks); + STACK_FREE (jumps_to_end); + STACK_FREE (prop_getters); + STACK_FREE (breaks); + STACK_FREE (continues); + STACK_FREE (break_targets); + STACK_FREE (continue_targets); + STACK_FREE (next_iterations); + STACK_FREE (case_clauses); + STACK_FREE (catches); + STACK_FREE (finallies); + STACK_FREE (tries); + STACK_FREE (temp_names); + STACK_FREE (reg_var_decls); +} diff --git a/src/libjsparser/opcodes-dumper.h b/src/libjsparser/opcodes-dumper.h new file mode 100644 index 000000000..21fdeeaff --- /dev/null +++ b/src/libjsparser/opcodes-dumper.h @@ -0,0 +1,233 @@ +/* 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. + */ + +#ifndef OPCODES_DUMPER_H +#define OPCODES_DUMPER_H + +#include "opcodes.h" +#include "ecma-globals.h" +#include "lexer.h" + +typedef enum +{ + OPERAND_LITERAL, + OPERAND_TMP +} +operand_type; + +typedef struct +{ + operand_type type; + union + { + idx_t uid; + literal_index_t lit_id; + } + data; +} +operand; + +typedef enum +{ + VARG_FUNC_DECL, + VARG_FUNC_EXPR, + VARG_ARRAY_DECL, + VARG_OBJ_DECL, + VARG_CONSTRUCT_EXPR, + VARG_CALL_EXPR +} +varg_list_type; + +operand empty_operand (void); +operand literal_operand (literal_index_t); +bool operand_is_empty (operand); + +void dumper_init (void); +void dumper_free (void); + +void dumper_new_statement (void); +void dumper_new_scope (void); +void dumper_finish_scope (void); + +bool dumper_is_intrinsic (operand); +operand dump_intrinsic (operand, operand); + +void dump_boolean_assignment (operand, bool); +operand dump_boolean_assignment_res (bool); +void dump_string_assignment (operand, literal_index_t); +operand dump_string_assignment_res (literal_index_t); +void dump_number_assignment (operand, literal_index_t); +operand dump_number_assignment_res (literal_index_t); +void dump_smallint_assignment (operand, idx_t); +operand dump_smallint_assignment_res (idx_t); +void dump_undefined_assignment (operand); +operand dump_undefined_assignment_res (void); +void dump_null_assignment (operand); +operand dump_null_assignment_res (void); +void dump_variable_assignment (operand, operand); +operand dump_variable_assignment_res (operand); + +void dump_varg_header_for_rewrite (varg_list_type, operand); +operand rewrite_varg_header_set_args_count (uint8_t); +void dump_this_arg (operand); +void dump_varg (operand); + +void dump_prop_name_and_value (operand, operand); +void dump_prop_getter_decl (operand, operand); +void dump_prop_setter_decl (operand, operand); +void dump_prop_getter (operand, operand, operand); +operand dump_prop_getter_res (operand, operand); +void dump_prop_setter (operand, operand, operand); + +void dump_function_end_for_rewrite (void); +void rewrite_function_end (varg_list_type); + +void dump_this (operand); +operand dump_this_res (void); + +void dump_post_increment (operand, operand); +operand dump_post_increment_res (operand); +void dump_post_decrement (operand, operand); +operand dump_post_decrement_res (operand); +void dump_pre_increment (operand, operand); +operand dump_pre_increment_res (operand); +void dump_pre_decrement (operand, operand); +operand dump_pre_decrement_res (operand); +void dump_unary_plus (operand, operand); +operand dump_unary_plus_res (operand); +void dump_unary_minus (operand, operand); +operand dump_unary_minus_res (operand); +void dump_bitwise_not (operand, operand); +operand dump_bitwise_not_res (operand); +void dump_logical_not (operand, operand); +operand dump_logical_not_res (operand); + +void dump_multiplication (operand, operand, operand); +operand dump_multiplication_res (operand, operand); +void dump_division (operand, operand, operand); +operand dump_division_res (operand, operand); +void dump_remainder (operand, operand, operand); +operand dump_remainder_res (operand, operand); +void dump_addition (operand, operand, operand); +operand dump_addition_res (operand, operand); +void dump_substraction (operand, operand, operand); +operand dump_substraction_res (operand, operand); +void dump_left_shift (operand, operand, operand); +operand dump_left_shift_res (operand, operand); +void dump_right_shift (operand, operand, operand); +operand dump_right_shift_res (operand, operand); +void dump_right_shift_ex (operand, operand, operand); +operand dump_right_shift_ex_res (operand, operand); +void dump_less_than (operand, operand, operand); +operand dump_less_than_res (operand, operand); +void dump_greater_than (operand, operand, operand); +operand dump_greater_than_res (operand, operand); +void dump_less_or_equal_than (operand, operand, operand); +operand dump_less_or_equal_than_res (operand, operand); +void dump_greater_or_equal_than (operand, operand, operand); +operand dump_greater_or_equal_than_res (operand, operand); +void dump_instanceof (operand, operand, operand); +operand dump_instanceof_res (operand, operand); +void dump_in (operand, operand, operand); +operand dump_in_res (operand, operand); +void dump_equal_value (operand, operand, operand); +operand dump_equal_value_res (operand, operand); +void dump_not_equal_value (operand, operand, operand); +operand dump_not_equal_value_res (operand, operand); +void dump_equal_value_type (operand, operand, operand); +operand dump_equal_value_type_res (operand, operand); +void dump_not_equal_value_type (operand, operand, operand); +operand dump_not_equal_value_type_res (operand, operand); +void dump_bitwise_and (operand, operand, operand); +operand dump_bitwise_and_res (operand, operand); +void dump_bitwise_xor (operand, operand, operand); +operand dump_bitwise_xor_res (operand, operand); +void dump_bitwise_or (operand, operand, operand); +operand dump_bitwise_or_res (operand, operand); + +void start_dumping_logical_and_checks (void); +void dump_logical_and_check_for_rewrite (operand); +void rewrite_logical_and_checks (void); +void start_dumping_logical_or_checks (void); +void dump_logical_or_check_for_rewrite (operand); +void rewrite_logical_or_checks (void); +void dump_conditional_check_for_rewrite (operand); +void rewrite_conditional_check (void); +void dump_jump_to_end_for_rewrite (void); +void rewrite_jump_to_end (void); + +void start_dumping_assignment_expression (void); +operand dump_prop_setter_or_variable_assignment_res (operand, operand); +operand dump_prop_setter_or_addition_res (operand, operand); +operand dump_prop_setter_or_multiplication_res (operand, operand); +operand dump_prop_setter_or_division_res (operand, operand); +operand dump_prop_setter_or_remainder_res (operand, operand); +operand dump_prop_setter_or_substraction_res (operand, operand); +operand dump_prop_setter_or_left_shift_res (operand, operand); +operand dump_prop_setter_or_right_shift_res (operand, operand); +operand dump_prop_setter_or_right_shift_ex_res (operand, operand); +operand dump_prop_setter_or_bitwise_and_res (operand, operand); +operand dump_prop_setter_or_bitwise_xor_res (operand, operand); +operand dump_prop_setter_or_bitwise_or_res (operand, operand); + +void start_collecting_breaks (void); +void start_collecting_continues (void); +void dumper_set_break_target (void); +void dumper_set_continue_target (void); +void dumper_set_next_interation_target (void); +void dump_continue_for_rewrite (void); +void dump_break_for_rewrite (void); +void rewrite_continues (void); +void rewrite_breaks (void); +void dump_continue_iterations_check (operand); + +void start_dumping_case_clauses (void); +void dump_case_clause_check_for_rewrite (operand, operand); +void dump_default_clause_check_for_rewrite (void); +void rewrite_case_clause (void); +void rewrite_default_clause (void); +void finish_dumping_case_clauses (void); + +void dump_delete (operand, operand, bool, locus); +operand dump_delete_res (operand, bool, locus); + +void dump_typeof (operand, operand); +operand dump_typeof_res (operand); + +void dump_with (operand); +void dump_with_end (void); + +void dump_try_for_rewrite (void); +void rewrite_try (void); +void dump_catch_for_rewrite (operand); +void rewrite_catch (void); +void dump_finally_for_rewrite (void); +void rewrite_finally (void); +void dump_end_try_catch_finally (void); +void dump_throw (operand); + +bool dumper_variable_declaration_exists (literal_index_t); +void dump_variable_declaration (literal_index_t); + +void dump_strict_mode_header (void); + +void dump_reg_var_decl_for_rewrite (void); +void rewrite_reg_var_decl (void); + +void dump_ret (void); +void dump_retval (operand op); +void dump_exit (void); + +#endif /* OPCODES_DUMPER_H */ diff --git a/src/libjsparser/parser.c b/src/libjsparser/parser.c index 5b675563e..35540eece 100644 --- a/src/libjsparser/parser.c +++ b/src/libjsparser/parser.c @@ -15,7 +15,6 @@ #include "optimizer-passes.h" #include "jerry-libc.h" -#include "lexer.h" #include "parser.h" #include "opcodes.h" #include "serializer.h" @@ -24,286 +23,33 @@ #include "hash-table.h" #include "deserializer.h" #include "opcodes-native-call.h" -#include "parse-error.h" #include "scopes-tree.h" #include "ecma-helpers.h" - -#define INTRINSICS_COUNT 1 - -typedef enum -{ - REWRITABLE_CONTINUE = 0, - REWRITABLE_BREAK, - REWRITABLE_OPCODES_COUNT -} -rewritable_opcode_type; - -typedef enum -{ - PROP_DATA, - PROP_SET, - PROP_GET, - VARG -} -prop_type; - -typedef struct -{ - prop_type type; - literal lit; -} -prop_literal; +#include "syntax-errors.h" +#include "opcodes-dumper.h" +#include "stdarg.h" #define NESTING_ITERATIONAL 1 #define NESTING_SWITCH 2 #define NESTING_FUNCTION 3 -#define GLOBAL(NAME, VAR) STACK_ELEMENT (NAME, VAR) - -enum -{ - no_in, - U8_global_size -}; -STATIC_STACK (U8, uint8_t, uint8_t) - -enum -{ - this_arg, - prop, - IDX_global_size -}; -STATIC_STACK (IDX, uint8_t, uint8_t) - -#define THIS_ARG() STACK_ELEMENT (IDX, this_arg) -#define SET_THIS_ARG(S) STACK_SET_ELEMENT (IDX, this_arg, S) -#define PROP() STACK_ELEMENT (IDX, prop) -#define SET_PROP(S) STACK_SET_ELEMENT (IDX, prop, S) - -#define ID(I) STACK_HEAD(IDX, I) +static token tok; enum { nestings_global_size }; -STATIC_STACK (nestings, uint8_t, uint8_t) +STATIC_STACK (nestings, uint8_t) enum { scopes_global_size }; -STATIC_STACK (scopes, uint8_t, scopes_tree) +STATIC_STACK (scopes, scopes_tree) -enum -{ - temp_name, - min_temp_name, - max_temp_name, - temp_names_global_size -}; -STATIC_STACK (temp_names, uint8_t, uint8_t) - -#define MAX_TEMP_NAME() \ -GLOBAL(temp_names, max_temp_name) - -#define SET_MAX_TEMP_NAME(S) \ -do { STACK_SET_ELEMENT (temp_names, max_temp_name, S); } while (0) - -#define MIN_TEMP_NAME() \ -GLOBAL(temp_names, min_temp_name) - -#define SET_MIN_TEMP_NAME(S) \ -do { STACK_SET_ELEMENT (temp_names, min_temp_name, S); } while (0) - -#define TEMP_NAME() \ -GLOBAL(temp_names, temp_name) - -#define SET_TEMP_NAME(S) \ -do { STACK_SET_ELEMENT (temp_names, temp_name, S); } while (0) - -enum -{ - tok = 0, - toks_global_size -}; -STATIC_STACK (toks, uint8_t, token) - -#define TOK() \ -GLOBAL(toks, tok) - -#define SET_TOK(S) \ -do { STACK_SET_ELEMENT (toks, tok, S); } while (0) - -enum -{ - ops_global_size -}; -STATIC_STACK (ops, uint8_t, opcode_t) - -enum -{ - locs_global_size -}; -STATIC_STACK (locs, uint8_t, locus) - -enum -{ - opcode_counter = 0, - U16_global_size -}; -STATIC_STACK (U16, uint8_t, uint16_t) - -#define OPCODE_COUNTER() \ -GLOBAL(U16, opcode_counter) - -#define SET_OPCODE_COUNTER(S) \ -do { STACK_SET_ELEMENT (U16, opcode_counter, S); } while (0) - -#define INCR_OPCODE_COUNTER() \ -do { STACK_INCR_ELEMENT(U16, opcode_counter); } while (0) - -#define DECR_OPCODE_COUNTER() \ -do { STACK_DECR_ELEMENT(U16, opcode_counter); } while (0) - -enum -{ - rewritable_continue_global_size -}; -STATIC_STACK (rewritable_continue, uint8_t, uint16_t) - -enum -{ - rewritable_break_global_size -}; -STATIC_STACK (rewritable_break, uint8_t, uint16_t) - -enum -{ - literals_global_size -}; -STATIC_STACK (literals, uint8_t, literal) - -enum -{ - props_global_size -}; -STATIC_STACK (props, uint8_t, prop_literal) - -#ifndef JERRY_NDEBUG -#define STACK_CHECK_USAGE_LHS() \ -JERRY_ASSERT (IDX.current == IDX_current + 1); -#else -#define STACK_CHECK_USAGE_LHS() ; -#endif - -#define LAST_OPCODE_IS(OP) (deserialize_opcode((opcode_counter_t)(OPCODE_COUNTER()-1)).op_idx == __op__idx_##OP) - -JERRY_STATIC_ASSERT (sizeof (idx_t) == sizeof (uint8_t)); - -JERRY_STATIC_ASSERT (sizeof (opcode_counter_t) == sizeof (uint16_t)); - -static void skip_newlines (void); -#define NEXT(TYPE) \ -do { skip_newlines (); parse_##TYPE (); } while (0) - -#define DUMP_VOID_OPCODE(GETOP) \ -do { \ - serializer_dump_opcode (getop_##GETOP ()); \ - INCR_OPCODE_COUNTER(); \ -} while (0) - -#define DUMP_OPCODE_1(GETOP, OP1) \ -do { \ - JERRY_ASSERT (0+OP1 <= 255); \ - serializer_dump_opcode (getop_##GETOP ((idx_t) (OP1))); \ - INCR_OPCODE_COUNTER(); \ -} while (0) - -#define DUMP_OPCODE_2(GETOP, OP1, OP2) \ -do { \ - JERRY_ASSERT (0+OP1 <= 255); \ - JERRY_ASSERT (0+OP2 <= 255); \ - serializer_dump_opcode (getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2))); \ - INCR_OPCODE_COUNTER(); \ -} while (0) - -#define DUMP_OPCODE_3(GETOP, OP1, OP2, OP3) \ -do { \ - JERRY_ASSERT (0+OP1 <= 255); \ - JERRY_ASSERT (0+OP2 <= 255); \ - JERRY_ASSERT (0+OP3 <= 255); \ - serializer_dump_opcode (getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2), (idx_t) (OP3))); \ - INCR_OPCODE_COUNTER(); \ -} while (0) - -#define REWRITE_VOID_OPCODE(OC, GETOP) \ -do { \ - serializer_rewrite_opcode (OC, getop_##GETOP ()); \ -} while (0) - -#define REWRITE_OPCODE_1(OC, GETOP, OP1) \ -do { \ - JERRY_ASSERT (0+OP1 <= 255); \ - serializer_rewrite_opcode ((opcode_counter_t) (OC), getop_##GETOP ((idx_t) (OP1))); \ -} while (0) - -#define REWRITE_OPCODE_2(OC, GETOP, OP1, OP2) \ -do { \ - JERRY_ASSERT (0+OP1 <= 255); \ - JERRY_ASSERT (0+OP2 <= 255); \ - serializer_rewrite_opcode ((opcode_counter_t) (OC), getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2))); \ -} while (0) - -#define REWRITE_OPCODE_3(OC, GETOP, OP1, OP2, OP3) \ -do { \ - JERRY_ASSERT (0+OP1 <= 255); \ - JERRY_ASSERT (0+OP2 <= 255); \ - JERRY_ASSERT (0+OP3 <= 255); \ - serializer_rewrite_opcode ((opcode_counter_t) (OC), getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2), (idx_t) (OP3))); \ -} while (0) - -#define REWRITE_COND_JMP(OC, GETOP, DIFF) \ -do { \ - JERRY_ASSERT (0+DIFF <= 256*256 - 1); \ - STACK_DECLARE_USAGE (IDX); \ - JERRY_STATIC_ASSERT (sizeof (idx_t) == 1); \ - STACK_PUSH (IDX, (idx_t) ((DIFF) >> JERRY_BITSINBYTE)); \ - STACK_PUSH (IDX, (idx_t) ((DIFF) & ((1 << JERRY_BITSINBYTE) - 1))); \ - JERRY_ASSERT ((DIFF) == calc_opcode_counter_from_idx_idx (ID(2), ID(1))); \ - serializer_rewrite_opcode (OC, getop_##GETOP (ID(3), ID(2), ID(1))); \ - STACK_DROP (IDX, 2); \ - STACK_CHECK_USAGE (IDX); \ -} while (0) - -#define REWRITE_JMP(OC, GETOP, DIFF) \ -do { \ - JERRY_ASSERT (0+DIFF <= 256*256 - 1); \ - STACK_DECLARE_USAGE (IDX) \ - JERRY_STATIC_ASSERT (sizeof (idx_t) == 1); \ - STACK_PUSH (IDX, (idx_t) ((DIFF) >> JERRY_BITSINBYTE)); \ - STACK_PUSH (IDX, (idx_t) ((DIFF) & ((1 << JERRY_BITSINBYTE) - 1))); \ - JERRY_ASSERT ((DIFF) == calc_opcode_counter_from_idx_idx (ID(2), ID(1))); \ - serializer_rewrite_opcode (OC, getop_##GETOP (ID(2), ID(1))); \ - STACK_DROP (IDX, 2); \ - STACK_CHECK_USAGE (IDX); \ -} while (0) - -#define REWRITE_TRY(OC) \ -do { \ - STACK_DECLARE_USAGE (IDX) \ - JERRY_STATIC_ASSERT (sizeof (idx_t) == 1); \ - STACK_PUSH (IDX, (idx_t) ((OPCODE_COUNTER () - OC) >> JERRY_BITSINBYTE)); \ - STACK_PUSH (IDX, (idx_t) ((OPCODE_COUNTER () - OC) & ((1 << JERRY_BITSINBYTE) - 1))); \ - JERRY_ASSERT ((OPCODE_COUNTER () - OC) \ - == calc_opcode_counter_from_idx_idx (ID(2), ID(1))); \ - serializer_rewrite_opcode ((OC), getop_try (ID(2), ID(1))); \ - STACK_DROP (IDX, 2); \ - STACK_CHECK_USAGE (IDX); \ -} while (0) - -#define EMIT_ERROR(MESSAGE) PARSE_ERROR(MESSAGE, TOK().loc) -#define EMIT_SORRY(MESSAGE) PARSE_SORRY(MESSAGE, TOK().loc) -#define EMIT_ERROR_VARG(MESSAGE, ...) PARSE_ERROR_VARG(MESSAGE, TOK().loc, __VA_ARGS__) +#define EMIT_ERROR(MESSAGE) PARSE_ERROR(MESSAGE, tok.loc) +#define EMIT_SORRY(MESSAGE) PARSE_SORRY(MESSAGE, tok.loc) +#define EMIT_ERROR_VARG(MESSAGE, ...) PARSE_ERROR_VARG(MESSAGE, tok.loc, __VA_ARGS__) #define NESTING_TO_STRING(I) (I == NESTING_FUNCTION \ ? "function" \ @@ -314,57 +60,13 @@ do { \ #define OPCODE_IS(OP, ID) (OP.op_idx == __op__idx_##ID) -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 operand parse_expression (bool); static void parse_statement (void); -static void parse_assignment_expression (void); +static operand parse_assignment_expression (bool); static void parse_source_element_list (bool); -static uint8_t parse_argument_list (argument_list_type, idx_t); +static operand parse_argument_list (varg_list_type, operand, uint8_t *, operand *); static void skip_braces (void); -static void parse_logical_expression (bool); - -static idx_t -next_temp_name (void) -{ - idx_t res = TEMP_NAME (); - STACK_INCR_ELEMENT (temp_names, temp_name); - if (MAX_TEMP_NAME () < TEMP_NAME ()) - { - SET_MAX_TEMP_NAME (TEMP_NAME ()); - } - return res; -} - -static void -start_new_scope (void) -{ - STACK_PUSH (temp_names, MAX_TEMP_NAME()); - SET_MAX_TEMP_NAME (MIN_TEMP_NAME ()); -} - -static void -finish_scope (void) -{ - SET_TEMP_NAME (STACK_HEAD (temp_names, 1)); - STACK_DROP (temp_names, 1); - SET_MAX_TEMP_NAME (TEMP_NAME ()); -} - -static void -reset_temp_name (void) -{ - SET_TEMP_NAME (MIN_TEMP_NAME ()); -} +static void skip_parens (void); static void push_nesting (uint8_t nesting_type) @@ -380,74 +82,56 @@ pop_nesting (uint8_t nesting_type) } 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 not_in, uint8_t insides_count, ...) { - STACK_DECLARE_USAGE (U8) // i, j - STACK_PUSH (U8, 0); - STACK_PUSH (U8, 0); -#define I() STACK_HEAD (U8, 2) -#define J() STACK_TOP (U8) -#define SET_I(S) STACK_SET_HEAD (U8, 2, (uint8_t) (S)) -#define SET_J(S) STACK_SET_HEAD (U8, 1, (uint8_t) (S)) - + va_list insides_list; if (STACK_SIZE(nestings) == 0) { EMIT_ERROR ("Shall be inside a nesting"); } - SET_I(STACK_SIZE(nestings)); - while (I() != 0) + va_start (insides_list, insides_count); + uint8_t *insides = mem_heap_alloc_block (insides_count, MEM_HEAP_ALLOC_SHORT_TERM); + for (uint8_t i = 0; i < insides_count; i++) { - if (STACK_ELEMENT (nestings, I() - 1) == not_in) + insides[i] = (uint8_t) va_arg (insides_list, int); + } + va_end (insides_list); + + for (uint8_t i = (uint8_t) STACK_SIZE (nestings); i != 0; i--) + { + for (uint8_t j = 0; j < insides_count; j++) + { + if (insides[j] == STACK_ELEMENT (nestings, i - 1)) + { + mem_heap_free_block (insides); + return; + } + } + if (STACK_ELEMENT (nestings, i - 1) == not_in) { EMIT_ERROR_VARG ("Shall not be inside a '%s' nesting", NESTING_TO_STRING(not_in)); } - - SET_J(0); - while (J() < insides_count) - { - if (STACK_ELEMENT (nestings, I() - 1) == inside[J()]) - { - goto cleanup; - } - SET_J(J()+1); - } - SET_I(I()-1); } - - switch (insides_count) - { - case 1: EMIT_ERROR_VARG ("Shall be inside a '%s' nesting", NESTING_TO_STRING(inside[0])); break; - case 2: EMIT_ERROR_VARG ("Shall be inside '%s' or '%s' nestings", - NESTING_TO_STRING(inside[0]), NESTING_TO_STRING(inside[1])); break; - default: JERRY_UNREACHABLE (); - } - -cleanup: - STACK_DROP (U8, 2); -#undef I -#undef J -#undef SET_I -#undef SET_J - STACK_CHECK_USAGE (U8); + EMIT_ERROR ("Shall be inside a nesting"); } static bool token_is (token_type tt) { - return TOK ().type == tt; + return tok.type == tt; } -static uint8_t +static literal_index_t token_data (void) { - return TOK ().uid; + return tok.uid; } static void skip_token (void) { - SET_TOK(lexer_next_token ()); + tok = lexer_next_token (); } static void @@ -515,227 +199,49 @@ token_after_newlines_must_be_keyword (keyword kw) } } -static void -boolean_true (void) -{ - STACK_DECLARE_USAGE (IDX) - - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_TRUE); - - STACK_CHECK_USAGE_LHS (); -} - -static void -add_to_rewritable_opcodes (rewritable_opcode_type type, opcode_counter_t oc) -{ - switch (type) - { - case REWRITABLE_BREAK: STACK_PUSH (rewritable_break, oc); break; - case REWRITABLE_CONTINUE: STACK_PUSH (rewritable_continue, oc); break; - default: JERRY_UNREACHABLE (); - } -} - -static void -rewrite_breaks (opcode_counter_t break_oc, opcode_counter_t dest_oc) -{ - REWRITE_JMP (break_oc, jmp_down, dest_oc - break_oc); -} - -static void -rewrite_continues (opcode_counter_t cont_oc, opcode_counter_t dest_oc) -{ - if (cont_oc > dest_oc) - { - REWRITE_JMP (cont_oc, jmp_up, cont_oc - dest_oc); - } - else - { - // in case of do-while loop we must jump to condition - REWRITE_JMP (cont_oc, jmp_down, dest_oc - cont_oc); - } -} - -static void -rewrite_rewritable_opcodes (rewritable_opcode_type type, uint8_t from, opcode_counter_t oc) -{ - STACK_DECLARE_USAGE (U8) - - STACK_PUSH (U8, 0); - - switch (type) - { - case REWRITABLE_BREAK: - { - STACK_ITERATE_VARG (rewritable_break, rewrite_breaks, from, oc); - STACK_DROP (rewritable_break, STACK_SIZE (rewritable_break) - from); - break; - } - case REWRITABLE_CONTINUE: - { - STACK_ITERATE_VARG (rewritable_continue, rewrite_continues, from, oc); - STACK_DROP (rewritable_continue, STACK_SIZE (rewritable_continue) - from); - break; - } - default: JERRY_UNREACHABLE (); - } - - STACK_DROP (U8, 1); - - STACK_CHECK_USAGE (U8); -} - -static void -dump_assert (idx_t arg) -{ - DUMP_OPCODE_3 (is_true_jmp_down, arg, 0, 2); - DUMP_OPCODE_1 (exitval, 1); -} - static bool -is_intrinsic (idx_t obj) +is_strict_mode (void) { - /* 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. */ - // U8 strs - bool result = false; - - STACK_DECLARE_USAGE (U8) - - STACK_PUSH (U8, lexer_get_literals_count ()); - if (obj < STACK_TOP (U8)) - { - if (literal_equal_type_s (lexer_get_literal_by_id (obj), "assert")) - { - result = true; - goto cleanup; - } - } - -cleanup: - STACK_DROP (U8, 1); - - STACK_CHECK_USAGE (U8); - return result; -} - -static void -dump_intrinsic (idx_t obj, idx_t arg) -{ - if (obj < lexer_get_literals_count ()) - { - if (literal_equal_type_s (lexer_get_literal_by_id (obj), "assert")) - { - dump_assert (arg); - return; - } - } - - JERRY_UNREACHABLE (); -} - -static idx_t -name_to_native_call_id (idx_t obj) -{ - if (obj >= lexer_get_literals_count ()) - { - return OPCODE_NATIVE_CALL__COUNT; - } - if (literal_equal_type_s (lexer_get_literal_by_id (obj), "LEDToggle")) - { - return OPCODE_NATIVE_CALL_LED_TOGGLE; - } - else if (literal_equal_type_s (lexer_get_literal_by_id (obj), "LEDOn")) - { - return OPCODE_NATIVE_CALL_LED_ON; - } - else if (literal_equal_type_s (lexer_get_literal_by_id (obj), "LEDOff")) - { - return OPCODE_NATIVE_CALL_LED_OFF; - } - else if (literal_equal_type_s (lexer_get_literal_by_id (obj), "LEDOnce")) - { - return OPCODE_NATIVE_CALL_LED_ONCE; - } - else if (literal_equal_type_s (lexer_get_literal_by_id (obj), "wait")) - { - return OPCODE_NATIVE_CALL_WAIT; - } - else if (literal_equal_type_s (lexer_get_literal_by_id (obj), "print")) - { - return OPCODE_NATIVE_CALL_PRINT; - } - return OPCODE_NATIVE_CALL__COUNT; -} - -static bool -is_native_call (idx_t obj) -{ - return name_to_native_call_id (obj) < OPCODE_NATIVE_CALL__COUNT; -} - -static prop_literal -create_prop_literal (literal lit, prop_type type) -{ - return (prop_literal) - { - .type = type, - .lit = lit - }; + return scopes_tree_strict_mode (STACK_TOP (scopes)); } /* property_name : Identifier + | Keyword | StringLiteral | NumericLiteral - ; */ -static void + ; +*/ +static operand parse_property_name (void) { - STACK_DECLARE_USAGE (IDX) - - switch (TOK ().type) + switch (tok.type) { case TOK_NAME: case TOK_STRING: - { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_STRING, token_data ()); - STACK_PUSH (literals, lexer_get_literal_by_id (token_data ())); - break; - } case TOK_NUMBER: { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_NUMBER, token_data ()); - STACK_PUSH (literals, lexer_get_literal_by_id (token_data ())); - break; + return literal_operand (token_data ()); } case TOK_SMALL_INT: { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_SMALLINT, token_data ()); - STACK_PUSH (literals, create_literal_from_num ((ecma_number_t) token_data ())); - break; + const literal lit = create_literal_from_num ((ecma_number_t) token_data ()); + lexer_add_literal_if_not_present (lit); + const literal_index_t lit_id = lexer_lookup_literal_uid (lit); + return literal_operand (lit_id); } case TOK_KEYWORD: { - literal lit = create_literal_from_str_compute_len (lexer_keyword_to_string (token_data ())); - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_STRING, - lexer_lookup_literal_uid (lit)); - STACK_PUSH (literals, lit); - break; + const literal lit = create_literal_from_str_compute_len (lexer_keyword_to_string (token_data ())); + lexer_add_literal_if_not_present (lit); + const literal_index_t lit_id = lexer_lookup_literal_uid (lit); + return literal_operand (lit_id); } default: { - JERRY_UNREACHABLE (); + EMIT_ERROR_VARG ("Wrong property name type: %s", lexer_token_type_to_string (tok.type)); } } - - STACK_CHECK_USAGE_LHS (); } /* property_name_and_value @@ -744,58 +250,12 @@ parse_property_name (void) static void parse_property_name_and_value (void) { - // IDX lhs, name, expr - STACK_DECLARE_USAGE (IDX) - - parse_property_name (); // push name - + const operand name = parse_property_name (); token_after_newlines_must_be (TOK_COLON); - NEXT (assignment_expression); // push expr - - DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_VARG_PROP_DATA, STACK_HEAD(IDX, 2), STACK_HEAD(IDX, 1)); - - STACK_PUSH (props, create_prop_literal (STACK_TOP (literals), PROP_DATA)); - STACK_DROP (literals, 1); - - STACK_DROP (IDX, 2); - STACK_CHECK_USAGE (IDX); -} - -static void -rewrite_meta_opcode_counter_set_oc (opcode_counter_t meta_oc, opcode_meta_type type, opcode_counter_t oc) -{ - // IDX oc_idx_1, oc_idx_2 - STACK_DECLARE_USAGE (IDX) - - JERRY_STATIC_ASSERT (sizeof (idx_t) == 1); - - STACK_PUSH (IDX, (idx_t) (oc >> JERRY_BITSINBYTE)); - STACK_PUSH (IDX, (idx_t) (oc & ((1 << JERRY_BITSINBYTE) - 1))); - - JERRY_ASSERT (oc == calc_opcode_counter_from_idx_idx (ID(2), ID(1))); - - REWRITE_OPCODE_3 (meta_oc, meta, type, ID(2), ID(1)); - - STACK_DROP (IDX, 2); - - STACK_CHECK_USAGE (IDX); -} - -static void -rewrite_meta_opcode_counter (opcode_counter_t meta_oc, opcode_meta_type type) -{ - rewrite_meta_opcode_counter_set_oc (meta_oc, type, (opcode_counter_t) (OPCODE_COUNTER () - meta_oc)); -} - -static void -generate_tmp_for_left_arg (void) -{ - STACK_DECLARE_USAGE (IDX); - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_VARIABLE, ID(2)); - STACK_SWAP (IDX); - STACK_DROP (IDX, 1); - STACK_CHECK_USAGE (IDX); + skip_newlines (); + const operand value = parse_assignment_expression (true); + dump_prop_name_and_value (name, value); + syntax_add_prop_name (name, PROP_DATA); } /* property_assignment @@ -806,11 +266,7 @@ generate_tmp_for_left_arg (void) static void parse_property_assignment (void) { - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (U16) - STACK_DECLARE_USAGE (toks) - STACK_DECLARE_USAGE (U8) - STACK_DECLARE_USAGE (literals) + STACK_DECLARE_USAGE (nestings); if (!token_is (TOK_NAME)) { @@ -818,471 +274,226 @@ parse_property_assignment (void) goto cleanup; } + bool is_setter; + if (literal_equal_type_s (lexer_get_literal_by_id (token_data ()), "get")) { - STACK_PUSH (toks, TOK ()); - skip_newlines (); - if (token_is (TOK_COLON)) - { - lexer_save_token (TOK ()); - SET_TOK (STACK_TOP (toks)); - STACK_DROP (toks, 1); - goto simple_prop; - } - STACK_DROP (toks, 1); - // name, lhs - parse_property_name (); // push name - STACK_PUSH (props, create_prop_literal (STACK_TOP (literals), PROP_GET)); - STACK_DROP (literals, 1); - - skip_newlines (); - parse_argument_list (AL_FUNC_EXPR, next_temp_name ()); // push lhs - - STACK_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); - - STACK_PUSH (U8, scopes_tree_strict_mode (STACK_TOP (scopes)) ? 1 : 0); - scopes_tree_set_strict_mode (STACK_TOP (scopes), false); - - skip_newlines (); - push_nesting (NESTING_FUNCTION); - parse_source_element_list (false); - pop_nesting (NESTING_FUNCTION); - - scopes_tree_set_strict_mode (STACK_TOP (scopes), STACK_TOP (U8) != 0); - STACK_DROP (U8, 1); - - token_after_newlines_must_be (TOK_CLOSE_BRACE); - - DUMP_VOID_OPCODE (ret); - rewrite_meta_opcode_counter (STACK_TOP (U16), OPCODE_META_TYPE_FUNCTION_END); - DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_VARG_PROP_GETTER, ID(2), ID(1)); - - STACK_DROP (IDX, 2); - STACK_DROP (U16, 1); - - goto cleanup; + is_setter = false; } else if (literal_equal_type_s (lexer_get_literal_by_id (token_data ()), "set")) { - STACK_PUSH (toks, TOK ()); - skip_newlines (); - if (token_is (TOK_COLON)) - { - lexer_save_token (TOK ()); - SET_TOK (STACK_TOP (toks)); - STACK_DROP (toks, 1); - goto simple_prop; - } - STACK_DROP (toks, 1); - // name, lhs - parse_property_name (); // push name - STACK_PUSH (props, create_prop_literal (STACK_TOP (literals), PROP_SET)); - STACK_DROP (literals, 1); - - skip_newlines (); - parse_argument_list (AL_FUNC_EXPR, next_temp_name ()); // push lhs - - STACK_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); - - STACK_PUSH (U8, scopes_tree_strict_mode (STACK_TOP (scopes)) ? 1 : 0); - scopes_tree_set_strict_mode (STACK_TOP (scopes), false); - - skip_newlines (); - push_nesting (NESTING_FUNCTION); - parse_source_element_list (false); - pop_nesting (NESTING_FUNCTION); - - scopes_tree_set_strict_mode (STACK_TOP (scopes), STACK_TOP (U8) != 0); - STACK_DROP (U8, 1); - - token_after_newlines_must_be (TOK_CLOSE_BRACE); - - DUMP_VOID_OPCODE (ret); - rewrite_meta_opcode_counter (STACK_TOP (U16), OPCODE_META_TYPE_FUNCTION_END); - DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_VARG_PROP_SETTER, ID(2), ID(1)); - - STACK_DROP (IDX, 2); - STACK_DROP (U16, 1); - - goto cleanup; + is_setter = true; } + else + { + goto simple_prop; + } + + const token temp = tok; + skip_newlines (); + if (token_is (TOK_COLON)) + { + lexer_save_token (tok); + tok = temp; + goto simple_prop; + } + + const operand name = parse_property_name (); + syntax_add_prop_name (name, is_setter ? PROP_SET : PROP_GET); + + skip_newlines (); + const operand func = parse_argument_list (VARG_FUNC_EXPR, name, NULL, NULL); + + dump_function_end_for_rewrite (); + + const bool is_strict = scopes_tree_strict_mode (STACK_TOP (scopes)); + scopes_tree_set_strict_mode (STACK_TOP (scopes), false); + + token_after_newlines_must_be (TOK_OPEN_BRACE); + skip_newlines (); + push_nesting (NESTING_FUNCTION); + parse_source_element_list (false); + pop_nesting (NESTING_FUNCTION); + token_after_newlines_must_be (TOK_CLOSE_BRACE); + + scopes_tree_set_strict_mode (STACK_TOP (scopes), is_strict); + + dump_ret (); + rewrite_function_end (VARG_FUNC_EXPR); + if (is_setter) + { + dump_prop_setter_decl (name, func); + } + else + { + dump_prop_getter_decl (name, func); + } + goto cleanup; simple_prop: parse_property_name_and_value (); cleanup: - STACK_CHECK_USAGE (literals); - STACK_CHECK_USAGE (U8); - STACK_CHECK_USAGE (toks); - STACK_CHECK_USAGE (U16); - STACK_CHECK_USAGE (IDX); -} - -static void -emit_error_on_eval_and_arguments (idx_t id) -{ - if (id < lexer_get_literals_count ()) - { - if (literal_equal_type_zt (lexer_get_literal_by_id (id), - ecma_get_magic_string_zt (ECMA_MAGIC_STRING_ARGUMENTS)) - || literal_equal_type_zt (lexer_get_literal_by_id (id), - ecma_get_magic_string_zt (ECMA_MAGIC_STRING_EVAL))) - { - EMIT_ERROR ("'eval' and 'arguments' are not allowed here in strict mode"); - } - } -} - -static void -check_for_eval_and_arguments_in_strict_mode (idx_t id) -{ - if (parser_strict_mode ()) - { - emit_error_on_eval_and_arguments (id); - } -} - -/* 13.1, 15.3.2 */ -static void -check_for_syntax_errors_in_formal_param_list (uint8_t from) -{ - if (STACK_SIZE (props) - from < 2 || !parser_strict_mode ()) - { - return; - } - for (uint8_t i = (uint8_t) (from + 1); i < STACK_SIZE (props); i = (uint8_t) (i + 1)) - { - JERRY_ASSERT (STACK_ELEMENT (props, i).type == VARG); - const literal previous = STACK_ELEMENT (props, i).lit; - JERRY_ASSERT (previous.type == LIT_STR || previous.type == LIT_MAGIC_STR); - for (uint8_t j = from; j < i; j = (uint8_t) (j + 1)) - { - JERRY_ASSERT (STACK_ELEMENT (props, j).type == VARG); - const literal current = STACK_ELEMENT (props, j).lit; - JERRY_ASSERT (current.type == LIT_STR || current.type == LIT_MAGIC_STR); - if (literal_equal_type (previous, current)) - { - EMIT_ERROR_VARG ("Duplication of literal '%s' in FormalParameterList is not allowed in strict mode", - (const char *) literal_to_zt (previous)); - } - } - } -} - -/* 11.1.5 */ -static void -check_for_syntax_errors_in_obj_decl (uint8_t from) -{ - if (STACK_SIZE (props) - from < 2) - { - return; - } - - for (uint8_t i = (uint8_t) (from + 1); i < STACK_SIZE (props); i = (uint8_t) (i + 1)) - { - const prop_literal previous = STACK_ELEMENT (props, i); - JERRY_ASSERT (previous.type == PROP_DATA - || previous.type == PROP_GET - || previous.type == PROP_SET); - for (uint8_t j = from; j < i; j = (uint8_t) (j + 1)) - { - /*4*/ - const prop_literal current = STACK_ELEMENT (props, j); - JERRY_ASSERT (current.type == PROP_DATA - || current.type == PROP_GET - || current.type == PROP_SET); - if (literal_equal (previous.lit, current.lit)) - { - /*a*/ - if (parser_strict_mode () && previous.type == PROP_DATA && current.type == PROP_DATA) - { - EMIT_ERROR_VARG ("Duplication of parameter name '%s' in ObjectDeclaration is not allowed in strict mode", - (const char *) literal_to_zt (current.lit)); - } - /*b*/ - if (previous.type == PROP_DATA - && (current.type == PROP_SET || current.type == PROP_GET)) - { - EMIT_ERROR_VARG ("Parameter name '%s' in ObjectDeclaration may not be both data and accessor", - (const char *) literal_to_zt (current.lit)); - } - /*c*/ - if (current.type == PROP_DATA - && (previous.type == PROP_SET || previous.type == PROP_GET)) - { - EMIT_ERROR_VARG ("Parameter name '%s' in ObjectDeclaration may not be both data and accessor", - (const char *) literal_to_zt (current.lit)); - } - /*d*/ - if ((previous.type == PROP_SET && current.type == PROP_SET) - || (previous.type == PROP_GET && current.type == PROP_GET)) - { - EMIT_ERROR_VARG ("Parameter name '%s' in ObjectDeclaration may not be accessor of same type", - (const char *) literal_to_zt (current.lit)); - } - } - } - } + STACK_CHECK_USAGE (nestings); } /** Parse list of identifiers, assigment expressions or properties, splitted by comma. For each ALT dumps appropriate bytecode. Uses OBJ during dump if neccesary. - Returns number of arguments. */ -static uint8_t -parse_argument_list (argument_list_type alt, idx_t obj) + Result tmp. */ +static operand +parse_argument_list (varg_list_type vlt, operand obj, uint8_t *args_count, operand *this_arg) { - // U8 open_tt, close_tt, args_count - // IDX lhs, current_arg - // U16 oc - STACK_DECLARE_USAGE (U8) - STACK_DECLARE_USAGE (U16) - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (temp_names) - STACK_DECLARE_USAGE (props) + token_type close_tt = TOK_CLOSE_PAREN; + uint8_t args_num = 0; - STACK_PUSH (U8, STACK_SIZE (props)); - STACK_PUSH (U8, TOK_OPEN_PAREN); - STACK_PUSH (U8, TOK_CLOSE_PAREN); - STACK_PUSH (U8, 0); - - STACK_PUSH (U16, OPCODE_COUNTER ()); - switch (alt) + switch (vlt) { - case AL_FUNC_DECL: + case VARG_FUNC_DECL: + case VARG_FUNC_EXPR: { - DUMP_OPCODE_2 (func_decl_n, obj, INVALID_VALUE); + syntax_start_checking_of_vargs (); + /* FALLTHRU */ + } + case VARG_CONSTRUCT_EXPR: + { + current_token_must_be (TOK_OPEN_PAREN); + dump_varg_header_for_rewrite (vlt, obj); break; } - case AL_FUNC_EXPR: + case VARG_CALL_EXPR: { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (func_expr_n, ID(1), obj, INVALID_VALUE); - break; - } - case AL_CONSTRUCT_EXPR: - { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (construct_n, ID(1), obj, INVALID_VALUE); - break; - } - case AL_CALL_EXPR: - { - if (is_intrinsic (obj)) + current_token_must_be (TOK_OPEN_PAREN); + if (dumper_is_intrinsic (obj)) { break; } - else if (is_native_call (obj)) + if (this_arg != NULL && this_arg->type == OPERAND_LITERAL) { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (native_call, ID(1), - name_to_native_call_id (obj), INVALID_VALUE); - } - else - { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (call_n, ID(1), obj, INVALID_VALUE); + *this_arg = dump_variable_assignment_res (*this_arg); } + dump_varg_header_for_rewrite (vlt, obj); break; } - case AL_ARRAY_DECL: + case VARG_ARRAY_DECL: { - STACK_SET_HEAD (U8, 3, TOK_OPEN_SQUARE); - STACK_SET_HEAD (U8, 2, TOK_CLOSE_SQUARE); - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_2 (array_decl, ID(1), INVALID_VALUE); + current_token_must_be (TOK_OPEN_SQUARE); + close_tt = TOK_CLOSE_SQUARE; + dump_varg_header_for_rewrite (vlt, obj); break; } - case AL_OBJ_DECL: + case VARG_OBJ_DECL: { - STACK_SET_HEAD (U8, 3, TOK_OPEN_BRACE); - STACK_SET_HEAD (U8, 2, TOK_CLOSE_BRACE); - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_2 (obj_decl, ID(1), INVALID_VALUE); + current_token_must_be (TOK_OPEN_BRACE); + close_tt = TOK_CLOSE_BRACE; + dump_varg_header_for_rewrite (vlt, obj); + syntax_start_checking_of_prop_names (); break; } - default: - { - JERRY_UNREACHABLE (); - } } - - current_token_must_be (STACK_HEAD (U8, 3)); - - switch (alt) + if (vlt == VARG_CALL_EXPR && this_arg != NULL && !operand_is_empty (*this_arg)) { - case AL_CALL_EXPR: - { - if (THIS_ARG () != INVALID_VALUE) - { - DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_THIS_ARG, THIS_ARG (), INVALID_VALUE); - STACK_INCR_HEAD (U8, 1); - } - break; - } - default: break; + dump_this_arg (*this_arg); + args_num++; } - STACK_PUSH (temp_names, TEMP_NAME ()); - skip_newlines (); - while (!token_is (STACK_HEAD (U8, 2))) + while (!token_is (close_tt)) { - STACK_SET_ELEMENT (temp_names, temp_name, STACK_TOP (temp_names)); - switch (alt) + operand op; + switch (vlt) { - case AL_FUNC_DECL: - case AL_FUNC_EXPR: + case VARG_FUNC_DECL: + case VARG_FUNC_EXPR: { current_token_must_be (TOK_NAME); - STACK_PUSH (IDX, token_data ()); - STACK_PUSH (props, - create_prop_literal (lexer_get_literal_by_id (token_data ()), - VARG)); - check_for_eval_and_arguments_in_strict_mode (STACK_TOP (IDX)); + op = literal_operand (token_data ()); + syntax_add_varg (op); + syntax_check_for_eval_and_arguments_in_strict_mode (op, is_strict_mode (), tok.loc); break; } - case AL_ARRAY_DECL: + case VARG_ARRAY_DECL: { if (token_is (TOK_COMMA)) { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_UNDEFINED); - DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_VARG, ID(1), INVALID_VALUE); - STACK_INCR_HEAD(U8, 1); - STACK_DROP (IDX, 1); + op = dump_undefined_assignment_res (); + dump_varg (op); + args_num++; skip_newlines (); continue; } /* FALLTHRU */ } - case AL_CONSTRUCT_EXPR: + case VARG_CONSTRUCT_EXPR: { - parse_assignment_expression (); + op = parse_assignment_expression (true); break; } - case AL_CALL_EXPR: + case VARG_CALL_EXPR: { - parse_assignment_expression (); - if (is_intrinsic (obj)) + op = parse_assignment_expression (true); + if (dumper_is_intrinsic (obj)) { - dump_intrinsic (obj, ID(1)); - goto next; + operand res = dump_intrinsic (obj, op); + token_after_newlines_must_be (close_tt); + return res; } break; } - case AL_OBJ_DECL: + case VARG_OBJ_DECL: { parse_property_assignment (); break; } - default: - { - JERRY_UNREACHABLE (); - } } - if (alt != AL_OBJ_DECL) + /* In case of obj_decl prop is already dumped. */ + if (vlt != VARG_OBJ_DECL) { - DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_VARG, ID(1), INVALID_VALUE); - STACK_DROP (IDX, 1); + dump_varg (op); } - STACK_INCR_HEAD(U8, 1); + args_num++; -next: skip_newlines (); if (!token_is (TOK_COMMA)) { - current_token_must_be (STACK_HEAD (U8, 2)); + current_token_must_be (close_tt); break; } skip_newlines (); } - STACK_DROP (temp_names, 1); - switch (alt) + if (args_count != NULL) { - case AL_FUNC_DECL: - { - check_for_syntax_errors_in_formal_param_list (STACK_HEAD (U8, 4)); - REWRITE_OPCODE_2 (STACK_TOP (U16), func_decl_n, obj, STACK_TOP (U8)); - break; - } - case AL_FUNC_EXPR: - { - check_for_syntax_errors_in_formal_param_list (STACK_HEAD (U8, 4)); - REWRITE_OPCODE_3 (STACK_TOP (U16), func_expr_n, ID(1), obj, STACK_TOP (U8)); - break; - } - case AL_CONSTRUCT_EXPR: - { - REWRITE_OPCODE_3 (STACK_TOP (U16), construct_n, ID(1), obj, STACK_TOP (U8)); - break; - } - case AL_CALL_EXPR: - { - if (is_intrinsic (obj)) - { - break; - } - else if (is_native_call (obj)) - { - REWRITE_OPCODE_3 (STACK_TOP (U16), native_call, ID(1), - name_to_native_call_id (obj), STACK_TOP (U8)); - } - else - { - REWRITE_OPCODE_3 (STACK_TOP (U16), call_n, ID(1), obj, - STACK_TOP (U8)); - } - break; - } - case AL_ARRAY_DECL: - { - REWRITE_OPCODE_2 (STACK_TOP (U16), array_decl, ID(1), STACK_TOP (U8)); - break; - } - case AL_OBJ_DECL: - { - check_for_syntax_errors_in_obj_decl (STACK_HEAD (U8, 4)); - REWRITE_OPCODE_2 (STACK_TOP (U16), obj_decl, ID(1), STACK_TOP (U8)); - break; - } - default: - { - JERRY_UNREACHABLE (); - } + *args_count = args_num; } - const uint8_t args_num = STACK_TOP (U8); - - STACK_DROP (props, (uint8_t) (STACK_SIZE (props) - STACK_HEAD (U8, 4))); - STACK_DROP (U8, 4); - STACK_DROP (U16, 1); - - STACK_CHECK_USAGE (props); - STACK_CHECK_USAGE (U8); - STACK_CHECK_USAGE (U16); - STACK_CHECK_USAGE (temp_names); - -#ifndef JERRY_NDEBUG - if (alt == AL_FUNC_DECL) + operand res; + switch (vlt) { - STACK_CHECK_USAGE (IDX); + case VARG_FUNC_DECL: + case VARG_FUNC_EXPR: + { + syntax_check_for_syntax_errors_in_formal_param_list (is_strict_mode (), tok.loc); + res = rewrite_varg_header_set_args_count (args_num); + break; + } + case VARG_CONSTRUCT_EXPR: + case VARG_ARRAY_DECL: + case VARG_CALL_EXPR: + { + /* Intrinsics are already processed. */ + res = rewrite_varg_header_set_args_count (args_num); + break; + } + case VARG_OBJ_DECL: + { + syntax_check_for_duplication_of_prop_names (is_strict_mode (), tok.loc); + res = rewrite_varg_header_set_args_count (args_num); + break; + } } - else - { - STACK_CHECK_USAGE_LHS (); - } -#endif - - return args_num; + return res; } /* function_declaration @@ -1295,30 +506,22 @@ next: static void parse_function_declaration (void) { - // IDX name - // U16 meta_oc - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (U16) - STACK_DECLARE_USAGE (nestings) - STACK_DECLARE_USAGE (scopes) - STACK_DECLARE_USAGE (U8) + STACK_DECLARE_USAGE (scopes); + STACK_DECLARE_USAGE (nestings); assert_keyword (KW_FUNCTION); token_after_newlines_must_be (TOK_NAME); - - STACK_PUSH (IDX, token_data ()); + const operand name = literal_operand (token_data ()); skip_newlines (); - SET_OPCODE_COUNTER (0); STACK_PUSH (scopes, scopes_tree_init (STACK_TOP (scopes))); serializer_set_scope (STACK_TOP (scopes)); scopes_tree_set_strict_mode (STACK_TOP (scopes), scopes_tree_strict_mode (STACK_HEAD (scopes, 2))); - STACK_PUSH (U8, parse_argument_list (AL_FUNC_DECL, ID(1))); - scopes_tree_set_strict_mode (STACK_TOP (scopes), false); + lexer_set_strict_mode (scopes_tree_strict_mode (STACK_TOP (scopes))); + parse_argument_list (VARG_FUNC_DECL, name, NULL, NULL); - STACK_PUSH (U16, OPCODE_COUNTER ()); - DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_UNDEFINED, INVALID_VALUE, INVALID_VALUE); + dump_function_end_for_rewrite (); token_after_newlines_must_be (TOK_OPEN_BRACE); @@ -1329,158 +532,100 @@ parse_function_declaration (void) next_token_must_be (TOK_CLOSE_BRACE); - DUMP_VOID_OPCODE (ret); + dump_ret (); + rewrite_function_end (VARG_FUNC_DECL); - rewrite_meta_opcode_counter_set_oc (STACK_TOP (U16), OPCODE_META_TYPE_FUNCTION_END, - (opcode_counter_t) ( - scopes_tree_count_opcodes (STACK_TOP (scopes)) - (STACK_TOP (U8) + 1))); - - STACK_DROP (U16, 1); - STACK_DROP (U8, 1); - STACK_DROP (IDX, 1); STACK_DROP (scopes, 1); - SET_OPCODE_COUNTER (scopes_tree_opcodes_num (STACK_TOP (scopes))); serializer_set_scope (STACK_TOP (scopes)); + lexer_set_strict_mode (scopes_tree_strict_mode (STACK_TOP (scopes))); - STACK_CHECK_USAGE (U8); - STACK_CHECK_USAGE (IDX); - STACK_CHECK_USAGE (U16); - STACK_CHECK_USAGE (nestings); STACK_CHECK_USAGE (scopes); + STACK_CHECK_USAGE (nestings); } /* function_expression : 'function' LT!* Identifier? LT!* '(' formal_parameter_list? LT!* ')' LT!* function_body ; */ -static void +static operand parse_function_expression (void) { - // IDX lhs, name - // U16 meta_oc - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (U16) STACK_DECLARE_USAGE (nestings) - STACK_DECLARE_USAGE (U8) assert_keyword (KW_FUNCTION); + operand res; + skip_newlines (); if (token_is (TOK_NAME)) { - STACK_PUSH (IDX, token_data ()); + const operand name = literal_operand (token_data ()); + skip_newlines (); + res = parse_argument_list (VARG_FUNC_EXPR, name, NULL, NULL); } else { - lexer_save_token (TOK()); - STACK_PUSH (IDX, next_temp_name ()); + lexer_save_token (tok); + skip_newlines (); + res = parse_argument_list (VARG_FUNC_EXPR, empty_operand (), NULL, NULL); } - skip_newlines (); - parse_argument_list (AL_FUNC_EXPR, ID(1)); // push lhs - - STACK_PUSH (U16, OPCODE_COUNTER ()); - DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_UNDEFINED, INVALID_VALUE, INVALID_VALUE); + dump_function_end_for_rewrite (); token_after_newlines_must_be (TOK_OPEN_BRACE); - - STACK_PUSH (U8, scopes_tree_strict_mode (STACK_TOP (scopes)) ? 1 : 0); - scopes_tree_set_strict_mode (STACK_TOP (scopes), false); - skip_newlines (); push_nesting (NESTING_FUNCTION); parse_source_element_list (false); pop_nesting (NESTING_FUNCTION); - - scopes_tree_set_strict_mode (STACK_TOP (scopes), STACK_TOP (U8) != 0); - STACK_DROP (U8, 1); - next_token_must_be (TOK_CLOSE_BRACE); - DUMP_VOID_OPCODE (ret); - rewrite_meta_opcode_counter (STACK_TOP (U16), OPCODE_META_TYPE_FUNCTION_END); + dump_ret (); + rewrite_function_end (VARG_FUNC_EXPR); - STACK_SWAP (IDX); - STACK_DROP (IDX, 1); - STACK_DROP (U16, 1); - - STACK_CHECK_USAGE (U8); - STACK_CHECK_USAGE (U16); - STACK_CHECK_USAGE_LHS (); STACK_CHECK_USAGE (nestings); + + return res; } /* array_literal : '[' LT!* assignment_expression? (LT!* ',' (LT!* assignment_expression)?)* LT!* ']' LT!* ; */ -static void +static operand parse_array_literal (void) { - STACK_DECLARE_USAGE (IDX) - - parse_argument_list (AL_ARRAY_DECL, 0); - - STACK_CHECK_USAGE_LHS (); + return parse_argument_list (VARG_ARRAY_DECL, empty_operand (), NULL, NULL); } /* object_literal : '{' LT!* property_assignment (LT!* ',' LT!* property_assignment)* LT!* '}' ; */ -static void +static operand parse_object_literal (void) { - STACK_DECLARE_USAGE (IDX) - - parse_argument_list (AL_OBJ_DECL, 0); - - STACK_CHECK_USAGE_LHS ();; + return parse_argument_list (VARG_OBJ_DECL, empty_operand (), NULL, NULL); } -static void +/* literal + : 'null' + | 'true' + | 'false' + | number_literal + | string_literal + ; */ +static operand parse_literal (void) { - // IDX lhs; - STACK_DECLARE_USAGE (IDX) - - switch (TOK ().type) + switch (tok.type) { - case TOK_NULL: - { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_NULL); - break; - } - case TOK_BOOL: - { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_SIMPLE, - token_data () ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); - break; - } - case TOK_NUMBER: - { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_NUMBER, token_data ()); - break; - } - case TOK_SMALL_INT: - { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_SMALLINT, token_data ()); - break; - } - case TOK_STRING: - { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_STRING, token_data ()); - break; - } + case TOK_NUMBER: return dump_number_assignment_res (token_data ()); + case TOK_STRING: return dump_string_assignment_res (token_data ()); + case TOK_NULL: return dump_null_assignment_res (); + case TOK_BOOL: return dump_boolean_assignment_res ((bool) token_data ()); + case TOK_SMALL_INT: return dump_smallint_assignment_res ((idx_t) token_data ()); default: { - JERRY_UNREACHABLE (); + EMIT_ERROR ("Expected literal"); } } - - STACK_CHECK_USAGE_LHS (); } /* primary_expression @@ -1492,64 +637,40 @@ parse_literal (void) | '{' LT!* object_literal LT!* '}' | '(' LT!* expression LT!* ')' ; */ -static void +static operand parse_primary_expression (void) { - // IDX lhs; - STACK_DECLARE_USAGE (IDX) - if (is_keyword (KW_THIS)) { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_1 (this, ID(1)); - goto cleanup; + return dump_this_res (); } - switch (TOK ().type) + switch (tok.type) { - case TOK_NAME: - { - STACK_PUSH (IDX, token_data ()); - break; - } case TOK_NULL: case TOK_BOOL: case TOK_SMALL_INT: case TOK_NUMBER: - case TOK_STRING: - { - parse_literal (); - break; - } - case TOK_OPEN_SQUARE: - { - parse_array_literal (); - break; - } - case TOK_OPEN_BRACE: - { - parse_object_literal (); - break; - } + case TOK_STRING: return parse_literal (); + case TOK_NAME: return literal_operand (token_data ()); + case TOK_OPEN_SQUARE: return parse_array_literal (); + case TOK_OPEN_BRACE: return parse_object_literal (); case TOK_OPEN_PAREN: { skip_newlines (); if (!token_is (TOK_CLOSE_PAREN)) { - parse_expression (); + operand res = parse_expression (true); token_after_newlines_must_be (TOK_CLOSE_PAREN); - break; + return res; } /* FALLTHRU */ } default: { - EMIT_ERROR_VARG ("Unknown token %s", lexer_token_type_to_string (TOK ().type)); + EMIT_ERROR_VARG ("Unknown token %s", lexer_token_type_to_string (tok.type)); } } - -cleanup: - STACK_CHECK_USAGE_LHS (); } /* member_expression @@ -1573,52 +694,45 @@ cleanup: property_reference_suffix : '.' LT!* Identifier ; */ -static void -parse_member_expression (void) +static operand +parse_member_expression (operand *this_arg, operand *prop_gl) { - // IDX obj, lhs, prop; - STACK_DECLARE_USAGE (IDX) - + operand expr; if (is_keyword (KW_FUNCTION)) { - parse_function_expression (); + expr = parse_function_expression (); } else if (is_keyword (KW_NEW)) { skip_newlines (); - parse_member_expression (); + expr = parse_member_expression (this_arg, prop_gl); skip_newlines (); if (token_is (TOK_OPEN_PAREN)) { - parse_argument_list (AL_CONSTRUCT_EXPR, ID(1)); // push obj + expr = parse_argument_list (VARG_CONSTRUCT_EXPR, expr, NULL, NULL); } else { - lexer_save_token (TOK ()); - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (construct_n, ID (1), ID (2), 0); + lexer_save_token (tok); + dump_varg_header_for_rewrite (VARG_CONSTRUCT_EXPR, expr); + expr = rewrite_varg_header_set_args_count (0); } - - STACK_SWAP (IDX); - STACK_DROP (IDX, 1); } else { - parse_primary_expression (); + expr = parse_primary_expression (); } skip_newlines (); while (token_is (TOK_OPEN_SQUARE) || token_is (TOK_DOT)) { - SET_THIS_ARG(ID (1)); - - STACK_PUSH (IDX, next_temp_name ()); + operand prop = empty_operand (); if (token_is (TOK_OPEN_SQUARE)) { - NEXT (expression); // push prop - SET_PROP (ID (1)); + skip_newlines (); + prop = parse_expression (true); next_token_must_be (TOK_CLOSE_SQUARE); } else if (token_is (TOK_DOT)) @@ -1626,44 +740,38 @@ parse_member_expression (void) skip_newlines (); if (token_is (TOK_NAME)) { - STACK_PUSH (IDX, next_temp_name ()); - SET_PROP (ID (1)); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_STRING, token_data ()); + prop = dump_string_assignment_res (token_data ()); } else if (token_is (TOK_KEYWORD)) { const literal lit = create_literal_from_str_compute_len (lexer_keyword_to_string (token_data ())); - const idx_t uid = lexer_lookup_literal_uid (lit); - if (uid == INVALID_VALUE) + const literal_index_t lit_id = lexer_lookup_literal_uid (lit); + if (lit_id == INVALID_LITERAL) { EMIT_ERROR ("Expected identifier"); } - STACK_PUSH (IDX, next_temp_name ()); - SET_PROP (ID (1)); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_STRING, uid); + prop = dump_string_assignment_res (lit_id); } else { EMIT_ERROR ("Expected identifier"); } } - else - { - JERRY_UNREACHABLE (); - } - - DUMP_OPCODE_3 (prop_getter, ID(2), ID(3), ID(1)); - STACK_DROP (IDX, 1); - STACK_SWAP (IDX); - skip_newlines (); - STACK_DROP (IDX, 1); + if (this_arg) + { + *this_arg = expr; + } + if (prop_gl) + { + *prop_gl = prop; + } + expr = dump_prop_getter_res (expr, prop); } - lexer_save_token (TOK ()); - - STACK_CHECK_USAGE_LHS (); + lexer_save_token (tok); + return expr; } /* call_expression @@ -1679,435 +787,423 @@ parse_member_expression (void) arguments : '(' LT!* assignment_expression LT!* (',' LT!* assignment_expression * LT!*)* ')' ; */ -static void -parse_call_expression (void) +static operand +parse_call_expression (operand *this_arg_gl, operand *prop_gl) { - // IDX obj, lhs, prop; - STACK_DECLARE_USAGE (IDX) - SET_THIS_ARG (INVALID_VALUE); - - parse_member_expression (); + operand this_arg = empty_operand (); + operand expr = parse_member_expression (&this_arg, prop_gl); + operand prop; skip_newlines (); if (!token_is (TOK_OPEN_PAREN)) { - lexer_save_token (TOK ()); - goto cleanup; + lexer_save_token (tok); + if (this_arg_gl != NULL) + { + *this_arg_gl = this_arg; + } + return expr; } - if (THIS_ARG () < lexer_get_literals_count ()) - { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_VARIABLE, THIS_ARG ()); - SET_THIS_ARG (ID(1)); - STACK_DROP (IDX, 1); - } - - parse_argument_list (AL_CALL_EXPR, ID(1)); // push lhs - SET_THIS_ARG (INVALID_VALUE); - STACK_SWAP (IDX); + expr = parse_argument_list (VARG_CALL_EXPR, expr, NULL, &this_arg); + this_arg = empty_operand (); skip_newlines (); while (token_is (TOK_OPEN_PAREN) || token_is (TOK_OPEN_SQUARE) || token_is (TOK_DOT)) { - STACK_DROP (IDX, 1); - if (TOK ().type == TOK_OPEN_PAREN) + if (tok.type == TOK_OPEN_PAREN) { - parse_argument_list (AL_CALL_EXPR, ID(1)); // push lhs + expr = parse_argument_list (VARG_CALL_EXPR, expr, NULL, &this_arg); skip_newlines (); } else { - SET_THIS_ARG (ID (1)); - if (TOK ().type == TOK_OPEN_SQUARE) + this_arg = expr; + if (tok.type == TOK_OPEN_SQUARE) { - NEXT (expression); // push prop + skip_newlines (); + prop = parse_expression (true); next_token_must_be (TOK_CLOSE_SQUARE); } - else if (TOK ().type == TOK_DOT) + else if (tok.type == TOK_DOT) { token_after_newlines_must_be (TOK_NAME); - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_STRING, token_data ()); + prop = dump_string_assignment_res (token_data ()); } - else - { - JERRY_UNREACHABLE (); - } - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (prop_getter, ID(1), ID(3), ID(2)); - STACK_SWAP (IDX); - STACK_DROP (IDX, 1); + expr = dump_prop_getter_res (expr, prop); skip_newlines (); } - STACK_SWAP (IDX); } - lexer_save_token (TOK ()); - - STACK_DROP (IDX, 1); - -cleanup: - STACK_CHECK_USAGE_LHS (); + lexer_save_token (tok); + if (this_arg_gl != NULL) + { + *this_arg_gl = this_arg; + } + if (prop_gl != NULL) + { + *prop_gl = prop; + } + return expr; } /* left_hand_side_expression : call_expression | new_expression ; */ -static void -parse_left_hand_side_expression (void) +static operand +parse_left_hand_side_expression (operand *this_arg, operand *prop) { - STACK_DECLARE_USAGE (IDX) - - parse_call_expression (); - - STACK_CHECK_USAGE_LHS (); + return parse_call_expression (this_arg, prop); } /* postfix_expression : left_hand_side_expression ('++' | '--')? ; */ -static void +static operand parse_postfix_expression (void) { - // IDX expr, lhs - STACK_DECLARE_USAGE (IDX) - SET_PROP (INVALID_VALUE); - - parse_left_hand_side_expression (); // push expr + operand this_arg = empty_operand (), prop = empty_operand (); + operand expr = parse_left_hand_side_expression (&this_arg, &prop); if (lexer_prev_token ().type == TOK_NEWLINE) { - goto cleanup; + return expr; } - check_for_eval_and_arguments_in_strict_mode (STACK_TOP (IDX)); + syntax_check_for_eval_and_arguments_in_strict_mode (expr, is_strict_mode (), tok.loc); skip_token (); if (token_is (TOK_DOUBLE_PLUS)) { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_2 (post_incr, ID(1), ID(2)); - if (THIS_ARG () != INVALID_VALUE && PROP () != INVALID_VALUE) + const operand res = dump_post_increment_res (expr); + if (!operand_is_empty (this_arg) && !operand_is_empty (prop)) { - DUMP_OPCODE_3 (prop_setter, THIS_ARG (), PROP (), ID (2)); + dump_prop_setter (this_arg, prop, expr); } - STACK_SWAP (IDX); - STACK_DROP (IDX, 1); + expr = res; } else if (token_is (TOK_DOUBLE_MINUS)) { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_2 (post_decr, ID(1), ID(2)); - if (THIS_ARG () != INVALID_VALUE && PROP () != INVALID_VALUE) + const operand res = dump_post_decrement_res (expr); + if (!operand_is_empty (this_arg) && !operand_is_empty (prop)) { - DUMP_OPCODE_3 (prop_setter, THIS_ARG (), PROP (), ID (2)); + dump_prop_setter (this_arg, prop, expr); } - STACK_SWAP (IDX); - STACK_DROP (IDX, 1); + expr = res; } else { - lexer_save_token (TOK ()); + lexer_save_token (tok); } -cleanup: - STACK_CHECK_USAGE_LHS (); -} - -static void -dump_boolean_true (void) -{ - STACK_DECLARE_USAGE (IDX); - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID (1), OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_TRUE); - STACK_CHECK_USAGE_LHS (); + return expr; } /* unary_expression : postfix_expression | ('delete' | 'void' | 'typeof' | '++' | '--' | '+' | '-' | '~' | '!') unary_expression ; */ -static void -parse_unary_expression (void) +static operand +parse_unary_expression (operand *this_arg_gl, operand *prop_gl) { - // IDX expr, lhs; - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (ops) - - switch (TOK ().type) + operand expr, this_arg = empty_operand (), prop = empty_operand (); + switch (tok.type) { case TOK_DOUBLE_PLUS: { - NEXT (unary_expression); - check_for_eval_and_arguments_in_strict_mode (STACK_TOP (IDX)); - DUMP_OPCODE_2 (pre_incr, next_temp_name (), ID(1)); - if (THIS_ARG () != INVALID_VALUE && PROP () != INVALID_VALUE) + skip_newlines (); + expr = parse_unary_expression (&this_arg, &prop); + syntax_check_for_eval_and_arguments_in_strict_mode (expr, is_strict_mode (), tok.loc); + expr = dump_pre_increment_res (expr); + if (!operand_is_empty (this_arg) && !operand_is_empty (prop)) { - DUMP_OPCODE_3 (prop_setter, THIS_ARG (), PROP (), ID (1)); + dump_prop_setter (this_arg, prop, expr); } break; } case TOK_DOUBLE_MINUS: { - NEXT (unary_expression); - check_for_eval_and_arguments_in_strict_mode (STACK_TOP (IDX)); - DUMP_OPCODE_2 (pre_decr, next_temp_name (), ID(1)); - if (THIS_ARG () != INVALID_VALUE && PROP () != INVALID_VALUE) + skip_newlines (); + expr = parse_unary_expression (&this_arg, &prop); + syntax_check_for_eval_and_arguments_in_strict_mode (expr, is_strict_mode (), tok.loc); + expr = dump_pre_decrement_res (expr); + if (!operand_is_empty (this_arg) && !operand_is_empty (prop)) { - DUMP_OPCODE_3 (prop_setter, THIS_ARG (), PROP (), ID (1)); + dump_prop_setter (this_arg, prop, expr); } break; } case TOK_PLUS: { - STACK_PUSH (IDX, next_temp_name ()); - NEXT (unary_expression); - DUMP_OPCODE_2 (unary_plus, ID(2), ID(1)); - STACK_DROP (IDX, 1); + skip_newlines (); + expr = parse_unary_expression (NULL, NULL); + expr = dump_unary_plus_res (expr); break; } case TOK_MINUS: { - STACK_PUSH (IDX, next_temp_name ()); - NEXT (unary_expression); - DUMP_OPCODE_2 (unary_minus, ID(2), ID(1)); - STACK_DROP (IDX, 1); + skip_newlines (); + expr = parse_unary_expression (NULL, NULL); + expr = dump_unary_minus_res (expr); break; } case TOK_COMPL: { - STACK_PUSH (IDX, next_temp_name ()); - NEXT (unary_expression); - DUMP_OPCODE_2 (b_not, ID(2), ID(1)); - STACK_DROP (IDX, 1); + skip_newlines (); + expr = parse_unary_expression (NULL, NULL); + expr = dump_bitwise_not_res (expr); break; } case TOK_NOT: { - STACK_PUSH (IDX, next_temp_name ()); - NEXT (unary_expression); - DUMP_OPCODE_2 (logical_not, ID(2), ID(1)); - STACK_DROP (IDX, 1); + skip_newlines (); + expr = parse_unary_expression (NULL, NULL); + expr = dump_logical_not_res (expr); break; } case TOK_KEYWORD: { if (is_keyword (KW_DELETE)) { - NEXT (unary_expression); - if (ID (1) < lexer_get_literals_count ()) - { - literal lit = lexer_get_literal_by_id (ID (1)); - if (lit.type == LIT_MAGIC_STR || lit.type == LIT_STR) - { - if (parser_strict_mode ()) - { - EMIT_ERROR ("'delete' operator shall not apply on identifier in strict mode."); - } - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_2 (delete_var, ID (1), ID (2)); - STACK_SWAP (IDX); - STACK_DROP (IDX, 1); - break; - } - else if (lit.type == LIT_NUMBER) - { - dump_boolean_true (); - STACK_SWAP (IDX); - STACK_DROP (IDX, 1); - } - else - { - JERRY_UNREACHABLE (); - } - } - STACK_PUSH (ops, deserialize_opcode ((opcode_counter_t) (OPCODE_COUNTER () - 1))); - if (LAST_OPCODE_IS (assignment) - && STACK_TOP (ops).data.assignment.type_value_right == OPCODE_ARG_TYPE_VARIABLE) - { - STACK_PUSH (IDX, next_temp_name ()); - REWRITE_OPCODE_2 (OPCODE_COUNTER () - 1, delete_var, ID (1), STACK_TOP (ops).data.assignment.value_right); - STACK_SWAP (IDX); - STACK_DROP (IDX, 1); - } - else if (LAST_OPCODE_IS (prop_getter)) - { - STACK_PUSH (IDX, next_temp_name ()); - REWRITE_OPCODE_3 (OPCODE_COUNTER () - 1, delete_prop, ID (1), - STACK_TOP (ops).data.prop_getter.obj, STACK_TOP (ops).data.prop_getter.prop); - STACK_SWAP (IDX); - STACK_DROP (IDX, 1); - } - else - { - dump_boolean_true (); - STACK_SWAP (IDX); - STACK_DROP (IDX, 1); - } - STACK_DROP (ops, 1); + skip_newlines (); + expr = parse_unary_expression (NULL, NULL); + expr = dump_delete_res (expr, is_strict_mode (), tok.loc); break; } else if (is_keyword (KW_VOID)) { - STACK_PUSH (IDX, next_temp_name ()); - NEXT (unary_expression); - DUMP_OPCODE_3 (assignment, ID(2), OPCODE_ARG_TYPE_VARIABLE, ID (1)); - DUMP_OPCODE_3 (assignment, ID(2), OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_UNDEFINED); - STACK_DROP (IDX, 1); + skip_newlines (); + expr = parse_unary_expression (NULL, NULL); + expr = dump_variable_assignment_res (expr); + dump_undefined_assignment (expr); break; } else if (is_keyword (KW_TYPEOF)) { - STACK_PUSH (IDX, next_temp_name ()); - NEXT (unary_expression); - DUMP_OPCODE_2 (typeof, ID(2), ID(1)); - STACK_DROP (IDX, 1); + skip_newlines (); + expr = parse_unary_expression (NULL, NULL); + expr = dump_typeof_res (expr); break; } /* FALLTHRU. */ } default: { - parse_postfix_expression (); + expr = parse_postfix_expression (); } } - STACK_CHECK_USAGE_LHS (); - STACK_CHECK_USAGE (ops); + if (this_arg_gl != NULL) + { + *this_arg_gl = this_arg; + } + if (prop_gl != NULL) + { + *prop_gl = prop; + } + + return expr; } -#define DUMP_OF(GETOP, EXPR) \ -do { \ - generate_tmp_for_left_arg (); \ - STACK_PUSH (IDX, next_temp_name ()); \ - NEXT (EXPR);\ - DUMP_OPCODE_3 (GETOP, ID(2), ID(3), ID(1)); \ - STACK_DROP (IDX, 1); \ - STACK_SWAP (IDX); \ - STACK_DROP (IDX, 1); \ -} while (0) +static operand +dump_assignment_of_lhs_if_literal (operand lhs) +{ + if (lhs.type == OPERAND_LITERAL) + { + lhs = dump_variable_assignment_res (lhs); + } + return lhs; +} /* multiplicative_expression : unary_expression (LT!* ('*' | '/' | '%') LT!* unary_expression)* ; */ -static void +static operand parse_multiplicative_expression (void) { - // IDX expr1, lhs, expr2; - STACK_DECLARE_USAGE (IDX) - - parse_unary_expression (); + operand expr = parse_unary_expression (NULL, NULL); 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 ()); goto cleanup; + case TOK_MULT: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_multiplication_res (expr, parse_unary_expression (NULL, NULL)); + break; + } + case TOK_DIV: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_division_res (expr, parse_unary_expression (NULL, NULL)); + break; + } + case TOK_MOD: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_remainder_res (expr, parse_unary_expression (NULL, NULL)); + break; + } + default: + { + lexer_save_token (tok); + goto done; + } } - skip_newlines (); } - -cleanup: - STACK_CHECK_USAGE_LHS (); +done: + return expr; } /* additive_expression : multiplicative_expression (LT!* ('+' | '-') LT!* multiplicative_expression)* ; */ -static void +static operand parse_additive_expression (void) { - // IDX expr1, lhs, expr2; - STACK_DECLARE_USAGE (IDX) - - parse_multiplicative_expression (); + operand expr = 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 ()); goto cleanup; + case TOK_PLUS: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_addition_res (expr, parse_multiplicative_expression ()); + break; + } + case TOK_MINUS: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_substraction_res (expr, parse_multiplicative_expression ()); + break; + } + default: + { + lexer_save_token (tok); + goto done; + } } - skip_newlines (); } - -cleanup: - STACK_CHECK_USAGE_LHS (); +done: + return expr; } /* shift_expression : additive_expression (LT!* ('<<' | '>>' | '>>>') LT!* additive_expression)* ; */ -static void +static operand parse_shift_expression (void) { - // IDX expr1, lhs, expr2; - STACK_DECLARE_USAGE (IDX) - - parse_additive_expression (); + operand expr = 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 ()); goto cleanup; + case TOK_LSHIFT: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_left_shift_res (expr, parse_additive_expression ()); + break; + } + case TOK_RSHIFT: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_right_shift_res (expr, parse_additive_expression ()); + break; + } + case TOK_RSHIFT_EX: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_right_shift_ex_res (expr, parse_additive_expression ()); + break; + } + default: + { + lexer_save_token (tok); + goto done; + } } - skip_newlines (); } - -cleanup: - STACK_CHECK_USAGE_LHS (); +done: + return expr; } /* relational_expression : shift_expression (LT!* ('<' | '>' | '<=' | '>=' | 'instanceof' | 'in') LT!* shift_expression)* ; */ -static void -parse_relational_expression (void) +static operand +parse_relational_expression (bool in_allowed) { - // IDX expr1, lhs, expr2; - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (U8) - - parse_shift_expression (); + operand expr = 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; - case TOK_LESS_EQ: DUMP_OF (less_or_equal_than, shift_expression); break; - case TOK_GREATER_EQ: DUMP_OF (greater_or_equal_than, shift_expression); break; + case TOK_LESS: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_less_than_res (expr, parse_shift_expression ()); + break; + } + case TOK_GREATER: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_greater_than_res (expr, parse_shift_expression ()); + break; + } + case TOK_LESS_EQ: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_less_or_equal_than_res (expr, parse_shift_expression ()); + break; + } + case TOK_GREATER_EQ: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_greater_or_equal_than_res (expr, parse_shift_expression ()); + break; + } case TOK_KEYWORD: { if (is_keyword (KW_INSTANCEOF)) { - DUMP_OF (instanceof, shift_expression); + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_instanceof_res (expr, parse_shift_expression ()); break; } else if (is_keyword (KW_IN)) { - if (STACK_ELEMENT (U8, no_in) == 0) + if (in_allowed) { - DUMP_OF (in, shift_expression); + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_in_res (expr, parse_shift_expression ()); break; } } @@ -2115,562 +1211,400 @@ parse_relational_expression (void) } default: { - lexer_save_token (TOK ()); - goto cleanup; + lexer_save_token (tok); + goto done; } } - skip_newlines (); } - -cleanup: - STACK_CHECK_USAGE (U8); - STACK_CHECK_USAGE_LHS (); +done: + return expr; } /* equality_expression : relational_expression (LT!* ('==' | '!=' | '===' | '!==') LT!* relational_expression)* ; */ -static void -parse_equality_expression (void) +static operand +parse_equality_expression (bool in_allowed) { - // IDX expr1, lhs, expr2; - STACK_DECLARE_USAGE (IDX) - - parse_relational_expression (); + operand expr = parse_relational_expression (in_allowed); 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; - case TOK_TRIPLE_EQ: DUMP_OF (equal_value_type, relational_expression); break; - case TOK_NOT_DOUBLE_EQ: DUMP_OF (not_equal_value_type, relational_expression); break; + case TOK_DOUBLE_EQ: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_equal_value_res (expr, parse_relational_expression (in_allowed)); + break; + } + case TOK_NOT_EQ: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_not_equal_value_res (expr, parse_relational_expression (in_allowed)); + break; + } + case TOK_TRIPLE_EQ: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_equal_value_type_res (expr, parse_relational_expression (in_allowed)); + break; + } + case TOK_NOT_DOUBLE_EQ: + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_not_equal_value_type_res (expr, parse_relational_expression (in_allowed)); + break; + } default: { - lexer_save_token (TOK ()); - goto cleanup; + lexer_save_token (tok); + goto done; } } - skip_newlines (); } - -cleanup: - STACK_CHECK_USAGE_LHS (); -} - -#define PARSE_OF(FUNC, EXPR, TOK_TYPE, GETOP) \ -static void parse_##FUNC (void) { \ - STACK_DECLARE_USAGE (IDX) \ - parse_##EXPR (); \ - skip_newlines (); \ - while (true) \ - { \ - switch (TOK ().type) \ - { \ - case TOK_##TOK_TYPE: DUMP_OF (GETOP, EXPR); break; \ - default: lexer_save_token (TOK ()); goto cleanup; \ - } \ - skip_newlines (); \ - } \ -cleanup: \ - STACK_CHECK_USAGE_LHS () \ +done: + return expr; } /* bitwise_and_expression : equality_expression (LT!* '&' LT!* equality_expression)* ; */ -PARSE_OF (bitwise_and_expression, equality_expression, AND, b_and) +static operand +parse_bitwise_and_expression (bool in_allowed) +{ + operand expr = parse_equality_expression (in_allowed); + skip_newlines (); + while (true) + { + if (tok.type == TOK_AND) + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_bitwise_and_res (expr, parse_equality_expression (in_allowed)); + } + else + { + lexer_save_token (tok); + goto done; + } + skip_newlines (); + } +done: + return expr; +} /* bitwise_xor_expression : bitwise_and_expression (LT!* '^' LT!* bitwise_and_expression)* ; */ -PARSE_OF (bitwise_xor_expression, bitwise_and_expression, XOR, b_xor) +static operand +parse_bitwise_xor_expression (bool in_allowed) +{ + operand expr = parse_bitwise_and_expression (in_allowed); + skip_newlines (); + while (true) + { + if (tok.type == TOK_XOR) + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_bitwise_xor_res (expr, parse_bitwise_and_expression (in_allowed)); + } + else + { + lexer_save_token (tok); + goto done; + } + skip_newlines (); + } +done: + return expr; +} /* bitwise_or_expression : bitwise_xor_expression (LT!* '|' LT!* bitwise_xor_expression)* ; */ -PARSE_OF (bitwise_or_expression, bitwise_xor_expression, OR, b_or) - -static void -dump_logical_check_and_op (bool logical_or) +static operand +parse_bitwise_or_expression (bool in_allowed) { - STACK_DECLARE_USAGE (IDX); - - STACK_PUSH (U16, OPCODE_COUNTER ()); - if (logical_or) + operand expr = parse_bitwise_xor_expression (in_allowed); + skip_newlines (); + while (true) { - DUMP_OPCODE_3 (is_true_jmp_down, ID (1), INVALID_VALUE, INVALID_VALUE); + if (tok.type == TOK_OR) + { + expr = dump_assignment_of_lhs_if_literal (expr); + skip_newlines (); + expr = dump_bitwise_or_res (expr, parse_bitwise_xor_expression (in_allowed)); + } + else + { + lexer_save_token (tok); + goto done; + } skip_newlines (); - parse_logical_expression (false); - } - else - { - DUMP_OPCODE_3 (is_false_jmp_down, ID (1), INVALID_VALUE, INVALID_VALUE); - NEXT (bitwise_or_expression); - } - DUMP_OPCODE_3 (assignment, ID(2), OPCODE_ARG_TYPE_VARIABLE, ID (1)); - STACK_DROP (IDX, 1); - - STACK_CHECK_USAGE (IDX); -} - -static void -rewrite_logical_check (bool logical_or, uint8_t elem) -{ - if (logical_or) - { - REWRITE_COND_JMP (STACK_ELEMENT (U16, elem), is_true_jmp_down, - OPCODE_COUNTER () - STACK_ELEMENT (U16, elem)); - } - else - { - REWRITE_COND_JMP (STACK_ELEMENT (U16, elem), is_false_jmp_down, - OPCODE_COUNTER () - STACK_ELEMENT (U16, elem)); } +done: + return expr; } /* logical_and_expression : bitwise_or_expression (LT!* '&&' LT!* bitwise_or_expression)* - ; - logical_or_expression - : logical_and_expression (LT!* '||' LT!* logical_and_expression)* ; */ -static void -parse_logical_expression (bool logical_or) +static operand +parse_logical_and_expression (bool in_allowed) { - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (U16) - STACK_DECLARE_USAGE (U8) - - STACK_PUSH (U8, logical_or ? TOK_DOUBLE_OR : TOK_DOUBLE_AND); - STACK_PUSH (U8, STACK_SIZE (U16)); - - if (logical_or) + operand expr = parse_bitwise_or_expression (in_allowed), tmp; + skip_newlines (); + if (token_is (TOK_DOUBLE_AND)) { - parse_logical_expression (false); + tmp = dump_variable_assignment_res (expr); + start_dumping_logical_and_checks (); + dump_logical_and_check_for_rewrite (tmp); } else { - parse_bitwise_or_expression (); + lexer_save_token (tok); + return expr; } - - skip_newlines (); - if (token_is (STACK_HEAD (U8, 2))) + while (token_is (TOK_DOUBLE_AND)) { - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_VARIABLE, ID (2)); - dump_logical_check_and_op (logical_or); skip_newlines (); - } - while (token_is (STACK_HEAD (U8, 2))) - { - dump_logical_check_and_op (logical_or); + expr = parse_bitwise_or_expression (in_allowed); + dump_variable_assignment (tmp, expr); skip_newlines (); - } - lexer_save_token (TOK ()); - - if (STACK_TOP (U8) != STACK_SIZE (U16)) - { - for (uint8_t i = STACK_TOP (U8); i < STACK_SIZE (U16); i++) + if (token_is (TOK_DOUBLE_AND)) { - rewrite_logical_check (logical_or, i); + dump_logical_and_check_for_rewrite (tmp); } - STACK_SWAP (IDX); - STACK_DROP (IDX, 1); } + lexer_save_token (tok); + rewrite_logical_and_checks (); + return tmp; +} - STACK_DROP (U16, STACK_SIZE (U16) - STACK_TOP (U8)); - STACK_DROP (U8, 2); - - STACK_CHECK_USAGE (U16); - STACK_CHECK_USAGE (U8); - STACK_CHECK_USAGE_LHS (); +/* logical_or_expression + : logical_and_expression (LT!* '||' LT!* logical_and_expression)* + ; */ +static operand +parse_logical_or_expression (bool in_allowed) +{ + operand expr = parse_logical_and_expression (in_allowed), tmp; + skip_newlines (); + if (token_is (TOK_DOUBLE_OR)) + { + tmp = dump_variable_assignment_res (expr); + start_dumping_logical_or_checks (); + dump_logical_or_check_for_rewrite (tmp); + } + else + { + lexer_save_token (tok); + return expr; + } + while (token_is (TOK_DOUBLE_OR)) + { + skip_newlines (); + expr = parse_logical_and_expression (in_allowed); + dump_variable_assignment (tmp, expr); + skip_newlines (); + if (token_is (TOK_DOUBLE_OR)) + { + dump_logical_or_check_for_rewrite (tmp); + } + } + lexer_save_token (tok); + rewrite_logical_or_checks (); + return tmp; } /* conditional_expression : logical_or_expression (LT!* '?' LT!* assignment_expression LT!* ':' LT!* assignment_expression)? ; */ -static void -parse_conditional_expression (void) +static operand +parse_conditional_expression (bool in_allowed, bool *is_conditional) { - // IDX expr, res, lhs - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (U16) - STACK_DECLARE_USAGE (U8) - - parse_logical_expression (true); - + operand expr = parse_logical_or_expression (in_allowed); skip_newlines (); if (token_is (TOK_QUERY)) { - generate_tmp_for_left_arg (); - STACK_PUSH (U16, OPCODE_COUNTER ()); - DUMP_OPCODE_3 (is_false_jmp_down, ID(1), INVALID_VALUE, INVALID_VALUE); - - STACK_PUSH (IDX, next_temp_name ()); - NEXT (assignment_expression); - DUMP_OPCODE_3 (assignment, ID(2), OPCODE_ARG_TYPE_VARIABLE, ID(1)); - STACK_DROP (IDX, 1); - STACK_SWAP (IDX); + dump_conditional_check_for_rewrite (expr); + skip_newlines (); + expr = parse_assignment_expression (in_allowed); + operand tmp = dump_variable_assignment_res (expr); token_after_newlines_must_be (TOK_COLON); - - STACK_PUSH (U16, OPCODE_COUNTER ()); - DUMP_OPCODE_2 (jmp_down, INVALID_VALUE, INVALID_VALUE); - - REWRITE_COND_JMP (STACK_HEAD (U16, 2), is_false_jmp_down, OPCODE_COUNTER () - STACK_HEAD (U16, 2)); - - STACK_DROP (IDX, 1); - NEXT (assignment_expression); - DUMP_OPCODE_3 (assignment, ID(2), OPCODE_ARG_TYPE_VARIABLE, ID(1)); - REWRITE_JMP (STACK_TOP (U16), jmp_down, OPCODE_COUNTER () - STACK_TOP (U16)); - - STACK_DROP (U8, 1); - STACK_DROP (U16, 2); - STACK_PUSH (U8, 1); - STACK_DROP (IDX, 1); + dump_jump_to_end_for_rewrite (); + rewrite_conditional_check (); + skip_newlines (); + expr = parse_assignment_expression (in_allowed); + dump_variable_assignment (tmp, expr); + rewrite_jump_to_end (); + if (is_conditional != NULL) + { + *is_conditional = true; + } + return tmp; } else { - lexer_save_token (TOK ()); + lexer_save_token (tok); + return expr; } - - STACK_CHECK_USAGE (U16); - STACK_CHECK_USAGE (U8); - STACK_CHECK_USAGE_LHS (); } /* assignment_expression : conditional_expression | left_hand_side_expression LT!* assignment_operator LT!* assignment_expression ; */ -static void -parse_assignment_expression (void) +static operand +parse_assignment_expression (bool in_allowed) { - // IDX lhs, rhs; - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (U16); - STACK_DECLARE_USAGE (U8); - STACK_DECLARE_USAGE (ops); - - STACK_PUSH (U8, 0); - - parse_conditional_expression (); - if (STACK_TOP (U8)) + bool is_conditional = false; + operand expr = parse_conditional_expression (in_allowed, &is_conditional); + if (is_conditional) { - goto cleanup; + return expr; } - - /* Rewrite prop_getter with nop and generate prop_setter in constructions like: - a.b = c; */ - if (LAST_OPCODE_IS (prop_getter)) - { - STACK_PUSH (U16, (opcode_counter_t) (OPCODE_COUNTER () - 1)); - STACK_DROP (U8, 1); - STACK_PUSH (U8, 1); - } - - check_for_eval_and_arguments_in_strict_mode (STACK_TOP (IDX)); - + syntax_check_for_eval_and_arguments_in_strict_mode (expr, is_strict_mode (), tok.loc); skip_newlines (); - switch (TOK ().type) + switch (tok.type) { case TOK_EQ: { - if (STACK_TOP (U8)) - { - STACK_PUSH (ops, deserialize_opcode (STACK_TOP (U16))); - JERRY_ASSERT (OPCODE_IS (STACK_TOP (ops), prop_getter)); - DECR_OPCODE_COUNTER (); - serializer_set_writing_position (OPCODE_COUNTER ()); - NEXT (assignment_expression); - DUMP_OPCODE_3 (prop_setter, STACK_TOP (ops).data.prop_getter.obj, - STACK_TOP (ops).data.prop_getter.prop, ID(1)); - STACK_DROP (ops, 1); - STACK_DROP (U16, 1); - } - else - { - NEXT (assignment_expression); - DUMP_OPCODE_3 (assignment, ID(2), OPCODE_ARG_TYPE_VARIABLE, - ID(1)); - } + skip_newlines (); + start_dumping_assignment_expression (); + const operand assign_expr = parse_assignment_expression (in_allowed); + expr = dump_prop_setter_or_variable_assignment_res (expr, assign_expr); break; } case TOK_MULT_EQ: { - NEXT (assignment_expression); - if (STACK_TOP (U8)) - { - STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); - DUMP_OPCODE_3 (multiplication, ID(2), ID(2), - ID(1)); - DUMP_OPCODE_3 (prop_setter, STACK_TOP (ops).data.prop_getter.obj, - STACK_TOP (ops).data.prop_getter.prop, ID(2)); - STACK_DROP (ops, 1); - STACK_DROP (U16, 1); - } - else - { - DUMP_OPCODE_3 (multiplication, ID(2), ID(2), - ID(1)); - } + skip_newlines (); + start_dumping_assignment_expression (); + const operand assign_expr = parse_assignment_expression (in_allowed); + expr = dump_prop_setter_or_multiplication_res (expr, assign_expr); break; } case TOK_DIV_EQ: { - NEXT (assignment_expression); - if (STACK_TOP (U8)) - { - STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); - DUMP_OPCODE_3 (division, ID(2), ID(2), - ID(1)); - DUMP_OPCODE_3 (prop_setter, STACK_TOP (ops).data.prop_getter.obj, - STACK_TOP (ops).data.prop_getter.prop, ID(2)); - STACK_DROP (ops, 1); - STACK_DROP (U16, 1); - } - else - { - DUMP_OPCODE_3 (division, ID(2), ID(2), - ID(1)); - } + skip_newlines (); + start_dumping_assignment_expression (); + const operand assign_expr = parse_assignment_expression (in_allowed); + expr = dump_prop_setter_or_division_res (expr, assign_expr); break; } case TOK_MOD_EQ: { - NEXT (assignment_expression); - if (STACK_TOP (U8)) - { - STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); - DUMP_OPCODE_3 (remainder, ID(2), ID(2), - ID(1)); - DUMP_OPCODE_3 (prop_setter, STACK_TOP (ops).data.prop_getter.obj, - STACK_TOP (ops).data.prop_getter.prop, ID(2)); - STACK_DROP (ops, 1); - STACK_DROP (U16, 1); - } - else - { - DUMP_OPCODE_3 (remainder, ID(2), ID(2), - ID(1)); - } + skip_newlines (); + start_dumping_assignment_expression (); + const operand assign_expr = parse_assignment_expression (in_allowed); + expr = dump_prop_setter_or_remainder_res (expr, assign_expr); break; } case TOK_PLUS_EQ: { - NEXT (assignment_expression); - if (STACK_TOP (U8)) - { - STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); - DUMP_OPCODE_3 (addition, ID(2), ID(2), - ID(1)); - DUMP_OPCODE_3 (prop_setter, STACK_TOP (ops).data.prop_getter.obj, - STACK_TOP (ops).data.prop_getter.prop, ID(2)); - STACK_DROP (ops, 1); - STACK_DROP (U16, 1); - } - else - { - DUMP_OPCODE_3 (addition, ID(2), ID(2), - ID(1)); - } + skip_newlines (); + start_dumping_assignment_expression (); + const operand assign_expr = parse_assignment_expression (in_allowed); + expr = dump_prop_setter_or_addition_res (expr, assign_expr); break; } case TOK_MINUS_EQ: { - NEXT (assignment_expression); - if (STACK_TOP (U8)) - { - STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); - DUMP_OPCODE_3 (substraction, ID(2), ID(2), - ID(1)); - DUMP_OPCODE_3 (prop_setter, STACK_TOP (ops).data.prop_getter.obj, - STACK_TOP (ops).data.prop_getter.prop, ID(2)); - STACK_DROP (ops, 1); - STACK_DROP (U16, 1); - } - else - { - DUMP_OPCODE_3 (substraction, ID(2), ID(2), - ID(1)); - } + skip_newlines (); + start_dumping_assignment_expression (); + const operand assign_expr = parse_assignment_expression (in_allowed); + expr = dump_prop_setter_or_substraction_res (expr, assign_expr); break; } case TOK_LSHIFT_EQ: { - NEXT (assignment_expression); - if (STACK_TOP (U8)) - { - STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); - DUMP_OPCODE_3 (b_shift_left, ID(2), ID(2), - ID(1)); - DUMP_OPCODE_3 (prop_setter, STACK_TOP (ops).data.prop_getter.obj, - STACK_TOP (ops).data.prop_getter.prop, ID(2)); - STACK_DROP (ops, 1); - STACK_DROP (U16, 1); - } - else - { - DUMP_OPCODE_3 (b_shift_left, ID(2), ID(2), - ID(1)); - } + skip_newlines (); + start_dumping_assignment_expression (); + const operand assign_expr = parse_assignment_expression (in_allowed); + expr = dump_prop_setter_or_left_shift_res (expr, assign_expr); break; } case TOK_RSHIFT_EQ: { - NEXT (assignment_expression); - if (STACK_TOP (U8)) - { - STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); - DUMP_OPCODE_3 (b_shift_right, ID(2), ID(2), - ID(1)); - DUMP_OPCODE_3 (prop_setter, STACK_TOP (ops).data.prop_getter.obj, - STACK_TOP (ops).data.prop_getter.prop, ID(2)); - STACK_DROP (ops, 1); - STACK_DROP (U16, 1); - } - else - { - DUMP_OPCODE_3 (b_shift_right, ID(2), ID(2), - ID(1)); - } + skip_newlines (); + start_dumping_assignment_expression (); + const operand assign_expr = parse_assignment_expression (in_allowed); + expr = dump_prop_setter_or_right_shift_res (expr, assign_expr); break; } case TOK_RSHIFT_EX_EQ: { - NEXT (assignment_expression); - if (STACK_TOP (U8)) - { - STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); - DUMP_OPCODE_3 (b_shift_uright, ID(2), ID(2), - ID(1)); - DUMP_OPCODE_3 (prop_setter, STACK_TOP (ops).data.prop_getter.obj, - STACK_TOP (ops).data.prop_getter.prop, ID(2)); - STACK_DROP (ops, 1); - STACK_DROP (U16, 1); - } - else - { - DUMP_OPCODE_3 (b_shift_uright, ID(2), ID(2), - ID(1)); - } + skip_newlines (); + start_dumping_assignment_expression (); + const operand assign_expr = parse_assignment_expression (in_allowed); + expr = dump_prop_setter_or_right_shift_ex_res (expr, assign_expr); break; } case TOK_AND_EQ: { - NEXT (assignment_expression); - if (STACK_TOP (U8)) - { - STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); - DUMP_OPCODE_3 (b_and, ID(2), ID(2), - ID(1)); - DUMP_OPCODE_3 (prop_setter, STACK_TOP (ops).data.prop_getter.obj, - STACK_TOP (ops).data.prop_getter.prop, ID(2)); - STACK_DROP (ops, 1); - STACK_DROP (U16, 1); - } - else - { - DUMP_OPCODE_3 (b_and, ID(2), ID(2), - ID(1)); - } + skip_newlines (); + start_dumping_assignment_expression (); + const operand assign_expr = parse_assignment_expression (in_allowed); + expr = dump_prop_setter_or_bitwise_and_res (expr, assign_expr); break; } case TOK_XOR_EQ: { - NEXT (assignment_expression); - if (STACK_TOP (U8)) - { - STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); - DUMP_OPCODE_3 (b_xor, ID(2), ID(2), - ID(1)); - DUMP_OPCODE_3 (prop_setter, STACK_TOP (ops).data.prop_getter.obj, - STACK_TOP (ops).data.prop_getter.prop, ID(2)); - STACK_DROP (ops, 1); - STACK_DROP (U16, 1); - } - else - { - DUMP_OPCODE_3 (b_xor, ID(2), ID(2), - ID(1)); - } + skip_newlines (); + start_dumping_assignment_expression (); + const operand assign_expr = parse_assignment_expression (in_allowed); + expr = dump_prop_setter_or_bitwise_xor_res (expr, assign_expr); break; } case TOK_OR_EQ: { - NEXT (assignment_expression); - if (STACK_TOP (U8)) - { - STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); - DUMP_OPCODE_3 (b_or, ID(2), ID(2), - ID(1)); - DUMP_OPCODE_3 (prop_setter, STACK_TOP (ops).data.prop_getter.obj, - STACK_TOP (ops).data.prop_getter.prop, ID(2)); - STACK_DROP (ops, 1); - STACK_DROP (U16, 1); - } - else - { - DUMP_OPCODE_3 (b_or, ID(2), ID(2), - ID(1)); - } + skip_newlines (); + start_dumping_assignment_expression (); + const operand assign_expr = parse_assignment_expression (in_allowed); + expr = dump_prop_setter_or_bitwise_or_res (expr, assign_expr); break; } default: { - if (STACK_TOP (U8)) - { - STACK_DROP (U16, 1); - } - lexer_save_token (TOK ()); - goto cleanup; + lexer_save_token (tok); + break; } } - - STACK_DROP (IDX, 1); - -cleanup: - STACK_DROP (U8, 1); - - STACK_CHECK_USAGE (U16); - STACK_CHECK_USAGE (U8); - STACK_CHECK_USAGE (ops); - STACK_CHECK_USAGE_LHS (); + return expr; } /* expression : assignment_expression (LT!* ',' LT!* assignment_expression)* ; */ -static void -parse_expression (void) +static operand +parse_expression (bool in_allowed) { - // IDX expr - STACK_DECLARE_USAGE (IDX) - - parse_assignment_expression (); + operand expr = parse_assignment_expression (in_allowed); while (true) { skip_newlines (); if (token_is (TOK_COMMA)) { - NEXT (assignment_expression); - STACK_SWAP (IDX); - STACK_DROP (IDX, 1); + skip_newlines (); + expr = parse_assignment_expression (in_allowed); } else { - lexer_save_token (TOK ()); + lexer_save_token (tok); break; } } - - STACK_CHECK_USAGE_LHS (); + return expr; } /* variable_declaration @@ -2682,28 +1616,20 @@ parse_expression (void) static void parse_variable_declaration (void) { - //IDX name, expr; - - STACK_DECLARE_USAGE (IDX) - current_token_must_be (TOK_NAME); - STACK_PUSH (IDX, token_data ()); + const operand name = literal_operand (token_data ()); skip_newlines (); if (token_is (TOK_EQ)) { - NEXT (assignment_expression); - DUMP_OPCODE_3 (assignment, ID(2), OPCODE_ARG_TYPE_VARIABLE, ID(1)); - STACK_DROP (IDX, 1); + skip_newlines (); + const operand expr = parse_assignment_expression (true); + dump_variable_assignment (name, expr); } else { - lexer_save_token (TOK ()); + lexer_save_token (tok); } - - STACK_DROP (IDX, 1); - - STACK_CHECK_USAGE (IDX); } /* variable_declaration_list @@ -2713,8 +1639,6 @@ parse_variable_declaration (void) static void parse_variable_declaration_list (bool *several_decls) { - STACK_DECLARE_USAGE (IDX) - while (true) { parse_variable_declaration (); @@ -2722,7 +1646,7 @@ parse_variable_declaration_list (bool *several_decls) skip_newlines (); if (!token_is (TOK_COMMA)) { - lexer_save_token (TOK ()); + lexer_save_token (tok); return; } @@ -2732,8 +1656,98 @@ parse_variable_declaration_list (bool *several_decls) *several_decls = true; } } +} - STACK_CHECK_USAGE (IDX); +static void +parse_plain_for (void) +{ + /* Represent loop like + + for (i = 0; i < 10; i++) { + body; + } + + as + + assign i, 0 + jmp_down %cond +%body + body + post_incr i +%cond + less_than i, 10 + is_true_jmp_up %body + + */ + + dump_jump_to_end_for_rewrite (); + + // Skip till body + JERRY_ASSERT (token_is (TOK_SEMICOLON)); + skip_newlines (); + const locus cond_loc = tok.loc; + while (!token_is (TOK_SEMICOLON)) + { + skip_newlines (); + } + skip_newlines (); + const locus incr_loc = tok.loc; + while (!token_is (TOK_CLOSE_PAREN)) + { + skip_newlines (); + } + + start_collecting_continues (); + start_collecting_breaks (); + dumper_set_next_interation_target (); + + // Parse body + skip_newlines (); + push_nesting (NESTING_ITERATIONAL); + parse_statement (); + pop_nesting (NESTING_ITERATIONAL); + + const locus end_loc = tok.loc; + + dumper_set_continue_target (); + + lexer_seek (incr_loc); + skip_token (); + if (!token_is (TOK_CLOSE_PAREN)) + { + parse_expression (true); + } + + rewrite_jump_to_end (); + + lexer_seek (cond_loc); + skip_token (); + if (token_is (TOK_SEMICOLON)) + { + dump_continue_iterations_check (empty_operand ()); + } + else + { + const operand cond = parse_expression (true); + dump_continue_iterations_check (cond); + } + + dumper_set_break_target (); + rewrite_breaks (); + rewrite_continues (); + + lexer_seek (end_loc); + skip_token (); + if (tok.type != TOK_CLOSE_BRACE) + { + lexer_save_token (tok); + } +} + +static void +parse_for_in (void) +{ + EMIT_SORRY ("'for in' loops are not supported yet"); } /* for_statement @@ -2759,20 +1773,14 @@ parse_variable_declaration_list (bool *several_decls) static void parse_for_or_for_in_statement (void) { - // IDX stop; - // U16 cond_oc, body_oc, step_oc, end_oc; - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (U16) - STACK_DECLARE_USAGE (nestings) - STACK_DECLARE_USAGE (U8) - assert_keyword (KW_FOR); token_after_newlines_must_be (TOK_OPEN_PAREN); skip_newlines (); if (token_is (TOK_SEMICOLON)) { - goto plain_for; + parse_plain_for (); + return; } /* Both for_statement_initialiser_part and for_in_statement_initialiser_part contains 'var'. Check it first. */ @@ -2784,18 +1792,21 @@ parse_for_or_for_in_statement (void) if (several_decls) { token_after_newlines_must_be (TOK_SEMICOLON); - goto plain_for; + parse_plain_for (); + return; } else { skip_newlines (); if (token_is (TOK_SEMICOLON)) { - goto plain_for; + parse_plain_for (); + return; } else if (is_keyword (KW_IN)) { - goto for_in; + parse_for_in (); + return; } else { @@ -2805,125 +1816,33 @@ parse_for_or_for_in_statement (void) } /* expression contains left_hand_side_expression. */ - STACK_SET_ELEMENT (U8, no_in, 1); - parse_expression (); - STACK_SET_ELEMENT (U8, no_in, 0); - STACK_DROP (IDX, 1); + parse_expression (false); skip_newlines (); if (token_is (TOK_SEMICOLON)) { - goto plain_for; + parse_plain_for (); + return; } else if (is_keyword (KW_IN)) { - goto for_in; + parse_for_in (); + return; } else { EMIT_ERROR ("Expected either ';' or 'in' token"); } - - JERRY_UNREACHABLE (); - -plain_for: - /* Represent loop like - - for (i = 0; i < 10; i++) { - body; - } - - as - - 11 i = #0; - cond_oc: - 12 tmp1 = #10; - 13 tmp2 = i < tmp1; - end_oc: - 14 is_false_jmp_down tmp2, +8 // end of loop - body_oc: - 15 jmp_down 5 // body - step_oc: - 16 tmp3 = #1; - 17 tmp4 = i + 1; - 18 i = tmp4; - 19 jmp_up 7; // cond_oc - - 20 body - - 21 jmp_up 5; // step_oc; - 22 ... - */ - STACK_PUSH (U8, STACK_SIZE (rewritable_continue)); - STACK_PUSH (U8, STACK_SIZE (rewritable_break)); - - STACK_PUSH (U16, OPCODE_COUNTER ()); // cond_oc; - skip_newlines (); - if (!token_is (TOK_SEMICOLON)) - { - parse_expression (); - next_token_must_be (TOK_SEMICOLON); - } - else - { - boolean_true (); - } - - STACK_PUSH (U16, OPCODE_COUNTER ()); // end_oc; - DUMP_OPCODE_3 (is_false_jmp_down, INVALID_VALUE, INVALID_VALUE, INVALID_VALUE); - - STACK_PUSH (U16, OPCODE_COUNTER ()); // body_oc; - DUMP_OPCODE_2 (jmp_down, INVALID_VALUE, INVALID_VALUE); - - STACK_PUSH (U16, OPCODE_COUNTER ()); // step_oc; - skip_newlines (); - if (!token_is (TOK_CLOSE_PAREN)) - { - parse_expression (); - STACK_DROP (IDX, 1); - next_token_must_be (TOK_CLOSE_PAREN); - } - DUMP_OPCODE_2 (jmp_up, 0, OPCODE_COUNTER () - STACK_HEAD (U16, 4)); - REWRITE_JMP (STACK_HEAD (U16, 2), jmp_down, OPCODE_COUNTER () - STACK_HEAD (U16, 2)); - - skip_newlines (); - push_nesting (NESTING_ITERATIONAL); - parse_statement (); - pop_nesting (NESTING_ITERATIONAL); - - DUMP_OPCODE_2 (jmp_up, 0, OPCODE_COUNTER () - STACK_TOP (U16)); - REWRITE_COND_JMP (STACK_HEAD (U16, 3), is_false_jmp_down, OPCODE_COUNTER () - STACK_HEAD (U16, 3)); - - rewrite_rewritable_opcodes (REWRITABLE_CONTINUE, STACK_HEAD (U8, 2), STACK_TOP (U16)); - rewrite_rewritable_opcodes (REWRITABLE_BREAK, STACK_TOP (U8), OPCODE_COUNTER ()); - - STACK_DROP (U8, 2); - STACK_DROP (IDX, 1); - STACK_DROP (U16, 4); - - goto cleanup; - -for_in: - EMIT_SORRY ("'for in' loops are not supported yet"); - -cleanup: - STACK_CHECK_USAGE (IDX); - STACK_CHECK_USAGE (U16); - STACK_CHECK_USAGE (U8); - STACK_CHECK_USAGE (nestings); } -static void +static operand parse_expression_inside_parens (void) { - // IDX expr; - STACK_DECLARE_USAGE (IDX) - token_after_newlines_must_be (TOK_OPEN_PAREN); - NEXT (expression); + skip_newlines (); + const operand res = parse_expression (true); token_after_newlines_must_be (TOK_CLOSE_PAREN); - - STACK_CHECK_USAGE_LHS (); + return res; } /* statement_list @@ -2932,8 +1851,6 @@ parse_expression_inside_parens (void) static void parse_statement_list (void) { - STACK_DECLARE_USAGE (IDX) - while (true) { parse_statement (); @@ -2945,17 +1862,15 @@ parse_statement_list (void) } if (token_is (TOK_CLOSE_BRACE)) { - lexer_save_token (TOK ()); + lexer_save_token (tok); break; } if (is_keyword (KW_CASE) || is_keyword (KW_DEFAULT)) { - lexer_save_token (TOK ()); + lexer_save_token (tok); break; } } - - STACK_CHECK_USAGE (IDX); } /* if_statement @@ -2964,16 +1879,10 @@ parse_statement_list (void) static void parse_if_statement (void) { - // IDX cond; - // U16 cond_oc; - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (U16) - assert_keyword (KW_IF); - parse_expression_inside_parens (); - STACK_PUSH (U16, OPCODE_COUNTER ()); - DUMP_OPCODE_3 (is_false_jmp_down, INVALID_VALUE, INVALID_VALUE, INVALID_VALUE); + const operand cond = parse_expression_inside_parens (); + dump_conditional_check_for_rewrite (cond); skip_newlines (); parse_statement (); @@ -2981,29 +1890,19 @@ parse_if_statement (void) skip_newlines (); if (is_keyword (KW_ELSE)) { - STACK_PUSH (U16, OPCODE_COUNTER ()); - DUMP_OPCODE_2 (jmp_down, INVALID_VALUE, INVALID_VALUE); - - REWRITE_COND_JMP (STACK_HEAD (U16, 2), is_false_jmp_down, OPCODE_COUNTER () - STACK_HEAD (U16, 2)); + dump_jump_to_end_for_rewrite (); + rewrite_conditional_check (); skip_newlines (); parse_statement (); - REWRITE_JMP (STACK_TOP (U16), jmp_down, OPCODE_COUNTER () - STACK_TOP (U16)); - - STACK_DROP (U16, 1); + rewrite_jump_to_end (); } else { - REWRITE_COND_JMP (STACK_TOP (U16), is_false_jmp_down, OPCODE_COUNTER () - STACK_TOP (U16)); - lexer_save_token (TOK ()); + lexer_save_token (tok); + rewrite_conditional_check (); } - - STACK_DROP (U16, 1); - STACK_DROP (IDX, 1); - - STACK_CHECK_USAGE (U16); - STACK_CHECK_USAGE (IDX); } /* do_while_statement @@ -3012,41 +1911,28 @@ parse_if_statement (void) static void parse_do_while_statement (void) { - // IDX cond; - // U16 loop_oc; - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (U16) - STACK_DECLARE_USAGE (U8) - STACK_DECLARE_USAGE (nestings) - assert_keyword (KW_DO); - STACK_PUSH (U8, STACK_SIZE (rewritable_continue)); - STACK_PUSH (U8, STACK_SIZE (rewritable_break)); + start_collecting_continues (); + start_collecting_breaks (); + + dumper_set_next_interation_target (); - STACK_PUSH (U16, OPCODE_COUNTER ()); skip_newlines (); push_nesting (NESTING_ITERATIONAL); parse_statement (); pop_nesting (NESTING_ITERATIONAL); - rewrite_rewritable_opcodes (REWRITABLE_CONTINUE, STACK_HEAD (U8, 2), OPCODE_COUNTER ()); + dumper_set_continue_target (); + token_after_newlines_must_be_keyword (KW_WHILE); - parse_expression_inside_parens (); - STACK_PUSH (U16, OPCODE_COUNTER ()); - DUMP_OPCODE_3 (is_true_jmp_up, INVALID_VALUE, INVALID_VALUE, INVALID_VALUE); - REWRITE_COND_JMP (STACK_HEAD(U16, 1), is_true_jmp_up, STACK_HEAD(U16, 1) - STACK_HEAD (U16, 2)); + const operand cond = parse_expression_inside_parens (); + dump_continue_iterations_check (cond); - rewrite_rewritable_opcodes (REWRITABLE_BREAK, STACK_TOP (U8), OPCODE_COUNTER ()); + dumper_set_break_target (); - STACK_DROP (IDX, 1); - STACK_DROP (U16, 2); - STACK_DROP (U8, 2); - - STACK_CHECK_USAGE (U8); - STACK_CHECK_USAGE (U16); - STACK_CHECK_USAGE (IDX); - STACK_CHECK_USAGE (nestings); + rewrite_breaks (); + rewrite_continues (); } /* while_statement @@ -3055,44 +1941,40 @@ parse_do_while_statement (void) static void parse_while_statement (void) { - // IDX cond; - // U16 cond_oc, jmp_oc; - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (U16) - STACK_DECLARE_USAGE (U8) - STACK_DECLARE_USAGE (nestings) - assert_keyword (KW_WHILE); - STACK_PUSH (U8, STACK_SIZE (rewritable_continue)); - STACK_PUSH (U8, STACK_SIZE (rewritable_break)); + token_after_newlines_must_be (TOK_OPEN_PAREN); + const locus cond_loc = tok.loc; + skip_parens (); - STACK_PUSH (U16, OPCODE_COUNTER ()); // cond_oc; - parse_expression_inside_parens (); - STACK_PUSH (U16, OPCODE_COUNTER ()); // jmp_oc; - DUMP_OPCODE_3 (is_false_jmp_down, INVALID_VALUE, INVALID_VALUE, INVALID_VALUE); + dump_jump_to_end_for_rewrite (); + + dumper_set_next_interation_target (); + + start_collecting_continues (); + start_collecting_breaks (); skip_newlines (); push_nesting (NESTING_ITERATIONAL); parse_statement (); pop_nesting (NESTING_ITERATIONAL); - STACK_PUSH (U16, OPCODE_COUNTER ()); - DUMP_OPCODE_2 (jmp_up, INVALID_VALUE, INVALID_VALUE); - REWRITE_JMP (STACK_TOP (U16), jmp_up, STACK_TOP (U16) - STACK_HEAD (U16, 3)); - REWRITE_COND_JMP (STACK_HEAD (U16, 2), is_false_jmp_down, OPCODE_COUNTER () - STACK_HEAD (U16, 2)); + dumper_set_continue_target (); - rewrite_rewritable_opcodes (REWRITABLE_CONTINUE, STACK_HEAD (U8, 2), STACK_HEAD (U16, 3)); - rewrite_rewritable_opcodes (REWRITABLE_BREAK, STACK_TOP (U8), OPCODE_COUNTER ()); + rewrite_jump_to_end (); - STACK_DROP (IDX, 1); - STACK_DROP (U16, 3); - STACK_DROP (U8, 2); + const locus end_loc = tok.loc; + lexer_seek (cond_loc); + const operand cond = parse_expression_inside_parens (); + dump_continue_iterations_check (cond); + + dumper_set_break_target (); - STACK_CHECK_USAGE (U8); - STACK_CHECK_USAGE (U16); - STACK_CHECK_USAGE (IDX); - STACK_CHECK_USAGE (nestings); + rewrite_breaks (); + rewrite_continues (); + + lexer_seek (end_loc); + skip_token (); } /* with_statement @@ -3101,28 +1983,16 @@ parse_while_statement (void) static void parse_with_statement (void) { - // IDX expr; - STACK_DECLARE_USAGE (IDX) - assert_keyword (KW_WITH); - - if (parser_strict_mode ()) + if (is_strict_mode ()) { EMIT_ERROR ("'with' expression is not allowed in strict mode."); } - - parse_expression_inside_parens (); - - DUMP_OPCODE_1 (with, ID(1)); - + const operand expr = parse_expression_inside_parens (); + dump_with (expr); skip_newlines (); parse_statement (); - - DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_END_WITH, INVALID_VALUE, INVALID_VALUE); - - STACK_DROP (IDX, 1); - - STACK_CHECK_USAGE (IDX); + dump_with_end (); } static void @@ -3151,70 +2021,50 @@ skip_case_clause_body (void) static void parse_switch_statement (void) { - STACK_DECLARE_USAGE (rewritable_break) - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (U16) - STACK_DECLARE_USAGE (U8) - STACK_DECLARE_USAGE (locs) - assert_keyword (KW_SWITCH); - STACK_PUSH (U8, 0); - STACK_PUSH (U8, 0); - STACK_PUSH (U8, STACK_SIZE (IDX)); - STACK_PUSH (U8, STACK_SIZE (U16)); - STACK_PUSH (U8, STACK_SIZE (rewritable_break)); - - parse_expression_inside_parens (); + const operand switch_expr = parse_expression_inside_parens (); token_after_newlines_must_be (TOK_OPEN_BRACE); -#define SWITCH_EXPR() STACK_ELEMENT (IDX, STACK_HEAD (U8, 3)) -#define CURRENT_JUMP() STACK_HEAD (U8, 4) -#define INCR_CURRENT_JUMP() STACK_INCR_HEAD (U8, 4) -#define WAS_DEFAULT() STACK_HEAD (U8, 5) -#define SET_WAS_DEFAULT(S) STACK_SET_HEAD (U8, 5, S); - - STACK_PUSH (locs, TOK ().loc); - // Fisrt, generate table of jumps + start_dumping_case_clauses (); + const locus start_loc = tok.loc; + bool was_default = false; + // First, generate table of jumps skip_newlines (); while (is_keyword (KW_CASE) || is_keyword (KW_DEFAULT)) { if (is_keyword (KW_CASE)) { - NEXT (expression); + skip_newlines (); + const operand case_expr = parse_expression (true); next_token_must_be (TOK_COLON); - STACK_PUSH (IDX, next_temp_name ()); - DUMP_OPCODE_3 (equal_value_type, ID (1), ID (2), SWITCH_EXPR ()); - STACK_SWAP (IDX); - STACK_DROP (IDX, 1); - STACK_PUSH (U16, OPCODE_COUNTER ()); - DUMP_OPCODE_3 (is_true_jmp_down, STACK_TOP (IDX), INVALID_VALUE, INVALID_VALUE); + dump_case_clause_check_for_rewrite (switch_expr, case_expr); skip_newlines (); skip_case_clause_body (); } else if (is_keyword (KW_DEFAULT)) { - SET_WAS_DEFAULT (1); + if (was_default) + { + EMIT_ERROR ("Duplication of 'default' clause"); + } + was_default = true; token_after_newlines_must_be (TOK_COLON); skip_newlines (); skip_case_clause_body (); } - else - { - JERRY_UNREACHABLE (); - } } current_token_must_be (TOK_CLOSE_BRACE); - if (WAS_DEFAULT ()) + if (was_default) { - STACK_PUSH (U16, OPCODE_COUNTER ()); - DUMP_OPCODE_2 (jmp_down, INVALID_VALUE, INVALID_VALUE); + dump_default_clause_check_for_rewrite (); } - lexer_seek (STACK_TOP (locs)); + lexer_seek (start_loc); next_token_must_be (TOK_OPEN_BRACE); + start_collecting_breaks (); push_nesting (NESTING_SWITCH); // Second, parse case clauses' bodies and rewrite jumps skip_newlines (); @@ -3226,17 +2076,11 @@ parse_switch_statement (void) { skip_newlines (); } - REWRITE_OPCODE_3 (STACK_ELEMENT (U16, STACK_HEAD (U8, 2) + CURRENT_JUMP ()), - is_true_jmp_down, - STACK_ELEMENT (IDX, STACK_HEAD (U8, 3) + CURRENT_JUMP () + 1), - (idx_t) ((OPCODE_COUNTER () - STACK_ELEMENT ( - U16, STACK_HEAD (U8, 2) + CURRENT_JUMP ())) >> JERRY_BITSINBYTE), - (idx_t) ((OPCODE_COUNTER () - STACK_ELEMENT ( - U16, STACK_HEAD (U8, 2) + CURRENT_JUMP ())) & ((1 << JERRY_BITSINBYTE) - 1))); + rewrite_case_clause (); skip_newlines (); if (is_keyword (KW_CASE) || is_keyword (KW_DEFAULT)) { - goto next; + continue; } parse_statement_list (); } @@ -3251,42 +2095,21 @@ parse_switch_statement (void) parse_statement_list (); continue; } - else - { - JERRY_UNREACHABLE (); - } skip_newlines (); - -next: - INCR_CURRENT_JUMP (); } current_token_must_be (TOK_CLOSE_BRACE); skip_token (); pop_nesting (NESTING_SWITCH); // Finally, dump 'finally' jump - if (WAS_DEFAULT ()) + if (was_default) { - REWRITE_JMP (STACK_TOP (U16), jmp_down, OPCODE_COUNTER () - STACK_TOP (U16)); + rewrite_default_clause (); } - rewrite_rewritable_opcodes (REWRITABLE_BREAK, STACK_TOP (U8), OPCODE_COUNTER ()); - STACK_DROP (U16, STACK_SIZE (U16) - STACK_HEAD (U8, 2)); - STACK_DROP (IDX, STACK_SIZE (IDX) - STACK_HEAD (U8, 3)); - STACK_DROP (U8, 5); - STACK_DROP (locs, 1); - -#undef WAS_DEFAULT -#undef SET_WAS_DEFAULT -#undef CURRENT_JUMP -#undef INCR_CURRENT_JUMP -#undef SWITCH_EXPR - - STACK_CHECK_USAGE (locs); - STACK_CHECK_USAGE (IDX); - STACK_CHECK_USAGE (U16); - STACK_CHECK_USAGE (U8); - STACK_CHECK_USAGE (rewritable_break); + dumper_set_break_target (); + rewrite_breaks (); + finish_dumping_case_clauses (); } /* catch_clause @@ -3295,35 +2118,22 @@ next: static void parse_catch_clause (void) { - // IDX ex_name; - // U16 catch_oc; - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (U16) - assert_keyword (KW_CATCH); token_after_newlines_must_be (TOK_OPEN_PAREN); token_after_newlines_must_be (TOK_NAME); - STACK_PUSH (IDX, token_data ()); - check_for_eval_and_arguments_in_strict_mode (STACK_TOP (IDX)); + const operand exception = literal_operand (token_data ()); + syntax_check_for_eval_and_arguments_in_strict_mode (exception, is_strict_mode (), tok.loc); token_after_newlines_must_be (TOK_CLOSE_PAREN); - STACK_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, ID(1), INVALID_VALUE); + dump_catch_for_rewrite (exception); token_after_newlines_must_be (TOK_OPEN_BRACE); skip_newlines (); parse_statement_list (); next_token_must_be (TOK_CLOSE_BRACE); - rewrite_meta_opcode_counter (STACK_TOP (U16), OPCODE_META_TYPE_CATCH); - - STACK_DROP (U16, 1); - STACK_DROP (IDX, 1); - - STACK_CHECK_USAGE (IDX); - STACK_CHECK_USAGE (U16); + rewrite_catch (); } /* finally_clause @@ -3332,24 +2142,16 @@ parse_catch_clause (void) static void parse_finally_clause (void) { - // U16 finally_oc; - STACK_DECLARE_USAGE (U16) - assert_keyword (KW_FINALLY); - STACK_PUSH (U16, OPCODE_COUNTER ()); - DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_FINALLY, INVALID_VALUE, INVALID_VALUE); + dump_finally_for_rewrite (); token_after_newlines_must_be (TOK_OPEN_BRACE); skip_newlines (); parse_statement_list (); next_token_must_be (TOK_CLOSE_BRACE); - rewrite_meta_opcode_counter (STACK_TOP (U16), OPCODE_META_TYPE_FINALLY); - - STACK_DROP (U16, 1); - - STACK_CHECK_USAGE (U16); + rewrite_finally (); } /* try_statement @@ -3358,20 +2160,16 @@ parse_finally_clause (void) static void parse_try_statement (void) { - // U16 try_oc; - STACK_DECLARE_USAGE (U16) - assert_keyword (KW_TRY); - STACK_PUSH (U16, OPCODE_COUNTER ()); - DUMP_OPCODE_2 (try, INVALID_VALUE, INVALID_VALUE); + dump_try_for_rewrite (); token_after_newlines_must_be (TOK_OPEN_BRACE); skip_newlines (); parse_statement_list (); next_token_must_be (TOK_CLOSE_BRACE); - REWRITE_TRY (STACK_TOP (U16)); + rewrite_try (); token_after_newlines_must_be (TOK_KEYWORD); if (is_keyword (KW_CATCH)) @@ -3385,7 +2183,7 @@ parse_try_statement (void) } else { - lexer_save_token (TOK ()); + lexer_save_token (tok); } } else if (is_keyword (KW_FINALLY)) @@ -3397,26 +2195,22 @@ parse_try_statement (void) EMIT_ERROR ("Expected either 'catch' or 'finally' token"); } - DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_END_TRY_CATCH_FINALLY, INVALID_VALUE, INVALID_VALUE); - - STACK_DROP (U16, 1); - - STACK_CHECK_USAGE (U16); + dump_end_try_catch_finally (); } static void insert_semicolon (void) { - // We cannot use TOK (), since we may use lexer_save_token + // We cannot use tok, since we may use lexer_save_token skip_token (); if (token_is (TOK_NEWLINE) || lexer_prev_token ().type == TOK_NEWLINE) { - lexer_save_token (TOK ()); + lexer_save_token (tok); return; } if (token_is (TOK_CLOSE_BRACE)) { - lexer_save_token (TOK ()); + lexer_save_token (tok); return; } else if (!token_is (TOK_SEMICOLON)) @@ -3491,15 +2285,12 @@ insert_semicolon (void) static void parse_statement (void) { - reset_temp_name (); - - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (toks) + dumper_new_statement (); if (token_is (TOK_CLOSE_BRACE)) { - lexer_save_token (TOK ()); - goto cleanup; + lexer_save_token (tok); + return; } if (token_is (TOK_OPEN_BRACE)) { @@ -3509,113 +2300,101 @@ parse_statement (void) parse_statement_list (); next_token_must_be (TOK_CLOSE_BRACE); } - goto cleanup; + return; } if (is_keyword (KW_VAR)) { skip_newlines (); parse_variable_declaration_list (NULL); - goto cleanup; + return; } if (is_keyword (KW_FUNCTION)) { parse_function_declaration (); - goto cleanup; + return; } if (token_is (TOK_SEMICOLON)) { - goto cleanup; + return; } if (is_keyword (KW_CASE) || is_keyword (KW_DEFAULT)) { - goto cleanup; + return; } if (is_keyword (KW_IF)) { parse_if_statement (); - goto cleanup; + return; } if (is_keyword (KW_DO)) { parse_do_while_statement (); - goto cleanup; + return; } if (is_keyword (KW_WHILE)) { parse_while_statement (); - goto cleanup; + return; } if (is_keyword (KW_FOR)) { parse_for_or_for_in_statement (); - goto cleanup; + return; } if (is_keyword (KW_CONTINUE)) { - 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; + must_be_inside_but_not_in (NESTING_FUNCTION, 1, NESTING_ITERATIONAL); + dump_continue_for_rewrite (); + return; } if (is_keyword (KW_BREAK)) { - 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 ()); - mem_heap_free_block (temp); - DUMP_OPCODE_2 (jmp_down, INVALID_VALUE, INVALID_VALUE); - goto cleanup; + must_be_inside_but_not_in (NESTING_FUNCTION, 2, NESTING_ITERATIONAL, NESTING_SWITCH); + dump_break_for_rewrite (); + return; } if (is_keyword (KW_RETURN)) { skip_token (); if (!token_is (TOK_SEMICOLON) && !token_is (TOK_NEWLINE)) { - parse_expression (); - DUMP_OPCODE_1 (retval, ID(1)); - STACK_DROP (IDX, 1); + const operand op = parse_expression (true); + dump_retval (op); insert_semicolon (); - goto cleanup; + return; } else { - DUMP_VOID_OPCODE (ret); - goto cleanup; + dump_ret (); + return; } } if (is_keyword (KW_WITH)) { parse_with_statement (); - goto cleanup; + return; } if (is_keyword (KW_SWITCH)) { parse_switch_statement (); - goto cleanup; + return; } if (is_keyword (KW_THROW)) { skip_token (); - parse_expression (); + const operand op = parse_expression (true); insert_semicolon (); - - DUMP_OPCODE_1 (throw, ID(1)); - STACK_DROP (IDX, 1); - goto cleanup; + dump_throw (op); + return; } if (is_keyword (KW_TRY)) { parse_try_statement (); - goto cleanup; + return; } if (token_is (TOK_NAME)) { - STACK_PUSH (toks, TOK ()); + const token temp = tok; skip_newlines (); if (token_is (TOK_COLON)) { @@ -3624,29 +2403,22 @@ parse_statement (void) } else { - lexer_save_token (TOK ()); - SET_TOK (STACK_TOP (toks)); - STACK_DROP (toks, 1); - parse_expression (); - STACK_DROP (IDX, 1); + lexer_save_token (tok); + tok = temp; + parse_expression (true); skip_newlines (); if (!token_is (TOK_SEMICOLON)) { - lexer_save_token (TOK ()); + lexer_save_token (tok); } - goto cleanup; + return; } } else { - parse_expression (); - STACK_DROP (IDX, 1); - goto cleanup; + parse_expression (true); + return; } - -cleanup: - STACK_CHECK_USAGE (IDX); - STACK_CHECK_USAGE (toks); } /* source_element @@ -3656,8 +2428,6 @@ cleanup: static void parse_source_element (void) { - STACK_DECLARE_USAGE (IDX) - if (is_keyword (KW_FUNCTION)) { parse_function_declaration (); @@ -3666,8 +2436,6 @@ parse_source_element (void) { parse_statement (); } - - STACK_CHECK_USAGE (IDX); } static void @@ -3691,22 +2459,19 @@ skip_optional_name_and_parens (void) static void skip_braces (void) { - STACK_DECLARE_USAGE (U8) - current_token_must_be (TOK_OPEN_BRACE); - STACK_PUSH (U8, 1); - - while (STACK_TOP (U8) > 0) + uint8_t nesting_level = 1; + while (nesting_level > 0) { skip_newlines (); if (token_is (TOK_OPEN_BRACE)) { - STACK_INCR_HEAD (U8, 1); + nesting_level++; } else if (token_is (TOK_CLOSE_BRACE)) { - STACK_DECR_HEAD (U8, 1); + nesting_level--; } else if (token_is (TOK_KEYWORD)) { @@ -3718,7 +2483,7 @@ skip_braces (void) } else { - lexer_save_token (TOK ()); + lexer_save_token (tok); } } else if (token_is (TOK_NAME)) @@ -3737,19 +2502,16 @@ skip_braces (void) } else { - lexer_save_token (TOK ()); + lexer_save_token (tok); } } else { - lexer_save_token (TOK ()); + lexer_save_token (tok); } } } } - - STACK_DROP (U8,1); - STACK_CHECK_USAGE (U8); } static void @@ -3764,84 +2526,47 @@ skip_function (void) static void skip_squares (void) { - STACK_DECLARE_USAGE (U8); - current_token_must_be (TOK_OPEN_SQUARE); - STACK_PUSH (U8, 1); - - while (STACK_TOP (U8) > 0) + uint8_t nesting_level = 1; + while (nesting_level > 0) { skip_newlines (); if (token_is (TOK_OPEN_SQUARE)) { - STACK_INCR_HEAD (U8, 1); + nesting_level++; } else if (token_is (TOK_CLOSE_SQUARE)) { - STACK_DECR_HEAD (U8, 1); + nesting_level--; } } - - STACK_DROP (U8,1); - STACK_CHECK_USAGE (U8); } static void skip_parens (void) { - STACK_DECLARE_USAGE (U8); - current_token_must_be (TOK_OPEN_PAREN); - STACK_PUSH (U8, 1); - - while (STACK_TOP (U8) > 0) + uint8_t nesting_level = 1; + while (nesting_level > 0) { skip_newlines (); if (token_is (TOK_OPEN_PAREN)) { - STACK_INCR_HEAD (U8, 1); + nesting_level++; } else if (token_is (TOK_CLOSE_PAREN)) { - STACK_DECR_HEAD (U8, 1); + nesting_level--; } } - - STACK_DROP (U8,1); - STACK_CHECK_USAGE (U8); } static bool -var_declared (idx_t var_id) +var_declared (literal_index_t var_id) { - STACK_DECLARE_USAGE (U16) - STACK_DECLARE_USAGE (ops) - bool result = false; - - STACK_PUSH (U16, (opcode_counter_t) (OPCODE_COUNTER () - 1)); - STACK_PUSH (ops, deserialize_opcode (STACK_TOP (U16))); - - while (OPCODE_IS (STACK_TOP (ops), var_decl)) - { - if (STACK_TOP (ops).data.var_decl.variable_name == var_id) - { - result = true; - goto cleanup; - } - STACK_DECR_HEAD (U16, 1); - STACK_SET_HEAD (ops, 1, deserialize_opcode (STACK_TOP (U16))); - } - -cleanup: - STACK_DROP (U16, 1); - STACK_DROP (ops, 1); - - STACK_CHECK_USAGE (U16); - STACK_CHECK_USAGE (ops); - - return result; + return dumper_variable_declaration_exists (var_id); } static void @@ -3856,7 +2581,10 @@ preparse_var_decls (void) { if (!var_declared (token_data ())) { - DUMP_OPCODE_1 (var_decl, token_data ()); + syntax_check_for_eval_and_arguments_in_strict_mode (literal_operand (token_data ()), + is_strict_mode (), + tok.loc); + dump_variable_declaration (token_data ()); } skip_token (); continue; @@ -3896,50 +2624,23 @@ preparse_var_decls (void) } } -static void -check_for_eval_and_arguments_in_var_decls (opcode_counter_t first_var_decl) -{ - if (!parser_strict_mode ()) - { - return; - } - - STACK_DECLARE_USAGE (ops); - - for (opcode_counter_t oc = first_var_decl; oc < OPCODE_COUNTER (); oc = (opcode_counter_t) (oc + 1)) - { - STACK_PUSH (ops, deserialize_opcode (oc)); - if (!OPCODE_IS (STACK_TOP (ops), var_decl)) - { - STACK_DROP (ops, 1); - break; - } - check_for_eval_and_arguments_in_strict_mode (STACK_TOP (ops).data.var_decl.variable_name); - STACK_DROP (ops, 1); - } - - STACK_CHECK_USAGE (ops); -} - static void preparse_scope (bool is_global) { - STACK_DECLARE_USAGE (locs); - STACK_DECLARE_USAGE (U8) - - STACK_PUSH (locs, TOK ().loc); - STACK_PUSH (U8, is_global ? TOK_EOF : TOK_CLOSE_BRACE); + const locus start_loc = tok.loc; + const token_type end_tt = is_global ? TOK_EOF : TOK_CLOSE_BRACE; if (token_is (TOK_STRING) && literal_equal_s (lexer_get_literal_by_id (token_data ()), "use strict")) { scopes_tree_set_strict_mode (STACK_TOP (scopes), true); - DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_STRICT_CODE, INVALID_VALUE, INVALID_VALUE); + dump_strict_mode_header (); } - STACK_PUSH (U16, OPCODE_COUNTER ()); - DUMP_OPCODE_2 (reg_var_decl, MIN_TEMP_NAME (), INVALID_VALUE); + lexer_set_strict_mode (scopes_tree_strict_mode (STACK_TOP (scopes))); - while (!token_is (STACK_TOP (U8))) + dump_reg_var_decl_for_rewrite (); + + while (!token_is (end_tt)) { if (is_keyword (KW_VAR)) { @@ -3947,34 +2648,16 @@ preparse_scope (bool is_global) } else if (is_keyword (KW_FUNCTION)) { - STACK_PUSH (U8, scopes_tree_strict_mode (STACK_TOP (scopes)) ? 1 : 0); - scopes_tree_set_strict_mode (STACK_TOP (scopes), false); skip_function (); - scopes_tree_set_strict_mode (STACK_TOP (scopes), STACK_TOP (U8) != 0); - STACK_DROP (U8, 1); } else if (token_is (TOK_OPEN_BRACE)) { - STACK_PUSH (U8, scopes_tree_strict_mode (STACK_TOP (scopes)) ? 1 : 0); - scopes_tree_set_strict_mode (STACK_TOP (scopes), false); skip_braces (); - scopes_tree_set_strict_mode (STACK_TOP (scopes), STACK_TOP (U8) != 0); - STACK_DROP (U8, 1); } skip_newlines (); } - if (parser_strict_mode ()) - { - check_for_eval_and_arguments_in_var_decls ((opcode_counter_t) (STACK_TOP (U16) + 1)); - } - - lexer_seek (STACK_TOP (locs)); - STACK_DROP (locs, 1); - STACK_DROP (U8, 1); - - STACK_CHECK_USAGE (U8); - STACK_CHECK_USAGE (locs); + lexer_seek (start_loc); } /* source_element_list @@ -3983,36 +2666,18 @@ preparse_scope (bool is_global) static void parse_source_element_list (bool is_global) { - // U16 reg_var_decl_loc; - STACK_DECLARE_USAGE (U16) - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (temp_names) - - + dumper_new_scope (); preparse_scope (is_global); - if (is_global) - { - SET_MAX_TEMP_NAME (lexer_get_literals_count ()); - SET_TEMP_NAME (lexer_get_literals_count ()); - SET_MIN_TEMP_NAME (lexer_get_literals_count ()); - } - start_new_scope (); skip_newlines (); while (!token_is (TOK_EOF) && !token_is (TOK_CLOSE_BRACE)) { parse_source_element (); skip_newlines (); } - lexer_save_token (TOK ()); - REWRITE_OPCODE_2 (STACK_TOP (U16), reg_var_decl, MIN_TEMP_NAME (), MAX_TEMP_NAME ()); - finish_scope (); - - STACK_DROP (U16, 1); - - STACK_CHECK_USAGE (U16); - STACK_CHECK_USAGE (IDX); - STACK_CHECK_USAGE (temp_names); + lexer_save_token (tok); + rewrite_reg_var_decl (); + dumper_finish_scope (); } /* program @@ -4021,18 +2686,16 @@ parse_source_element_list (bool is_global) void parser_parse_program (void) { - STACK_DECLARE_USAGE (IDX) - STACK_DECLARE_USAGE (scopes); - STACK_PUSH (scopes, scopes_tree_init (NULL)); serializer_set_scope (STACK_TOP (scopes)); + lexer_set_strict_mode (scopes_tree_strict_mode (STACK_TOP (scopes))); skip_newlines (); parse_source_element_list (true); skip_newlines (); JERRY_ASSERT (token_is (TOK_EOF)); - DUMP_OPCODE_1 (exitval, 0); + dump_exit (); serializer_dump_literals (lexer_get_literals (), lexer_get_literals_count ()); serializer_merge_scopes_into_bytecode (); @@ -4041,22 +2704,6 @@ parser_parse_program (void) scopes_tree_free (STACK_TOP (scopes)); STACK_DROP (scopes, 1); - - STACK_CHECK_USAGE (IDX); - STACK_CHECK_USAGE (scopes); -} - -bool -parser_strict_mode (void) -{ - if (STACK_SIZE (scopes) > 0) - { - return scopes_tree_strict_mode (STACK_TOP (scopes)); - } - else - { - return false; - } } void @@ -4064,42 +2711,21 @@ parser_init (const char *source, size_t source_size, bool show_opcodes) { lexer_init (source, source_size, show_opcodes); serializer_init (show_opcodes); + dumper_init (); + syntax_init (); - STACK_INIT (U8); - STACK_INIT (IDX); STACK_INIT (nestings); - STACK_INIT (temp_names); - STACK_INIT (toks); - STACK_INIT (ops); - STACK_INIT (U16); - STACK_INIT (rewritable_continue); - STACK_INIT (rewritable_break); - STACK_INIT (locs); STACK_INIT (scopes); - STACK_INIT (props); - STACK_INIT (literals); - - SET_OPCODE_COUNTER (0); - STACK_SET_ELEMENT (U8, no_in, 0); } void parser_free (void) { - STACK_FREE (U8); - STACK_FREE (IDX); STACK_FREE (nestings); - STACK_FREE (temp_names); - STACK_FREE (toks); - STACK_FREE (ops); - STACK_FREE (U16); - STACK_FREE (rewritable_continue); - STACK_FREE (rewritable_break); - STACK_FREE (locs); STACK_FREE (scopes); - STACK_FREE (props); - STACK_FREE (literals); + syntax_free (); + dumper_free (); serializer_free (); lexer_free (); } diff --git a/src/libjsparser/parser.h b/src/libjsparser/parser.h index 5b404fb59..16ca1e4d0 100644 --- a/src/libjsparser/parser.h +++ b/src/libjsparser/parser.h @@ -21,6 +21,5 @@ void parser_init (const char *, size_t, bool); void parser_parse_program (void); void parser_free (void); -bool parser_strict_mode (void); #endif diff --git a/src/libjsparser/scopes-tree.c b/src/libjsparser/scopes-tree.c index 0c2f780d7..c62b0fb68 100644 --- a/src/libjsparser/scopes-tree.c +++ b/src/libjsparser/scopes-tree.c @@ -16,8 +16,15 @@ #include "scopes-tree.h" #include "mem-heap.h" #include "jerry-libc.h" +#include "lexer.h" +#include "bytecode-data.h" -#define NAME_TO_ID(op) (__op__idx_##op) +#define OPCODE(op) (__op__idx_##op) +#define HASH_SIZE 128 + +static hash_table lit_id_to_uid = null_hash; +static opcode_counter_t global_oc = 0; +static idx_t next_uid; static void assert_tree (scopes_tree t) @@ -26,6 +33,22 @@ assert_tree (scopes_tree t) JERRY_ASSERT (t->t.magic == TREE_MAGIC); } +static idx_t +get_uid (op_meta *op, uint8_t i) +{ + JERRY_ASSERT (i < 4); + raw_opcode *raw = (raw_opcode *) &op->op; + return raw->uids[i + 1]; +} + +static void +set_uid (op_meta *op, uint8_t i, idx_t uid) +{ + JERRY_ASSERT (i < 4); + raw_opcode *raw = (raw_opcode *) &op->op; + raw->uids[i + 1] = uid; +} + opcode_counter_t scopes_tree_opcodes_num (scopes_tree t) { @@ -34,18 +57,18 @@ scopes_tree_opcodes_num (scopes_tree t) } void -scopes_tree_add_opcode (scopes_tree tree, opcode_t op) +scopes_tree_add_op_meta (scopes_tree tree, op_meta op) { assert_tree (tree); - linked_list_set_element (tree->opcodes, sizeof (opcode_t), tree->opcodes_num++, &op); + linked_list_set_element (tree->opcodes, tree->opcodes_num++, &op); } void -scopes_tree_set_opcode (scopes_tree tree, opcode_counter_t oc, opcode_t op) +scopes_tree_set_op_meta (scopes_tree tree, opcode_counter_t oc, op_meta op) { assert_tree (tree); JERRY_ASSERT (oc < tree->opcodes_num); - linked_list_set_element (tree->opcodes, sizeof (opcode_t), oc, &op); + linked_list_set_element (tree->opcodes, oc, &op); } void @@ -56,12 +79,12 @@ scopes_tree_set_opcodes_num (scopes_tree tree, opcode_counter_t oc) tree->opcodes_num = oc; } -opcode_t -scopes_tree_opcode (scopes_tree tree, opcode_counter_t oc) +op_meta +scopes_tree_op_meta (scopes_tree tree, opcode_counter_t oc) { assert_tree (tree); JERRY_ASSERT (oc < tree->opcodes_num); - return *(opcode_t *) linked_list_element (tree->opcodes, sizeof (opcode_t), oc); + return *(op_meta *) linked_list_element (tree->opcodes, oc); } opcode_counter_t @@ -71,64 +94,295 @@ scopes_tree_count_opcodes (scopes_tree t) opcode_counter_t res = t->opcodes_num; for (uint8_t i = 0; i < t->t.children_num; i++) { - res = (opcode_counter_t) (res - + scopes_tree_count_opcodes (*(scopes_tree *) linked_list_element (t->t.children, - sizeof (scopes_tree), - i))); + res = (opcode_counter_t) ( + res + scopes_tree_count_opcodes ( + *(scopes_tree *) linked_list_element (t->t.children, i))); } return res; } -static opcode_counter_t -merge_subscopes (scopes_tree tree, opcode_t *data) +static uint16_t +lit_id_hash (void * lit_id) +{ + return *(literal_index_t *) lit_id % HASH_SIZE; +} + +static void +start_new_block_if_necessary (void) +{ + if (global_oc % BLOCK_SIZE == 0) + { + next_uid = 0; + if (lit_id_to_uid != null_hash) + { + hash_table_free (lit_id_to_uid); + lit_id_to_uid = null_hash; + } + lit_id_to_uid = hash_table_init (sizeof (literal_index_t), sizeof (idx_t), HASH_SIZE, lit_id_hash, + MEM_HEAP_ALLOC_SHORT_TERM); + } +} + +static bool +is_possible_literal (uint16_t mask, uint8_t index) +{ + int res; + switch (index) + { + case 0: + { + res = mask >> 8; + break; + } + case 1: + { + res = (mask & 0xF0) >> 4; + break; + } + default: + { + JERRY_ASSERT (index = 2); + res = mask & 0x0F; + } + } + JERRY_ASSERT (res == 0 || res == 1); + return res == 1; +} + +static void +change_uid (op_meta *om, hash_table lit_ids, uint16_t mask) +{ + for (uint8_t i = 0; i < 3; i++) + { + if (is_possible_literal (mask, i)) + { + if (get_uid (om, i) == LITERAL_TO_REWRITE) + { + JERRY_ASSERT (om->lit_id[i] != NOT_A_LITERAL); + literal_index_t lit_id = om->lit_id[i]; + idx_t *uid = hash_table_lookup (lit_id_to_uid, &lit_id); + if (uid == NULL) + { + hash_table_insert (lit_id_to_uid, &lit_id, &next_uid); + lit_id_table_key key = create_lit_id_table_key (next_uid, global_oc); + hash_table_insert (lit_ids, &key, &lit_id); + uid = hash_table_lookup (lit_id_to_uid, &lit_id); + JERRY_ASSERT (uid != NULL); + JERRY_ASSERT (*uid == next_uid); + next_uid++; + } + set_uid (om, i, *uid); + } + else + { + JERRY_ASSERT (om->lit_id[i] == NOT_A_LITERAL); + } + } + else + { + JERRY_ASSERT (om->lit_id[i] == NOT_A_LITERAL); + } + } +} + +static op_meta * +extract_op_meta (scopes_tree tree, opcode_counter_t opc_index) +{ + return (op_meta *) linked_list_element (tree->opcodes, opc_index); +} + +static opcode_t +generate_opcode (scopes_tree tree, opcode_counter_t opc_index, hash_table lit_ids) +{ + start_new_block_if_necessary (); + op_meta *om = extract_op_meta (tree, opc_index); + /* Now we should change uids of opcodes. + Since different opcodes has different literals/tmps in different places, + we should change only them. + For each case possible literal positions are shown as 0xYYY literal, + where Y is set to '1' when there is a possible literal in this position, + and '0' otherwise. */ + switch (om->op.op_idx) + { + case OPCODE (prop_getter): + case OPCODE (prop_setter): + case OPCODE (delete_prop): + case OPCODE (b_shift_left): + case OPCODE (b_shift_right): + case OPCODE (b_shift_uright): + case OPCODE (b_and): + case OPCODE (b_or): + case OPCODE (b_xor): + case OPCODE (equal_value): + case OPCODE (not_equal_value): + case OPCODE (equal_value_type): + case OPCODE (not_equal_value_type): + case OPCODE (less_than): + case OPCODE (greater_than): + case OPCODE (less_or_equal_than): + case OPCODE (greater_or_equal_than): + case OPCODE (instanceof): + case OPCODE (in): + case OPCODE (addition): + case OPCODE (substraction): + case OPCODE (division): + case OPCODE (multiplication): + case OPCODE (remainder): + { + change_uid (om, lit_ids, 0x111); + break; + } + case OPCODE (call_n): + case OPCODE (native_call): + case OPCODE (construct_n): + case OPCODE (func_expr_n): + case OPCODE (delete_var): + case OPCODE (typeof): + case OPCODE (b_not): + case OPCODE (logical_not): + case OPCODE (post_incr): + case OPCODE (post_decr): + case OPCODE (pre_incr): + case OPCODE (pre_decr): + case OPCODE (unary_plus): + case OPCODE (unary_minus): + { + change_uid (om, lit_ids, 0x110); + break; + } + case OPCODE (assignment): + { + switch (om->op.data.assignment.type_value_right) + { + case OPCODE_ARG_TYPE_SIMPLE: + case OPCODE_ARG_TYPE_SMALLINT: + case OPCODE_ARG_TYPE_SMALLINT_NEGATE: + { + change_uid (om, lit_ids, 0x100); + break; + } + case OPCODE_ARG_TYPE_NUMBER: + case OPCODE_ARG_TYPE_NUMBER_NEGATE: + case OPCODE_ARG_TYPE_STRING: + case OPCODE_ARG_TYPE_VARIABLE: + { + change_uid (om, lit_ids, 0x101); + break; + } + } + break; + } + case OPCODE (func_decl_n): + case OPCODE (array_decl): + case OPCODE (obj_decl): + case OPCODE (this): + case OPCODE (with): + case OPCODE (throw): + case OPCODE (is_true_jmp_up): + case OPCODE (is_true_jmp_down): + case OPCODE (is_false_jmp_up): + case OPCODE (is_false_jmp_down): + case OPCODE (var_decl): + case OPCODE (retval): + { + change_uid (om, lit_ids, 0x100); + break; + } + case OPCODE (exitval): + case OPCODE (ret): + case OPCODE (try): + case OPCODE (jmp_up): + case OPCODE (jmp_down): + case OPCODE (nop): + case OPCODE (reg_var_decl): + { + change_uid (om, lit_ids, 0x000); + break; + } + case OPCODE (meta): + { + switch (om->op.data.meta.type) + { + case OPCODE_META_TYPE_VARG_PROP_DATA: + case OPCODE_META_TYPE_VARG_PROP_GETTER: + case OPCODE_META_TYPE_VARG_PROP_SETTER: + { + change_uid (om, lit_ids, 0x011); + break; + } + case OPCODE_META_TYPE_THIS_ARG: + case OPCODE_META_TYPE_VARG: + case OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER: + { + change_uid (om, lit_ids, 0x010); + break; + } + case OPCODE_META_TYPE_UNDEFINED: + case OPCODE_META_TYPE_END_WITH: + case OPCODE_META_TYPE_FUNCTION_END: + case OPCODE_META_TYPE_CATCH: + case OPCODE_META_TYPE_FINALLY: + case OPCODE_META_TYPE_END_TRY_CATCH_FINALLY: + case OPCODE_META_TYPE_STRICT_CODE: + { + change_uid (om, lit_ids, 0x000); + break; + } + } + break; + } + } + return om->op; +} + +static void +merge_subscopes (scopes_tree tree, opcode_t *data, hash_table lit_ids) { assert_tree (tree); JERRY_ASSERT (data); - opcode_counter_t opc_index, data_index; + opcode_counter_t opc_index; bool header = true; - for (opc_index = 0, data_index = 0; opc_index < tree->opcodes_num; opc_index++, data_index++) + for (opc_index = 0; opc_index < tree->opcodes_num; opc_index++) { - opcode_t *op = (opcode_t *) linked_list_element (tree->opcodes, sizeof (opcode_t), opc_index); - JERRY_ASSERT (op); - if (op->op_idx != NAME_TO_ID (var_decl) - && op->op_idx != NAME_TO_ID (nop) - && op->op_idx != NAME_TO_ID (meta) && !header) + op_meta *om = extract_op_meta (tree, opc_index); + if (om->op.op_idx != OPCODE (var_decl) + && om->op.op_idx != OPCODE (meta) && !header) { break; } - if (op->op_idx == NAME_TO_ID (reg_var_decl)) + if (om->op.op_idx == OPCODE (reg_var_decl)) { header = false; } - data[data_index] = *op; + data[global_oc] = generate_opcode (tree, opc_index, lit_ids); + global_oc++; } for (uint8_t child_id = 0; child_id < tree->t.children_num; child_id++) { - data_index = (opcode_counter_t) (data_index - + merge_subscopes (*(scopes_tree *) linked_list_element (tree->t.children, - sizeof (scopes_tree), - child_id), - data + data_index)); + merge_subscopes (*(scopes_tree *) linked_list_element (tree->t.children, child_id), + data, lit_ids); } - for (; opc_index < tree->opcodes_num; opc_index++, data_index++) + for (; opc_index < tree->opcodes_num; opc_index++) { - opcode_t *op = (opcode_t *) linked_list_element (tree->opcodes, sizeof (opcode_t), opc_index); - data[data_index] = *op; + data[global_oc] = generate_opcode (tree, opc_index, lit_ids); + global_oc++; } - return data_index; } opcode_t * -scopes_tree_raw_data (scopes_tree tree, opcode_counter_t *num) +scopes_tree_raw_data (scopes_tree tree, hash_table lit_ids) { assert_tree (tree); - opcode_counter_t res = scopes_tree_count_opcodes (tree); - size_t size = ((size_t) (res + 1) * sizeof (opcode_t)); // +1 for valgrind + opcode_counter_t opcodes_count = scopes_tree_count_opcodes (tree); + size_t size = ((size_t) (opcodes_count + 1) * sizeof (opcode_t)); // +1 for valgrind opcode_t *opcodes = (opcode_t *) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_LONG_TERM); __memset (opcodes, 0, size); - opcode_counter_t merged = merge_subscopes (tree, opcodes); - JERRY_ASSERT (merged == res); - *num = res; + merge_subscopes (tree, opcodes, lit_ids); + if (lit_id_to_uid != null_hash) + { + hash_table_free (lit_id_to_uid); + lit_id_to_uid = null_hash; + } return opcodes; } @@ -150,7 +404,7 @@ scopes_tree scopes_tree_init (scopes_tree parent) { scopes_tree tree = (scopes_tree) mem_heap_alloc_block (sizeof (scopes_tree_int), MEM_HEAP_ALLOC_SHORT_TERM); - __memset (tree, 0, sizeof (scopes_tree)); + __memset (tree, 0, sizeof (scopes_tree_int)); tree->t.magic = TREE_MAGIC; tree->t.parent = (tree_header *) parent; tree->t.children = null_list; @@ -161,14 +415,14 @@ scopes_tree_init (scopes_tree parent) { parent->t.children = linked_list_init (sizeof (scopes_tree)); } - linked_list_set_element (parent->t.children, sizeof (scopes_tree), parent->t.children_num, &tree); - void *added = linked_list_element (parent->t.children, sizeof (scopes_tree), parent->t.children_num); + linked_list_set_element (parent->t.children, parent->t.children_num, &tree); + void *added = linked_list_element (parent->t.children, parent->t.children_num); JERRY_ASSERT (*(scopes_tree *) added == tree); parent->t.children_num++; } tree->opcodes_num = 0; tree->strict_mode = 0; - tree->opcodes = linked_list_init (sizeof (opcode_t)); + tree->opcodes = linked_list_init (sizeof (op_meta)); return tree; } @@ -180,7 +434,7 @@ scopes_tree_free (scopes_tree tree) { for (uint8_t i = 0; i < tree->t.children_num; ++i) { - scopes_tree_free (*(scopes_tree *) linked_list_element (tree->t.children, sizeof (scopes_tree), i)); + scopes_tree_free (*(scopes_tree *) linked_list_element (tree->t.children, i)); } linked_list_free (tree->t.children); } diff --git a/src/libjsparser/scopes-tree.h b/src/libjsparser/scopes-tree.h index abf4d0470..250111f95 100644 --- a/src/libjsparser/scopes-tree.h +++ b/src/libjsparser/scopes-tree.h @@ -18,8 +18,20 @@ #include "tree.h" #include "linked-list.h" +#include "lexer.h" +#include "ecma-globals.h" +#include "hash-table.h" #include "opcodes.h" +#define NOT_A_LITERAL (INVALID_LITERAL - 1) + +typedef struct +{ + literal_index_t lit_id[3]; + opcode_t op; +} +op_meta; + typedef struct { tree_header t; @@ -34,12 +46,12 @@ typedef scopes_tree_int * scopes_tree; scopes_tree scopes_tree_init (scopes_tree); void scopes_tree_free (scopes_tree); opcode_counter_t scopes_tree_opcodes_num (scopes_tree); -void scopes_tree_add_opcode (scopes_tree, opcode_t); -void scopes_tree_set_opcode (scopes_tree, opcode_counter_t, opcode_t); +void scopes_tree_add_op_meta (scopes_tree, op_meta); +void scopes_tree_set_op_meta (scopes_tree, opcode_counter_t, op_meta); void scopes_tree_set_opcodes_num (scopes_tree, opcode_counter_t); -opcode_t scopes_tree_opcode (scopes_tree, opcode_counter_t); +op_meta scopes_tree_op_meta (scopes_tree, opcode_counter_t); opcode_counter_t scopes_tree_count_opcodes (scopes_tree); -opcode_t *scopes_tree_raw_data (scopes_tree, opcode_counter_t *); +opcode_t *scopes_tree_raw_data (scopes_tree, hash_table); void scopes_tree_set_strict_mode (scopes_tree, bool); bool scopes_tree_strict_mode (scopes_tree); diff --git a/src/libjsparser/syntax-errors.c b/src/libjsparser/syntax-errors.c new file mode 100644 index 000000000..637d9bf3e --- /dev/null +++ b/src/libjsparser/syntax-errors.c @@ -0,0 +1,223 @@ +/* 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 "syntax-errors.h" +#include "stack.h" +#include "globals.h" +#include "parser.h" +#include "jerry-libc.h" +#include "ecma-helpers.h" + +typedef struct +{ + prop_type type; + literal lit; +} +prop_literal; + +enum +{ + props_global_size +}; +STATIC_STACK (props, prop_literal) + +enum +{ + U8_global_size +}; +STATIC_STACK (U8, uint8_t) + +static prop_literal +create_prop_literal (literal lit, prop_type type) +{ + return (prop_literal) + { + .type = type, + .lit = lit + }; +} + +void +syntax_start_checking_of_prop_names (void) +{ + STACK_PUSH (U8, (uint8_t) STACK_SIZE (props)); +} + +void +syntax_add_prop_name (operand op, prop_type pt) +{ + JERRY_ASSERT (op.type == OPERAND_LITERAL); + STACK_PUSH (props, create_prop_literal (lexer_get_literal_by_id (op.data.lit_id), pt)); +} + +void +syntax_check_for_duplication_of_prop_names (bool is_strict, locus loc) +{ + if (STACK_SIZE (props) - STACK_TOP (U8) < 2) + { + STACK_DROP (U8, 1); + return; + } + + for (uint8_t i = (uint8_t) (STACK_TOP (U8) + 1); + i < STACK_SIZE (props); + i++) + { + const prop_literal previous = STACK_ELEMENT (props, i); + if (previous.type == VARG) + { + continue; + } + JERRY_ASSERT (previous.type == PROP_DATA + || previous.type == PROP_GET + || previous.type == PROP_SET); + for (uint8_t j = STACK_TOP (U8); j < i; j = (uint8_t) (j + 1)) + { + /*4*/ + const prop_literal current = STACK_ELEMENT (props, j); + if (current.type == VARG) + { + continue; + } + JERRY_ASSERT (current.type == PROP_DATA + || current.type == PROP_GET + || current.type == PROP_SET); + if (literal_equal (previous.lit, current.lit)) + { + /*a*/ + if (is_strict && previous.type == PROP_DATA && current.type == PROP_DATA) + { + PARSE_ERROR_VARG ("Duplication of parameter name '%s' in ObjectDeclaration is not allowed in strict mode", + loc, (const char *) literal_to_zt (current.lit)); + } + /*b*/ + if (previous.type == PROP_DATA + && (current.type == PROP_SET || current.type == PROP_GET)) + { + PARSE_ERROR_VARG ("Parameter name '%s' in ObjectDeclaration may not be both data and accessor", + loc, (const char *) literal_to_zt (current.lit)); + } + /*c*/ + if (current.type == PROP_DATA + && (previous.type == PROP_SET || previous.type == PROP_GET)) + { + PARSE_ERROR_VARG ("Parameter name '%s' in ObjectDeclaration may not be both data and accessor", + loc, (const char *) literal_to_zt (current.lit)); + } + /*d*/ + if ((previous.type == PROP_SET && current.type == PROP_SET) + || (previous.type == PROP_GET && current.type == PROP_GET)) + { + PARSE_ERROR_VARG ("Parameter name '%s' in ObjectDeclaration may not be accessor of same type", + loc, (const char *) literal_to_zt (current.lit)); + } + } + } + } + + STACK_DROP (props, (uint8_t) (STACK_SIZE (props) - STACK_TOP (U8))); + STACK_DROP (U8, 1); +} + +void +syntax_start_checking_of_vargs (void) +{ + STACK_PUSH (U8, (uint8_t) STACK_SIZE (props)); +} + +void syntax_add_varg (operand op) +{ + JERRY_ASSERT (op.type == OPERAND_LITERAL); + STACK_PUSH (props, create_prop_literal (lexer_get_literal_by_id (op.data.lit_id), VARG)); +} + +static void +emit_error_on_eval_and_arguments (operand op, locus loc) +{ + if (op.type == OPERAND_LITERAL) + { + if (literal_equal_type_zt (lexer_get_literal_by_id (op.data.lit_id), + ecma_get_magic_string_zt (ECMA_MAGIC_STRING_ARGUMENTS)) + || literal_equal_type_zt (lexer_get_literal_by_id (op.data.lit_id), + ecma_get_magic_string_zt (ECMA_MAGIC_STRING_EVAL))) + { + PARSE_ERROR ("'eval' and 'arguments' are not allowed here in strict mode", loc); + } + } +} + +void +syntax_check_for_eval_and_arguments_in_strict_mode (operand op, bool is_strict, locus loc) +{ + if (is_strict) + { + emit_error_on_eval_and_arguments (op, loc); + } +} + +/* 13.1, 15.3.2 */ +void +syntax_check_for_syntax_errors_in_formal_param_list (bool is_strict, locus loc) +{ + if (STACK_SIZE (props) - STACK_TOP (U8) < 2 || !is_strict) + { + STACK_DROP (U8, 1); + return; + } + for (uint8_t i = (uint8_t) (STACK_TOP (U8) + 1); i < STACK_SIZE (props); i = (uint8_t) (i + 1)) + { + JERRY_ASSERT (STACK_ELEMENT (props, i).type == VARG); + const literal previous = STACK_ELEMENT (props, i).lit; + JERRY_ASSERT (previous.type == LIT_STR || previous.type == LIT_MAGIC_STR); + for (uint8_t j = STACK_TOP (U8); j < i; j = (uint8_t) (j + 1)) + { + JERRY_ASSERT (STACK_ELEMENT (props, j).type == VARG); + const literal current = STACK_ELEMENT (props, j).lit; + JERRY_ASSERT (current.type == LIT_STR || current.type == LIT_MAGIC_STR); + if (literal_equal_type (previous, current)) + { + PARSE_ERROR_VARG ("Duplication of literal '%s' in FormalParameterList is not allowed in strict mode", + loc, (const char *) literal_to_zt (previous)); + } + } + } + + STACK_DROP (props, (uint8_t) (STACK_SIZE (props) - STACK_TOP (U8))); + STACK_DROP (U8, 1); +} + +void +syntax_check_delete (bool is_strict, locus loc) +{ + if (is_strict) + { + PARSE_ERROR ("'delete' operator shall not apply on identifier in strict mode.", loc); + } +} + +void +syntax_init (void) +{ + STACK_INIT (props); + STACK_INIT (U8); +} + +void +syntax_free (void) +{ + STACK_FREE (U8); + STACK_FREE (props); +} + diff --git a/src/libjsparser/parse-error.h b/src/libjsparser/syntax-errors.h similarity index 74% rename from src/libjsparser/parse-error.h rename to src/libjsparser/syntax-errors.h index 2e4a7ef4d..33a12d23b 100644 --- a/src/libjsparser/parse-error.h +++ b/src/libjsparser/syntax-errors.h @@ -13,8 +13,12 @@ * limitations under the License. */ -#ifndef PARSE_ERROR_H -#define PARSE_ERROR_H +#ifndef SYNTAX_ERRORS_H +#define SYNTAX_ERRORS_H + +#include "literal.h" +#include "opcodes-dumper.h" +#include "lexer.h" #define PARSE_ERROR(MESSAGE, LOCUS) do { \ size_t line, column; \ @@ -60,4 +64,27 @@ __exit (-1); \ } while (0) -#endif /* PARSE_ERROR_H */ +typedef enum +{ + PROP_DATA, + PROP_SET, + PROP_GET, + VARG +} +prop_type; + +void syntax_init (void); +void syntax_free (void); + +void syntax_start_checking_of_prop_names (void); +void syntax_add_prop_name (operand, prop_type); +void syntax_check_for_duplication_of_prop_names (bool, locus); + +void syntax_start_checking_of_vargs (void); +void syntax_add_varg (operand); +void syntax_check_for_eval_and_arguments_in_strict_mode (operand, bool, locus); +void syntax_check_for_syntax_errors_in_formal_param_list (bool, locus); + +void syntax_check_delete (bool, locus); + +#endif /* SYNTAX_ERRORS_H */ diff --git a/src/liboptimizer/bytecode-data.h b/src/liboptimizer/bytecode-data.h index ab1fa35d8..2ceb5d0fd 100644 --- a/src/liboptimizer/bytecode-data.h +++ b/src/liboptimizer/bytecode-data.h @@ -22,26 +22,28 @@ #include "literal.h" #include "scopes-tree.h" -/* bytecode_data contains identifiers, string and num literals. - Memory map if the following. +#define BLOCK_SIZE 64 - bytecode_data { - U8 strs_count; - U8 string_offsets[str_count]; - U8* strings[str_count]; +typedef struct +{ + opcode_counter_t oc; + idx_t uid; + uint8_t reserved; +} +lit_id_table_key; - U8 nums_count; - U32 nums[nums_count]; - } */ struct { const literal *literals; const opcode_t *opcodes; - uint8_t literals_count; + literal_index_t literals_count; opcode_counter_t opcodes_count; + hash_table lit_id_hash; } bytecode_data; +lit_id_table_key create_lit_id_table_key (idx_t, opcode_counter_t); + scopes_tree current_scope; #endif // BYTECODE_DATA_H diff --git a/src/liboptimizer/deserializer.c b/src/liboptimizer/deserializer.c index c80e82b17..83f1d121a 100644 --- a/src/liboptimizer/deserializer.c +++ b/src/liboptimizer/deserializer.c @@ -19,6 +19,17 @@ const ecma_char_t *strings_buffer; +lit_id_table_key +create_lit_id_table_key (idx_t id, opcode_counter_t oc) +{ + return (lit_id_table_key) + { + .uid = id, + .oc = oc / BLOCK_SIZE, + .reserved = 0 + }; +} + void deserializer_set_strings_buffer (const ecma_char_t *s) { @@ -26,12 +37,31 @@ deserializer_set_strings_buffer (const ecma_char_t *s) } literal -deserialize_literal_by_id (uint8_t id) +deserialize_literal_by_id (literal_index_t id) { + JERRY_ASSERT (id != INVALID_LITERAL); JERRY_ASSERT (id < bytecode_data.literals_count); return bytecode_data.literals[id]; } +literal_index_t +deserialize_lit_id_by_uid (uint8_t id, opcode_counter_t oc) +{ + // __printf ("uid: %d, oc: %d\n", id, oc); + // if (id == 2 && oc == 64) + // { + // __printf ("HIT!\n"); + // } + if (bytecode_data.lit_id_hash == null_hash) + { + return INVALID_LITERAL; + } + lit_id_table_key key = create_lit_id_table_key (id, oc); + void *res = hash_table_lookup (bytecode_data.lit_id_hash, &key); + JERRY_ASSERT (res != NULL); + return *(literal_index_t *) res; +} + const void * deserialize_bytecode (void) { @@ -42,18 +72,25 @@ deserialize_bytecode (void) opcode_t deserialize_opcode (opcode_counter_t oc) { - if (bytecode_data.opcodes) + if (bytecode_data.opcodes == NULL) { - JERRY_ASSERT (oc < bytecode_data.opcodes_count); - return bytecode_data.opcodes[oc]; + return deserialize_op_meta (oc).op; } - return scopes_tree_opcode (current_scope, oc); + JERRY_ASSERT (oc < bytecode_data.opcodes_count); + return bytecode_data.opcodes[oc]; +} + +op_meta +deserialize_op_meta (opcode_counter_t oc) +{ + JERRY_ASSERT (current_scope); + return scopes_tree_op_meta (current_scope, oc); } uint8_t deserialize_min_temp (void) { - return bytecode_data.literals_count; + return 128; } void @@ -71,6 +108,13 @@ deserializer_free (void) { mem_heap_free_block ((uint8_t *) strings_buffer); } - mem_heap_free_block ((uint8_t *) bytecode_data.literals); + if (bytecode_data.lit_id_hash != null_hash) + { + hash_table_free (bytecode_data.lit_id_hash); + } + if (bytecode_data.literals != NULL) + { + mem_heap_free_block ((uint8_t *) bytecode_data.literals); + } mem_heap_free_block ((uint8_t *) bytecode_data.opcodes); } diff --git a/src/liboptimizer/deserializer.h b/src/liboptimizer/deserializer.h index 1d540006f..6541796c6 100644 --- a/src/liboptimizer/deserializer.h +++ b/src/liboptimizer/deserializer.h @@ -19,13 +19,16 @@ #include "globals.h" #include "ecma-globals.h" #include "opcodes.h" +#include "scopes-tree.h" #include "literal.h" void deserializer_init (void); void deserializer_set_strings_buffer (const ecma_char_t *); -literal deserialize_literal_by_id (uint8_t); +literal deserialize_literal_by_id (literal_index_t); +literal_index_t deserialize_lit_id_by_uid (uint8_t, opcode_counter_t); const void *deserialize_bytecode (void); opcode_t deserialize_opcode (opcode_counter_t); +op_meta deserialize_op_meta (opcode_counter_t); uint8_t deserialize_min_temp (void); void deserializer_free (void); diff --git a/src/liboptimizer/pretty-printer.c b/src/liboptimizer/pretty-printer.c index e80830247..c59c6bc5c 100644 --- a/src/liboptimizer/pretty-printer.c +++ b/src/liboptimizer/pretty-printer.c @@ -21,12 +21,11 @@ #include "deserializer.h" #include "opcodes-native-call.h" #include "ecma-helpers.h" +#include "ecma-globals.h" #include #define NAME_TO_ID(op) (__op__idx_##op) -#define FIELD(op, field) (opcode.data.op.field) - #define __OPCODE_STR(name, arg1, arg2, arg3) \ #name, @@ -52,7 +51,14 @@ dump_literal (literal lit) { case LIT_NUMBER: { - __printf ("%d : NUMBER", lit.data.num); + if (ecma_number_is_nan (lit.data.num)) + { + __printf ("%s : NUMBER", "NaN"); + } + else + { + __printf ("%d : NUMBER", lit.data.num); + } break; } case LIT_MAGIC_STR: @@ -73,10 +79,10 @@ dump_literal (literal lit) } void -pp_literals (const literal lits[], uint8_t size) +pp_literals (const literal lits[], literal_index_t size) { __printf ("LITERALS %d:\n", size); - for (uint8_t i = 0; i < size; i++) + for (literal_index_t i = 0; i < size; i++) { __printf ("%3d ", i); dump_literal (lits[i]); @@ -84,52 +90,84 @@ pp_literals (const literal lits[], uint8_t size) } } -static const char * -var_id_to_string (char *res, idx_t id) +static char buff[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; + +static void +clear_temp_buffer (void) +{ + __memset (buff, 0, ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER); +} + +static const char * +lit_id_to_str (literal_index_t id) { - if (id >= lexer_get_literals_count ()) - { - __strncpy (res, "tmp", 3); - if (id / 100 != 0) - { - res[3] = (char) (id / 100 + '0'); - res[4] = (char) ((id % 100) / 10 + '0'); - res[5] = (char) (id % 10 + '0'); - return res; - } - else if (id / 10 != 0) - { - res[3] = (char) (id / 10 + '0'); - res[4] = (char) (id % 10 + '0'); - return res; - } - else - { - res[3] = (char) (id + '0'); - return res; - } - } literal lit = lexer_get_literal_by_id (id); if (lit.type == LIT_STR || lit.type == LIT_MAGIC_STR) { return (char *) literal_to_zt (lit); } - else if (lit.type == LIT_NUMBER) + else { - ecma_number_to_zt_string (lit.data.num, (ecma_char_t *) res, ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER); - return res; + JERRY_ASSERT (lit.type == LIT_NUMBER); + clear_temp_buffer (); + ecma_number_to_zt_string (lit.data.num, (ecma_char_t *) buff, ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER); + return buff; + } +} + +static const char * +tmp_id_to_str (idx_t id) +{ + JERRY_ASSERT (id != LITERAL_TO_REWRITE); + JERRY_ASSERT (id >= 128); + clear_temp_buffer (); + __strncpy (buff, "tmp", 3); + if (id / 100 != 0) + { + buff[3] = (char) (id / 100 + '0'); + buff[4] = (char) ((id % 100) / 10 + '0'); + buff[5] = (char) (id % 10 + '0'); + } + else if (id / 10 != 0) + { + buff[3] = (char) (id / 10 + '0'); + buff[4] = (char) (id % 10 + '0'); } else { - JERRY_UNREACHABLE (); + buff[3] = (char) (id + '0'); + } + return buff; +} + +static const char * +var_to_str (opcode_t opcode, literal_index_t lit_ids[], opcode_counter_t oc, uint8_t current_arg) +{ + raw_opcode raw = *(raw_opcode*) &opcode; + if (raw.uids[current_arg] == LITERAL_TO_REWRITE) + { + if (lit_ids == NULL) + { + return "hz"; + } + JERRY_ASSERT (lit_ids[current_arg - 1] != NOT_A_LITERAL + && lit_ids[current_arg - 1] != INVALID_LITERAL); + return lit_id_to_str (lit_ids[current_arg - 1]); + } + else if (raw.uids[current_arg] >= 128) + { + return tmp_id_to_str (raw.uids[current_arg]); + } + else + { + return lit_id_to_str (deserialize_lit_id_by_uid (raw.uids[current_arg], oc)); } } static void -pp_printf (const char *format, ...) +pp_printf (const char *format, opcode_t opcode, literal_index_t lit_ids[], opcode_counter_t oc) { - va_list args; - va_start (args, format); + uint8_t current_arg = 1; while (*format) { if (*format != '%') @@ -144,57 +182,46 @@ pp_printf (const char *format, ...) { case 'd': { - __printf ("%d", va_arg (args, int)); + raw_opcode raw = *(raw_opcode*) &opcode; + __printf ("%d", raw.uids[current_arg]); break; } case 's': { - char res[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER] = {'\0'}; - __printf ("%s", var_id_to_string (res, (idx_t) va_arg (args, int))); - break; - } - case '%': - { - __printf ("%%"); + __printf ("%s", var_to_str (opcode, lit_ids, oc, current_arg)); break; } default: { - JERRY_UNREACHABLE (); + __putchar ('%'); + continue; } } + current_arg++; format++; } - va_end (args); } -#define PP_OP_0(op, format) \ - case NAME_TO_ID(op): pp_printf (format); break; - -#define PP_OP_1(op, format, field1) \ - case NAME_TO_ID(op): pp_printf (format, opcode.data.op.field1); break; - -#define PP_OP_2(op, format, field1, field2) \ - case NAME_TO_ID(op): pp_printf (format, opcode.data.op.field1, opcode.data.op.field2); break; - -#define PP_OP_3(op, format, field1, field2, field3) \ - case NAME_TO_ID(op): pp_printf (format, opcode.data.op.field1, opcode.data.op.field2, opcode.data.op.field3); break; +#define PP_OP(op_name, format) \ + case NAME_TO_ID(op_name): pp_printf (format, opm.op, opm.lit_id, oc); break; +#define VAR(i) var_to_str (opm.op, opm.lit_id, oc, i) +#define OC(i, j) __extension__({ raw_opcode* raw = (raw_opcode *) &opm.op; \ + calc_opcode_counter_from_idx_idx (raw->uids[i], raw->uids[j]); }) static int vargs_num = 0; static int seen_vargs = 0; -void -pp_opcode (opcode_counter_t oc, opcode_t opcode, bool is_rewrite) +static void +dump_asm (opcode_counter_t oc, opcode_t opcode) { - uint8_t i = 1; + uint8_t i = 0; uint8_t opcode_id = opcode.op_idx; - __printf ("%3d: %20s ", oc, opcode_names[opcode_id]); if (opcode_id != NAME_TO_ID (nop) && opcode_id != NAME_TO_ID (ret)) { for (i = 1; i < opcode_sizes[opcode_id]; i++) { - __printf ("%4d ", ((uint8_t*) & opcode)[i]); + __printf ("%4d ", ((raw_opcode *) &opcode)->uids[i]); } } @@ -202,255 +229,208 @@ pp_opcode (opcode_counter_t oc, opcode_t opcode, bool is_rewrite) { __printf (" "); } +} +void +pp_op_meta (opcode_counter_t oc, op_meta opm, bool rewrite) +{ + dump_asm (oc, opm.op); __printf (" // "); - switch (opcode_id) + switch (opm.op.op_idx) { - PP_OP_3 (addition, "%s = %s + %s;", dst, var_left, var_right); - PP_OP_3 (substraction, "%s = %s - %s;", dst, var_left, var_right); - PP_OP_3 (division, "%s = %s - %s;", dst, var_left, var_right); - PP_OP_3 (multiplication, "%s = %s * %s;", dst, var_left, var_right); - PP_OP_3 (remainder, "%s = %s %% %s;", dst, var_left, var_right); - PP_OP_2 (unary_minus, "%s = -%s;", dst, var); - PP_OP_2 (unary_plus, "%s = +%s;", dst, var); - PP_OP_3 (b_shift_left, "%s = %s << %s;", dst, var_left, var_right); - PP_OP_3 (b_shift_right, "%s = %s >> %s;", dst, var_left, var_right); - PP_OP_3 (b_shift_uright, "%s = %s >>> %s;", dst, var_left, var_right); - PP_OP_3 (b_and, "%s = %s & %s;", dst, var_left, var_right); - PP_OP_3 (b_or, "%s = %s | %s;", dst, var_left, var_right); - PP_OP_3 (b_xor, "%s = %s ^ %s;", dst, var_left, var_right); - PP_OP_2 (b_not, "%s = ~ %s;", dst, var_right); - PP_OP_2 (logical_not, "%s = ! %s;", dst, var_right); - PP_OP_3 (equal_value, "%s = %s == %s;", dst, var_left, var_right); - PP_OP_3 (not_equal_value, "%s = %s != %s;", dst, var_left, var_right); - PP_OP_3 (equal_value_type, "%s = %s === %s;", dst, var_left, var_right); - PP_OP_3 (not_equal_value_type, "%s = %s !== %s;", dst, var_left, var_right); - PP_OP_3 (less_than, "%s = %s < %s;", dst, var_left, var_right); - PP_OP_3 (greater_than, "%s = %s > %s;", dst, var_left, var_right); - PP_OP_3 (less_or_equal_than, "%s = %s <= %s;", dst, var_left, var_right); - PP_OP_3 (greater_or_equal_than, "%s = %s >= %s;", dst, var_left, var_right); - PP_OP_3 (instanceof, "%s = %s instanceof %s;", dst, var_left, var_right); - PP_OP_3 (in, "%s = %s in %s;", dst, var_left, var_right); - PP_OP_2 (post_incr, "%s = %s++;", dst, var_right); - PP_OP_2 (post_decr, "%s = %s--;", dst, var_right); - PP_OP_2 (pre_incr, "%s = ++%s;", dst, var_right); - PP_OP_2 (pre_decr, "%s = --%s;", dst, var_right); - PP_OP_1 (throw, "throw %s;", var); - PP_OP_2 (reg_var_decl, "var %s .. %s;", min, max); - PP_OP_1 (var_decl, "var %s;", variable_name); - PP_OP_0 (nop, ";"); - PP_OP_1 (exitval, "exit %d;", status_code); - PP_OP_1 (retval, "return %s;", ret_value); - PP_OP_0 (ret, "ret;"); - PP_OP_3 (prop_getter, "%s = %s[%s];", lhs, obj, prop); - PP_OP_3 (prop_setter, "%s[%s] = %s;", obj, prop, rhs); - PP_OP_1 (this, "%s = this;", lhs); - PP_OP_2 (delete_var, "%s = delete %s;", lhs, name); - PP_OP_3 (delete_prop, "%s = delete %s.%s;", lhs, base, name); - PP_OP_2 (typeof, "%s = typeof %s;", lhs, obj); - PP_OP_1 (with, "with (%s);", expr); - case NAME_TO_ID (is_true_jmp_up): - { - pp_printf ("if (%s) goto %d;", opcode.data.is_true_jmp_up.value, - oc - calc_opcode_counter_from_idx_idx (opcode.data.is_true_jmp_up.opcode_1, - opcode.data.is_true_jmp_up.opcode_2)); - break; - } - case NAME_TO_ID (is_false_jmp_up): - { - pp_printf ("if (%s) goto %d;", opcode.data.is_false_jmp_up.value, - oc - calc_opcode_counter_from_idx_idx (opcode.data.is_false_jmp_up.opcode_1, - opcode.data.is_false_jmp_up.opcode_2)); - break; - } - case NAME_TO_ID (is_true_jmp_down): - { - pp_printf ("if (%s) goto %d;", opcode.data.is_true_jmp_down.value, - oc + calc_opcode_counter_from_idx_idx (opcode.data.is_true_jmp_down.opcode_1, - opcode.data.is_true_jmp_down.opcode_2)); - break; - } - case NAME_TO_ID (is_false_jmp_down): - { - pp_printf ("if (%s == false) goto %d;", opcode.data.is_false_jmp_down.value, - oc + calc_opcode_counter_from_idx_idx (opcode.data.is_false_jmp_down.opcode_1, - opcode.data.is_false_jmp_down.opcode_2)); - break; - } - case NAME_TO_ID (jmp_up): - { - pp_printf ("goto %d;", - oc - calc_opcode_counter_from_idx_idx (opcode.data.jmp_up.opcode_1, - opcode.data.jmp_up.opcode_2)); - break; - } - case NAME_TO_ID (jmp_down): - { - pp_printf ("goto %d;", - oc + calc_opcode_counter_from_idx_idx (opcode.data.jmp_down.opcode_1, - opcode.data.jmp_down.opcode_2)); - break; - } - case NAME_TO_ID (try): - { - pp_printf ("try (end: %d);", oc + calc_opcode_counter_from_idx_idx (opcode.data.try.oc_idx_1, - opcode.data.try.oc_idx_2)); - break; - } + PP_OP (addition, "%s = %s + %s;"); + PP_OP (substraction, "%s = %s - %s;"); + PP_OP (division, "%s = %s - %s;"); + PP_OP (multiplication, "%s = %s * %s;"); + PP_OP (remainder, "%s = %s %% %s;"); + PP_OP (unary_minus, "%s = -%s;"); + PP_OP (unary_plus, "%s = +%s;"); + PP_OP (b_shift_left, "%s = %s << %s;"); + PP_OP (b_shift_right, "%s = %s >> %s;"); + PP_OP (b_shift_uright, "%s = %s >>> %s;"); + PP_OP (b_and, "%s = %s & %s;"); + PP_OP (b_or, "%s = %s | %s;"); + PP_OP (b_xor, "%s = %s ^ %s;"); + PP_OP (b_not, "%s = ~ %s;"); + PP_OP (logical_not, "%s = ! %s;"); + PP_OP (equal_value, "%s = %s == %s;"); + PP_OP (not_equal_value, "%s = %s != %s;"); + PP_OP (equal_value_type, "%s = %s === %s;"); + PP_OP (not_equal_value_type, "%s = %s !== %s;"); + PP_OP (less_than, "%s = %s < %s;"); + PP_OP (greater_than, "%s = %s > %s;"); + PP_OP (less_or_equal_than, "%s = %s <= %s;"); + PP_OP (greater_or_equal_than, "%s = %s >= %s;"); + PP_OP (instanceof, "%s = %s instanceof %s;"); + PP_OP (in, "%s = %s in %s;"); + PP_OP (post_incr, "%s = %s++;"); + PP_OP (post_decr, "%s = %s--;"); + PP_OP (pre_incr, "%s = ++%s;"); + PP_OP (pre_decr, "%s = --%s;"); + PP_OP (throw, "throw %s;"); + PP_OP (reg_var_decl, "var %s .. %s;"); + PP_OP (var_decl, "var %s;"); + PP_OP (nop, ";"); + PP_OP (exitval, "exit %d;"); + PP_OP (retval, "return %s;"); + PP_OP (ret, "ret;"); + PP_OP (prop_getter, "%s = %s[%s];"); + PP_OP (prop_setter, "%s[%s] = %s;"); + PP_OP (this, "%s = this;"); + PP_OP (delete_var, "%s = delete %s;"); + PP_OP (delete_prop, "%s = delete %s.%s;"); + PP_OP (typeof, "%s = typeof %s;"); + PP_OP (with, "with (%s);"); + case NAME_TO_ID (is_true_jmp_up): __printf ("if (%s) goto %d;", VAR (1), oc - OC (2, 3)); break; + case NAME_TO_ID (is_false_jmp_up): __printf ("if (%s == false) goto %d;", VAR (1), oc - OC (2, 3)); break; + case NAME_TO_ID (is_true_jmp_down): __printf ("if (%s) goto %d;", VAR (1), oc + OC (2, 3)); break; + case NAME_TO_ID (is_false_jmp_down): __printf ("if (%s == false) goto %d;", VAR (1), oc + OC (2, 3)); break; + case NAME_TO_ID (jmp_up): __printf ("goto %d;", oc - OC (1, 2)); break; + case NAME_TO_ID (jmp_down): __printf ("goto %d;", oc + OC (1, 2)); break; + case NAME_TO_ID (try): __printf ("try (end: %d);", oc + OC (1, 2)); break; case NAME_TO_ID (assignment): { - pp_printf ("%s = ", opcode.data.assignment.var_left); - switch (opcode.data.assignment.type_value_right) + __printf ("%s = ", VAR (1)); + switch (opm.op.data.assignment.type_value_right) { + case OPCODE_ARG_TYPE_STRING: __printf ("'%s': STRING;", VAR (3)); break; + case OPCODE_ARG_TYPE_NUMBER: __printf ("%s: NUMBER;", VAR (3)); break; + case OPCODE_ARG_TYPE_NUMBER_NEGATE: __printf ("-%s: NUMBER;", VAR (3)); break; + case OPCODE_ARG_TYPE_SMALLINT: __printf ("%d: SMALLINT;", opm.op.data.assignment.value_right); break; + case OPCODE_ARG_TYPE_SMALLINT_NEGATE: __printf ("-%d: SMALLINT;", opm.op.data.assignment.value_right); break; + case OPCODE_ARG_TYPE_VARIABLE: __printf ("%s : TYPEOF(%s);", VAR (3), VAR (3)); break; case OPCODE_ARG_TYPE_SIMPLE: { - switch (opcode.data.assignment.value_right) + switch (opm.op.data.assignment.value_right) { - case ECMA_SIMPLE_VALUE_NULL: pp_printf ("null"); break; - case ECMA_SIMPLE_VALUE_FALSE: pp_printf ("false"); break; - case ECMA_SIMPLE_VALUE_TRUE: pp_printf ("true"); break; - case ECMA_SIMPLE_VALUE_UNDEFINED: pp_printf ("undefined"); break; + case ECMA_SIMPLE_VALUE_NULL: __printf ("null"); break; + case ECMA_SIMPLE_VALUE_FALSE: __printf ("false"); break; + case ECMA_SIMPLE_VALUE_TRUE: __printf ("true"); break; + case ECMA_SIMPLE_VALUE_UNDEFINED: __printf ("undefined"); break; default: JERRY_UNREACHABLE (); } - pp_printf (": SIMPLE;"); + __printf (": SIMPLE;"); break; } - case OPCODE_ARG_TYPE_STRING: - { - pp_printf ("'%s': STRING;", opcode.data.assignment.value_right); - break; - } - case OPCODE_ARG_TYPE_NUMBER: - { - pp_printf ("%s: NUMBER;", opcode.data.assignment.value_right); - break; - } - case OPCODE_ARG_TYPE_SMALLINT: - { - pp_printf ("%d: SMALLINT;", opcode.data.assignment.value_right); - break; - } - case OPCODE_ARG_TYPE_VARIABLE: - { - pp_printf ("%s : TYPEOF(%s);", opcode.data.assignment.value_right, opcode.data.assignment.value_right); - break; - } - default: - { - JERRY_UNREACHABLE (); - } } break; } case NAME_TO_ID (call_n): { - if (opcode.data.call_n.arg_list == 0) + if (opm.op.data.call_n.arg_list == 0) { - pp_printf ("%s = %s ();", opcode.data.call_n.lhs, opcode.data.call_n.name_lit_idx); + __printf ("%s = %s ();", VAR (1), VAR (2)); } else { - vargs_num = opcode.data.call_n.arg_list; + vargs_num = opm.op.data.call_n.arg_list; seen_vargs = 0; } break; } case NAME_TO_ID (native_call): { - if (opcode.data.native_call.arg_list == 0) + if (opm.op.data.native_call.arg_list == 0) { - pp_printf ("%s = ", opcode.data.native_call.lhs); - switch (opcode.data.native_call.name) + __printf ("%s = ", VAR (1)); + switch (opm.op.data.native_call.name) { - case OPCODE_NATIVE_CALL_LED_TOGGLE: pp_printf ("LEDToggle ();"); break; - case OPCODE_NATIVE_CALL_LED_ON: pp_printf ("LEDOn ();"); break; - case OPCODE_NATIVE_CALL_LED_OFF: pp_printf ("LEDOff ();"); break; - case OPCODE_NATIVE_CALL_LED_ONCE: pp_printf ("LEDOnce ();"); break; - case OPCODE_NATIVE_CALL_WAIT: pp_printf ("wait ();"); break; - case OPCODE_NATIVE_CALL_PRINT: pp_printf ("print ();"); break; + case OPCODE_NATIVE_CALL_LED_TOGGLE: __printf ("LEDToggle ();"); break; + case OPCODE_NATIVE_CALL_LED_ON: __printf ("LEDOn ();"); break; + case OPCODE_NATIVE_CALL_LED_OFF: __printf ("LEDOff ();"); break; + case OPCODE_NATIVE_CALL_LED_ONCE: __printf ("LEDOnce ();"); break; + case OPCODE_NATIVE_CALL_WAIT: __printf ("wait ();"); break; + case OPCODE_NATIVE_CALL_PRINT: __printf ("print ();"); break; default: JERRY_UNREACHABLE (); } } else { - vargs_num = opcode.data.native_call.arg_list; + vargs_num = opm.op.data.native_call.arg_list; seen_vargs = 0; } break; } case NAME_TO_ID (construct_n): { - if (opcode.data.construct_n.arg_list == 0) + if (opm.op.data.construct_n.arg_list == 0) { - pp_printf ("%s = new %s;", opcode.data.construct_n.lhs, opcode.data.construct_n.name_lit_idx); + __printf ("%s = new %s;", VAR (1), VAR (2)); } else { - vargs_num = opcode.data.construct_n.arg_list; + vargs_num = opm.op.data.construct_n.arg_list; seen_vargs = 0; } break; } case NAME_TO_ID (func_decl_n): { - if (opcode.data.func_decl_n.arg_list == 0) + if (opm.op.data.func_decl_n.arg_list == 0) { - pp_printf ("function %s ();", opcode.data.func_decl_n.name_lit_idx); + __printf ("function %s ();", VAR (1)); } else { - vargs_num = opcode.data.func_decl_n.arg_list; + vargs_num = opm.op.data.func_decl_n.arg_list; seen_vargs = 0; } break; } case NAME_TO_ID (func_expr_n): { - if (opcode.data.func_expr_n.arg_list == 0) + if (opm.op.data.func_expr_n.arg_list == 0) { - pp_printf ("%s = function %s ();", opcode.data.func_expr_n.lhs, opcode.data.func_expr_n.name_lit_idx); + if (opm.op.data.func_expr_n.name_lit_idx == INVALID_VALUE) + { + __printf ("%s = function ();", VAR (1)); + } + else + { + __printf ("%s = function %s ();", VAR (1), VAR (2)); + } } else { - vargs_num = opcode.data.func_expr_n.arg_list; + vargs_num = opm.op.data.func_expr_n.arg_list; seen_vargs = 0; } break; } case NAME_TO_ID (array_decl): { - if (opcode.data.array_decl.list == 0) + if (opm.op.data.array_decl.list == 0) { - pp_printf ("%s = [];", opcode.data.array_decl.lhs); + __printf ("%s = [];", VAR (1)); } else { - vargs_num = opcode.data.array_decl.list; + vargs_num = opm.op.data.array_decl.list; seen_vargs = 0; } break; } case NAME_TO_ID (obj_decl): { - if (opcode.data.obj_decl.list == 0) + if (opm.op.data.obj_decl.list == 0) { - pp_printf ("%s = {};", opcode.data.obj_decl.lhs); + __printf ("%s = {};", VAR (1)); } else { - vargs_num = opcode.data.obj_decl.list; + vargs_num = opm.op.data.obj_decl.list; seen_vargs = 0; } break; } case NAME_TO_ID (meta): { - switch (opcode.data.meta.type) + switch (opm.op.data.meta.type) { case OPCODE_META_TYPE_UNDEFINED: { - pp_printf ("unknown meta;"); + __printf ("unknown meta;"); break; } case OPCODE_META_TYPE_THIS_ARG: @@ -487,48 +467,57 @@ pp_opcode (opcode_counter_t oc, opcode_t opcode, bool is_rewrite) { case NAME_TO_ID (call_n): { - pp_printf ("%s = %s (", start_op.data.call_n.lhs, start_op.data.call_n.name_lit_idx); + __printf ("%s = %s (", var_to_str (start_op, NULL, start, 1), + var_to_str (start_op, NULL, start, 2)); break; } case NAME_TO_ID (native_call): { - pp_printf ("%s = ", start_op.data.native_call.lhs); + __printf ("%s = ", var_to_str (start_op, NULL, start, 1)); switch (start_op.data.native_call.name) { - case OPCODE_NATIVE_CALL_LED_TOGGLE: pp_printf ("LEDToggle ("); break; - case OPCODE_NATIVE_CALL_LED_ON: pp_printf ("LEDOn ("); break; - case OPCODE_NATIVE_CALL_LED_OFF: pp_printf ("LEDOff ("); break; - case OPCODE_NATIVE_CALL_LED_ONCE: pp_printf ("LEDOnce ("); break; - case OPCODE_NATIVE_CALL_WAIT: pp_printf ("wait ("); break; - case OPCODE_NATIVE_CALL_PRINT: pp_printf ("print ("); break; + case OPCODE_NATIVE_CALL_LED_TOGGLE: __printf ("LEDToggle ("); break; + case OPCODE_NATIVE_CALL_LED_ON: __printf ("LEDOn ("); break; + case OPCODE_NATIVE_CALL_LED_OFF: __printf ("LEDOff ("); break; + case OPCODE_NATIVE_CALL_LED_ONCE: __printf ("LEDOnce ("); break; + case OPCODE_NATIVE_CALL_WAIT: __printf ("wait ("); break; + case OPCODE_NATIVE_CALL_PRINT: __printf ("print ("); break; default: JERRY_UNREACHABLE (); } break; } case NAME_TO_ID (construct_n): { - pp_printf ("%s = new %s (", start_op.data.construct_n.lhs, start_op.data.construct_n.name_lit_idx); + __printf ("%s = new %s (", var_to_str (start_op, NULL, start, 1), + var_to_str (start_op, NULL, start, 2)); break; } case NAME_TO_ID (func_decl_n): { - pp_printf ("function %s (", start_op.data.func_decl_n.name_lit_idx); + __printf ("function %s (", var_to_str (start_op, NULL, start, 1)); break; } case NAME_TO_ID (func_expr_n): { - pp_printf ("%s = function %s (", start_op.data.func_expr_n.lhs, - start_op.data.func_expr_n.name_lit_idx); + if (start_op.data.func_expr_n.name_lit_idx == INVALID_VALUE) + { + __printf ("%s = function (", var_to_str (start_op, NULL, start, 1)); + } + else + { + __printf ("%s = function %s (", var_to_str (start_op, NULL, start, 1), + var_to_str (start_op, NULL, start, 2)); + } break; } case NAME_TO_ID (array_decl): { - pp_printf ("%s = [", start_op.data.array_decl.lhs); + __printf ("%s = [", var_to_str (start_op, NULL, start, 1)); break; } case NAME_TO_ID (obj_decl): { - pp_printf ("%s = {", start_op.data.obj_decl.lhs); + __printf ("%s = {", var_to_str (start_op, NULL, start, 1)); break; } default: @@ -543,41 +532,44 @@ pp_opcode (opcode_counter_t oc, opcode_t opcode, bool is_rewrite) { case NAME_TO_ID (meta): { - switch (opcode.data.meta.type) + switch (meta_op.data.meta.type) { case OPCODE_META_TYPE_THIS_ARG: { - pp_printf ("this_arg = %s", meta_op.data.meta.data_1); + __printf ("this_arg = %s", var_to_str (meta_op, NULL, counter, 2)); break; } case OPCODE_META_TYPE_VARG: { - pp_printf ("%s", meta_op.data.meta.data_1); + __printf ("%s", var_to_str (meta_op, NULL, counter, 2)); break; } case OPCODE_META_TYPE_VARG_PROP_DATA: { - pp_printf ("%s:%s", meta_op.data.meta.data_1, meta_op.data.meta.data_2); + __printf ("%s:%s", var_to_str (meta_op, NULL, counter, 2), + var_to_str (meta_op, NULL, counter, 3)); break; } case OPCODE_META_TYPE_VARG_PROP_GETTER: { - pp_printf ("%s = get ();", meta_op.data.meta.data_1); + __printf ("%s = get %s ();", var_to_str (meta_op, NULL, counter, 2), + var_to_str (meta_op, NULL, counter, 3)); break; } case OPCODE_META_TYPE_VARG_PROP_SETTER: { - pp_printf ("%s = set (%s);", meta_op.data.meta.data_1, meta_op.data.meta.data_2); + __printf ("%s = set (%s);", var_to_str (meta_op, NULL, counter, 2), + var_to_str (meta_op, NULL, counter, 3)); break; } default: { - JERRY_UNREACHABLE (); + continue; } } if (counter != oc) { - pp_printf (", "); + __printf (", "); } break; } @@ -587,17 +579,17 @@ pp_opcode (opcode_counter_t oc, opcode_t opcode, bool is_rewrite) { case NAME_TO_ID (array_decl): { - pp_printf ("];"); + __printf ("];"); break; } case NAME_TO_ID (obj_decl): { - pp_printf ("};"); + __printf ("};"); break; } default: { - pp_printf (");"); + __printf (");"); } } } @@ -605,40 +597,37 @@ pp_opcode (opcode_counter_t oc, opcode_t opcode, bool is_rewrite) } case OPCODE_META_TYPE_END_WITH: { - pp_printf ("end with;"); + __printf ("end with;"); break; } case OPCODE_META_TYPE_FUNCTION_END: { - pp_printf ("function end: %d;", oc + calc_opcode_counter_from_idx_idx (opcode.data.meta.data_1, - opcode.data.meta.data_2)); + __printf ("function end: %d;", oc + OC (2, 3)); break; } case OPCODE_META_TYPE_CATCH: { - pp_printf ("catch end: %d;", oc + calc_opcode_counter_from_idx_idx (opcode.data.meta.data_1, - opcode.data.meta.data_2)); + __printf ("catch end: %d;", oc + OC (2, 3)); break; } case OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER: { - pp_printf ("catch (%s);", opcode.data.meta.data_1); + __printf ("catch (%s);", VAR (2)); break; } case OPCODE_META_TYPE_FINALLY: { - pp_printf ("finally end: %d;", oc + calc_opcode_counter_from_idx_idx (opcode.data.meta.data_1, - opcode.data.meta.data_2)); + __printf ("finally end: %d;", oc + OC (2, 3)); break; } case OPCODE_META_TYPE_END_TRY_CATCH_FINALLY: { - pp_printf ("end try"); + __printf ("end try"); break; } case OPCODE_META_TYPE_STRICT_CODE: { - pp_printf ("use strict;"); + __printf ("use strict;"); break; } default: @@ -654,7 +643,7 @@ pp_opcode (opcode_counter_t oc, opcode_t opcode, bool is_rewrite) } } - if (is_rewrite) + if (rewrite) { __printf (" // REWRITE"); } diff --git a/src/liboptimizer/pretty-printer.h b/src/liboptimizer/pretty-printer.h index 1a91a87e8..f9e2b512c 100644 --- a/src/liboptimizer/pretty-printer.h +++ b/src/liboptimizer/pretty-printer.h @@ -20,9 +20,11 @@ #ifdef JERRY_ENABLE_PP #include "interpreter.h" #include "literal.h" +#include "scopes-tree.h" void pp_opcode (opcode_counter_t, opcode_t, bool); -void pp_literals (const literal *, uint8_t); +void pp_op_meta (opcode_counter_t, op_meta, bool); +void pp_literals (const literal *, literal_index_t); #endif // JERRY_ENABLE_PP #endif // PRETTY_PRINTER diff --git a/src/liboptimizer/serializer.c b/src/liboptimizer/serializer.c index 71f7a5425..dd534bf6c 100644 --- a/src/liboptimizer/serializer.c +++ b/src/liboptimizer/serializer.c @@ -29,15 +29,27 @@ serializer_set_scope (scopes_tree new_scope) current_scope = new_scope; } +static uint16_t +hash_function (void *raw_key) +{ + lit_id_table_key *key = (lit_id_table_key *) raw_key; + JERRY_ASSERT (bytecode_data.opcodes_count > 0); + return (uint16_t) (key->oc + key->uid) & ((1u << CONFIG_LITERAL_HASH_TABLE_KEY_BITS) - 1); +} + void serializer_merge_scopes_into_bytecode (void) { - bytecode_data.opcodes = scopes_tree_raw_data (current_scope, &bytecode_data.opcodes_count); + JERRY_ASSERT (bytecode_data.lit_id_hash == null_hash); + bytecode_data.opcodes_count = scopes_tree_count_opcodes (current_scope); + bytecode_data.lit_id_hash = hash_table_init (sizeof (lit_id_table_key), sizeof (literal_index_t), + 1u << CONFIG_LITERAL_HASH_TABLE_KEY_BITS, hash_function, + MEM_HEAP_ALLOC_LONG_TERM); + bytecode_data.opcodes = scopes_tree_raw_data (current_scope, bytecode_data.lit_id_hash); } - void -serializer_dump_literals (const literal literals[], uint8_t literals_count) +serializer_dump_literals (const literal literals[], literal_index_t literals_count) { #ifdef JERRY_ENABLE_PP if (print_opcodes) @@ -51,20 +63,32 @@ serializer_dump_literals (const literal literals[], uint8_t literals_count) } void -serializer_dump_opcode (opcode_t opcode) +serializer_dump_op_meta (op_meta op) { JERRY_ASSERT (scopes_tree_opcodes_num (current_scope) < MAX_OPCODES); - scopes_tree_add_opcode (current_scope, opcode); + scopes_tree_add_op_meta (current_scope, op); #ifdef JERRY_ENABLE_PP if (print_opcodes) { - pp_opcode ((opcode_counter_t) (scopes_tree_opcodes_num (current_scope) - 1), opcode, false); + pp_op_meta ((opcode_counter_t) (scopes_tree_opcodes_num (current_scope) - 1), op, false); } #endif } +opcode_counter_t +serializer_get_current_opcode_counter (void) +{ + return scopes_tree_opcodes_num (current_scope); +} + +opcode_counter_t +serializer_count_opcodes_in_subscopes (void) +{ + return (opcode_counter_t) (scopes_tree_count_opcodes (current_scope) - scopes_tree_opcodes_num (current_scope)); +} + void serializer_set_writing_position (opcode_counter_t oc) { @@ -72,14 +96,14 @@ serializer_set_writing_position (opcode_counter_t oc) } void -serializer_rewrite_opcode (const opcode_counter_t loc, opcode_t opcode) +serializer_rewrite_op_meta (const opcode_counter_t loc, op_meta op) { - scopes_tree_set_opcode (current_scope, loc, opcode); + scopes_tree_set_op_meta (current_scope, loc, op); #ifdef JERRY_ENABLE_PP if (print_opcodes) { - pp_opcode (loc, opcode, true); + pp_op_meta (loc, op, true); } #endif } @@ -99,7 +123,15 @@ serializer_print_opcodes (void) for (loc = 0; loc < bytecode_data.opcodes_count; loc++) { - pp_opcode (loc, bytecode_data.opcodes[loc], false); + const op_meta opm = (op_meta) + { + .op = bytecode_data.opcodes[loc], + .lit_id = + { + NOT_A_LITERAL + } + }; + pp_op_meta (loc, opm, false); } #endif } diff --git a/src/liboptimizer/serializer.h b/src/liboptimizer/serializer.h index 13ab2e2ff..f42068111 100644 --- a/src/liboptimizer/serializer.h +++ b/src/liboptimizer/serializer.h @@ -17,18 +17,21 @@ #define SERIALIZER_H #include "globals.h" +#include "ecma-globals.h" #include "opcodes.h" #include "interpreter.h" #include "literal.h" #include "scopes-tree.h" void serializer_init (bool show_opcodes); -void serializer_dump_literals (const literal *, uint8_t); +void serializer_dump_literals (const literal *, literal_index_t); void serializer_set_scope (scopes_tree); void serializer_merge_scopes_into_bytecode (void); -void serializer_dump_opcode (opcode_t); +void serializer_dump_op_meta (op_meta); +opcode_counter_t serializer_get_current_opcode_counter (void); +opcode_counter_t serializer_count_opcodes_in_subscopes (void); void serializer_set_writing_position (opcode_counter_t); -void serializer_rewrite_opcode (const opcode_counter_t, opcode_t); +void serializer_rewrite_op_meta (opcode_counter_t, op_meta); void serializer_print_opcodes (void); void serializer_free (void); diff --git a/tests/unit/test_preparser.c b/tests/unit/test_preparser.c index 3a52e6b84..d2ab6d599 100644 --- a/tests/unit/test_preparser.c +++ b/tests/unit/test_preparser.c @@ -28,21 +28,21 @@ int main( int __unused argc, char __unused **argv) { - char program[] = {'a','=','1',';','v','a','r',' ','a',';','\0'}; + char program[] = "a=1;var a;"; bool is_ok; - mem_init(); + mem_init (); deserializer_init (); parser_init (program, __strlen (program), true); parser_parse_program (); parser_free (); if (!opcodes_equal(deserialize_bytecode (), (opcode_t[]) { - [0] = getop_reg_var_decl (1, 2), // var tmp1 .. tmp2; - [1] = getop_var_decl (0), // var a; - [2] = getop_assignment (1, 1, 1), // tmp1 = 1: SMALLINT; - [3] = getop_assignment (0, 4, 1), // a = tmp1: TYPEOF(tmp1); - [4] = getop_exitval (0) // exit 0; + [0] = getop_reg_var_decl (128, 129), // var tmp128 .. tmp129; + [1] = getop_var_decl (0), // var a; + [2] = getop_assignment (129, 1, 1), // tmp129 = 1: SMALLINT; + [3] = getop_assignment (0, 6, 129), // a = tmp129 : TYPEOF(tmp129); + [4] = getop_exitval (0) // exit 0; }, 5)) { is_ok = false;