diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index d01d6c4b0..8c23e7cbf 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -163,6 +163,15 @@ typedef int32_t ecma_integer_value_t; #define ECMA_IS_INTEGER_NUMBER(num) \ (ECMA_INTEGER_NUMBER_MIN <= (num) && (num) <= ECMA_INTEGER_NUMBER_MAX) +/** + * Maximum integer number, which if squared, still fits in ecma_integer_value_t + */ +#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 +#define ECMA_INTEGER_MULTIPLY_MAX 0xb50 +#else /* CONFIG_ECMA_NUMBER_TYPE != CONFIG_ECMA_NUMBER_FLOAT32 */ +#define ECMA_INTEGER_MULTIPLY_MAX 0x2d41 +#endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 */ + /** * Internal properties' identifiers. */ diff --git a/jerry-core/ecma/base/ecma-helpers-value.c b/jerry-core/ecma/base/ecma-helpers-value.c index ec2aff688..c156e766c 100644 --- a/jerry-core/ecma/base/ecma-helpers-value.c +++ b/jerry-core/ecma/base/ecma-helpers-value.c @@ -218,6 +218,22 @@ ecma_is_value_integer_number (ecma_value_t value) /**< ecma value */ return (value & ECMA_DIRECT_TYPE_MASK) == ECMA_DIRECT_TYPE_INTEGER_VALUE; } /* ecma_is_value_integer_number */ +/** + * Check if both values are integer ecma-numbers. + * + * @return true - if both values contain integer ecma-number values, + * false - otherwise. + */ +inline bool __attr_pure___ __attr_always_inline___ +ecma_are_values_integer_numbers (ecma_value_t first_value, /**< first ecma value */ + ecma_value_t second_value) /**< second ecma value */ +{ + JERRY_STATIC_ASSERT (ECMA_DIRECT_TYPE_INTEGER_VALUE == 0, + ecma_direct_type_integer_value_must_be_zero); + + return ((first_value | second_value) & ECMA_DIRECT_TYPE_MASK) == ECMA_DIRECT_TYPE_INTEGER_VALUE; +} /* ecma_are_values_integer_numbers */ + /** * Check if the value is floating-point ecma-number. * @@ -471,6 +487,19 @@ ecma_make_error_obj_value (const ecma_object_t *object_p) /**< object to referen return ecma_make_error_value (ecma_make_object_value (object_p)); } /* ecma_make_error_obj_value */ +/** + * Get integer value from an integer ecma value + * + * @return floating point value + */ +inline ecma_integer_value_t __attr_pure___ __attr_always_inline___ +ecma_get_integer_from_value (ecma_value_t value) /**< ecma value */ +{ + JERRY_ASSERT (ecma_is_value_integer_number (value)); + + return ((ecma_integer_value_t) value) >> ECMA_DIRECT_SHIFT; +} /* ecma_get_integer_from_value */ + /** * Get floating point value from an ecma value * @@ -481,7 +510,7 @@ ecma_get_number_from_value (ecma_value_t value) /**< ecma value */ { if (ecma_is_value_integer_number (value)) { - return (ecma_number_t) (((ecma_integer_value_t) value) >> ECMA_DIRECT_SHIFT); + return (ecma_number_t) ecma_get_integer_from_value (value); } JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_FLOAT); diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index 4e3444b23..9125e0450 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -123,6 +123,7 @@ extern bool ecma_is_value_false (ecma_value_t); extern bool ecma_is_value_array_hole (ecma_value_t); extern bool ecma_is_value_integer_number (ecma_value_t); +extern bool ecma_are_values_integer_numbers (ecma_value_t, ecma_value_t); extern bool ecma_is_value_float_number (ecma_value_t); extern bool ecma_is_value_number (ecma_value_t); extern bool ecma_is_value_string (ecma_value_t); @@ -141,6 +142,7 @@ extern ecma_value_t ecma_make_string_value (const ecma_string_t *); 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); 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___; diff --git a/jerry-core/vm/opcodes-ecma-arithmetics.c b/jerry-core/vm/opcodes-ecma-arithmetics.c index e5f35c82f..a00d0a202 100644 --- a/jerry-core/vm/opcodes-ecma-arithmetics.c +++ b/jerry-core/vm/opcodes-ecma-arithmetics.c @@ -45,6 +45,69 @@ 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_ADDITION: + { + 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_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); diff --git a/jerry-core/vm/opcodes-ecma-bitwise.c b/jerry-core/vm/opcodes-ecma-bitwise.c index 0c3ba07ca..877be369d 100644 --- a/jerry-core/vm/opcodes-ecma-bitwise.c +++ b/jerry-core/vm/opcodes-ecma-bitwise.c @@ -43,6 +43,55 @@ do_number_bitwise_logic (number_bitwise_logic_op op, /**< number bitwise logic o ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { + JERRY_STATIC_ASSERT (ECMA_DIRECT_TYPE_INTEGER_VALUE == 0, + ecma_direct_type_integer_value_must_be_zero_for_bitwise_logic); + JERRY_STATIC_ASSERT ((ECMA_DIRECT_TYPE_MASK | ECMA_VALUE_ERROR_FLAG) == ((1 << ECMA_DIRECT_SHIFT) - 1), + direct_type_mask_and_error_flag_must_fill_all_bits_before_the_value_starts); + + 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_BITWISE_LOGIC_AND: + { + return left_value & right_value; + } + case NUMBER_BITWISE_LOGIC_OR: + { + return left_value | right_value; + } + case NUMBER_BITWISE_LOGIC_XOR: + { + return (left_value ^ right_value) & (ecma_value_t) (~((1 << ECMA_DIRECT_SHIFT) - 1)); + } + case NUMBER_BITWISE_SHIFT_LEFT: + { + 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 & 0x1f))); + } + case NUMBER_BITWISE_SHIFT_RIGHT: + { + 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_integer_value (left_integer >> (right_integer & 0x1f)); + } + case NUMBER_BITWISE_SHIFT_URIGHT: + { + uint32_t left_uint32 = (uint32_t) ecma_get_integer_from_value (left_value); + ecma_integer_value_t right_integer = ecma_get_integer_from_value (right_value); + return ecma_make_uint32_value (left_uint32 >> (right_integer & 0x1f)); + } + case NUMBER_BITWISE_NOT: + { + return (~right_value) & (ecma_value_t) (~((1 << ECMA_DIRECT_SHIFT) - 1)); + } + } + } + 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); diff --git a/jerry-core/vm/opcodes-ecma-equality.c b/jerry-core/vm/opcodes-ecma-equality.c index 369a3e6da..f908b87ae 100644 --- a/jerry-core/vm/opcodes-ecma-equality.c +++ b/jerry-core/vm/opcodes-ecma-equality.c @@ -44,6 +44,18 @@ ecma_value_t opfunc_equal_value (ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { + JERRY_ASSERT (!ecma_is_value_error (left_value) + && !ecma_is_value_error (right_value)); + + if (ecma_are_values_integer_numbers (left_value, right_value)) + { + if (left_value == right_value) + { + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); + } + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); + } + ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (compare_result, @@ -72,6 +84,18 @@ ecma_value_t opfunc_not_equal_value (ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { + JERRY_ASSERT (!ecma_is_value_error (left_value) + && !ecma_is_value_error (right_value)); + + if (ecma_are_values_integer_numbers (left_value, right_value)) + { + if (left_value == right_value) + { + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); + } + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); + } + ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (compare_result, @@ -102,6 +126,18 @@ ecma_value_t opfunc_equal_value_type (ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { + JERRY_ASSERT (!ecma_is_value_error (left_value) + && !ecma_is_value_error (right_value)); + + if (ecma_are_values_integer_numbers (left_value, right_value)) + { + if (left_value == right_value) + { + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); + } + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); + } + bool is_equal = ecma_op_strict_equality_compare (left_value, right_value); return ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE @@ -120,6 +156,18 @@ ecma_value_t opfunc_not_equal_value_type (ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { + JERRY_ASSERT (!ecma_is_value_error (left_value) + && !ecma_is_value_error (right_value)); + + if (ecma_are_values_integer_numbers (left_value, right_value)) + { + if (left_value == right_value) + { + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); + } + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); + } + bool is_equal = ecma_op_strict_equality_compare (left_value, right_value); return ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE diff --git a/jerry-core/vm/opcodes-ecma-relational.c b/jerry-core/vm/opcodes-ecma-relational.c index 5b43061e9..5e700fbd1 100644 --- a/jerry-core/vm/opcodes-ecma-relational.c +++ b/jerry-core/vm/opcodes-ecma-relational.c @@ -41,6 +41,18 @@ ecma_value_t opfunc_less_than (ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { + JERRY_ASSERT (!ecma_is_value_error (left_value) + && !ecma_is_value_error (right_value)); + + if (ecma_are_values_integer_numbers (left_value, right_value)) + { + if ((ecma_integer_value_t) left_value < (ecma_integer_value_t) right_value) + { + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); + } + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); + } + ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (compare_result, @@ -75,6 +87,18 @@ ecma_value_t opfunc_greater_than (ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { + JERRY_ASSERT (!ecma_is_value_error (left_value) + && !ecma_is_value_error (right_value)); + + if (ecma_are_values_integer_numbers (left_value, right_value)) + { + if ((ecma_integer_value_t) left_value > (ecma_integer_value_t) right_value) + { + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); + } + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); + } + ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (compare_result, @@ -109,6 +133,18 @@ ecma_value_t opfunc_less_or_equal_than (ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { + JERRY_ASSERT (!ecma_is_value_error (left_value) + && !ecma_is_value_error (right_value)); + + if (ecma_are_values_integer_numbers (left_value, right_value)) + { + if ((ecma_integer_value_t) left_value <= (ecma_integer_value_t) right_value) + { + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); + } + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); + } + ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (compare_result, @@ -150,6 +186,18 @@ ecma_value_t opfunc_greater_or_equal_than (ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { + JERRY_ASSERT (!ecma_is_value_error (left_value) + && !ecma_is_value_error (right_value)); + + if (ecma_are_values_integer_numbers (left_value, right_value)) + { + if ((ecma_integer_value_t) left_value >= (ecma_integer_value_t) right_value) + { + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); + } + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); + } + ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (compare_result,