|
|
@ -16,15 +16,21 @@ typedef union { |
|
|
|
duk_uint8_t c[8]; |
|
|
|
} duk__test_double_union; |
|
|
|
|
|
|
|
/* Self test failed. Expects a local variable 'error_count' to exist. */ |
|
|
|
#define DUK__FAILED(msg) do { \ |
|
|
|
DUK_D(DUK_DPRINT("self test failed: " #msg)); \ |
|
|
|
error_count++; \ |
|
|
|
} while (0) |
|
|
|
|
|
|
|
#define DUK__DBLUNION_CMP_TRUE(a,b) do { \ |
|
|
|
if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) != 0) { \ |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares false (expected true)"); \ |
|
|
|
DUK__FAILED("double union compares false (expected true)"); \ |
|
|
|
} \ |
|
|
|
} while (0) |
|
|
|
|
|
|
|
#define DUK__DBLUNION_CMP_FALSE(a,b) do { \ |
|
|
|
if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) == 0) { \ |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares true (expected false)"); \ |
|
|
|
DUK__FAILED("double union compares true (expected false)"); \ |
|
|
|
} \ |
|
|
|
} while (0) |
|
|
|
|
|
|
@ -37,19 +43,21 @@ typedef union { |
|
|
|
* Various sanity checks for typing |
|
|
|
*/ |
|
|
|
|
|
|
|
DUK_LOCAL void duk__selftest_types(void) { |
|
|
|
DUK_LOCAL duk_uint_t duk__selftest_types(void) { |
|
|
|
duk_uint_t error_count = 0; |
|
|
|
|
|
|
|
if (!(sizeof(duk_int8_t) == 1 && |
|
|
|
sizeof(duk_uint8_t) == 1 && |
|
|
|
sizeof(duk_int16_t) == 2 && |
|
|
|
sizeof(duk_uint16_t) == 2 && |
|
|
|
sizeof(duk_int32_t) == 4 && |
|
|
|
sizeof(duk_uint32_t) == 4)) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_(u)int{8,16,32}_t size"); |
|
|
|
DUK__FAILED("duk_(u)int{8,16,32}_t size"); |
|
|
|
} |
|
|
|
#if defined(DUK_USE_64BIT_OPS) |
|
|
|
if (!(sizeof(duk_int64_t) == 8 && |
|
|
|
sizeof(duk_uint64_t) == 8)) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_(u)int64_t size"); |
|
|
|
DUK__FAILED("duk_(u)int64_t size"); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
@ -57,30 +65,37 @@ DUK_LOCAL void duk__selftest_types(void) { |
|
|
|
/* Some internal code now assumes that all duk_uint_t values
|
|
|
|
* can be expressed with a duk_size_t. |
|
|
|
*/ |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_size_t is smaller than duk_uint_t"); |
|
|
|
DUK__FAILED("duk_size_t is smaller than duk_uint_t"); |
|
|
|
} |
|
|
|
if (!(sizeof(duk_int_t) >= 4)) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_int_t is not 32 bits"); |
|
|
|
DUK__FAILED("duk_int_t is not 32 bits"); |
|
|
|
} |
|
|
|
|
|
|
|
return error_count; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* Packed tval sanity |
|
|
|
*/ |
|
|
|
|
|
|
|
DUK_LOCAL void duk__selftest_packed_tval(void) { |
|
|
|
DUK_LOCAL duk_uint_t duk__selftest_packed_tval(void) { |
|
|
|
duk_uint_t error_count = 0; |
|
|
|
|
|
|
|
#if defined(DUK_USE_PACKED_TVAL) |
|
|
|
if (sizeof(void *) > 4) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: packed duk_tval in use but sizeof(void *) > 4"); |
|
|
|
DUK__FAILED("packed duk_tval in use but sizeof(void *) > 4"); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
return error_count; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* Two's complement arithmetic. |
|
|
|
*/ |
|
|
|
|
|
|
|
DUK_LOCAL void duk__selftest_twos_complement(void) { |
|
|
|
DUK_LOCAL duk_uint_t duk__selftest_twos_complement(void) { |
|
|
|
duk_uint_t error_count = 0; |
|
|
|
volatile int test; |
|
|
|
test = -1; |
|
|
|
|
|
|
@ -88,8 +103,10 @@ DUK_LOCAL void duk__selftest_twos_complement(void) { |
|
|
|
* 'test' will be 0xFF for two's complement. |
|
|
|
*/ |
|
|
|
if (((volatile duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: two's complement arithmetic"); |
|
|
|
DUK__FAILED("two's complement arithmetic"); |
|
|
|
} |
|
|
|
|
|
|
|
return error_count; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
@ -98,7 +115,8 @@ DUK_LOCAL void duk__selftest_twos_complement(void) { |
|
|
|
* defines. |
|
|
|
*/ |
|
|
|
|
|
|
|
DUK_LOCAL void duk__selftest_byte_order(void) { |
|
|
|
DUK_LOCAL duk_uint_t duk__selftest_byte_order(void) { |
|
|
|
duk_uint_t error_count = 0; |
|
|
|
duk__test_u32_union u1; |
|
|
|
duk__test_double_union u2; |
|
|
|
|
|
|
@ -130,19 +148,22 @@ DUK_LOCAL void duk__selftest_byte_order(void) { |
|
|
|
#endif |
|
|
|
|
|
|
|
if (u1.i != (duk_uint32_t) 0xdeadbeefUL) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_uint32_t byte order"); |
|
|
|
DUK__FAILED("duk_uint32_t byte order"); |
|
|
|
} |
|
|
|
|
|
|
|
if (u2.d != (double) 102030405060.0) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double byte order"); |
|
|
|
DUK__FAILED("double byte order"); |
|
|
|
} |
|
|
|
|
|
|
|
return error_count; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* DUK_BSWAP macros |
|
|
|
*/ |
|
|
|
|
|
|
|
DUK_LOCAL void duk__selftest_bswap_macros(void) { |
|
|
|
DUK_LOCAL duk_uint_t duk__selftest_bswap_macros(void) { |
|
|
|
duk_uint_t error_count = 0; |
|
|
|
duk_uint32_t x32; |
|
|
|
duk_uint16_t x16; |
|
|
|
duk_double_union du; |
|
|
@ -151,13 +172,13 @@ DUK_LOCAL void duk__selftest_bswap_macros(void) { |
|
|
|
x16 = 0xbeefUL; |
|
|
|
x16 = DUK_BSWAP16(x16); |
|
|
|
if (x16 != (duk_uint16_t) 0xefbeUL) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_BSWAP16"); |
|
|
|
DUK__FAILED("DUK_BSWAP16"); |
|
|
|
} |
|
|
|
|
|
|
|
x32 = 0xdeadbeefUL; |
|
|
|
x32 = DUK_BSWAP32(x32); |
|
|
|
if (x32 != (duk_uint32_t) 0xefbeaddeUL) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_BSWAP32"); |
|
|
|
DUK__FAILED("DUK_BSWAP32"); |
|
|
|
} |
|
|
|
|
|
|
|
/* >>> struct.unpack('>d', '4000112233445566'.decode('hex'))
|
|
|
@ -169,7 +190,7 @@ DUK_LOCAL void duk__selftest_bswap_macros(void) { |
|
|
|
DUK_DBLUNION_DOUBLE_NTOH(&du); |
|
|
|
du_diff = du.d - 2.008366013071895; |
|
|
|
#if 0 |
|
|
|
DUK_FPRINTF(DUK_STDERR, "du_diff: %lg\n", (double) du_diff); |
|
|
|
DUK_D(DUK_DPRINT("du_diff: %lg\n", (double) du_diff)); |
|
|
|
#endif |
|
|
|
if (du_diff > 1e-15) { |
|
|
|
/* Allow very small lenience because some compilers won't parse
|
|
|
@ -177,41 +198,44 @@ DUK_LOCAL void duk__selftest_bswap_macros(void) { |
|
|
|
* Linux gcc-4.8 -m32 at least). |
|
|
|
*/ |
|
|
|
#if 0 |
|
|
|
DUK_FPRINTF(DUK_STDERR, "Result of DUK_DBLUNION_DOUBLE_NTOH: %02x %02x %02x %02x %02x %02x %02x %02x\n", |
|
|
|
DUK_D(DUK_DPRINT("Result of DUK_DBLUNION_DOUBLE_NTOH: %02x %02x %02x %02x %02x %02x %02x %02x\n", |
|
|
|
(unsigned int) du.uc[0], (unsigned int) du.uc[1], |
|
|
|
(unsigned int) du.uc[2], (unsigned int) du.uc[3], |
|
|
|
(unsigned int) du.uc[4], (unsigned int) du.uc[5], |
|
|
|
(unsigned int) du.uc[6], (unsigned int) du.uc[7]); |
|
|
|
(unsigned int) du.uc[6], (unsigned int) du.uc[7])); |
|
|
|
#endif |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_DBLUNION_DOUBLE_NTOH"); |
|
|
|
DUK__FAILED("DUK_DBLUNION_DOUBLE_NTOH"); |
|
|
|
} |
|
|
|
|
|
|
|
return error_count; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* Basic double / byte union memory layout. |
|
|
|
*/ |
|
|
|
|
|
|
|
DUK_LOCAL void duk__selftest_double_union_size(void) { |
|
|
|
DUK_LOCAL duk_uint_t duk__selftest_double_union_size(void) { |
|
|
|
duk_uint_t error_count = 0; |
|
|
|
|
|
|
|
if (sizeof(duk__test_double_union) != 8) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: invalid union size"); |
|
|
|
DUK__FAILED("invalid union size"); |
|
|
|
} |
|
|
|
|
|
|
|
return error_count; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* Union aliasing, see misc/clang_aliasing.c. |
|
|
|
*/ |
|
|
|
|
|
|
|
DUK_LOCAL void duk__selftest_double_aliasing(void) { |
|
|
|
duk__test_double_union a, b; |
|
|
|
|
|
|
|
DUK_LOCAL duk_uint_t duk__selftest_double_aliasing(void) { |
|
|
|
/* This testcase fails when Emscripten-generated code runs on Firefox.
|
|
|
|
* It's not an issue because the failure should only affect packed |
|
|
|
* duk_tval representation, which is not used with Emscripten. |
|
|
|
*/ |
|
|
|
#if !defined(DUK_USE_PACKED_TVAL) |
|
|
|
DUK_D(DUK_DPRINT("skip double aliasing self test when duk_tval is not packed")); |
|
|
|
return; |
|
|
|
#endif |
|
|
|
#if defined(DUK_USE_PACKED_TVAL) |
|
|
|
duk_uint_t error_count = 0; |
|
|
|
duk__test_double_union a, b; |
|
|
|
|
|
|
|
/* Test signaling NaN and alias assignment in all endianness combinations.
|
|
|
|
*/ |
|
|
@ -233,18 +257,27 @@ DUK_LOCAL void duk__selftest_double_aliasing(void) { |
|
|
|
a.c[4] = 0x11; a.c[5] = 0x22; a.c[6] = 0x33; a.c[7] = 0x44; |
|
|
|
b = a; |
|
|
|
DUK__DBLUNION_CMP_TRUE(&a, &b); |
|
|
|
|
|
|
|
return error_count; |
|
|
|
#else |
|
|
|
DUK_D(DUK_DPRINT("skip double aliasing self test when duk_tval is not packed")); |
|
|
|
return 0; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* Zero sign, see misc/tcc_zerosign2.c. |
|
|
|
*/ |
|
|
|
|
|
|
|
DUK_LOCAL void duk__selftest_double_zero_sign(void) { |
|
|
|
DUK_LOCAL duk_uint_t duk__selftest_double_zero_sign(void) { |
|
|
|
duk_uint_t error_count = 0; |
|
|
|
duk__test_double_union a, b; |
|
|
|
|
|
|
|
a.d = 0.0; |
|
|
|
b.d = -a.d; |
|
|
|
DUK__DBLUNION_CMP_FALSE(&a, &b); |
|
|
|
|
|
|
|
return error_count; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
@ -254,20 +287,23 @@ DUK_LOCAL void duk__selftest_double_zero_sign(void) { |
|
|
|
* selftest ensures they're correctly detected and used. |
|
|
|
*/ |
|
|
|
|
|
|
|
DUK_LOCAL void duk__selftest_struct_align(void) { |
|
|
|
DUK_LOCAL duk_uint_t duk__selftest_struct_align(void) { |
|
|
|
duk_uint_t error_count = 0; |
|
|
|
|
|
|
|
#if (DUK_USE_ALIGN_BY == 4) |
|
|
|
if ((sizeof(duk_hbuffer_fixed) % 4) != 0) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: sizeof(duk_hbuffer_fixed) not aligned to 4"); |
|
|
|
DUK__FAILED("sizeof(duk_hbuffer_fixed) not aligned to 4"); |
|
|
|
} |
|
|
|
#elif (DUK_USE_ALIGN_BY == 8) |
|
|
|
if ((sizeof(duk_hbuffer_fixed) % 8) != 0) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: sizeof(duk_hbuffer_fixed) not aligned to 8"); |
|
|
|
DUK__FAILED("sizeof(duk_hbuffer_fixed) not aligned to 8"); |
|
|
|
} |
|
|
|
#elif (DUK_USE_ALIGN_BY == 1) |
|
|
|
/* no check */ |
|
|
|
#else |
|
|
|
#error invalid DUK_USE_ALIGN_BY |
|
|
|
#endif |
|
|
|
return error_count; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
@ -277,7 +313,8 @@ DUK_LOCAL void duk__selftest_struct_align(void) { |
|
|
|
* but don't work correctly. Test for known cases. |
|
|
|
*/ |
|
|
|
|
|
|
|
DUK_LOCAL void duk__selftest_64bit_arithmetic(void) { |
|
|
|
DUK_LOCAL duk_uint_t duk__selftest_64bit_arithmetic(void) { |
|
|
|
duk_uint_t error_count = 0; |
|
|
|
#if defined(DUK_USE_64BIT_OPS) |
|
|
|
volatile duk_int64_t i; |
|
|
|
volatile duk_double_t d; |
|
|
@ -286,22 +323,25 @@ DUK_LOCAL void duk__selftest_64bit_arithmetic(void) { |
|
|
|
d = 2147483648.0; |
|
|
|
i = (duk_int64_t) d; |
|
|
|
if (i != 0x80000000LL) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: casting 2147483648.0 to duk_int64_t failed"); |
|
|
|
DUK__FAILED("casting 2147483648.0 to duk_int64_t failed"); |
|
|
|
} |
|
|
|
#else |
|
|
|
/* nop */ |
|
|
|
#endif |
|
|
|
return error_count; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* Casting |
|
|
|
*/ |
|
|
|
|
|
|
|
DUK_LOCAL void duk__selftest_cast_double_to_small_uint(void) { |
|
|
|
DUK_LOCAL duk_uint_t duk__selftest_cast_double_to_small_uint(void) { |
|
|
|
/*
|
|
|
|
* https://github.com/svaarala/duktape/issues/127#issuecomment-77863473
|
|
|
|
*/ |
|
|
|
|
|
|
|
duk_uint_t error_count = 0; |
|
|
|
|
|
|
|
duk_double_t d1, d2; |
|
|
|
duk_small_uint_t u; |
|
|
|
|
|
|
@ -315,7 +355,7 @@ DUK_LOCAL void duk__selftest_cast_double_to_small_uint(void) { |
|
|
|
d2 = (duk_double_t) u; |
|
|
|
|
|
|
|
if (!(d1 == 1.0 && u == 1 && d2 == 1.0 && d1 == d2)) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_small_uint_t cast failed"); |
|
|
|
DUK__FAILED("double to duk_small_uint_t cast failed"); |
|
|
|
} |
|
|
|
|
|
|
|
/* Same test with volatiles */ |
|
|
@ -325,11 +365,13 @@ DUK_LOCAL void duk__selftest_cast_double_to_small_uint(void) { |
|
|
|
d2v = (duk_double_t) uv; |
|
|
|
|
|
|
|
if (!(d1v == 1.0 && uv == 1 && d2v == 1.0 && d1v == d2v)) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_small_uint_t cast failed"); |
|
|
|
DUK__FAILED("double to duk_small_uint_t cast failed"); |
|
|
|
} |
|
|
|
|
|
|
|
return error_count; |
|
|
|
} |
|
|
|
|
|
|
|
DUK_LOCAL void duk__selftest_cast_double_to_uint32(void) { |
|
|
|
DUK_LOCAL duk_uint_t duk__selftest_cast_double_to_uint32(void) { |
|
|
|
/*
|
|
|
|
* This test fails on an exotic ARM target; double-to-uint |
|
|
|
* cast is incorrectly clamped to -signed- int highest value. |
|
|
@ -337,6 +379,7 @@ DUK_LOCAL void duk__selftest_cast_double_to_uint32(void) { |
|
|
|
* https://github.com/svaarala/duktape/issues/336
|
|
|
|
*/ |
|
|
|
|
|
|
|
duk_uint_t error_count = 0; |
|
|
|
duk_double_t dv; |
|
|
|
duk_uint32_t uv; |
|
|
|
|
|
|
@ -344,29 +387,40 @@ DUK_LOCAL void duk__selftest_cast_double_to_uint32(void) { |
|
|
|
uv = (duk_uint32_t) dv; |
|
|
|
|
|
|
|
if (uv != 0xdeadbeefUL) { |
|
|
|
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_uint32_t cast failed"); |
|
|
|
DUK__FAILED("double to duk_uint32_t cast failed"); |
|
|
|
} |
|
|
|
|
|
|
|
return error_count; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* Self test main |
|
|
|
*/ |
|
|
|
|
|
|
|
DUK_INTERNAL void duk_selftest_run_tests(void) { |
|
|
|
duk__selftest_types(); |
|
|
|
duk__selftest_packed_tval(); |
|
|
|
duk__selftest_twos_complement(); |
|
|
|
duk__selftest_byte_order(); |
|
|
|
duk__selftest_bswap_macros(); |
|
|
|
duk__selftest_double_union_size(); |
|
|
|
duk__selftest_double_aliasing(); |
|
|
|
duk__selftest_double_zero_sign(); |
|
|
|
duk__selftest_struct_align(); |
|
|
|
duk__selftest_64bit_arithmetic(); |
|
|
|
duk__selftest_cast_double_to_small_uint(); |
|
|
|
duk__selftest_cast_double_to_uint32(); |
|
|
|
DUK_INTERNAL duk_uint_t duk_selftest_run_tests(void) { |
|
|
|
duk_uint_t error_count = 0; |
|
|
|
|
|
|
|
DUK_D(DUK_DPRINT("self test starting")); |
|
|
|
|
|
|
|
error_count += duk__selftest_types(); |
|
|
|
error_count += duk__selftest_packed_tval(); |
|
|
|
error_count += duk__selftest_twos_complement(); |
|
|
|
error_count += duk__selftest_byte_order(); |
|
|
|
error_count += duk__selftest_bswap_macros(); |
|
|
|
error_count += duk__selftest_double_union_size(); |
|
|
|
error_count += duk__selftest_double_aliasing(); |
|
|
|
error_count += duk__selftest_double_zero_sign(); |
|
|
|
error_count += duk__selftest_struct_align(); |
|
|
|
error_count += duk__selftest_64bit_arithmetic(); |
|
|
|
error_count += duk__selftest_cast_double_to_small_uint(); |
|
|
|
error_count += duk__selftest_cast_double_to_uint32(); |
|
|
|
|
|
|
|
DUK_D(DUK_DPRINT("self test complete, total error count: %ld", (long) error_count)); |
|
|
|
|
|
|
|
return error_count; |
|
|
|
} |
|
|
|
|
|
|
|
#undef DUK__FAILED |
|
|
|
#undef DUK__DBLUNION_CMP_TRUE |
|
|
|
#undef DUK__DBLUNION_CMP_FALSE |
|
|
|
|
|
|
|