mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
The removal of these macros enabled cppcheck to reveal new errors. These errors are also fixed by the patch. JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
574 lines
14 KiB
C
574 lines
14 KiB
C
/* Copyright JS Foundation and other contributors, http://js.foundation
|
|
*
|
|
* 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 "ecma-bigint.h"
|
|
#include "ecma-comparison.h"
|
|
#include "ecma-conversion.h"
|
|
#include "ecma-globals.h"
|
|
#include "ecma-objects.h"
|
|
#include "jrt.h"
|
|
|
|
/** \addtogroup ecma ECMA
|
|
* @{
|
|
*
|
|
* \addtogroup ecmacomparison ECMA comparison
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* ECMA abstract equality comparison routine.
|
|
*
|
|
* See also: ECMA-262 v5, 11.9.3
|
|
*
|
|
* Note:
|
|
* This function might raise an exception, so the
|
|
* returned value must be freed with ecma_free_value.
|
|
*
|
|
* @return true - if values are equal,
|
|
* false - otherwise
|
|
* error - in case of any problems
|
|
*/
|
|
ecma_value_t
|
|
ecma_op_abstract_equality_compare (ecma_value_t x, /**< first operand */
|
|
ecma_value_t y) /**< second operand */
|
|
{
|
|
if (x == y)
|
|
{
|
|
return ECMA_VALUE_TRUE;
|
|
}
|
|
|
|
if (ecma_are_values_integer_numbers (x, y))
|
|
{
|
|
/* Note: the (x == y) comparison captures the true case. */
|
|
return ECMA_VALUE_FALSE;
|
|
}
|
|
|
|
if (ecma_is_value_number (x))
|
|
{
|
|
if (ecma_is_value_number (y))
|
|
{
|
|
/* 1.c */
|
|
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);
|
|
|
|
#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 */
|
|
|
|
return ecma_make_boolean_value (is_x_equal_to_y);
|
|
}
|
|
|
|
/* Swap values. */
|
|
x ^= y;
|
|
y ^= x;
|
|
x ^= y;
|
|
}
|
|
|
|
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);
|
|
|
|
return ecma_make_boolean_value (is_equal);
|
|
}
|
|
|
|
if (ecma_is_value_number (y))
|
|
{
|
|
/* 4. */
|
|
ecma_number_t num;
|
|
ecma_value_t x_num_value = ecma_op_to_number (x, &num);
|
|
|
|
if (ECMA_IS_VALUE_ERROR (x_num_value))
|
|
{
|
|
return x_num_value;
|
|
}
|
|
ecma_value_t num_value = ecma_make_number_value (num);
|
|
ecma_value_t compare_result = ecma_op_abstract_equality_compare (num_value, y);
|
|
|
|
ecma_free_value (num_value);
|
|
return compare_result;
|
|
}
|
|
|
|
/* Swap values. */
|
|
x ^= y;
|
|
y ^= x;
|
|
x ^= y;
|
|
}
|
|
|
|
if (ecma_is_value_boolean (y))
|
|
{
|
|
if (ecma_is_value_boolean (x))
|
|
{
|
|
/* 1., e. */
|
|
/* Note: the (x == y) comparison captures the true case. */
|
|
return ECMA_VALUE_FALSE;
|
|
}
|
|
|
|
/* 7. */
|
|
return ecma_op_abstract_equality_compare (x, ecma_make_integer_value (ecma_is_value_true (y) ? 1 : 0));
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
#if JERRY_BUILTIN_BIGINT
|
|
if (JERRY_UNLIKELY (ecma_is_value_bigint (x)))
|
|
{
|
|
if (ecma_is_value_bigint (y))
|
|
{
|
|
return ecma_make_boolean_value (ecma_bigint_is_equal_to_bigint (x, y));
|
|
}
|
|
|
|
if (ecma_is_value_string (y))
|
|
{
|
|
ecma_value_t bigint = ecma_bigint_parse_string_value (y, ECMA_BIGINT_PARSE_DISALLOW_SYNTAX_ERROR);
|
|
|
|
if (ECMA_IS_VALUE_ERROR (bigint)
|
|
|| bigint == ECMA_VALUE_FALSE)
|
|
{
|
|
return bigint;
|
|
}
|
|
|
|
JERRY_ASSERT (ecma_is_value_bigint (bigint));
|
|
|
|
ecma_value_t result = ecma_make_boolean_value (ecma_bigint_is_equal_to_bigint (x, bigint));
|
|
|
|
ecma_free_value (bigint);
|
|
return result;
|
|
}
|
|
|
|
if (ecma_is_value_number (y))
|
|
{
|
|
return ecma_make_boolean_value (ecma_bigint_is_equal_to_number (x, ecma_get_number_from_value (y)));
|
|
}
|
|
|
|
/* Swap values. */
|
|
x ^= y;
|
|
y ^= x;
|
|
x ^= y;
|
|
}
|
|
#endif /* JERRY_BUILTIN_BIGINT */
|
|
|
|
if (ecma_is_value_undefined (x)
|
|
|| ecma_is_value_null (x))
|
|
{
|
|
/* 1. a., b. */
|
|
/* 2., 3. */
|
|
bool is_equal = ecma_is_value_undefined (y) || ecma_is_value_null (y);
|
|
|
|
return ecma_make_boolean_value (is_equal);
|
|
}
|
|
|
|
#if JERRY_ESNEXT
|
|
if (JERRY_UNLIKELY (ecma_is_value_symbol (x)))
|
|
{
|
|
if (!ecma_is_value_object (y))
|
|
{
|
|
return ECMA_VALUE_FALSE;
|
|
}
|
|
|
|
/* Swap values. */
|
|
x ^= y;
|
|
y ^= x;
|
|
x ^= y;
|
|
}
|
|
#endif /* JERRY_ESNEXT */
|
|
|
|
JERRY_ASSERT (ecma_is_value_object (x));
|
|
|
|
if (ecma_is_value_string (y)
|
|
#if JERRY_ESNEXT
|
|
|| ecma_is_value_symbol (y)
|
|
#endif /* JERRY_ESNEXT */
|
|
#if JERRY_BUILTIN_BIGINT
|
|
|| ecma_is_value_bigint (y)
|
|
#endif /* JERRY_BUILTIN_BIGINT */
|
|
|| ecma_is_value_number (y))
|
|
{
|
|
/* 9. */
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (x);
|
|
|
|
ecma_value_t def_value = ecma_op_object_default_value (obj_p, ECMA_PREFERRED_TYPE_NO);
|
|
|
|
if (ECMA_IS_VALUE_ERROR (def_value))
|
|
{
|
|
return def_value;
|
|
}
|
|
|
|
ecma_value_t compare_result = ecma_op_abstract_equality_compare (def_value, y);
|
|
|
|
ecma_free_value (def_value);
|
|
|
|
return compare_result;
|
|
}
|
|
|
|
return ECMA_VALUE_FALSE;
|
|
} /* ecma_op_abstract_equality_compare */
|
|
|
|
/**
|
|
* ECMA strict equality comparison routine.
|
|
*
|
|
* See also: ECMA-262 v5, 11.9.6
|
|
*
|
|
* @return true - if values are strict equal,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
ecma_op_strict_equality_compare (ecma_value_t x, /**< first operand */
|
|
ecma_value_t y) /**< second operand */
|
|
{
|
|
if (ecma_is_value_direct (x)
|
|
|| ecma_is_value_direct (y)
|
|
#if JERRY_ESNEXT
|
|
|| ecma_is_value_symbol (x)
|
|
|| ecma_is_value_symbol (y)
|
|
#endif /* JERRY_ESNEXT */
|
|
|| ecma_is_value_object (x)
|
|
|| ecma_is_value_object (y))
|
|
{
|
|
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);
|
|
}
|
|
|
|
/* The +0 === -0 case handled below. */
|
|
}
|
|
|
|
JERRY_ASSERT (ecma_is_value_number (x) || ecma_is_value_string (x) ||
|
|
ecma_is_value_bigint (x));
|
|
JERRY_ASSERT (ecma_is_value_number (y) || ecma_is_value_string (y) ||
|
|
ecma_is_value_bigint (y));
|
|
|
|
if (ecma_is_value_string (x))
|
|
{
|
|
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);
|
|
}
|
|
|
|
#if JERRY_BUILTIN_BIGINT
|
|
if (JERRY_UNLIKELY (ecma_is_value_bigint (x)))
|
|
{
|
|
if (!ecma_is_value_bigint (y))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return ecma_bigint_is_equal_to_bigint (x, y);
|
|
}
|
|
#endif /* JERRY_BUILTIN_BIGINT */
|
|
|
|
if (!ecma_is_value_number (y))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
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);
|
|
|
|
#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 */
|
|
|
|
return is_x_equal_to_y;
|
|
} /* ecma_op_strict_equality_compare */
|
|
|
|
/**
|
|
* ECMA abstract relational comparison routine.
|
|
*
|
|
* See also: ECMA-262 v5, 11.8.5
|
|
*
|
|
* @return ecma value
|
|
* Returned value must be freed with ecma_free_value
|
|
*/
|
|
ecma_value_t
|
|
ecma_op_abstract_relational_compare (ecma_value_t x, /**< first operand */
|
|
ecma_value_t y, /**< second operand */
|
|
bool left_first) /**< 'LeftFirst' flag */
|
|
{
|
|
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
|
|
|
|
/* 1., 2. */
|
|
ecma_value_t prim_first_converted_value = ecma_op_to_primitive (x, ECMA_PREFERRED_TYPE_NUMBER);
|
|
if (ECMA_IS_VALUE_ERROR (prim_first_converted_value))
|
|
{
|
|
return prim_first_converted_value;
|
|
}
|
|
|
|
ecma_value_t prim_second_converted_value = ecma_op_to_primitive (y, ECMA_PREFERRED_TYPE_NUMBER);
|
|
if (ECMA_IS_VALUE_ERROR (prim_second_converted_value))
|
|
{
|
|
ecma_free_value (prim_first_converted_value);
|
|
return prim_second_converted_value;
|
|
}
|
|
|
|
ecma_value_t px = left_first ? prim_first_converted_value : prim_second_converted_value;
|
|
ecma_value_t py = left_first ? prim_second_converted_value : prim_first_converted_value;
|
|
|
|
const bool is_px_string = ecma_is_value_string (px);
|
|
const bool is_py_string = ecma_is_value_string (py);
|
|
|
|
if (!(is_px_string && is_py_string))
|
|
{
|
|
#if JERRY_BUILTIN_BIGINT
|
|
if (JERRY_LIKELY (!ecma_is_value_bigint (px))
|
|
&& JERRY_LIKELY (!ecma_is_value_bigint (py)))
|
|
{
|
|
#endif /* JERRY_BUILTIN_BIGINT */
|
|
/* 3. */
|
|
|
|
/* a. */
|
|
|
|
ecma_number_t nx;
|
|
ecma_number_t ny;
|
|
|
|
if (ECMA_IS_VALUE_ERROR (ecma_op_to_number (px, &nx))
|
|
|| ECMA_IS_VALUE_ERROR (ecma_op_to_number (py, &ny)))
|
|
{
|
|
ret_value = ECMA_VALUE_ERROR;
|
|
goto end;
|
|
}
|
|
|
|
/* b. */
|
|
if (ecma_number_is_nan (nx)
|
|
|| ecma_number_is_nan (ny))
|
|
{
|
|
/* c., d. */
|
|
ret_value = ECMA_VALUE_UNDEFINED;
|
|
}
|
|
else
|
|
{
|
|
bool is_x_less_than_y = (nx < ny);
|
|
|
|
#ifndef JERRY_NDEBUG
|
|
bool is_x_less_than_y_check;
|
|
|
|
if (nx == ny
|
|
|| (ecma_number_is_zero (nx)
|
|
&& ecma_number_is_zero (ny)))
|
|
{
|
|
/* e., f., g. */
|
|
is_x_less_than_y_check = false;
|
|
}
|
|
else if (ecma_number_is_infinity (nx)
|
|
&& !ecma_number_is_negative (nx))
|
|
{
|
|
/* h. */
|
|
is_x_less_than_y_check = false;
|
|
}
|
|
else if (ecma_number_is_infinity (ny)
|
|
&& !ecma_number_is_negative (ny))
|
|
{
|
|
/* i. */
|
|
is_x_less_than_y_check = true;
|
|
}
|
|
else if (ecma_number_is_infinity (ny)
|
|
&& ecma_number_is_negative (ny))
|
|
{
|
|
/* j. */
|
|
is_x_less_than_y_check = false;
|
|
}
|
|
else if (ecma_number_is_infinity (nx)
|
|
&& ecma_number_is_negative (nx))
|
|
{
|
|
/* k. */
|
|
is_x_less_than_y_check = true;
|
|
}
|
|
else
|
|
{
|
|
/* l. */
|
|
JERRY_ASSERT (!ecma_number_is_nan (nx)
|
|
&& !ecma_number_is_infinity (nx));
|
|
JERRY_ASSERT (!ecma_number_is_nan (ny)
|
|
&& !ecma_number_is_infinity (ny));
|
|
JERRY_ASSERT (!(ecma_number_is_zero (nx)
|
|
&& ecma_number_is_zero (ny)));
|
|
|
|
if (nx < ny)
|
|
{
|
|
is_x_less_than_y_check = true;
|
|
}
|
|
else
|
|
{
|
|
is_x_less_than_y_check = false;
|
|
}
|
|
}
|
|
|
|
JERRY_ASSERT (is_x_less_than_y_check == is_x_less_than_y);
|
|
#endif /* !JERRY_NDEBUG */
|
|
|
|
ret_value = ecma_make_boolean_value (is_x_less_than_y);
|
|
}
|
|
#if JERRY_BUILTIN_BIGINT
|
|
}
|
|
else
|
|
{
|
|
bool invert_result = false;
|
|
int compare_result = 0;
|
|
|
|
if (!ecma_is_value_bigint (px))
|
|
{
|
|
ecma_value_t tmp = px;
|
|
px = py;
|
|
py = tmp;
|
|
invert_result = true;
|
|
}
|
|
|
|
JERRY_ASSERT (ecma_is_value_bigint (px));
|
|
|
|
if (ecma_is_value_bigint (py))
|
|
{
|
|
compare_result = ecma_bigint_compare_to_bigint (px, py);
|
|
}
|
|
else if (ecma_is_value_string (py))
|
|
{
|
|
ret_value = ecma_bigint_parse_string_value (py, ECMA_BIGINT_PARSE_DISALLOW_SYNTAX_ERROR);
|
|
|
|
if (!ECMA_IS_VALUE_ERROR (ret_value))
|
|
{
|
|
if (ret_value == ECMA_VALUE_FALSE)
|
|
{
|
|
ret_value = ECMA_VALUE_UNDEFINED;
|
|
}
|
|
else
|
|
{
|
|
compare_result = ecma_bigint_compare_to_bigint (px, ret_value);
|
|
ecma_free_value (ret_value);
|
|
ret_value = ECMA_VALUE_EMPTY;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ecma_number_t ny;
|
|
if (ECMA_IS_VALUE_ERROR (ecma_op_to_number (py, &ny)))
|
|
{
|
|
ret_value = ECMA_VALUE_ERROR;
|
|
goto end;
|
|
}
|
|
|
|
if (ecma_number_is_nan (ny))
|
|
{
|
|
ret_value = ECMA_VALUE_UNDEFINED;
|
|
}
|
|
else
|
|
{
|
|
compare_result = ecma_bigint_compare_to_number (px, ny);
|
|
}
|
|
}
|
|
|
|
if (ret_value == ECMA_VALUE_EMPTY)
|
|
{
|
|
if (invert_result)
|
|
{
|
|
compare_result = -compare_result;
|
|
}
|
|
|
|
ret_value = ecma_make_boolean_value (compare_result < 0);
|
|
}
|
|
}
|
|
#endif /* JERRY_BUILTIN_BIGINT */
|
|
}
|
|
else
|
|
{ /* 4. */
|
|
JERRY_ASSERT (is_px_string && is_py_string);
|
|
|
|
ecma_string_t *str_x_p = ecma_get_string_from_value (px);
|
|
ecma_string_t *str_y_p = ecma_get_string_from_value (py);
|
|
|
|
bool is_px_less = ecma_compare_ecma_strings_relational (str_x_p, str_y_p);
|
|
|
|
ret_value = ecma_make_boolean_value (is_px_less);
|
|
}
|
|
|
|
end:
|
|
ecma_free_value (prim_second_converted_value);
|
|
ecma_free_value (prim_first_converted_value);
|
|
|
|
return ret_value;
|
|
} /* ecma_op_abstract_relational_compare */
|
|
|
|
/**
|
|
* @}
|
|
* @}
|
|
*/
|