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;