Implement missing Math functions from ES6 standard (#3593)

First step to fix issue #3568.

Changes:
- Implemented Math.clz32(), Math.fround(), Math.imul(), Math.hypot().
- Implemented all remaining Math functions with calling the standard
libm functions, but they throw UNIMPLEMENTED exception with jerry-libm,
because the necessary fdlibm functions are missing and should be ported.

All Math related test262 tests pass (except function name and length tests)

JerryScript-DCO-1.0-Signed-off-by: Csaba Osztrogonác oszi@inf.u-szeged.hu
This commit is contained in:
Csaba Osztrogonác
2020-03-10 11:15:00 +01:00
committed by GitHub
parent 6c3a42ec48
commit 72f8ef344c
5 changed files with 333 additions and 11 deletions
@@ -29,6 +29,10 @@
#include "jrt.h"
#include "jrt-libc-includes.h"
#if defined (WIN32)
#include <intrin.h>
#endif
#if ENABLED (JERRY_BUILTIN_MATH)
#define ECMA_BUILTINS_INTERNAL
@@ -55,21 +59,37 @@ enum
ECMA_MATH_OBJECT_EXP, /* ECMA-262 v5, 15.8.2.8 */
ECMA_MATH_OBJECT_FLOOR, /* ECMA-262 v5, 15.8.2.9 */
ECMA_MATH_OBJECT_LOG, /* ECMA-262 v5, 15.8.2.10 */
#if ENABLED (JERRY_ES2015)
ECMA_MATH_OBJECT_TRUNC, /* ECMA-262 v6, 20.2.2.35 */
ECMA_MATH_OBJECT_SIGN, /* ECMA-262 v6, 20.2.2.29 */
#endif /* ENABLED (JERRY_ES2015) */
ECMA_MATH_OBJECT_ROUND, /* ECMA-262 v5, 15.8.2.15 */
ECMA_MATH_OBJECT_SIN, /* ECMA-262 v5, 15.8.2.16 */
ECMA_MATH_OBJECT_SQRT, /* ECMA-262 v5, 15.8.2.17 */
ECMA_MATH_OBJECT_TAN, /* ECMA-262 v5, 15.8.2.18 */
ECMA_MATH_OBJECT_ATAN2, /* ECMA-262 v5, 15.8.2.5 */
ECMA_MATH_OBJECT_POW, /* ECMA-262 v5, 15.8.2.13 */
#if ENABLED (JERRY_ES2015)
ECMA_MATH_OBJECT_ACOSH, /* ECMA-262 v6, 20.2.2.3 */
ECMA_MATH_OBJECT_ASINH, /* ECMA-262 v6, 20.2.2.5 */
ECMA_MATH_OBJECT_ATANH, /* ECMA-262 v6, 20.2.2.7 */
ECMA_MATH_OBJECT_CBRT, /* ECMA-262 v6, 20.2.2.9 */
ECMA_MATH_OBJECT_CLZ32, /* ECMA-262 v6, 20.2.2.11 */
ECMA_MATH_OBJECT_COSH, /* ECMA-262 v6, 20.2.2.13 */
ECMA_MATH_OBJECT_EXPM1, /* ECMA-262 v6, 20.2.2.15 */
ECMA_MATH_OBJECT_FROUND, /* ECMA-262 v6, 20.2.2.17 */
ECMA_MATH_OBJECT_LOG1P, /* ECMA-262 v6, 20.2.2.21 */
ECMA_MATH_OBJECT_LOG10, /* ECMA-262 v6, 20.2.2.22 */
ECMA_MATH_OBJECT_LOG2, /* ECMA-262 v6, 20.2.2.23 */
ECMA_MATH_OBJECT_SIGN, /* ECMA-262 v6, 20.2.2.29 */
ECMA_MATH_OBJECT_SINH, /* ECMA-262 v6, 20.2.2.31 */
ECMA_MATH_OBJECT_TANH, /* ECMA-262 v6, 20.2.2.34 */
ECMA_MATH_OBJECT_TRUNC, /* ECMA-262 v6, 20.2.2.35 */
#endif /* ENABLED (JERRY_ES2015) */
ECMA_MATH_OBJECT_ATAN2, /* ECMA-262 v5, 15.8.2.5 */ /* first routine with 2 arguments */
#if ENABLED (JERRY_ES2015)
ECMA_MATH_OBJECT_IMUL, /* ECMA-262 v6, 20.2.2.19 */
#endif /* ENABLED (JERRY_ES2015) */
ECMA_MATH_OBJECT_POW, /* ECMA-262 v5, 15.8.2.13 */ /* last routine with 1 or 2 arguments*/
ECMA_MATH_OBJECT_MAX, /* ECMA-262 v5, 15.8.2.11 */
ECMA_MATH_OBJECT_MIN, /* ECMA-262 v5, 15.8.2.12 */
#if ENABLED (JERRY_ES2015)
ECMA_MATH_OBJECT_HYPOT, /* ECMA-262 v6, 20.2.2.18 */
#endif /* ENABLED (JERRY_ES2015) */
ECMA_MATH_OBJECT_RANDOM, /* ECMA-262 v5, 15.8.2.14 */
};
@@ -164,6 +184,76 @@ ecma_builtin_math_object_max_min (bool is_max, /**< 'max' or 'min' operation */
} /* ecma_builtin_math_object_max_min */
#if ENABLED (JERRY_ES2015)
/**
* The Math object's 'hypot' routine
*
* See also:
* ECMA-262 v6, 20.2.2.18
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_builtin_math_object_hypot (const ecma_value_t *arg, /**< arguments list */
ecma_length_t args_number) /**< number of arguments */
{
if (args_number == 0)
{
return ecma_make_number_value (0.0);
}
bool nan_found = false;
bool inf_found = false;
ecma_number_t result_num = 0;
while (args_number > 0)
{
ecma_number_t arg_num;
if (ecma_is_value_number (*arg))
{
arg_num = ecma_get_number_from_value (*arg);
}
else
{
ecma_value_t value = ecma_op_to_number (*arg);
if (ECMA_IS_VALUE_ERROR (value))
{
return value;
}
arg_num = ecma_get_number_from_value (value);
ecma_fast_free_value (value);
}
arg++;
args_number--;
if (JERRY_UNLIKELY (inf_found || ecma_number_is_infinity (arg_num)))
{
inf_found = true;
continue;
}
if (JERRY_UNLIKELY (nan_found || ecma_number_is_nan (arg_num)))
{
nan_found = true;
continue;
}
result_num += arg_num * arg_num;
}
if (JERRY_UNLIKELY (inf_found))
{
return ecma_make_number_value (ecma_number_make_infinity (false));
}
if (JERRY_UNLIKELY (nan_found))
{
return ecma_make_nan_value ();
}
return ecma_make_number_value (sqrt (result_num));
} /* ecma_builtin_math_object_hypot */
/**
* The Math object's 'trunc' routine
@@ -432,10 +522,141 @@ ecma_builtin_math_dispatch_routine (uint16_t builtin_routine_id, /**< built-in w
}
break;
}
#if ENABLED (JERRY_ES2015)
case ECMA_MATH_OBJECT_ACOSH:
{
#ifdef JERRY_LIBM_MATH_H
return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Math.acosh"));
#else /* !JERRY_LIBM_MATH_H */
x = DOUBLE_TO_ECMA_NUMBER_T (acosh (x));
#endif /* JERRY_LIBM_MATH_H */
break;
}
case ECMA_MATH_OBJECT_ASINH:
{
#ifdef JERRY_LIBM_MATH_H
return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Math.asinh"));
#else /* !JERRY_LIBM_MATH_H */
x = DOUBLE_TO_ECMA_NUMBER_T (asinh (x));
#endif /* JERRY_LIBM_MATH_H */
break;
}
case ECMA_MATH_OBJECT_ATANH:
{
#ifdef JERRY_LIBM_MATH_H
return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Math.atanh"));
#else /* !JERRY_LIBM_MATH_H */
x = DOUBLE_TO_ECMA_NUMBER_T (atanh (x));
#endif /* JERRY_LIBM_MATH_H */
break;
}
case ECMA_MATH_OBJECT_CBRT:
{
#ifdef JERRY_LIBM_MATH_H
return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Math.cbrt"));
#else /* !JERRY_LIBM_MATH_H */
x = DOUBLE_TO_ECMA_NUMBER_T (cbrt (x));
#endif /* JERRY_LIBM_MATH_H */
break;
}
case ECMA_MATH_OBJECT_COSH:
{
#ifdef JERRY_LIBM_MATH_H
return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Math.cosh"));
#else /* !JERRY_LIBM_MATH_H */
x = DOUBLE_TO_ECMA_NUMBER_T (cosh (x));
#endif /* JERRY_LIBM_MATH_H */
break;
}
case ECMA_MATH_OBJECT_EXPM1:
{
#ifdef JERRY_LIBM_MATH_H
return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Math.expm1"));
#else /* !JERRY_LIBM_MATH_H */
x = DOUBLE_TO_ECMA_NUMBER_T (expm1 (x));
#endif /* JERRY_LIBM_MATH_H */
break;
}
case ECMA_MATH_OBJECT_LOG1P:
{
#ifdef JERRY_LIBM_MATH_H
return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Math.log1p"));
#else /* !JERRY_LIBM_MATH_H */
x = DOUBLE_TO_ECMA_NUMBER_T (log1p (x));
#endif /* JERRY_LIBM_MATH_H */
break;
}
case ECMA_MATH_OBJECT_LOG10:
{
#ifdef JERRY_LIBM_MATH_H
return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Math.log10"));
#else /* !JERRY_LIBM_MATH_H */
x = DOUBLE_TO_ECMA_NUMBER_T (log10 (x));
#endif /* JERRY_LIBM_MATH_H */
break;
}
case ECMA_MATH_OBJECT_LOG2:
{
#ifdef JERRY_LIBM_MATH_H
return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Math.log2"));
#else /* !JERRY_LIBM_MATH_H */
x = DOUBLE_TO_ECMA_NUMBER_T (log2 (x));
#endif /* JERRY_LIBM_MATH_H */
break;
}
case ECMA_MATH_OBJECT_SINH:
{
#ifdef JERRY_LIBM_MATH_H
return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Math.sinh"));
#else /* !JERRY_LIBM_MATH_H */
x = DOUBLE_TO_ECMA_NUMBER_T (sinh (x));
#endif /* JERRY_LIBM_MATH_H */
break;
}
case ECMA_MATH_OBJECT_TANH:
{
#ifdef JERRY_LIBM_MATH_H
return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Math.tanh"));
#else /* !JERRY_LIBM_MATH_H */
x = DOUBLE_TO_ECMA_NUMBER_T (tanh (x));
#endif /* JERRY_LIBM_MATH_H */
break;
}
case ECMA_MATH_OBJECT_CLZ32:
{
uint32_t n = ecma_number_to_uint32 (x);
#if defined (__GNUC__) || defined (__clang__)
x = n ? __builtin_clz (n) : 32;
#elif defined (WIN32)
unsigned long ret;
x = _BitScanReverse (&ret, n) ? 31 - ret : 32;
#else
x = 32;
for (int i = 31; i >= 0; i--)
{
if (n >> i)
{
x = 31 - i;
break;
}
}
#endif
break;
}
case ECMA_MATH_OBJECT_FROUND:
{
x = (float) x;
break;
}
case ECMA_MATH_OBJECT_IMUL:
{
x = (int32_t) (ecma_number_to_uint32 (x) * ecma_number_to_uint32 (y));
break;
}
#endif /* ENABLED (JERRY_ES2015) */
}
return ecma_make_number_value (x);
}
} /* if (builtin_routine_id <= ECMA_MATH_OBJECT_POW) */
if (builtin_routine_id <= ECMA_MATH_OBJECT_MIN)
{
@@ -444,6 +665,13 @@ ecma_builtin_math_dispatch_routine (uint16_t builtin_routine_id, /**< built-in w
arguments_number);
}
#if ENABLED (JERRY_ES2015)
if (builtin_routine_id == ECMA_MATH_OBJECT_HYPOT)
{
return ecma_builtin_math_object_hypot (arguments_list, arguments_number);
}
#endif /* ENABLED (JERRY_ES2015) */
JERRY_ASSERT (builtin_routine_id == ECMA_MATH_OBJECT_RANDOM);
return ecma_builtin_math_object_random ();
@@ -92,7 +92,22 @@ ROUTINE (LIT_MAGIC_STRING_SIN, ECMA_MATH_OBJECT_SIN, 1, 1)
ROUTINE (LIT_MAGIC_STRING_SQRT, ECMA_MATH_OBJECT_SQRT, 1, 1)
ROUTINE (LIT_MAGIC_STRING_TAN, ECMA_MATH_OBJECT_TAN, 1, 1)
#if ENABLED (JERRY_ES2015)
ROUTINE (LIT_MAGIC_STRING_ACOSH, ECMA_MATH_OBJECT_ACOSH, 1, 1)
ROUTINE (LIT_MAGIC_STRING_ASINH, ECMA_MATH_OBJECT_ASINH, 1, 1)
ROUTINE (LIT_MAGIC_STRING_ATANH, ECMA_MATH_OBJECT_ATANH, 1, 1)
ROUTINE (LIT_MAGIC_STRING_CBRT, ECMA_MATH_OBJECT_CBRT, 1, 1)
ROUTINE (LIT_MAGIC_STRING_CLZ32, ECMA_MATH_OBJECT_CLZ32, 1, 1)
ROUTINE (LIT_MAGIC_STRING_COSH, ECMA_MATH_OBJECT_COSH, 1, 1)
ROUTINE (LIT_MAGIC_STRING_EXPM1, ECMA_MATH_OBJECT_EXPM1, 1, 1)
ROUTINE (LIT_MAGIC_STRING_FROUND, ECMA_MATH_OBJECT_FROUND, 1, 1)
ROUTINE (LIT_MAGIC_STRING_HYPOT, ECMA_MATH_OBJECT_HYPOT, NON_FIXED, 2)
ROUTINE (LIT_MAGIC_STRING_IMUL, ECMA_MATH_OBJECT_IMUL, 2, 2)
ROUTINE (LIT_MAGIC_STRING_LOG1P, ECMA_MATH_OBJECT_LOG1P, 1, 1)
ROUTINE (LIT_MAGIC_STRING_LOG10, ECMA_MATH_OBJECT_LOG10, 1, 1)
ROUTINE (LIT_MAGIC_STRING_LOG2, ECMA_MATH_OBJECT_LOG2, 1, 1)
ROUTINE (LIT_MAGIC_STRING_SIGN, ECMA_MATH_OBJECT_SIGN, 1, 1)
ROUTINE (LIT_MAGIC_STRING_SINH, ECMA_MATH_OBJECT_SINH, 1, 1)
ROUTINE (LIT_MAGIC_STRING_TANH, ECMA_MATH_OBJECT_TANH, 1, 1)
ROUTINE (LIT_MAGIC_STRING_TRUNC, ECMA_MATH_OBJECT_TRUNC, 1, 1)
#endif /* ENABLED (JERRY_ES2015) */