Initial import
This commit is contained in:
152
third_party/duktape/duk_tval.c
vendored
Normal file
152
third_party/duktape/duk_tval.c
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
#include "third_party/duktape/duk_internal.h"
|
||||
|
||||
#if defined(DUK_USE_FASTINT)
|
||||
|
||||
/*
|
||||
* Manually optimized double-to-fastint downgrade check.
|
||||
*
|
||||
* This check has a large impact on performance, especially for fastint
|
||||
* slow paths, so must be changed carefully. The code should probably be
|
||||
* optimized for the case where the result does not fit into a fastint,
|
||||
* to minimize the penalty for "slow path code" dealing with fractions etc.
|
||||
*
|
||||
* At least on one tested soft float ARM platform double-to-int64 coercion
|
||||
* is very slow (and sometimes produces incorrect results, see self tests).
|
||||
* This algorithm combines a fastint compatibility check and extracting the
|
||||
* integer value from an IEEE double for setting the tagged fastint. For
|
||||
* other platforms a more naive approach might be better.
|
||||
*
|
||||
* See doc/fastint.rst for details.
|
||||
*/
|
||||
|
||||
DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x) {
|
||||
duk_double_union du;
|
||||
duk_int64_t i;
|
||||
duk_small_int_t expt;
|
||||
duk_small_int_t shift;
|
||||
|
||||
/* XXX: optimize for packed duk_tval directly? */
|
||||
|
||||
du.d = x;
|
||||
i = (duk_int64_t) DUK_DBLUNION_GET_INT64(&du);
|
||||
expt = (duk_small_int_t) ((i >> 52) & 0x07ff);
|
||||
shift = expt - 1023;
|
||||
|
||||
if (shift >= 0 && shift <= 46) { /* exponents 1023 to 1069 */
|
||||
duk_int64_t t;
|
||||
|
||||
if (((DUK_I64_CONSTANT(0x000fffffffffffff) >> shift) & i) == 0) {
|
||||
t = i | DUK_I64_CONSTANT(0x0010000000000000); /* implicit leading one */
|
||||
t = t & DUK_I64_CONSTANT(0x001fffffffffffff);
|
||||
t = t >> (52 - shift);
|
||||
if (i < 0) {
|
||||
t = -t;
|
||||
}
|
||||
DUK_TVAL_SET_FASTINT(tv, t);
|
||||
return;
|
||||
}
|
||||
} else if (shift == -1023) { /* exponent 0 */
|
||||
if (i >= 0 && (i & DUK_I64_CONSTANT(0x000fffffffffffff)) == 0) {
|
||||
/* Note: reject negative zero. */
|
||||
DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) 0);
|
||||
return;
|
||||
}
|
||||
} else if (shift == 47) { /* exponent 1070 */
|
||||
if (i < 0 && (i & DUK_I64_CONSTANT(0x000fffffffffffff)) == 0) {
|
||||
DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) DUK_FASTINT_MIN);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DUK_TVAL_SET_DOUBLE(tv, x);
|
||||
return;
|
||||
}
|
||||
|
||||
DUK_INTERNAL DUK_NOINLINE void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x) {
|
||||
duk_tval_set_number_chkfast_fast(tv, x);
|
||||
}
|
||||
|
||||
/*
|
||||
* Manually optimized number-to-double conversion
|
||||
*/
|
||||
|
||||
#if defined(DUK_USE_FASTINT) && defined(DUK_USE_PACKED_TVAL)
|
||||
DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_packed(duk_tval *tv) {
|
||||
duk_double_union du;
|
||||
duk_uint64_t t;
|
||||
|
||||
t = (duk_uint64_t) DUK_DBLUNION_GET_UINT64(tv);
|
||||
if ((t >> 48) != DUK_TAG_FASTINT) {
|
||||
return tv->d;
|
||||
} else if (t & DUK_U64_CONSTANT(0x0000800000000000)) {
|
||||
t = (duk_uint64_t) (-((duk_int64_t) t)); /* avoid unary minus on unsigned */
|
||||
t = t & DUK_U64_CONSTANT(0x0000ffffffffffff); /* negative */
|
||||
t |= DUK_U64_CONSTANT(0xc330000000000000);
|
||||
DUK_DBLUNION_SET_UINT64(&du, t);
|
||||
return du.d + 4503599627370496.0; /* 1 << 52 */
|
||||
} else if (t != 0) {
|
||||
t &= DUK_U64_CONSTANT(0x0000ffffffffffff); /* positive */
|
||||
t |= DUK_U64_CONSTANT(0x4330000000000000);
|
||||
DUK_DBLUNION_SET_UINT64(&du, t);
|
||||
return du.d - 4503599627370496.0; /* 1 << 52 */
|
||||
} else {
|
||||
return 0.0; /* zero */
|
||||
}
|
||||
}
|
||||
#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
|
||||
|
||||
#if 0 /* unused */
|
||||
#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL)
|
||||
DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked(duk_tval *tv) {
|
||||
duk_double_union du;
|
||||
duk_uint64_t t;
|
||||
|
||||
DUK_ASSERT(tv->t == DUK_TAG_NUMBER || tv->t == DUK_TAG_FASTINT);
|
||||
|
||||
if (tv->t == DUK_TAG_FASTINT) {
|
||||
if (tv->v.fi >= 0) {
|
||||
t = DUK_U64_CONSTANT(0x4330000000000000) | (duk_uint64_t) tv->v.fi;
|
||||
DUK_DBLUNION_SET_UINT64(&du, t);
|
||||
return du.d - 4503599627370496.0; /* 1 << 52 */
|
||||
} else {
|
||||
t = DUK_U64_CONSTANT(0xc330000000000000) | (duk_uint64_t) (-tv->v.fi);
|
||||
DUK_DBLUNION_SET_UINT64(&du, t);
|
||||
return du.d + 4503599627370496.0; /* 1 << 52 */
|
||||
}
|
||||
} else {
|
||||
return tv->v.d;
|
||||
}
|
||||
}
|
||||
#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
|
||||
#endif /* 0 */
|
||||
|
||||
#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL)
|
||||
DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv) {
|
||||
duk_double_union du;
|
||||
duk_uint64_t t;
|
||||
|
||||
DUK_ASSERT(tv->t == DUK_TAG_FASTINT);
|
||||
|
||||
if (tv->v.fi >= 0) {
|
||||
t = DUK_U64_CONSTANT(0x4330000000000000) | (duk_uint64_t) tv->v.fi;
|
||||
DUK_DBLUNION_SET_UINT64(&du, t);
|
||||
return du.d - 4503599627370496.0; /* 1 << 52 */
|
||||
} else {
|
||||
t = DUK_U64_CONSTANT(0xc330000000000000) | (duk_uint64_t) (-tv->v.fi);
|
||||
DUK_DBLUNION_SET_UINT64(&du, t);
|
||||
return du.d + 4503599627370496.0; /* 1 << 52 */
|
||||
}
|
||||
}
|
||||
#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
|
||||
|
||||
#endif /* DUK_USE_FASTINT */
|
||||
|
||||
/*
|
||||
* Assertion helpers.
|
||||
*/
|
||||
|
||||
#if defined(DUK_USE_ASSERTIONS)
|
||||
DUK_INTERNAL void duk_tval_assert_valid(duk_tval *tv) {
|
||||
DUK_ASSERT(tv != NULL);
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user