mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Ubuntu 14.04 reached its end of life on April 30m 2019. Let's bump the reference to the latest LTS, which is 18.04. Ubuntu 18.04 has newer Pylint and Cppcheck, the necessary fixes and suppresses are also included in this PR. JerryScript-DCO-1.0-Signed-off-by: Csaba Osztrogonác oszi@inf.u-szeged.hu
1054 lines
29 KiB
C
1054 lines
29 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-conversion.h"
|
|
#include "lit-char-helpers.h"
|
|
|
|
/** \addtogroup ecma ECMA
|
|
* @{
|
|
*
|
|
* \addtogroup ecmahelpers Helpers for operations with ECMA data types
|
|
* @{
|
|
*/
|
|
|
|
JERRY_STATIC_ASSERT (sizeof (ecma_value_t) == sizeof (ecma_integer_value_t),
|
|
size_of_ecma_value_t_must_be_equal_to_the_size_of_ecma_integer_value_t);
|
|
|
|
JERRY_STATIC_ASSERT (ECMA_DIRECT_SHIFT == ECMA_VALUE_SHIFT + 1,
|
|
currently_directly_encoded_values_has_one_extra_flag);
|
|
|
|
JERRY_STATIC_ASSERT (((1 << (ECMA_DIRECT_SHIFT - 1)) | ECMA_TYPE_DIRECT) == ECMA_DIRECT_TYPE_SIMPLE_VALUE,
|
|
currently_directly_encoded_values_start_after_direct_type_simple_value);
|
|
/**
|
|
* Position of the sign bit in ecma-numbers
|
|
*/
|
|
#define ECMA_NUMBER_SIGN_POS (ECMA_NUMBER_FRACTION_WIDTH + \
|
|
ECMA_NUMBER_BIASED_EXP_WIDTH)
|
|
|
|
#if !ENABLED (JERRY_NUMBER_TYPE_FLOAT64)
|
|
JERRY_STATIC_ASSERT (sizeof (ecma_number_t) == sizeof (uint32_t),
|
|
size_of_ecma_number_t_must_be_equal_to_4_bytes);
|
|
|
|
/**
|
|
* Packing sign, fraction and biased exponent to ecma-number
|
|
*
|
|
* @return ecma-number with specified sign, biased_exponent and fraction
|
|
*/
|
|
static ecma_number_t
|
|
ecma_number_pack (bool sign, /**< sign */
|
|
uint32_t biased_exp, /**< biased exponent */
|
|
uint64_t fraction) /**< fraction */
|
|
{
|
|
JERRY_ASSERT ((biased_exp & ~((1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)) == 0);
|
|
JERRY_ASSERT ((fraction & ~((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1)) == 0);
|
|
|
|
uint32_t packed_value = (((sign ? 1u : 0u) << ECMA_NUMBER_SIGN_POS) |
|
|
(biased_exp << ECMA_NUMBER_FRACTION_WIDTH) |
|
|
((uint32_t) fraction));
|
|
|
|
ecma_number_accessor_t u;
|
|
u.as_uint32_t = packed_value;
|
|
return u.as_ecma_number_t;
|
|
} /* ecma_number_pack */
|
|
|
|
/**
|
|
* Unpacking sign, fraction and biased exponent from ecma-number
|
|
*/
|
|
static void
|
|
ecma_number_unpack (ecma_number_t num, /**< ecma-number */
|
|
bool *sign_p, /**< [out] sign (optional) */
|
|
uint32_t *biased_exp_p, /**< [out] biased exponent (optional) */
|
|
uint64_t *fraction_p) /**< [out] fraction (optional) */
|
|
{
|
|
ecma_number_accessor_t u;
|
|
u.as_ecma_number_t = num;
|
|
uint32_t packed_value = u.as_uint32_t;
|
|
|
|
if (sign_p != NULL)
|
|
{
|
|
*sign_p = ((packed_value >> ECMA_NUMBER_SIGN_POS) != 0);
|
|
}
|
|
|
|
if (biased_exp_p != NULL)
|
|
{
|
|
*biased_exp_p = (((packed_value) & ~(1u << ECMA_NUMBER_SIGN_POS)) >> ECMA_NUMBER_FRACTION_WIDTH);
|
|
}
|
|
|
|
if (fraction_p != NULL)
|
|
{
|
|
*fraction_p = (packed_value & ((1u << ECMA_NUMBER_FRACTION_WIDTH) - 1));
|
|
}
|
|
} /* ecma_number_unpack */
|
|
|
|
/**
|
|
* Value used to calculate exponent from biased exponent
|
|
*
|
|
* See also:
|
|
* IEEE-754 2008, 3.6, Table 3.5
|
|
*/
|
|
const int32_t ecma_number_exponent_bias = 127;
|
|
|
|
#elif ENABLED (JERRY_NUMBER_TYPE_FLOAT64)
|
|
JERRY_STATIC_ASSERT (sizeof (ecma_number_t) == sizeof (uint64_t),
|
|
size_of_ecma_number_t_must_be_equal_to_8_bytes);
|
|
|
|
/**
|
|
* Packing sign, fraction and biased exponent to ecma-number
|
|
*
|
|
* @return ecma-number with specified sign, biased_exponent and fraction
|
|
*/
|
|
static ecma_number_t
|
|
ecma_number_pack (bool sign, /**< sign */
|
|
uint32_t biased_exp, /**< biased exponent */
|
|
uint64_t fraction) /**< fraction */
|
|
{
|
|
uint64_t packed_value = (((sign ? 1ull : 0ull) << ECMA_NUMBER_SIGN_POS) |
|
|
(((uint64_t) biased_exp) << ECMA_NUMBER_FRACTION_WIDTH) |
|
|
fraction);
|
|
|
|
JERRY_ASSERT ((biased_exp & ~((1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)) == 0);
|
|
JERRY_ASSERT ((fraction & ~((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1)) == 0);
|
|
|
|
ecma_number_accessor_t u;
|
|
u.as_uint64_t = packed_value;
|
|
return u.as_ecma_number_t;
|
|
} /* ecma_number_pack */
|
|
|
|
/**
|
|
* Unpacking sign, fraction and biased exponent from ecma-number
|
|
*/
|
|
static void
|
|
ecma_number_unpack (ecma_number_t num, /**< ecma-number */
|
|
bool *sign_p, /**< [out] sign (optional) */
|
|
uint32_t *biased_exp_p, /**< [out] biased exponent (optional) */
|
|
uint64_t *fraction_p) /**< [out] fraction (optional) */
|
|
{
|
|
ecma_number_accessor_t u;
|
|
u.as_ecma_number_t = num;
|
|
uint64_t packed_value = u.as_uint64_t;
|
|
|
|
if (sign_p != NULL)
|
|
{
|
|
*sign_p = ((packed_value >> ECMA_NUMBER_SIGN_POS) != 0);
|
|
}
|
|
|
|
if (biased_exp_p != NULL)
|
|
{
|
|
*biased_exp_p = (uint32_t) (((packed_value) & ~(1ull << ECMA_NUMBER_SIGN_POS)) >> ECMA_NUMBER_FRACTION_WIDTH);
|
|
}
|
|
|
|
if (fraction_p != NULL)
|
|
{
|
|
*fraction_p = (packed_value & ((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1));
|
|
}
|
|
} /* ecma_number_unpack */
|
|
|
|
/**
|
|
* Value used to calculate exponent from biased exponent
|
|
*
|
|
* See also:
|
|
* IEEE-754 2008, 3.6, Table 3.5
|
|
*/
|
|
const int32_t ecma_number_exponent_bias = 1023;
|
|
|
|
#endif /* ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
|
|
|
|
/**
|
|
* Get fraction of number
|
|
*
|
|
* @return normalized fraction field of number
|
|
*/
|
|
static uint64_t
|
|
ecma_number_get_fraction_field (ecma_number_t num) /**< ecma-number */
|
|
{
|
|
uint64_t fraction;
|
|
|
|
ecma_number_unpack (num, NULL, NULL, &fraction);
|
|
|
|
return fraction;
|
|
} /* ecma_number_get_fraction_field */
|
|
|
|
/**
|
|
* Get exponent of number
|
|
*
|
|
* @return exponent corresponding to normalized fraction of number
|
|
*/
|
|
static uint32_t
|
|
ecma_number_get_biased_exponent_field (ecma_number_t num) /**< ecma-number */
|
|
{
|
|
uint32_t biased_exp;
|
|
|
|
ecma_number_unpack (num, NULL, &biased_exp, NULL);
|
|
|
|
return biased_exp;
|
|
} /* ecma_number_get_biased_exponent_field */
|
|
|
|
/**
|
|
* Get sign bit of number
|
|
*
|
|
* @return 0 or 1 - value of sign bit
|
|
*/
|
|
static uint32_t
|
|
ecma_number_get_sign_field (ecma_number_t num) /**< ecma-number */
|
|
{
|
|
bool sign;
|
|
|
|
ecma_number_unpack (num, &sign, NULL, NULL);
|
|
|
|
return sign;
|
|
} /* ecma_number_get_sign_field */
|
|
|
|
/**
|
|
* Check if ecma-number is NaN
|
|
*
|
|
* @return true - if biased exponent is filled with 1 bits and
|
|
fraction is filled with anything but not all zero bits,
|
|
* false - otherwise
|
|
*/
|
|
extern inline bool JERRY_ATTR_ALWAYS_INLINE
|
|
ecma_number_is_nan (ecma_number_t num) /**< ecma-number */
|
|
{
|
|
bool is_nan = (num != num);
|
|
|
|
#ifndef JERRY_NDEBUG
|
|
uint32_t biased_exp = ecma_number_get_biased_exponent_field (num);
|
|
uint64_t fraction = ecma_number_get_fraction_field (num);
|
|
|
|
/* IEEE-754 2008, 3.4, a */
|
|
bool is_nan_ieee754 = ((biased_exp == (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)
|
|
&& (fraction != 0));
|
|
|
|
JERRY_ASSERT (is_nan == is_nan_ieee754);
|
|
#endif /* !JERRY_NDEBUG */
|
|
|
|
return is_nan;
|
|
} /* ecma_number_is_nan */
|
|
|
|
/**
|
|
* Make a NaN.
|
|
*
|
|
* @return NaN value
|
|
*/
|
|
ecma_number_t
|
|
ecma_number_make_nan (void)
|
|
{
|
|
/* IEEE754 QNaN = sign bit: 0, exponent: all 1 bits, fraction: 1....0 */
|
|
ecma_number_accessor_t f;
|
|
#if ENABLED (JERRY_NUMBER_TYPE_FLOAT64)
|
|
f.as_uint64_t = 0x7ff8000000000000ull; /* double QNaN, same as the C99 nan("") returns. */
|
|
#else /* !ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
|
|
f.as_uint32_t = 0x7fc00000u; /* float QNaN, same as the C99 nanf("") returns. */
|
|
#endif /* ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
|
|
return f.as_ecma_number_t;
|
|
} /* ecma_number_make_nan */
|
|
|
|
/**
|
|
* Make an Infinity.
|
|
*
|
|
* @return if !sign - +Infinity value,
|
|
* else - -Infinity value.
|
|
*/
|
|
ecma_number_t
|
|
ecma_number_make_infinity (bool sign) /**< true - for negative Infinity,
|
|
false - for positive Infinity */
|
|
{
|
|
/* IEEE754 INF = sign bit: sign, exponent: all 1 bits, fraction: 0....0 */
|
|
ecma_number_accessor_t f;
|
|
#if ENABLED (JERRY_NUMBER_TYPE_FLOAT64)
|
|
f.as_uint64_t = sign ? 0xfff0000000000000ull : 0x7ff0000000000000ull;
|
|
#else /* !ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
|
|
f.as_uint32_t = sign ? 0xff800000u : 0x7f800000u;
|
|
#endif /* ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
|
|
return f.as_ecma_number_t;
|
|
} /* ecma_number_make_infinity */
|
|
|
|
/**
|
|
* Check if ecma-number is negative
|
|
*
|
|
* @return true - if sign bit of ecma-number is set
|
|
* false - otherwise
|
|
*/
|
|
inline bool JERRY_ATTR_ALWAYS_INLINE
|
|
ecma_number_is_negative (ecma_number_t num) /**< ecma-number */
|
|
{
|
|
JERRY_ASSERT (!ecma_number_is_nan (num));
|
|
|
|
/* IEEE-754 2008, 3.4 */
|
|
return (ecma_number_get_sign_field (num) != 0);
|
|
} /* ecma_number_is_negative */
|
|
|
|
/**
|
|
* Check if ecma-number is zero
|
|
*
|
|
* @return true - if fraction is zero and biased exponent is zero,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
ecma_number_is_zero (ecma_number_t num) /**< ecma-number */
|
|
{
|
|
bool is_zero = (num == ECMA_NUMBER_ZERO);
|
|
|
|
#ifndef JERRY_NDEBUG
|
|
/* IEEE-754 2008, 3.4, e */
|
|
bool is_zero_ieee754 = (ecma_number_get_fraction_field (num) == 0
|
|
&& ecma_number_get_biased_exponent_field (num) == 0);
|
|
|
|
JERRY_ASSERT (is_zero == is_zero_ieee754);
|
|
#endif /* !JERRY_NDEBUG */
|
|
|
|
return is_zero;
|
|
} /* ecma_number_is_zero */
|
|
|
|
/**
|
|
* Check if number is infinity
|
|
*
|
|
* @return true - if biased exponent is filled with 1 bits and
|
|
* fraction is filled with zero bits,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
ecma_number_is_infinity (ecma_number_t num) /**< ecma-number */
|
|
{
|
|
uint32_t biased_exp = ecma_number_get_biased_exponent_field (num);
|
|
uint64_t fraction = ecma_number_get_fraction_field (num);
|
|
|
|
/* IEEE-754 2008, 3.4, b */
|
|
return ((biased_exp == (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)
|
|
&& (fraction == 0));
|
|
} /* ecma_number_is_infinity */
|
|
|
|
/**
|
|
* Check if number is finite
|
|
*
|
|
* @return true - if number is finite
|
|
* false - if number is NaN or infinity
|
|
*/
|
|
extern inline bool JERRY_ATTR_ALWAYS_INLINE
|
|
ecma_number_is_finite (ecma_number_t num) /**< ecma-number */
|
|
{
|
|
#if defined (__GNUC__) || defined (__clang__)
|
|
return __builtin_isfinite (num);
|
|
#elif defined (WIN32)
|
|
return isfinite (num);
|
|
#else
|
|
return !ecma_number_is_nan (num) && !ecma_number_is_infinity (num);
|
|
#endif /* defined (__GNUC__) || defined (__clang__) */
|
|
} /* ecma_number_is_finite */
|
|
|
|
/**
|
|
* Get fraction and exponent of the number
|
|
*
|
|
* @return shift of dot in the fraction
|
|
*/
|
|
static int32_t
|
|
ecma_number_get_fraction_and_exponent (ecma_number_t num, /**< ecma-number */
|
|
uint64_t *out_fraction_p, /**< [out] fraction of the number */
|
|
int32_t *out_exponent_p) /**< [out] exponent of the number */
|
|
{
|
|
JERRY_ASSERT (!ecma_number_is_nan (num));
|
|
|
|
uint32_t biased_exp = ecma_number_get_biased_exponent_field (num);
|
|
uint64_t fraction = ecma_number_get_fraction_field (num);
|
|
int32_t exponent;
|
|
|
|
if (JERRY_UNLIKELY (biased_exp == 0))
|
|
{
|
|
/* IEEE-754 2008, 3.4, d */
|
|
if (ecma_number_is_zero (num))
|
|
{
|
|
exponent = -ecma_number_exponent_bias;
|
|
}
|
|
else
|
|
{
|
|
exponent = 1 - ecma_number_exponent_bias;
|
|
|
|
while (!(fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)))
|
|
{
|
|
JERRY_ASSERT (fraction != 0);
|
|
|
|
fraction <<= 1;
|
|
exponent--;
|
|
}
|
|
}
|
|
}
|
|
else if (ecma_number_is_infinity (num))
|
|
{
|
|
/* The fraction and exponent should round to infinity */
|
|
exponent = (int32_t) biased_exp - ecma_number_exponent_bias;
|
|
|
|
JERRY_ASSERT ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0);
|
|
fraction |= 1ull << ECMA_NUMBER_FRACTION_WIDTH;
|
|
}
|
|
else
|
|
{
|
|
/* IEEE-754 2008, 3.4, c */
|
|
exponent = (int32_t) biased_exp - ecma_number_exponent_bias;
|
|
|
|
JERRY_ASSERT (biased_exp > 0 && biased_exp < (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1);
|
|
JERRY_ASSERT ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0);
|
|
fraction |= 1ull << ECMA_NUMBER_FRACTION_WIDTH;
|
|
}
|
|
|
|
*out_fraction_p = fraction;
|
|
*out_exponent_p = exponent;
|
|
return ECMA_NUMBER_FRACTION_WIDTH;
|
|
} /* ecma_number_get_fraction_and_exponent */
|
|
|
|
/**
|
|
* Make normalised positive Number from given fraction and exponent
|
|
*
|
|
* @return ecma-number
|
|
*/
|
|
static ecma_number_t
|
|
ecma_number_make_normal_positive_from_fraction_and_exponent (uint64_t fraction, /**< fraction */
|
|
int32_t exponent) /**< exponent */
|
|
{
|
|
uint32_t biased_exp = (uint32_t) (exponent + ecma_number_exponent_bias);
|
|
JERRY_ASSERT (biased_exp > 0 && biased_exp < (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1);
|
|
JERRY_ASSERT ((fraction & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) == 0);
|
|
JERRY_ASSERT ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) != 0);
|
|
|
|
return ecma_number_pack (false,
|
|
biased_exp,
|
|
fraction & ~(1ull << ECMA_NUMBER_FRACTION_WIDTH));
|
|
} /* ecma_number_make_normal_positive_from_fraction_and_exponent */
|
|
|
|
/**
|
|
* Make Number of given sign from given mantissa value and binary exponent
|
|
*
|
|
* @return ecma-number (possibly Infinity of specified sign)
|
|
*/
|
|
ecma_number_t
|
|
ecma_number_make_from_sign_mantissa_and_exponent (bool sign, /**< true - for negative sign,
|
|
false - for positive sign */
|
|
uint64_t mantissa, /**< mantissa */
|
|
int32_t exponent) /**< binary exponent */
|
|
{
|
|
/* Rounding mantissa to fit into fraction field width */
|
|
if (mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1))
|
|
{
|
|
/* Rounded mantissa looks like the following: |00...0|1|fraction_width mantissa bits| */
|
|
while ((mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) != 0)
|
|
{
|
|
uint64_t rightmost_bit = (mantissa & 1);
|
|
|
|
exponent++;
|
|
mantissa >>= 1;
|
|
|
|
if ((mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) == 0)
|
|
{
|
|
/* Rounding to nearest value */
|
|
mantissa += rightmost_bit;
|
|
|
|
/* In the first case loop is finished,
|
|
and in the second - just one shift follows and then loop finishes */
|
|
JERRY_ASSERT (((mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) == 0)
|
|
|| (mantissa == (1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1))));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Normalizing mantissa */
|
|
while (mantissa != 0
|
|
&& ((mantissa & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0))
|
|
{
|
|
exponent--;
|
|
mantissa <<= 1;
|
|
}
|
|
|
|
/* Moving floating point */
|
|
exponent += ECMA_NUMBER_FRACTION_WIDTH - 1;
|
|
|
|
int32_t biased_exp_signed = exponent + ecma_number_exponent_bias;
|
|
|
|
if (biased_exp_signed < 1)
|
|
{
|
|
/* Denormalizing mantissa if biased_exponent is less than zero */
|
|
while (biased_exp_signed < 0)
|
|
{
|
|
biased_exp_signed++;
|
|
mantissa >>= 1;
|
|
}
|
|
|
|
/* Rounding to nearest value */
|
|
mantissa += 1;
|
|
mantissa >>= 1;
|
|
|
|
/* Encoding denormalized exponent */
|
|
biased_exp_signed = 0;
|
|
}
|
|
else
|
|
{
|
|
/* Clearing highest mantissa bit that should have been non-zero if mantissa is non-zero */
|
|
mantissa &= ~(1ull << ECMA_NUMBER_FRACTION_WIDTH);
|
|
}
|
|
|
|
uint32_t biased_exp = (uint32_t) biased_exp_signed;
|
|
|
|
if (biased_exp >= ((1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1))
|
|
{
|
|
return ecma_number_make_infinity (sign);
|
|
}
|
|
|
|
JERRY_ASSERT (biased_exp < (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1);
|
|
JERRY_ASSERT ((mantissa & ~((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1)) == 0);
|
|
|
|
return ecma_number_pack (sign,
|
|
biased_exp,
|
|
mantissa);
|
|
} /* ecma_number_make_from_sign_mantissa_and_exponent */
|
|
|
|
/**
|
|
* Get previous representable ecma-number
|
|
*
|
|
* @return maximum ecma-number that is less compared to passed argument
|
|
*/
|
|
ecma_number_t
|
|
ecma_number_get_prev (ecma_number_t num) /**< ecma-number */
|
|
{
|
|
JERRY_ASSERT (!ecma_number_is_nan (num));
|
|
JERRY_ASSERT (!ecma_number_is_zero (num));
|
|
|
|
if (ecma_number_is_negative (num))
|
|
{
|
|
return -ecma_number_get_next (num);
|
|
}
|
|
|
|
uint32_t biased_exp = ecma_number_get_biased_exponent_field (num);
|
|
uint64_t fraction = ecma_number_get_fraction_field (num);
|
|
|
|
if (fraction == 0 && biased_exp != 0)
|
|
{
|
|
fraction = (1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1;
|
|
|
|
biased_exp--;
|
|
}
|
|
else
|
|
{
|
|
fraction--;
|
|
}
|
|
|
|
return ecma_number_pack (false,
|
|
biased_exp,
|
|
fraction);
|
|
} /* ecma_number_get_prev */
|
|
|
|
/**
|
|
* Get next representable ecma-number
|
|
*
|
|
* @return minimum ecma-number that is greater compared to passed argument
|
|
*/
|
|
ecma_number_t
|
|
ecma_number_get_next (ecma_number_t num) /**< ecma-number */
|
|
{
|
|
JERRY_ASSERT (!ecma_number_is_nan (num));
|
|
JERRY_ASSERT (!ecma_number_is_infinity (num));
|
|
|
|
if (ecma_number_is_negative (num))
|
|
{
|
|
return -ecma_number_get_prev (num);
|
|
}
|
|
|
|
uint32_t biased_exp = ecma_number_get_biased_exponent_field (num);
|
|
uint64_t fraction = ecma_number_get_fraction_field (num);
|
|
|
|
fraction |= (1ull << ECMA_NUMBER_FRACTION_WIDTH);
|
|
|
|
fraction++;
|
|
|
|
if ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0)
|
|
{
|
|
fraction >>= 1;
|
|
|
|
biased_exp++;
|
|
}
|
|
|
|
JERRY_ASSERT (fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH));
|
|
|
|
fraction &= ~(1ull << ECMA_NUMBER_FRACTION_WIDTH);
|
|
|
|
return ecma_number_pack (false,
|
|
biased_exp,
|
|
fraction);
|
|
} /* ecma_number_get_next */
|
|
|
|
/**
|
|
* Truncate fractional part of the number
|
|
*
|
|
* @return integer part of the number
|
|
*/
|
|
ecma_number_t
|
|
ecma_number_trunc (ecma_number_t num) /**< ecma-number */
|
|
{
|
|
JERRY_ASSERT (!ecma_number_is_nan (num));
|
|
|
|
uint64_t fraction;
|
|
int32_t exponent;
|
|
const int32_t dot_shift = ecma_number_get_fraction_and_exponent (num, &fraction, &exponent);
|
|
const bool sign = ecma_number_is_negative (num);
|
|
|
|
if (exponent < 0)
|
|
{
|
|
return ECMA_NUMBER_ZERO;
|
|
}
|
|
else if (exponent < dot_shift)
|
|
{
|
|
fraction &= ~((1ull << (dot_shift - exponent)) - 1);
|
|
|
|
ecma_number_t tmp = ecma_number_make_normal_positive_from_fraction_and_exponent (fraction,
|
|
exponent);
|
|
if (sign)
|
|
{
|
|
return -tmp;
|
|
}
|
|
else
|
|
{
|
|
return tmp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return num;
|
|
}
|
|
} /* ecma_number_trunc */
|
|
|
|
/**
|
|
* Calculate remainder of division of two numbers,
|
|
* as specified in ECMA-262 v5, 11.5.3, item 6.
|
|
*
|
|
* Note:
|
|
* operands shouldn't contain NaN, Infinity, or zero.
|
|
*
|
|
* @return number - calculated remainder.
|
|
*/
|
|
ecma_number_t
|
|
ecma_number_calc_remainder (ecma_number_t left_num, /**< left operand */
|
|
ecma_number_t right_num) /**< right operand */
|
|
{
|
|
JERRY_ASSERT (!ecma_number_is_nan (left_num)
|
|
&& !ecma_number_is_zero (left_num)
|
|
&& !ecma_number_is_infinity (left_num));
|
|
JERRY_ASSERT (!ecma_number_is_nan (right_num)
|
|
&& !ecma_number_is_zero (right_num)
|
|
&& !ecma_number_is_infinity (right_num));
|
|
|
|
const ecma_number_t q = ecma_number_trunc (left_num / right_num);
|
|
ecma_number_t r = left_num - right_num * q;
|
|
|
|
if (ecma_number_is_zero (r)
|
|
&& ecma_number_is_negative (left_num))
|
|
{
|
|
r = -r;
|
|
}
|
|
|
|
return r;
|
|
} /* ecma_number_calc_remainder */
|
|
|
|
/**
|
|
* ECMA-integer number multiplication.
|
|
*
|
|
* @return number - result of multiplication.
|
|
*/
|
|
inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
|
|
ecma_integer_multiply (ecma_integer_value_t left_integer, /**< left operand */
|
|
ecma_integer_value_t right_integer) /**< right operand */
|
|
{
|
|
#if defined (__GNUC__) || defined (__clang__)
|
|
/* Check if left_integer is power of 2 */
|
|
if (JERRY_UNLIKELY ((left_integer & (left_integer - 1)) == 0))
|
|
{
|
|
/* Right shift right_integer with log2 (left_integer) */
|
|
return ecma_make_integer_value (right_integer << (__builtin_ctz ((unsigned int) left_integer)));
|
|
}
|
|
else if (JERRY_UNLIKELY ((right_integer & (right_integer - 1)) == 0))
|
|
{
|
|
/* Right shift left_integer with log2 (right_integer) */
|
|
return ecma_make_integer_value (left_integer << (__builtin_ctz ((unsigned int) right_integer)));
|
|
}
|
|
#endif /* defined (__GNUC__) || defined (__clang__) */
|
|
return ecma_make_integer_value (left_integer * right_integer);
|
|
} /* ecma_integer_multiply */
|
|
|
|
/**
|
|
* The Number object's 'parseInt' routine
|
|
*
|
|
* See also:
|
|
* ECMA-262 v5, 15.1.2.2
|
|
*
|
|
* @return ecma value
|
|
* Returned value must be freed with ecma_free_value.
|
|
*/
|
|
ecma_value_t
|
|
ecma_number_parse_int (const lit_utf8_byte_t *string_buff, /**< routine's first argument's
|
|
* string buffer */
|
|
lit_utf8_size_t string_buff_size, /**< routine's first argument's
|
|
* string buffer's size */
|
|
ecma_value_t radix) /**< routine's second argument */
|
|
{
|
|
if (string_buff_size == 0)
|
|
{
|
|
return ecma_make_nan_value ();
|
|
}
|
|
|
|
const lit_utf8_byte_t *string_curr_p = string_buff;
|
|
|
|
/* 2. Remove leading whitespace. */
|
|
ecma_string_trim_helper (&string_curr_p, &string_buff_size);
|
|
|
|
const lit_utf8_byte_t *string_end_p = string_curr_p + string_buff_size;
|
|
const lit_utf8_byte_t *start_p = string_curr_p;
|
|
const lit_utf8_byte_t *end_p = string_end_p;
|
|
|
|
if (string_curr_p >= string_end_p)
|
|
{
|
|
return ecma_make_nan_value ();
|
|
}
|
|
|
|
/* 3. */
|
|
int sign = 1;
|
|
|
|
/* 4. */
|
|
ecma_char_t current = lit_cesu8_read_next (&string_curr_p);
|
|
if (current == LIT_CHAR_MINUS)
|
|
{
|
|
sign = -1;
|
|
}
|
|
|
|
/* 5. */
|
|
if (current == LIT_CHAR_MINUS || current == LIT_CHAR_PLUS)
|
|
{
|
|
start_p = string_curr_p;
|
|
if (string_curr_p < string_end_p)
|
|
{
|
|
current = lit_cesu8_read_next (&string_curr_p);
|
|
}
|
|
}
|
|
|
|
/* 6. */
|
|
ecma_number_t radix_num;
|
|
radix = ecma_get_number (radix, &radix_num);
|
|
|
|
if (!ecma_is_value_empty (radix))
|
|
{
|
|
return radix;
|
|
}
|
|
|
|
int32_t rad = ecma_number_to_int32 (radix_num);
|
|
|
|
/* 7.*/
|
|
bool strip_prefix = true;
|
|
|
|
/* 8. */
|
|
if (rad != 0)
|
|
{
|
|
/* 8.a */
|
|
if (rad < 2 || rad > 36)
|
|
{
|
|
return ecma_make_nan_value ();
|
|
}
|
|
/* 8.b */
|
|
else if (rad != 16)
|
|
{
|
|
strip_prefix = false;
|
|
}
|
|
}
|
|
/* 9. */
|
|
else
|
|
{
|
|
rad = 10;
|
|
}
|
|
|
|
/* 10. */
|
|
if (strip_prefix
|
|
&& ((end_p - start_p) >= 2)
|
|
&& (current == LIT_CHAR_0))
|
|
{
|
|
ecma_char_t next = *string_curr_p;
|
|
if (next == LIT_CHAR_LOWERCASE_X || next == LIT_CHAR_UPPERCASE_X)
|
|
{
|
|
/* Skip the 'x' or 'X' characters. */
|
|
start_p = ++string_curr_p;
|
|
rad = 16;
|
|
}
|
|
}
|
|
|
|
/* 11. Check if characters are in [0, Radix - 1]. We also convert them to number values in the process. */
|
|
string_curr_p = start_p;
|
|
while (string_curr_p < string_end_p)
|
|
{
|
|
ecma_char_t current_char = *string_curr_p++;
|
|
int32_t current_number;
|
|
|
|
if ((current_char >= LIT_CHAR_LOWERCASE_A && current_char <= LIT_CHAR_LOWERCASE_Z))
|
|
{
|
|
current_number = current_char - LIT_CHAR_LOWERCASE_A + 10;
|
|
}
|
|
else if ((current_char >= LIT_CHAR_UPPERCASE_A && current_char <= LIT_CHAR_UPPERCASE_Z))
|
|
{
|
|
current_number = current_char - LIT_CHAR_UPPERCASE_A + 10;
|
|
}
|
|
else if (lit_char_is_decimal_digit (current_char))
|
|
{
|
|
current_number = current_char - LIT_CHAR_0;
|
|
}
|
|
else
|
|
{
|
|
/* Not a valid number char, set value to radix so it fails to pass as a valid character. */
|
|
current_number = rad;
|
|
}
|
|
|
|
if (!(current_number < rad))
|
|
{
|
|
end_p = --string_curr_p;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* 12. */
|
|
if (end_p == start_p)
|
|
{
|
|
return ecma_make_nan_value ();
|
|
}
|
|
|
|
ecma_number_t value = ECMA_NUMBER_ZERO;
|
|
ecma_number_t multiplier = 1.0f;
|
|
|
|
/* 13. and 14. */
|
|
string_curr_p = end_p;
|
|
|
|
while (string_curr_p > start_p)
|
|
{
|
|
ecma_char_t current_char = *(--string_curr_p);
|
|
ecma_number_t current_number = ECMA_NUMBER_MINUS_ONE;
|
|
|
|
if ((current_char >= LIT_CHAR_LOWERCASE_A && current_char <= LIT_CHAR_LOWERCASE_Z))
|
|
{
|
|
current_number = (ecma_number_t) current_char - LIT_CHAR_LOWERCASE_A + 10;
|
|
}
|
|
else if ((current_char >= LIT_CHAR_UPPERCASE_A && current_char <= LIT_CHAR_UPPERCASE_Z))
|
|
{
|
|
current_number = (ecma_number_t) current_char - LIT_CHAR_UPPERCASE_A + 10;
|
|
}
|
|
else
|
|
{
|
|
JERRY_ASSERT (lit_char_is_decimal_digit (current_char));
|
|
current_number = (ecma_number_t) current_char - LIT_CHAR_0;
|
|
}
|
|
|
|
value += current_number * multiplier;
|
|
multiplier *= (ecma_number_t) rad;
|
|
}
|
|
|
|
/* 15. */
|
|
if (sign < 0)
|
|
{
|
|
value *= (ecma_number_t) sign;
|
|
}
|
|
return ecma_make_number_value (value);
|
|
} /* ecma_number_parse_int */
|
|
|
|
/**
|
|
* The Number object's 'parseFloat' routine
|
|
*
|
|
* See also:
|
|
* ECMA-262 v5, 15.1.2.2
|
|
*
|
|
* @return ecma value
|
|
* Returned value must be freed with ecma_free_value.
|
|
*/
|
|
ecma_value_t
|
|
ecma_number_parse_float (const lit_utf8_byte_t *string_buff, /**< routine's first argument's
|
|
* string buffer */
|
|
lit_utf8_size_t string_buff_size) /**< routine's first argument's
|
|
* string buffer's size */
|
|
{
|
|
if (string_buff_size == 0)
|
|
{
|
|
return ecma_make_nan_value ();
|
|
}
|
|
|
|
const lit_utf8_byte_t *str_curr_p = string_buff;
|
|
|
|
/* 2. Remove leading whitespace. */
|
|
ecma_string_trim_helper (&str_curr_p, &string_buff_size);
|
|
|
|
const lit_utf8_byte_t *str_end_p = str_curr_p + string_buff_size;
|
|
const lit_utf8_byte_t *start_p = str_curr_p;
|
|
const lit_utf8_byte_t *end_p = str_end_p;
|
|
|
|
bool sign = false;
|
|
ecma_char_t current;
|
|
|
|
if (str_curr_p < str_end_p)
|
|
{
|
|
/* Check if sign is present. */
|
|
current = *str_curr_p;
|
|
if (current == LIT_CHAR_MINUS)
|
|
{
|
|
sign = true;
|
|
}
|
|
|
|
if (current == LIT_CHAR_MINUS || current == LIT_CHAR_PLUS)
|
|
{
|
|
/* Set starting position to be after the sign character. */
|
|
start_p = ++str_curr_p;
|
|
}
|
|
}
|
|
|
|
const lit_utf8_byte_t *infinity_str_p = lit_get_magic_string_utf8 (LIT_MAGIC_STRING_INFINITY_UL);
|
|
lit_utf8_byte_t *infinity_str_curr_p = (lit_utf8_byte_t *) infinity_str_p;
|
|
lit_utf8_byte_t *infinity_str_end_p = infinity_str_curr_p + sizeof (*infinity_str_p);
|
|
|
|
/* Check if string is equal to "Infinity". */
|
|
while (str_curr_p < str_end_p
|
|
&& *str_curr_p++ == *infinity_str_curr_p++)
|
|
{
|
|
if (infinity_str_curr_p == infinity_str_end_p)
|
|
{
|
|
/* String matched Infinity. */
|
|
return ecma_make_number_value (ecma_number_make_infinity (sign));
|
|
}
|
|
}
|
|
|
|
/* Reset to starting position. */
|
|
str_curr_p = start_p;
|
|
|
|
/* String ended after sign character, or was empty after removing leading whitespace. */
|
|
if (str_curr_p >= str_end_p)
|
|
{
|
|
return ecma_make_nan_value ();
|
|
}
|
|
|
|
/* Reset to starting position. */
|
|
str_curr_p = start_p;
|
|
|
|
current = *str_curr_p;
|
|
|
|
bool has_whole_part = false;
|
|
bool has_fraction_part = false;
|
|
|
|
/* Check digits of whole part. */
|
|
if (lit_char_is_decimal_digit (current))
|
|
{
|
|
has_whole_part = true;
|
|
str_curr_p++;
|
|
|
|
while (str_curr_p < str_end_p)
|
|
{
|
|
current = *str_curr_p++;
|
|
if (!lit_char_is_decimal_digit (current))
|
|
{
|
|
str_curr_p--;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Set end position to the end of whole part. */
|
|
end_p = str_curr_p;
|
|
if (str_curr_p < str_end_p)
|
|
{
|
|
current = *str_curr_p;
|
|
|
|
/* Check decimal point. */
|
|
if (current == LIT_CHAR_DOT)
|
|
{
|
|
str_curr_p++;
|
|
|
|
if (str_curr_p < str_end_p)
|
|
{
|
|
current = *str_curr_p;
|
|
|
|
if (lit_char_is_decimal_digit (current))
|
|
{
|
|
has_fraction_part = true;
|
|
|
|
/* Check digits of fractional part. */
|
|
while (str_curr_p < str_end_p)
|
|
{
|
|
current = *str_curr_p++;
|
|
if (!lit_char_is_decimal_digit (current))
|
|
{
|
|
str_curr_p--;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Set end position to end of fraction part. */
|
|
end_p = str_curr_p;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (str_curr_p < str_end_p)
|
|
{
|
|
current = *str_curr_p++;
|
|
}
|
|
|
|
/* Check exponent. */
|
|
if ((current == LIT_CHAR_LOWERCASE_E || current == LIT_CHAR_UPPERCASE_E)
|
|
&& (has_whole_part || has_fraction_part)
|
|
&& str_curr_p < str_end_p)
|
|
{
|
|
current = *str_curr_p++;
|
|
|
|
/* Check sign of exponent. */
|
|
if ((current == LIT_CHAR_PLUS || current == LIT_CHAR_MINUS)
|
|
&& str_curr_p < str_end_p)
|
|
{
|
|
current = *str_curr_p++;
|
|
}
|
|
|
|
if (lit_char_is_decimal_digit (current))
|
|
{
|
|
/* Check digits of exponent part. */
|
|
while (str_curr_p < str_end_p)
|
|
{
|
|
current = *str_curr_p++;
|
|
if (!lit_char_is_decimal_digit (current))
|
|
{
|
|
str_curr_p--;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Set end position to end of exponent part. */
|
|
end_p = str_curr_p;
|
|
}
|
|
}
|
|
|
|
/* String did not contain a valid number. */
|
|
if (start_p == end_p)
|
|
{
|
|
return ecma_make_nan_value ();
|
|
}
|
|
|
|
/* 5. */
|
|
ecma_number_t ret_num = ecma_utf8_string_to_number (start_p, (lit_utf8_size_t) (end_p - start_p));
|
|
|
|
if (sign)
|
|
{
|
|
ret_num *= ECMA_NUMBER_MINUS_ONE;
|
|
}
|
|
|
|
return ecma_make_number_value (ret_num);
|
|
} /* ecma_number_parse_float */
|
|
|
|
/**
|
|
* @}
|
|
* @}
|
|
*/
|