Browse Source

Add byteswap macros and self tests

- DUK_BSWAP32() and DUK_BSWAP16() in duk_features.h so that platform specific
  macros, intrinsics, or inline assembly can be used if necessary
- DUK_DBLUNION_BSWAP() for byte swapping doubles (needed by debugger)
- duk_byteswap_bytes() helper for byte swapping arbitrary data (needed by
  debugger for pointers)
pull/113/head
Sami Vaarala 10 years ago
parent
commit
15f1be7f8d
  1. 27
      src/duk_dblunion.h.in
  2. 17
      src/duk_features.h.in
  3. 50
      src/duk_selftest.c
  4. 2
      src/duk_util.h
  5. 19
      src/duk_util_misc.c

27
src/duk_dblunion.h.in

@ -309,4 +309,31 @@ typedef union duk_double_union duk_double_union;
} while (0)
#endif /* DUK_USE_PACKED_TVAL */
/* Byteswap an (aligned) duk_double_union. */
#if defined(DUK_USE_DOUBLE_LE)
#define DUK_DBLUNION_BSWAP(u) do { \
duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
duk__bswaptmp1 = (u)->ui[0]; \
duk__bswaptmp2 = (u)->ui[1]; \
duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
(u)->ui[0] = duk__bswaptmp2; \
(u)->ui[1] = duk__bswaptmp1; \
} while (0)
#elif defined(DUK_USE_DOUBLE_ME)
#define DUK_DBLUNION_BSWAP(u) do { \
duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
duk__bswaptmp1 = (u)->ui[0]; \
duk__bswaptmp2 = (u)->ui[1]; \
duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
(u)->ui[0] = duk__bswaptmp1; \
(u)->ui[1] = duk__bswaptmp2; \
} while (0)
#elif defined(DUK_USE_DOUBLE_BE)
#define DUK_DBLUNION_BSWAP(u) do { } while (0)
#else
#error internal error, double endianness insane
#endif
#endif /* DUK_DBLUNION_H_INCLUDED */

17
src/duk_features.h.in

@ -2067,6 +2067,23 @@ typedef FILE duk_file;
#define DUK_FUNC_MACRO "unknown"
#endif
/*
* Byteswap macros
*
* These are here so that inline assembly or other platform functions can be
* used if available.
*/
#define DUK_BSWAP32(x) \
((((duk_uint32_t) (x)) >> 24) | \
((((duk_uint32_t) (x)) >> 8) & 0xff00UL) | \
((((duk_uint32_t) (x)) << 8) & 0xff0000UL) | \
(((duk_uint32_t) (x)) << 24))
#define DUK_BSWAP16(x) \
((duk_uint16_t) (x) >> 8) | \
((duk_uint16_t) (x) << 8)
/*
* Architecture string, human readable value exposed in Duktape.env
*/

50
src/duk_selftest.c

@ -134,6 +134,55 @@ DUK_LOCAL void duk__selftest_byte_order(void) {
}
}
/*
* DUK_BSWAP macros
*/
DUK_LOCAL void duk__selftest_bswap_macros(void) {
duk_uint32_t x32;
duk_uint16_t x16;
duk_double_union du;
duk_double_t du_diff;
x16 = 0xbeefUL;
x16 = DUK_BSWAP16(x16);
if (x16 != (duk_uint16_t) 0xefbeUL) {
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test 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");
}
/* >>> struct.unpack('>d', '4000112233445566'.decode('hex'))
* (2.008366013071895,)
*/
du.uc[0] = 0x40; du.uc[1] = 0x00; du.uc[2] = 0x11; du.uc[3] = 0x22;
du.uc[4] = 0x33; du.uc[5] = 0x44; du.uc[6] = 0x55; du.uc[7] = 0x66;
DUK_DBLUNION_BSWAP(&du);
du_diff = du.d - 2.008366013071895;
#if 0
DUK_FPRINTF(DUK_STDERR, "du_diff: %lg\n", (double) du_diff);
#endif
if (du_diff > 1e-15) {
/* Allow very small lenience because some compilers won't parse
* exact IEEE double constants (happened in matrix testing with
* Linux gcc-4.8 -m32 at least).
*/
#if 0
DUK_FPRINTF(DUK_STDERR, "Result of DUK_DBLUNION_BSWAP: %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]);
#endif
DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_DBLUNION_BSWAP");
}
}
/*
* Basic double / byte union memory layout.
*/
@ -227,6 +276,7 @@ DUK_INTERNAL void duk_selftest_run_tests(void) {
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();

2
src/duk_util.h

@ -67,4 +67,6 @@ DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx);
DUK_INTERNAL_DECL duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n);
DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr);
DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
#endif /* DUK_UTIL_H_INCLUDED */

19
src/duk_util_misc.c

@ -44,3 +44,22 @@ DUK_INTERNAL duk_int8_t duk_hex_dectab[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */
};
/*
* Arbitrary byteswap for potentially unaligned values
*
* Used to byteswap pointers e.g. in debugger code.
*/
DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) {
duk_uint8_t tmp;
duk_uint8_t *q = p + len - 1;
while (p - q < 0) {
tmp = *p;
*p = *q;
*q = tmp;
p++;
q--;
}
}

Loading…
Cancel
Save