#include #include "ant.h" #include "errors.h" #include "internal.h" #include "runtime.h" #include "modules/symbol.h" #include "modules/crypto.h" #if DBL_MANT_DIG >= 64 #error "Unsupported double mantissa width for Math.random" #endif enum { MATH_RANDOM_MANTISSA_BITS = DBL_MANT_DIG, MATH_RANDOM_DISCARD_BITS = 64 - DBL_MANT_DIG, }; static const double math_random_scale = 1.0 / (double)(UINT64_C(1) << MATH_RANDOM_MANTISSA_BITS); static ant_value_t builtin_Math_abs(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(fabs(x)); } static ant_value_t builtin_Math_acos(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(acos(x)); } static ant_value_t builtin_Math_acosh(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(acosh(x)); } static ant_value_t builtin_Math_asin(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(asin(x)); } static ant_value_t builtin_Math_asinh(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(asinh(x)); } static ant_value_t builtin_Math_atan(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(atan(x)); } static ant_value_t builtin_Math_atanh(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(atanh(x)); } static ant_value_t builtin_Math_atan2(ant_params_t) { double y = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); double x = (nargs < 2) ? JS_NAN : js_to_number(js, args[1]); if (isnan(y) || isnan(x)) return tov(JS_NAN); return tov(atan2(y, x)); } static ant_value_t builtin_Math_cbrt(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(cbrt(x)); } static ant_value_t builtin_Math_ceil(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(ceil(x)); } static ant_value_t builtin_Math_clz32(ant_params_t) { if (nargs < 1) return tov(32); uint32_t n = js_to_uint32(js_to_number(js, args[0])); if (n == 0) return tov(32); int lz = __builtin_clz(n); if (sizeof(unsigned int) > sizeof(uint32_t)) { lz -= (int)((sizeof(unsigned int) - sizeof(uint32_t)) * 8); } return tov((double)lz); } static ant_value_t builtin_Math_cos(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(cos(x)); } static ant_value_t builtin_Math_cosh(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(cosh(x)); } static ant_value_t builtin_Math_exp(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(exp(x)); } static ant_value_t builtin_Math_expm1(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(expm1(x)); } static ant_value_t builtin_Math_floor(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(floor(x)); } static ant_value_t builtin_Math_fround(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov((double)(float)x); } static ant_value_t builtin_Math_hypot(ant_params_t) { if (nargs == 0) return tov(0.0); double acc = 0.0; bool saw_nan = false; for (int i = 0; i < nargs; i++) { double v = js_to_number(js, args[i]); if (isinf(v)) return tov(JS_INF); if (isnan(v)) { saw_nan = true; continue; } acc = hypot(acc, v); } if (saw_nan) return tov(JS_NAN); return tov(acc); } static ant_value_t builtin_Math_imul(ant_params_t) { if (nargs < 2) return tov(0); int32_t a = js_to_int32(js_to_number(js, args[0])); int32_t b = js_to_int32(js_to_number(js, args[1])); return tov((double)((int32_t)((uint32_t)a * (uint32_t)b))); } static ant_value_t builtin_Math_log(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(log(x)); } static ant_value_t builtin_Math_log1p(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(log1p(x)); } static ant_value_t builtin_Math_log10(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(log10(x)); } static ant_value_t builtin_Math_log2(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(log2(x)); } static ant_value_t builtin_Math_max(ant_params_t) { if (nargs == 0) return tov(JS_NEG_INF); double max_val = js_to_number(js, args[0]); if (isnan(max_val)) return tov(JS_NAN); for (int i = 1; i < nargs; i++) { double v = js_to_number(js, args[i]); if (isnan(v)) return tov(JS_NAN); if (v > max_val) { max_val = v; continue; } if (v == 0.0 && max_val == 0.0 && !signbit(v) && signbit(max_val)) max_val = v; } return tov(max_val); } static ant_value_t builtin_Math_min(ant_params_t) { if (nargs == 0) return tov(JS_INF); double min_val = js_to_number(js, args[0]); if (isnan(min_val)) return tov(JS_NAN); for (int i = 1; i < nargs; i++) { double v = js_to_number(js, args[i]); if (isnan(v)) return tov(JS_NAN); if (v < min_val) { min_val = v; continue; } if (v == 0.0 && min_val == 0.0 && signbit(v) && !signbit(min_val) ) min_val = v; } return tov(min_val); } static ant_value_t builtin_Math_pow(ant_params_t) { double base = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); double exp = (nargs < 2) ? JS_NAN : js_to_number(js, args[1]); if (isnan(base) || isnan(exp)) return tov(JS_NAN); return tov(pow(base, exp)); } static ant_value_t builtin_Math_random(ant_params_t) { uint64_t r = 0; if (crypto_fill_random(&r, sizeof(r)) < 0) { return js_mkerr(js, "secure random generation failed"); } uint64_t fraction = r >> MATH_RANDOM_DISCARD_BITS; return tov((double)fraction * math_random_scale); } static ant_value_t builtin_Math_round(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x) || isinf(x) || x == 0.0) return tov(x); if (x < 0.0 && x >= -0.5) return tov(-0.0); return tov(floor(x + 0.5)); } static ant_value_t builtin_Math_sign(ant_params_t) { double v = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(v)) return tov(JS_NAN); if (v > 0) return tov(1.0); if (v < 0) return tov(-1.0); return tov(v); } static ant_value_t builtin_Math_sin(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(sin(x)); } static ant_value_t builtin_Math_sinh(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(sinh(x)); } static ant_value_t builtin_Math_sqrt(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(sqrt(x)); } static ant_value_t builtin_Math_tan(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(tan(x)); } static ant_value_t builtin_Math_tanh(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(tanh(x)); } static ant_value_t builtin_Math_trunc(ant_params_t) { double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]); if (isnan(x)) return tov(JS_NAN); return tov(trunc(x)); } void init_math_module(void) { ant_t *js = rt->js; ant_value_t glob = js_glob(js); ant_value_t math_obj = mkobj(js, 0); ant_value_t object_proto = js->sym.object_proto; js_set_proto_init(math_obj, object_proto); js_setprop(js, math_obj, js_mkstr(js, "E", 1), tov(M_E)); js_setprop(js, math_obj, js_mkstr(js, "LN10", 4), tov(M_LN10)); js_setprop(js, math_obj, js_mkstr(js, "LN2", 3), tov(M_LN2)); js_setprop(js, math_obj, js_mkstr(js, "LOG10E", 6), tov(M_LOG10E)); js_setprop(js, math_obj, js_mkstr(js, "LOG2E", 5), tov(M_LOG2E)); js_setprop(js, math_obj, js_mkstr(js, "PI", 2), tov(M_PI)); js_setprop(js, math_obj, js_mkstr(js, "SQRT1_2", 7), tov(M_SQRT1_2)); js_setprop(js, math_obj, js_mkstr(js, "SQRT2", 5), tov(M_SQRT2)); js_setprop(js, math_obj, js_mkstr(js, "abs", 3), js_mkfun(builtin_Math_abs)); js_setprop(js, math_obj, js_mkstr(js, "acos", 4), js_mkfun(builtin_Math_acos)); js_setprop(js, math_obj, js_mkstr(js, "acosh", 5), js_mkfun(builtin_Math_acosh)); js_setprop(js, math_obj, js_mkstr(js, "asin", 4), js_mkfun(builtin_Math_asin)); js_setprop(js, math_obj, js_mkstr(js, "asinh", 5), js_mkfun(builtin_Math_asinh)); js_setprop(js, math_obj, js_mkstr(js, "atan", 4), js_mkfun(builtin_Math_atan)); js_setprop(js, math_obj, js_mkstr(js, "atanh", 5), js_mkfun(builtin_Math_atanh)); js_setprop(js, math_obj, js_mkstr(js, "atan2", 5), js_mkfun(builtin_Math_atan2)); js_setprop(js, math_obj, js_mkstr(js, "cbrt", 4), js_mkfun(builtin_Math_cbrt)); js_setprop(js, math_obj, js_mkstr(js, "ceil", 4), js_mkfun(builtin_Math_ceil)); js_setprop(js, math_obj, js_mkstr(js, "clz32", 5), js_mkfun(builtin_Math_clz32)); js_setprop(js, math_obj, js_mkstr(js, "cos", 3), js_mkfun(builtin_Math_cos)); js_setprop(js, math_obj, js_mkstr(js, "cosh", 4), js_mkfun(builtin_Math_cosh)); js_setprop(js, math_obj, js_mkstr(js, "exp", 3), js_mkfun(builtin_Math_exp)); js_setprop(js, math_obj, js_mkstr(js, "expm1", 5), js_mkfun(builtin_Math_expm1)); js_setprop(js, math_obj, js_mkstr(js, "floor", 5), js_mkfun(builtin_Math_floor)); js_setprop(js, math_obj, js_mkstr(js, "fround", 6), js_mkfun(builtin_Math_fround)); js_setprop(js, math_obj, js_mkstr(js, "hypot", 5), js_mkfun(builtin_Math_hypot)); js_setprop(js, math_obj, js_mkstr(js, "imul", 4), js_mkfun(builtin_Math_imul)); js_setprop(js, math_obj, js_mkstr(js, "log", 3), js_mkfun(builtin_Math_log)); js_setprop(js, math_obj, js_mkstr(js, "log1p", 5), js_mkfun(builtin_Math_log1p)); js_setprop(js, math_obj, js_mkstr(js, "log10", 5), js_mkfun(builtin_Math_log10)); js_setprop(js, math_obj, js_mkstr(js, "log2", 4), js_mkfun(builtin_Math_log2)); js_setprop(js, math_obj, js_mkstr(js, "max", 3), js_mkfun(builtin_Math_max)); js_setprop(js, math_obj, js_mkstr(js, "min", 3), js_mkfun(builtin_Math_min)); js_setprop(js, math_obj, js_mkstr(js, "pow", 3), js_mkfun(builtin_Math_pow)); js_setprop(js, math_obj, js_mkstr(js, "random", 6), js_mkfun(builtin_Math_random)); js_setprop(js, math_obj, js_mkstr(js, "round", 5), js_mkfun(builtin_Math_round)); js_setprop(js, math_obj, js_mkstr(js, "sign", 4), js_mkfun(builtin_Math_sign)); js_setprop(js, math_obj, js_mkstr(js, "sin", 3), js_mkfun(builtin_Math_sin)); js_setprop(js, math_obj, js_mkstr(js, "sinh", 4), js_mkfun(builtin_Math_sinh)); js_setprop(js, math_obj, js_mkstr(js, "sqrt", 4), js_mkfun(builtin_Math_sqrt)); js_setprop(js, math_obj, js_mkstr(js, "tan", 3), js_mkfun(builtin_Math_tan)); js_setprop(js, math_obj, js_mkstr(js, "tanh", 4), js_mkfun(builtin_Math_tanh)); js_setprop(js, math_obj, js_mkstr(js, "trunc", 5), js_mkfun(builtin_Math_trunc)); js_set_sym(js, math_obj, get_toStringTag_sym(), js_mkstr(js, "Math", 4)); js_setprop(js, glob, js_mkstr(js, "Math", 4), math_obj); }