diff options
Diffstat (limited to '')
-rw-r--r-- | src/civetweb/src/third_party/duktape-1.5.2/src-separate/duk_bi_math.c | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/src/civetweb/src/third_party/duktape-1.5.2/src-separate/duk_bi_math.c b/src/civetweb/src/third_party/duktape-1.5.2/src-separate/duk_bi_math.c new file mode 100644 index 000000000..62c93414b --- /dev/null +++ b/src/civetweb/src/third_party/duktape-1.5.2/src-separate/duk_bi_math.c @@ -0,0 +1,348 @@ +/* + * Math built-ins + */ + +#include "duk_internal.h" + +#if defined(DUK_USE_MATH_BUILTIN) + +/* + * Use static helpers which can work with math.h functions matching + * the following signatures. This is not portable if any of these math + * functions is actually a macro. + * + * Typing here is intentionally 'double' wherever values interact with + * the standard library APIs. + */ + +typedef double (*duk__one_arg_func)(double); +typedef double (*duk__two_arg_func)(double, double); + +DUK_LOCAL duk_ret_t duk__math_minmax(duk_context *ctx, duk_double_t initial, duk__two_arg_func min_max) { + duk_idx_t n = duk_get_top(ctx); + duk_idx_t i; + duk_double_t res = initial; + duk_double_t t; + + /* + * Note: fmax() does not match the E5 semantics. E5 requires + * that if -any- input to Math.max() is a NaN, the result is a + * NaN. fmax() will return a NaN only if -both- inputs are NaN. + * Same applies to fmin(). + * + * Note: every input value must be coerced with ToNumber(), even + * if we know the result will be a NaN anyway: ToNumber() may have + * side effects for which even order of evaluation matters. + */ + + for (i = 0; i < n; i++) { + t = duk_to_number(ctx, i); + if (DUK_FPCLASSIFY(t) == DUK_FP_NAN || DUK_FPCLASSIFY(res) == DUK_FP_NAN) { + /* Note: not normalized, but duk_push_number() will normalize */ + res = (duk_double_t) DUK_DOUBLE_NAN; + } else { + res = (duk_double_t) min_max(res, (double) t); + } + } + + duk_push_number(ctx, res); + return 1; +} + +DUK_LOCAL double duk__fmin_fixed(double x, double y) { + /* fmin() with args -0 and +0 is not guaranteed to return + * -0 as Ecmascript requires. + */ + if (x == 0 && y == 0) { + /* XXX: what's the safest way of creating a negative zero? */ + if (DUK_SIGNBIT(x) != 0 || DUK_SIGNBIT(y) != 0) { + return -0.0; + } else { + return +0.0; + } + } +#ifdef DUK_USE_MATH_FMIN + return DUK_FMIN(x, y); +#else + return (x < y ? x : y); +#endif +} + +DUK_LOCAL double duk__fmax_fixed(double x, double y) { + /* fmax() with args -0 and +0 is not guaranteed to return + * +0 as Ecmascript requires. + */ + if (x == 0 && y == 0) { + if (DUK_SIGNBIT(x) == 0 || DUK_SIGNBIT(y) == 0) { + return +0.0; + } else { + return -0.0; + } + } +#ifdef DUK_USE_MATH_FMAX + return DUK_FMAX(x, y); +#else + return (x > y ? x : y); +#endif +} + +DUK_LOCAL double duk__round_fixed(double x) { + /* Numbers half-way between integers must be rounded towards +Infinity, + * e.g. -3.5 must be rounded to -3 (not -4). When rounded to zero, zero + * sign must be set appropriately. E5.1 Section 15.8.2.15. + * + * Note that ANSI C round() is "round to nearest integer, away from zero", + * which is incorrect for negative values. Here we make do with floor(). + */ + + duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x); + if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) { + return x; + } + + /* + * x is finite and non-zero + * + * -1.6 -> floor(-1.1) -> -2 + * -1.5 -> floor(-1.0) -> -1 (towards +Inf) + * -1.4 -> floor(-0.9) -> -1 + * -0.5 -> -0.0 (special case) + * -0.1 -> -0.0 (special case) + * +0.1 -> +0.0 (special case) + * +0.5 -> floor(+1.0) -> 1 (towards +Inf) + * +1.4 -> floor(+1.9) -> 1 + * +1.5 -> floor(+2.0) -> 2 (towards +Inf) + * +1.6 -> floor(+2.1) -> 2 + */ + + if (x >= -0.5 && x < 0.5) { + /* +0.5 is handled by floor, this is on purpose */ + if (x < 0.0) { + return -0.0; + } else { + return +0.0; + } + } + + return DUK_FLOOR(x + 0.5); +} + +DUK_LOCAL double duk__pow_fixed(double x, double y) { + /* The ANSI C pow() semantics differ from Ecmascript. + * + * E.g. when x==1 and y is +/- infinite, the Ecmascript required + * result is NaN, while at least Linux pow() returns 1. + */ + + duk_small_int_t cx, cy, sx; + + DUK_UNREF(cx); + DUK_UNREF(sx); + cy = (duk_small_int_t) DUK_FPCLASSIFY(y); + + if (cy == DUK_FP_NAN) { + goto ret_nan; + } + if (DUK_FABS(x) == 1.0 && cy == DUK_FP_INFINITE) { + goto ret_nan; + } +#if defined(DUK_USE_POW_NETBSD_WORKAROUND) + /* See test-bug-netbsd-math-pow.js: NetBSD 6.0 on x86 (at least) does not + * correctly handle some cases where x=+/-0. Specific fixes to these + * here. + */ + cx = (duk_small_int_t) DUK_FPCLASSIFY(x); + if (cx == DUK_FP_ZERO && y < 0.0) { + sx = (duk_small_int_t) DUK_SIGNBIT(x); + if (sx == 0) { + /* Math.pow(+0,y) should be Infinity when y<0. NetBSD pow() + * returns -Infinity instead when y is <0 and finite. The + * if-clause also catches y == -Infinity (which works even + * without the fix). + */ + return DUK_DOUBLE_INFINITY; + } else { + /* Math.pow(-0,y) where y<0 should be: + * - -Infinity if y<0 and an odd integer + * - Infinity otherwise + * NetBSD pow() returns -Infinity for all finite y<0. The + * if-clause also catches y == -Infinity (which works even + * without the fix). + */ + + /* fmod() return value has same sign as input (negative) so + * the result here will be in the range ]-2,0], 1 indicates + * odd. If x is -Infinity, NaN is returned and the odd check + * always concludes "not odd" which results in desired outcome. + */ + double tmp = DUK_FMOD(y, 2); + if (tmp == -1.0) { + return -DUK_DOUBLE_INFINITY; + } else { + /* Not odd, or y == -Infinity */ + return DUK_DOUBLE_INFINITY; + } + } + } +#endif + return DUK_POW(x, y); + + ret_nan: + return DUK_DOUBLE_NAN; +} + +/* Wrappers for calling standard math library methods. These may be required + * on platforms where one or more of the math built-ins are defined as macros + * or inline functions and are thus not suitable to be used as function pointers. + */ +#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS) +DUK_LOCAL double duk__fabs(double x) { + return DUK_FABS(x); +} +DUK_LOCAL double duk__acos(double x) { + return DUK_ACOS(x); +} +DUK_LOCAL double duk__asin(double x) { + return DUK_ASIN(x); +} +DUK_LOCAL double duk__atan(double x) { + return DUK_ATAN(x); +} +DUK_LOCAL double duk__ceil(double x) { + return DUK_CEIL(x); +} +DUK_LOCAL double duk__cos(double x) { + return DUK_COS(x); +} +DUK_LOCAL double duk__exp(double x) { + return DUK_EXP(x); +} +DUK_LOCAL double duk__floor(double x) { + return DUK_FLOOR(x); +} +DUK_LOCAL double duk__log(double x) { + return DUK_LOG(x); +} +DUK_LOCAL double duk__sin(double x) { + return DUK_SIN(x); +} +DUK_LOCAL double duk__sqrt(double x) { + return DUK_SQRT(x); +} +DUK_LOCAL double duk__tan(double x) { + return DUK_TAN(x); +} +DUK_LOCAL double duk__atan2(double x, double y) { + return DUK_ATAN2(x, y); +} +#endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */ + +/* order must match constants in genbuiltins.py */ +DUK_LOCAL const duk__one_arg_func duk__one_arg_funcs[] = { +#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS) + duk__fabs, + duk__acos, + duk__asin, + duk__atan, + duk__ceil, + duk__cos, + duk__exp, + duk__floor, + duk__log, + duk__round_fixed, + duk__sin, + duk__sqrt, + duk__tan +#else + DUK_FABS, + DUK_ACOS, + DUK_ASIN, + DUK_ATAN, + DUK_CEIL, + DUK_COS, + DUK_EXP, + DUK_FLOOR, + DUK_LOG, + duk__round_fixed, + DUK_SIN, + DUK_SQRT, + DUK_TAN +#endif +}; + +/* order must match constants in genbuiltins.py */ +DUK_LOCAL const duk__two_arg_func duk__two_arg_funcs[] = { +#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS) + duk__atan2, + duk__pow_fixed +#else + DUK_ATAN2, + duk__pow_fixed +#endif +}; + +DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx) { + duk_small_int_t fun_idx = duk_get_current_magic(ctx); + duk__one_arg_func fun; + + DUK_ASSERT(fun_idx >= 0); + DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__one_arg_funcs) / sizeof(duk__one_arg_func))); + fun = duk__one_arg_funcs[fun_idx]; + duk_push_number(ctx, (duk_double_t) fun((double) duk_to_number(ctx, 0))); + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx) { + duk_small_int_t fun_idx = duk_get_current_magic(ctx); + duk__two_arg_func fun; + + DUK_ASSERT(fun_idx >= 0); + DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__two_arg_funcs) / sizeof(duk__two_arg_func))); + fun = duk__two_arg_funcs[fun_idx]; + duk_push_number(ctx, (duk_double_t) fun((double) duk_to_number(ctx, 0), (double) duk_to_number(ctx, 1))); + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_context *ctx) { + return duk__math_minmax(ctx, -DUK_DOUBLE_INFINITY, duk__fmax_fixed); +} + +DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_context *ctx) { + return duk__math_minmax(ctx, DUK_DOUBLE_INFINITY, duk__fmin_fixed); +} + +DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_context *ctx) { + duk_push_number(ctx, (duk_double_t) duk_util_tinyrandom_get_double((duk_hthread *) ctx)); + return 1; +} + +#else /* DUK_USE_MATH_BUILTIN */ + +/* A stubbed built-in is useful for e.g. compilation torture testing with BCC. */ + +DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNIMPLEMENTED_ERROR; +} + +DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNIMPLEMENTED_ERROR; +} + +DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNIMPLEMENTED_ERROR; +} + +DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNIMPLEMENTED_ERROR; +} + +DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_context *ctx) { + DUK_UNREF(ctx); + return DUK_RET_UNIMPLEMENTED_ERROR; +} + +#endif /* DUK_USE_MATH_BUILTIN */ |