diff --git a/jerry-core/ecma/base/ecma-helpers-value.c b/jerry-core/ecma/base/ecma-helpers-value.c index 823687918..19554d986 100644 --- a/jerry-core/ecma/base/ecma-helpers-value.c +++ b/jerry-core/ecma/base/ecma-helpers-value.c @@ -732,6 +732,35 @@ ecma_value_assign_value (ecma_value_t *value_p, /**< [in, out] ecma value */ } } /* ecma_value_assign_value */ +/** + * Update the value of a float number to a new value + * + * Note: + * The original value is destroyed. + * + * @return updated ecma value + */ +ecma_value_t +ecma_update_float_number (ecma_value_t float_value, /**< original float value */ + ecma_number_t new_number) /**< updated number value */ +{ + JERRY_ASSERT (ecma_is_value_float_number (float_value)); + + ecma_integer_value_t integer_number = (ecma_integer_value_t) new_number; + ecma_number_t *number_p = (ecma_number_t *) ecma_get_pointer_from_ecma_value (float_value); + + if ((ecma_number_t) integer_number == new_number + && ((integer_number == 0) ? ecma_is_number_equal_to_positive_zero (new_number) + : ECMA_IS_INTEGER_NUMBER (integer_number))) + { + ecma_dealloc_number (number_p); + return ecma_make_integer_value (integer_number); + } + + *number_p = new_number; + return float_value; +} /* ecma_update_float_number */ + /** * Assign a float number to an ecma-value * diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index 931429dce..bd1623c88 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -143,7 +143,7 @@ extern ecma_value_t ecma_make_object_value (const ecma_object_t *); extern ecma_value_t ecma_make_error_value (ecma_value_t); extern ecma_value_t ecma_make_error_obj_value (const ecma_object_t *); extern ecma_integer_value_t ecma_get_integer_from_value (ecma_value_t) __attr_pure___; -extern ecma_number_t ecma_get_float_from_value (ecma_value_t value) __attr_pure___; +extern ecma_number_t ecma_get_float_from_value (ecma_value_t) __attr_pure___; extern ecma_number_t ecma_get_number_from_value (ecma_value_t) __attr_pure___; extern uint32_t ecma_get_uint32_from_value (ecma_value_t) __attr_pure___; extern ecma_string_t *ecma_get_string_from_value (ecma_value_t) __attr_pure___; @@ -153,6 +153,7 @@ extern ecma_value_t ecma_invert_boolean_value (ecma_value_t) __attr_pure___; extern ecma_value_t ecma_copy_value (ecma_value_t); extern ecma_value_t ecma_fast_copy_value (ecma_value_t); extern ecma_value_t ecma_copy_value_if_not_object (ecma_value_t); +extern ecma_value_t ecma_update_float_number (ecma_value_t, ecma_number_t); extern void ecma_value_assign_value (ecma_value_t *, ecma_value_t); extern void ecma_value_assign_number (ecma_value_t *, ecma_number_t); extern void ecma_value_assign_uint32 (ecma_value_t *, uint32_t); diff --git a/jerry-core/vm/opcodes-ecma-arithmetics.c b/jerry-core/vm/opcodes-ecma-arithmetics.c index f11525553..0047db9e6 100644 --- a/jerry-core/vm/opcodes-ecma-arithmetics.c +++ b/jerry-core/vm/opcodes-ecma-arithmetics.c @@ -46,63 +46,6 @@ do_number_arithmetic (number_arithmetic_op op, /**< number arithmetic operation ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { - JERRY_STATIC_ASSERT (ECMA_INTEGER_MULTIPLY_MAX * ECMA_INTEGER_MULTIPLY_MAX <= ECMA_INTEGER_NUMBER_MAX - && -(ECMA_INTEGER_MULTIPLY_MAX * ECMA_INTEGER_MULTIPLY_MAX) >= ECMA_INTEGER_NUMBER_MIN, - square_of_integer_multiply_max_must_fit_into_integer_value_range); - JERRY_STATIC_ASSERT (ECMA_INTEGER_NUMBER_MAX * 2 <= INT32_MAX - && ECMA_INTEGER_NUMBER_MIN * 2 >= INT32_MIN, - doubled_ecma_numbers_must_fit_into_int32_range); - - JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (left_value) - && !ECMA_IS_VALUE_ERROR (right_value)); - - if (ecma_are_values_integer_numbers (left_value, right_value)) - { - switch (op) - { - case NUMBER_ARITHMETIC_SUBSTRACTION: - { - ecma_integer_value_t left_integer = ecma_get_integer_from_value (left_value); - ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value); - return ecma_make_int32_value ((int32_t) (left_integer - right_integer)); - } - case NUMBER_ARITHMETIC_MULTIPLICATION: - { - ecma_integer_value_t left_integer = ecma_get_integer_from_value (left_value); - ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value); - - if (-ECMA_INTEGER_MULTIPLY_MAX <= left_integer - && left_integer <= ECMA_INTEGER_MULTIPLY_MAX - && -ECMA_INTEGER_MULTIPLY_MAX <= right_integer - && right_integer <= ECMA_INTEGER_MULTIPLY_MAX) - { - return ecma_make_integer_value (left_integer * right_integer); - } - break; - } - case NUMBER_ARITHMETIC_DIVISION: - { - /* Not optimized since the result is likely not an integer number. */ - break; - } - case NUMBER_ARITHMETIC_REMAINDER: - { - ecma_integer_value_t left_integer = ecma_get_integer_from_value (left_value); - ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value); - if (right_integer != 0) - { - ecma_integer_value_t result = left_integer % right_integer; - - if (result != 0 || left_integer >= 0) - { - return ecma_make_integer_value (result); - } - } - break; - } - } - } - ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_OP_TO_NUMBER_TRY_CATCH (num_left, left_value, ret_value); @@ -154,20 +97,6 @@ ecma_value_t opfunc_addition (ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { - if (ecma_are_values_integer_numbers (left_value, right_value)) - { - ecma_integer_value_t left_integer = ecma_get_integer_from_value (left_value); - ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value); - return ecma_make_int32_value ((int32_t) (left_integer + right_integer)); - } - - if (ecma_is_value_number (left_value) && ecma_is_value_number (right_value)) - { - ecma_number_t num_left = ecma_get_number_from_value (left_value); - ecma_number_t num_right = ecma_get_number_from_value (right_value); - return ecma_make_number_value (ecma_number_add (num_left, num_right)); - } - bool free_left_value = false; bool free_right_value = false; diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 11e4027af..cf98cc725 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -1203,44 +1203,29 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { uint32_t opcode_flags = VM_OC_GROUP_GET_INDEX (opcode_data) - VM_OC_PROP_PRE_INCR; - result = ecma_op_to_number (left_value); - - if (ECMA_IS_VALUE_ERROR (result)) - { - goto error; - } - byte_code_p = byte_code_start_p + 1; - if (ecma_is_value_integer_number (result)) + if (ecma_is_value_integer_number (left_value)) { + result = left_value; + left_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + ecma_integer_value_t int_value = (ecma_integer_value_t) result; - ecma_integer_value_t int_increase; + ecma_integer_value_t int_increase = 0; if (opcode_flags & VM_OC_DECREMENT_OPERATOR_FLAG) { - if (int_value <= (ECMA_INTEGER_NUMBER_MIN << ECMA_DIRECT_SHIFT)) - { - int_increase = 0; - } - else + if (int_value > (ECMA_INTEGER_NUMBER_MIN << ECMA_DIRECT_SHIFT)) { int_increase = -(1 << ECMA_DIRECT_SHIFT); } } - else + else if (int_value < (ECMA_INTEGER_NUMBER_MAX << ECMA_DIRECT_SHIFT)) { - if (int_value >= (ECMA_INTEGER_NUMBER_MAX << ECMA_DIRECT_SHIFT)) - { - int_increase = 0; - } - else - { - int_increase = 1 << ECMA_DIRECT_SHIFT; - } + int_increase = 1 << ECMA_DIRECT_SHIFT; } - if (int_increase != 0) + if (likely (int_increase != 0)) { /* Postfix operators require the unmodifed number value. */ if (opcode_flags & VM_OC_POST_INCR_DECR_OPERATOR_FLAG) @@ -1281,6 +1266,20 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ break; } } + else if (ecma_is_value_float_number (left_value)) + { + result = left_value; + left_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + } + else + { + result = ecma_op_to_number (left_value); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + } ecma_number_t increase = ECMA_NUMBER_ONE; ecma_number_t result_number = ecma_get_number_from_value (result); @@ -1326,7 +1325,14 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } } - ecma_value_assign_number (&result, result_number + increase); + if (ecma_is_value_integer_number (result)) + { + result = ecma_make_number_value (result_number + increase); + } + else + { + result = ecma_update_float_number (result, result_number + increase); + } break; } case VM_OC_ASSIGN: @@ -1651,6 +1657,36 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_ADD: { + if (ecma_are_values_integer_numbers (left_value, right_value)) + { + ecma_integer_value_t left_integer = ecma_get_integer_from_value (left_value); + ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value); + result = ecma_make_int32_value ((int32_t) (left_integer + right_integer)); + break; + } + + if (ecma_is_value_float_number (left_value) + && ecma_is_value_number (right_value)) + { + ecma_number_t new_value = ecma_number_add (ecma_get_float_from_value (left_value), + ecma_get_number_from_value (right_value)); + + result = ecma_update_float_number (left_value, new_value); + left_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + break; + } + + if (ecma_is_value_float_number (right_value) + && ecma_is_value_integer_number (left_value)) + { + ecma_number_t new_value = ecma_number_add ((ecma_number_t) ecma_get_integer_from_value (left_value), + ecma_get_float_from_value (right_value)); + + result = ecma_update_float_number (right_value, new_value); + right_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + break; + } + result = opfunc_addition (left_value, right_value); if (ECMA_IS_VALUE_ERROR (result)) @@ -1661,6 +1697,43 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_SUB: { + JERRY_STATIC_ASSERT (ECMA_INTEGER_NUMBER_MAX * 2 <= INT32_MAX + && ECMA_INTEGER_NUMBER_MIN * 2 >= INT32_MIN, + doubled_ecma_numbers_must_fit_into_int32_range); + + JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (left_value) + && !ECMA_IS_VALUE_ERROR (right_value)); + + if (ecma_are_values_integer_numbers (left_value, right_value)) + { + ecma_integer_value_t left_integer = ecma_get_integer_from_value (left_value); + ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value); + result = ecma_make_int32_value ((int32_t) (left_integer - right_integer)); + break; + } + + if (ecma_is_value_float_number (left_value) + && ecma_is_value_number (right_value)) + { + ecma_number_t new_value = ecma_number_substract (ecma_get_float_from_value (left_value), + ecma_get_number_from_value (right_value)); + + result = ecma_update_float_number (left_value, new_value); + left_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + break; + } + + if (ecma_is_value_float_number (right_value) + && ecma_is_value_integer_number (left_value)) + { + ecma_number_t new_value = ecma_number_substract ((ecma_number_t) ecma_get_integer_from_value (left_value), + ecma_get_float_from_value (right_value)); + + result = ecma_update_float_number (right_value, new_value); + right_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + break; + } + result = do_number_arithmetic (NUMBER_ARITHMETIC_SUBSTRACTION, left_value, right_value); @@ -1673,6 +1746,55 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_MUL: { + JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (left_value) + && !ECMA_IS_VALUE_ERROR (right_value)); + + JERRY_STATIC_ASSERT (ECMA_INTEGER_MULTIPLY_MAX * ECMA_INTEGER_MULTIPLY_MAX <= ECMA_INTEGER_NUMBER_MAX + && -(ECMA_INTEGER_MULTIPLY_MAX * ECMA_INTEGER_MULTIPLY_MAX) >= ECMA_INTEGER_NUMBER_MIN, + square_of_integer_multiply_max_must_fit_into_integer_value_range); + + if (ecma_are_values_integer_numbers (left_value, right_value)) + { + ecma_integer_value_t left_integer = ecma_get_integer_from_value (left_value); + ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value); + + if (-ECMA_INTEGER_MULTIPLY_MAX <= left_integer + && left_integer <= ECMA_INTEGER_MULTIPLY_MAX + && -ECMA_INTEGER_MULTIPLY_MAX <= right_integer + && right_integer <= ECMA_INTEGER_MULTIPLY_MAX) + { + result = ecma_make_integer_value (left_integer * right_integer); + break; + } + + ecma_number_t multiply = ecma_number_multiply ((ecma_number_t) left_integer, + (ecma_number_t) right_integer); + result = ecma_make_number_value (multiply); + break; + } + + if (ecma_is_value_float_number (left_value) + && ecma_is_value_number (right_value)) + { + ecma_number_t new_value = ecma_number_multiply (ecma_get_float_from_value (left_value), + ecma_get_number_from_value (right_value)); + + result = ecma_update_float_number (left_value, new_value); + left_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + break; + } + + if (ecma_is_value_float_number (right_value) + && ecma_is_value_integer_number (left_value)) + { + ecma_number_t new_value = ecma_number_multiply ((ecma_number_t) ecma_get_integer_from_value (left_value), + ecma_get_float_from_value (right_value)); + + result = ecma_update_float_number (right_value, new_value); + right_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + break; + } + result = do_number_arithmetic (NUMBER_ARITHMETIC_MULTIPLICATION, left_value, right_value); @@ -1685,6 +1807,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_DIV: { + JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (left_value) + && !ECMA_IS_VALUE_ERROR (right_value)); + result = do_number_arithmetic (NUMBER_ARITHMETIC_DIVISION, left_value, right_value); @@ -1697,6 +1822,26 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_MOD: { + JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (left_value) + && !ECMA_IS_VALUE_ERROR (right_value)); + + if (ecma_are_values_integer_numbers (left_value, right_value)) + { + ecma_integer_value_t left_integer = ecma_get_integer_from_value (left_value); + ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value); + + if (right_integer != 0) + { + ecma_integer_value_t mod_result = left_integer % right_integer; + + if (mod_result != 0 || left_integer >= 0) + { + result = ecma_make_integer_value (mod_result); + break; + } + } + } + result = do_number_arithmetic (NUMBER_ARITHMETIC_REMAINDER, left_value, right_value);