diff --git a/jerry-core/ecma/base/ecma-helpers-value.c b/jerry-core/ecma/base/ecma-helpers-value.c index e9d14f1a4d..2887793a79 100644 --- a/jerry-core/ecma/base/ecma-helpers-value.c +++ b/jerry-core/ecma/base/ecma-helpers-value.c @@ -113,6 +113,18 @@ ecma_get_pointer_from_ecma_value (ecma_value_t value) /**< value */ #endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ } /* ecma_get_pointer_from_ecma_value */ +/** + * Check if the value is direct ecma-value. + * + * @return true - if the value is a direct value, + * false - otherwise. + */ +inline bool __attr_pure___ __attr_always_inline___ +ecma_is_value_direct (ecma_value_t value) /**< ecma value */ +{ + return (ecma_get_value_type_field (value) == ECMA_TYPE_DIRECT); +} /* ecma_is_value_direct */ + /** * Check if the value is simple ecma-value. * diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index 061f7c8094..e9354a4c37 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -114,6 +114,7 @@ } /* ecma-helpers-value.c */ +extern bool ecma_is_value_direct (ecma_value_t) __attr_pure___; extern bool ecma_is_value_simple (ecma_value_t) __attr_pure___; extern bool ecma_is_value_empty (ecma_value_t) __attr_pure___; extern bool ecma_is_value_undefined (ecma_value_t) __attr_pure___; diff --git a/jerry-core/ecma/operations/ecma-comparison.c b/jerry-core/ecma/operations/ecma-comparison.c index d55877b2f4..6107548636 100644 --- a/jerry-core/ecma/operations/ecma-comparison.c +++ b/jerry-core/ecma/operations/ecma-comparison.c @@ -38,41 +38,22 @@ ecma_value_t ecma_op_abstract_equality_compare (ecma_value_t x, /**< first operand */ ecma_value_t y) /**< second operand */ { - const bool is_x_undefined = ecma_is_value_undefined (x); - const bool is_x_null = ecma_is_value_null (x); - const bool is_x_boolean = ecma_is_value_boolean (x); - const bool is_x_number = ecma_is_value_number (x); - const bool is_x_string = ecma_is_value_string (x); - const bool is_x_object = ecma_is_value_object (x); - - const bool is_y_undefined = ecma_is_value_undefined (y); - const bool is_y_null = ecma_is_value_null (y); - const bool is_y_boolean = ecma_is_value_boolean (y); - const bool is_y_number = ecma_is_value_number (y); - const bool is_y_string = ecma_is_value_string (y); - const bool is_y_object = ecma_is_value_object (y); - - const bool is_types_equal = ((is_x_undefined && is_y_undefined) - || (is_x_null && is_y_null) - || (is_x_boolean && is_y_boolean) - || (is_x_number && is_y_number) - || (is_x_string && is_y_string) - || (is_x_object && is_y_object)); - - ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); + if (x == y) + { + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); + } - if (is_types_equal) + if (ecma_are_values_integer_numbers (x, y)) { - // 1. + /* Note: the (x == y) comparison captures the true case. */ + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); + } - if (is_x_undefined - || is_x_null) + if (ecma_is_value_number (x)) + { + if (ecma_is_value_number (y)) { - // a., b. - ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); - } - else if (is_x_number) - { // c. + // 1.c ecma_number_t x_num = ecma_get_number_from_value (x); ecma_number_t y_num = ecma_get_number_from_value (y); @@ -100,111 +81,104 @@ ecma_op_abstract_equality_compare (ecma_value_t x, /**< first operand */ JERRY_ASSERT (is_x_equal_to_y == is_x_equal_to_y_check); #endif /* !JERRY_NDEBUG */ - ret_value = ecma_make_simple_value (is_x_equal_to_y ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); + return ecma_make_simple_value (is_x_equal_to_y ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } - else if (is_x_string) - { // d. + + /* Swap values. */ + ecma_value_t tmp = x; + x = y; + y = tmp; + } + + if (ecma_is_value_string (x)) + { + if (ecma_is_value_string (y)) + { + // 1., d. ecma_string_t *x_str_p = ecma_get_string_from_value (x); ecma_string_t *y_str_p = ecma_get_string_from_value (y); bool is_equal = ecma_compare_ecma_strings (x_str_p, y_str_p); - ret_value = ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); + return ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } - else if (is_x_boolean) - { // e. - bool is_equal = (ecma_is_value_true (x) == ecma_is_value_true (y)); - ret_value = ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); - } - else - { // f. - JERRY_ASSERT (is_x_object); + if (ecma_is_value_number (y)) + { + // 4. + ecma_value_t x_num_value = ecma_op_to_number (x); - bool is_equal = (ecma_get_object_from_value (x) == ecma_get_object_from_value (y)); + if (ecma_is_value_error (x_num_value)) + { + return x_num_value; + } - ret_value = ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); - } - } - else if ((is_x_null && is_y_undefined) - || (is_x_undefined && is_y_null)) - { // 2., 3. - ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); - } - else if (is_x_number && is_y_string) - { - // 4. - ECMA_TRY_CATCH (y_num_value, - ecma_op_to_number (y), - ret_value); + ecma_value_t compare_result = ecma_op_abstract_equality_compare (x_num_value, y); - ret_value = ecma_op_abstract_equality_compare (x, y_num_value); + ecma_free_value (x_num_value); + return compare_result; + } - ECMA_FINALIZE (y_num_value); + /* Swap values. */ + ecma_value_t tmp = x; + x = y; + y = tmp; } - else if (is_x_string && is_y_number) - { - // 5. - ECMA_TRY_CATCH (x_num_value, - ecma_op_to_number (x), - ret_value); - ret_value = ecma_op_abstract_equality_compare (x_num_value, y); - - ECMA_FINALIZE (x_num_value); - } - else if (is_x_boolean) + if (ecma_is_value_boolean (y)) { - // 6. - ECMA_TRY_CATCH (x_num_value, - ecma_op_to_number (x), - ret_value); - - ret_value = ecma_op_abstract_equality_compare (x_num_value, y); + if (ecma_is_value_boolean (x)) + { + // 1., e. + /* Note: the (x == y) comparison captures the true case. */ + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); + } - ECMA_FINALIZE (x_num_value); + // 7. + return ecma_op_abstract_equality_compare (x, ecma_make_integer_value (ecma_is_value_true (y) ? 1 : 0)); } - else if (is_y_boolean) + + if (ecma_is_value_object (x)) { - // 7. - ECMA_TRY_CATCH (y_num_value, - ecma_op_to_number (y), - ret_value); + if (ecma_is_value_string (y) + || ecma_is_value_number (y)) + { + // 9. + ecma_value_t x_prim_value = ecma_op_to_primitive (x, ECMA_PREFERRED_TYPE_NO); - ret_value = ecma_op_abstract_equality_compare (x, y_num_value); + if (ecma_is_value_error (x_prim_value)) + { + return x_prim_value; + } - ECMA_FINALIZE (y_num_value); - } - else if (is_y_object - && (is_x_number || is_x_string)) - { - // 8. - ECMA_TRY_CATCH (y_prim_value, - ecma_op_to_primitive (y, ECMA_PREFERRED_TYPE_NO), - ret_value); + ecma_value_t compare_result = ecma_op_abstract_equality_compare (x_prim_value, y); - ret_value = ecma_op_abstract_equality_compare (x, y_prim_value); + ecma_free_value (x_prim_value); + return compare_result; + } - ECMA_FINALIZE (y_prim_value); + // 1., f. + /* Note: the (x == y) comparison captures the true case. */ + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); } - else if (is_x_object - && (is_y_number || is_y_string)) - { - // 9. - ECMA_TRY_CATCH (x_prim_value, - ecma_op_to_primitive (x, ECMA_PREFERRED_TYPE_NO), - ret_value); - - ret_value = ecma_op_abstract_equality_compare (x_prim_value, y); - ECMA_FINALIZE (x_prim_value); + if (ecma_is_value_boolean (x)) + { + // 6. + return ecma_op_abstract_equality_compare (ecma_make_integer_value (ecma_is_value_true (x) ? 1 : 0), y); } - else + + if (ecma_is_value_undefined (x) + || ecma_is_value_null (x)) { - ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); + // 1. a., b. + // 2., 3. + bool is_equal = ecma_is_value_undefined (y) || ecma_is_value_null (y); + + return ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } - return ret_value; + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); } /* ecma_op_abstract_equality_compare */ /** @@ -219,104 +193,81 @@ bool ecma_op_strict_equality_compare (ecma_value_t x, /**< first operand */ ecma_value_t y) /**< second operand */ { - const bool is_x_undefined = ecma_is_value_undefined (x); - const bool is_x_null = ecma_is_value_null (x); - const bool is_x_boolean = ecma_is_value_boolean (x); - const bool is_x_number = ecma_is_value_number (x); - const bool is_x_string = ecma_is_value_string (x); - const bool is_x_object = ecma_is_value_object (x); - - const bool is_y_undefined = ecma_is_value_undefined (y); - const bool is_y_null = ecma_is_value_null (y); - const bool is_y_boolean = ecma_is_value_boolean (y); - const bool is_y_number = ecma_is_value_number (y); - const bool is_y_string = ecma_is_value_string (y); - const bool is_y_object = ecma_is_value_object (y); - - const bool is_types_equal = ((is_x_undefined && is_y_undefined) - || (is_x_null && is_y_null) - || (is_x_boolean && is_y_boolean) - || (is_x_number && is_y_number) - || (is_x_string && is_y_string) - || (is_x_object && is_y_object)); - - // 1. If Type (x) is different from Type (y), return false. - if (!is_types_equal) + if (ecma_is_value_direct (x) + || ecma_is_value_direct (y) + || ecma_is_value_object (x) + || ecma_is_value_object (y)) { - return false; - } + JERRY_ASSERT (!ecma_is_value_direct (x) + || ecma_is_value_undefined (x) + || ecma_is_value_null (x) + || ecma_is_value_boolean (x) + || ecma_is_value_integer_number (x)); + + JERRY_ASSERT (!ecma_is_value_direct (y) + || ecma_is_value_undefined (y) + || ecma_is_value_null (y) + || ecma_is_value_boolean (y) + || ecma_is_value_integer_number (y)); + + if ((x != ecma_make_integer_value (0) || !ecma_is_value_float_number (y)) + && (y != ecma_make_integer_value (0) || !ecma_is_value_float_number (x))) + { + return (x == y); + } - // 2. If Type (x) is Undefined, return true. - if (is_x_undefined) - { - return true; + /* The +0 === -0 case handled below. */ } - // 3. If Type (x) is Null, return true. - if (is_x_null) + JERRY_ASSERT (ecma_is_value_number (x) || ecma_is_value_string (x)); + JERRY_ASSERT (ecma_is_value_number (y) || ecma_is_value_string (y)); + + if (ecma_is_value_string (x)) { - return true; + if (!ecma_is_value_string (y)) + { + return false; + } + + ecma_string_t *x_str_p = ecma_get_string_from_value (x); + ecma_string_t *y_str_p = ecma_get_string_from_value (y); + + return ecma_compare_ecma_strings (x_str_p, y_str_p); } - // 4. If Type (x) is Number, then - if (is_x_number) + if (!ecma_is_value_number (y)) { - // a. If x is NaN, return false. - // b. If y is NaN, return false. - // c. If x is the same Number value as y, return true. - // d. If x is +0 and y is -0, return true. - // e. If x is -0 and y is +0, return true. + return false; + } - ecma_number_t x_num = ecma_get_number_from_value (x); - ecma_number_t y_num = ecma_get_number_from_value (y); + ecma_number_t x_num = ecma_get_number_from_value (x); + ecma_number_t y_num = ecma_get_number_from_value (y); - bool is_x_equal_to_y = (x_num == y_num); + bool is_x_equal_to_y = (x_num == y_num); #ifndef JERRY_NDEBUG - bool is_x_equal_to_y_check; - - if (ecma_number_is_nan (x_num) - || ecma_number_is_nan (y_num)) - { - is_x_equal_to_y_check = false; - } - else if (x_num == y_num - || (ecma_number_is_zero (x_num) - && ecma_number_is_zero (y_num))) - { - is_x_equal_to_y_check = true; - } - else - { - is_x_equal_to_y_check = false; - } - - JERRY_ASSERT (is_x_equal_to_y == is_x_equal_to_y_check); -#endif /* !JERRY_NDEBUG */ + bool is_x_equal_to_y_check; - return is_x_equal_to_y; + if (ecma_number_is_nan (x_num) + || ecma_number_is_nan (y_num)) + { + is_x_equal_to_y_check = false; } - - // 5. If Type (x) is String, then return true if x and y are exactly the same sequence of characters - // (same length and same characters in corresponding positions); otherwise, return false. - if (is_x_string) + else if (x_num == y_num + || (ecma_number_is_zero (x_num) + && ecma_number_is_zero (y_num))) { - ecma_string_t *x_str_p = ecma_get_string_from_value (x); - ecma_string_t *y_str_p = ecma_get_string_from_value (y); - - return ecma_compare_ecma_strings (x_str_p, y_str_p); + is_x_equal_to_y_check = true; } - - // 6. If Type (x) is Boolean, return true if x and y are both true or both false; otherwise, return false. - if (is_x_boolean) + else { - return (ecma_is_value_true (x) == ecma_is_value_true (y)); + is_x_equal_to_y_check = false; } - // 7. Return true if x and y refer to the same object. Otherwise, return false. - JERRY_ASSERT (is_x_object); + JERRY_ASSERT (is_x_equal_to_y == is_x_equal_to_y_check); +#endif /* !JERRY_NDEBUG */ - return (ecma_get_object_from_value (x) == ecma_get_object_from_value (y)); + return is_x_equal_to_y; } /* ecma_op_strict_equality_compare */ /** diff --git a/jerry-core/vm/opcodes-ecma-equality.c b/jerry-core/vm/opcodes-ecma-equality.c index f908b87ae1..435a9d1785 100644 --- a/jerry-core/vm/opcodes-ecma-equality.c +++ b/jerry-core/vm/opcodes-ecma-equality.c @@ -47,29 +47,13 @@ opfunc_equal_value (ecma_value_t left_value, /**< left 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, - ecma_op_abstract_equality_compare (left_value, - right_value), - ret_value); - - JERRY_ASSERT (ecma_is_value_boolean (compare_result)); - - ret_value = compare_result; + ecma_value_t compare_result = ecma_op_abstract_equality_compare (left_value, + right_value); - ECMA_FINALIZE (compare_result); + JERRY_ASSERT (ecma_is_value_boolean (compare_result) + || ecma_is_value_error (compare_result)); - return ret_value; + return compare_result; } /* opfunc_equal_value */ /** @@ -87,92 +71,19 @@ opfunc_not_equal_value (ecma_value_t left_value, /**< left 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, - ecma_op_abstract_equality_compare (left_value, right_value), - ret_value); - - JERRY_ASSERT (ecma_is_value_boolean (compare_result)); - - bool is_equal = ecma_is_value_true (compare_result); - - ret_value = ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE - : ECMA_SIMPLE_VALUE_TRUE); - - ECMA_FINALIZE (compare_result); - - return ret_value; -} /* opfunc_not_equal_value */ - -/** - * 'Strict Equals' opcode handler. - * - * See also: ECMA-262 v5, 11.9.4 - * - * @return ecma value - * Returned value must be freed with ecma_free_value - */ -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); + ecma_value_t compare_result = ecma_op_abstract_equality_compare (left_value, + right_value); - return ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE - : ECMA_SIMPLE_VALUE_FALSE); -} /* opfunc_equal_value_type */ - -/** - * 'Strict Does-not-equals' opcode handler. - * - * See also: ECMA-262 v5, 11.9.5 - * - * @return ecma value - * Returned value must be freed with ecma_free_value - */ -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)); + JERRY_ASSERT (ecma_is_value_boolean (compare_result) + || ecma_is_value_error (compare_result)); - if (ecma_are_values_integer_numbers (left_value, right_value)) + if (!ecma_is_value_error (compare_result)) { - if (left_value == right_value) - { - return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); - } - return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); + compare_result = ecma_invert_boolean_value (compare_result); } - bool is_equal = ecma_op_strict_equality_compare (left_value, right_value); - - return ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE - : ECMA_SIMPLE_VALUE_TRUE); -} /* opfunc_not_equal_value_type */ + return compare_result; +} /* opfunc_not_equal_value */ /** * @} diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index 67de80c1db..531ee23032 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -62,12 +62,6 @@ opfunc_equal_value (ecma_value_t, ecma_value_t); ecma_value_t opfunc_not_equal_value (ecma_value_t, ecma_value_t); -ecma_value_t -opfunc_equal_value_type (ecma_value_t, ecma_value_t); - -ecma_value_t -opfunc_not_equal_value_type (ecma_value_t, ecma_value_t); - ecma_value_t do_number_arithmetic (number_arithmetic_op, ecma_value_t, ecma_value_t); diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index b6321b08de..e9ed48f284 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -19,6 +19,7 @@ #include "ecma-alloc.h" #include "ecma-array-object.h" #include "ecma-builtins.h" +#include "ecma-comparison.h" #include "ecma-conversion.h" #include "ecma-exceptions.h" #include "ecma-function-object.h" @@ -1483,17 +1484,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { JERRY_ASSERT (stack_top_p > frame_ctx_p->registers_p + register_end); - last_completion_value = opfunc_equal_value_type (left_value, - stack_top_p[-1]); - - if (ecma_is_value_error (last_completion_value)) - { - goto error; - } - - result = last_completion_value; - - if (result == ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE)) + if (ecma_op_strict_equality_compare (left_value, stack_top_p[-1])) { byte_code_p = byte_code_start_p + branch_offset; ecma_free_value (*--stack_top_p); @@ -1726,26 +1717,18 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_STRICT_EQUAL: { - last_completion_value = opfunc_equal_value_type (left_value, right_value); - - if (ecma_is_value_error (last_completion_value)) - { - goto error; - } + bool is_equal = ecma_op_strict_equality_compare (left_value, right_value); - result = last_completion_value; + result = ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE + : ECMA_SIMPLE_VALUE_FALSE); break; } case VM_OC_STRICT_NOT_EQUAL: { - last_completion_value = opfunc_not_equal_value_type (left_value, right_value); - - if (ecma_is_value_error (last_completion_value)) - { - goto error; - } + bool is_equal = ecma_op_strict_equality_compare (left_value, right_value); - result = last_completion_value; + result = ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE + : ECMA_SIMPLE_VALUE_TRUE); break; } case VM_OC_BIT_OR: