/* combined algorithm matching E5 Sections 9.5 and 9.6 */ DUK_LOCAL duk_double_t duk__toint32_touint32_helper(duk_double_t x, duk_bool_t is_toint32) { duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x); duk_small_int_t s; if (c == DUK_FP_NAN || c == DUK_FP_ZERO || c == DUK_FP_INFINITE) { return 0.0; } /* x = sign(x) * floor(abs(x)), i.e. truncate towards zero, keep sign */ s = (duk_small_int_t) DUK_SIGNBIT(x); x = DUK_FLOOR(DUK_FABS(x)); if (s) { x = -x; } /* NOTE: fmod(x) result sign is same as sign of x, which * differs from what Javascript wants (see Section 9.6). */ x = DUK_FMOD(x, DUK_DOUBLE_2TO32); /* -> x in ]-2**32, 2**32[ */ if (x < 0.0) { x += DUK_DOUBLE_2TO32; } /* -> x in [0, 2**32[ */ if (is_toint32) { if (x >= DUK_DOUBLE_2TO31) { /* x in [2**31, 2**32[ */ x -= DUK_DOUBLE_2TO32; /* -> x in [-2**31,2**31[ */ } } return x; }
DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t output_type) { duk_hthread *thr = (duk_hthread *) ctx; duk_idx_t idx_td; duk_small_int_t i; /* traceback depth fits into 16 bits */ duk_small_int_t t; /* stack type fits into 16 bits */ duk_small_int_t count_func = 0; /* traceback depth ensures fits into 16 bits */ const char *str_tailcall = " tailcall"; const char *str_strict = " strict"; const char *str_construct = " construct"; const char *str_prevyield = " preventsyield"; const char *str_directeval = " directeval"; const char *str_empty = ""; DUK_ASSERT_TOP(ctx, 0); /* fixed arg count */ DUK_UNREF(thr); duk_push_this(ctx); duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TRACEDATA); idx_td = duk_get_top_index(ctx); duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_4SPACE); duk_push_this(ctx); /* [ ... this tracedata sep this ] */ /* XXX: skip null filename? */ if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) { /* Current tracedata contains 2 entries per callstack entry. */ for (i = 0; ; i += 2) { duk_int_t pc; duk_int_t line; duk_int_t flags; duk_double_t d; const char *funcname; const char *filename; duk_hobject *h_func; duk_hstring *h_name; duk_require_stack(ctx, 5); duk_get_prop_index(ctx, idx_td, i); duk_get_prop_index(ctx, idx_td, i + 1); d = duk_to_number(ctx, -1); pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32); flags = (duk_int_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32); t = (duk_small_int_t) duk_get_type(ctx, -2); if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) { /* * Ecmascript/native function call or lightfunc call */ count_func++; /* [ ... v1(func) v2(pc+flags) ] */ h_func = duk_get_hobject(ctx, -2); /* NULL for lightfunc */ duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME); duk_get_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME); #if defined(DUK_USE_PC2LINE) line = duk_hobject_pc2line_query(ctx, -4, (duk_uint_fast32_t) pc); #else line = 0; #endif /* [ ... v1 v2 name filename ] */ /* When looking for .fileName/.lineNumber, blame first * function which has a .fileName. */ if (duk_is_string(ctx, -1)) { if (output_type == DUK__OUTPUT_TYPE_FILENAME) { return 1; } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { duk_push_int(ctx, line); return 1; } } /* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */ /* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */ h_name = duk_get_hstring(ctx, -2); /* may be NULL */ funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ? "[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name); filename = duk_get_string(ctx, -1); filename = filename ? filename : ""; DUK_ASSERT(funcname != NULL); DUK_ASSERT(filename != NULL); if (h_func == NULL) { duk_push_sprintf(ctx, "at %s light%s%s%s%s%s", (const char *) funcname, (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); } else if (DUK_HOBJECT_HAS_NATFUNC(h_func)) { duk_push_sprintf(ctx, "at %s (%s) native%s%s%s%s%s", (const char *) funcname, (const char *) filename, (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); } else { duk_push_sprintf(ctx, "at %s (%s:%ld)%s%s%s%s%s", (const char *) funcname, (const char *) filename, (long) line, (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); } duk_replace(ctx, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */ duk_pop_n(ctx, 3); /* -> [ ... str ] */ } else if (t == DUK_TYPE_STRING) { /* * __FILE__ / __LINE__ entry, here 'pc' is line number directly. * Sometimes __FILE__ / __LINE__ is reported as the source for * the error (fileName, lineNumber), sometimes not. */ /* [ ... v1(filename) v2(line+flags) ] */ /* When looking for .fileName/.lineNumber, blame compilation * or C call site unless flagged not to do so. */ if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) { if (output_type == DUK__OUTPUT_TYPE_FILENAME) { duk_pop(ctx); return 1; } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { duk_push_int(ctx, pc); return 1; } } duk_push_sprintf(ctx, "at [anon] (%s:%ld) internal", (const char *) duk_get_string(ctx, -2), (long) pc); duk_replace(ctx, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */ duk_pop(ctx); /* -> [ ... str ] */ } else { /* unknown, ignore */ duk_pop_2(ctx); break; } } if (count_func >= DUK_USE_TRACEBACK_DEPTH) { /* Possibly truncated; there is no explicit truncation * marker so this is the best we can do. */ duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS); } } /* [ ... this tracedata sep this str1 ... strN ] */ if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) { return 0; } else { /* The 'this' after 'sep' will get ToString() coerced by * duk_join() automatically. We don't want to do that * coercion when providing .fileName or .lineNumber (GH-254). */ duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/); return 1; } }
static 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. */ int cx, cy, sx; DUK_UNREF(cx); DUK_UNREF(sx); cy = 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_FPCLASSIFY(x); if (cx == DUK_FP_ZERO && y < 0.0) { sx = 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; }