1 /* 2 * Utilities 3 */ 4 5 #if !defined(DUK_UTIL_H_INCLUDED) 6 #define DUK_UTIL_H_INCLUDED 7 8 #if defined(DUK_USE_GET_RANDOM_DOUBLE) 9 #define DUK_UTIL_GET_RANDOM_DOUBLE(thr) DUK_USE_GET_RANDOM_DOUBLE((thr)->heap_udata) 10 #else 11 #define DUK_UTIL_GET_RANDOM_DOUBLE(thr) duk_util_tinyrandom_get_double(thr) 12 #endif 13 14 /* 15 * Some useful constants 16 */ 17 18 #define DUK_DOUBLE_2TO32 4294967296.0 19 #define DUK_DOUBLE_2TO31 2147483648.0 20 #define DUK_DOUBLE_LOG2E 1.4426950408889634 21 #define DUK_DOUBLE_LOG10E 0.4342944819032518 22 23 /* 24 * Endian conversion 25 */ 26 27 #if defined(DUK_USE_INTEGER_LE) 28 #define DUK_HTON32(x) DUK_BSWAP32((x)) 29 #define DUK_NTOH32(x) DUK_BSWAP32((x)) 30 #define DUK_HTON16(x) DUK_BSWAP16((x)) 31 #define DUK_NTOH16(x) DUK_BSWAP16((x)) 32 #elif defined(DUK_USE_INTEGER_BE) 33 #define DUK_HTON32(x) (x) 34 #define DUK_NTOH32(x) (x) 35 #define DUK_HTON16(x) (x) 36 #define DUK_NTOH16(x) (x) 37 #else 38 #error internal error, endianness defines broken 39 #endif 40 41 /* 42 * Bitstream decoder 43 */ 44 45 struct duk_bitdecoder_ctx { 46 const duk_uint8_t *data; 47 duk_size_t offset; 48 duk_size_t length; 49 duk_uint32_t currval; 50 duk_small_int_t currbits; 51 }; 52 53 #define DUK_BD_BITPACKED_STRING_MAXLEN 256 54 55 /* 56 * Bitstream encoder 57 */ 58 59 struct duk_bitencoder_ctx { 60 duk_uint8_t *data; 61 duk_size_t offset; 62 duk_size_t length; 63 duk_uint32_t currval; 64 duk_small_int_t currbits; 65 duk_small_int_t truncated; 66 }; 67 68 /* 69 * Raw write/read macros for big endian, unaligned basic values. 70 * Caller ensures there's enough space. The INC macro variants 71 * update the pointer argument automatically. 72 */ 73 74 #define DUK_RAW_WRITE_U8(ptr,val) do { \ 75 *(ptr) = (duk_uint8_t) (val); \ 76 } while (0) 77 #define DUK_RAW_WRITE_U16_BE(ptr,val) duk_raw_write_u16_be((ptr), (duk_uint16_t) (val)) 78 #define DUK_RAW_WRITE_U32_BE(ptr,val) duk_raw_write_u32_be((ptr), (duk_uint32_t) (val)) 79 #define DUK_RAW_WRITE_FLOAT_BE(ptr,val) duk_raw_write_float_be((ptr), (duk_float_t) (val)) 80 #define DUK_RAW_WRITE_DOUBLE_BE(ptr,val) duk_raw_write_double_be((ptr), (duk_double_t) (val)) 81 #define DUK_RAW_WRITE_XUTF8(ptr,val) duk_raw_write_xutf8((ptr), (duk_ucodepoint_t) (val)) 82 83 #define DUK_RAW_WRITEINC_U8(ptr,val) do { \ 84 *(ptr)++ = (duk_uint8_t) (val); \ 85 } while (0) 86 #define DUK_RAW_WRITEINC_U16_BE(ptr,val) duk_raw_writeinc_u16_be(&(ptr), (duk_uint16_t) (val)) 87 #define DUK_RAW_WRITEINC_U32_BE(ptr,val) duk_raw_writeinc_u32_be(&(ptr), (duk_uint32_t) (val)) 88 #define DUK_RAW_WRITEINC_FLOAT_BE(ptr,val) duk_raw_writeinc_float_be(&(ptr), (duk_float_t) (val)) 89 #define DUK_RAW_WRITEINC_DOUBLE_BE(ptr,val) duk_raw_writeinc_double_be(&(ptr), (duk_double_t) (val)) 90 #define DUK_RAW_WRITEINC_XUTF8(ptr,val) duk_raw_writeinc_xutf8(&(ptr), (duk_ucodepoint_t) (val)) 91 #define DUK_RAW_WRITEINC_CESU8(ptr,val) duk_raw_writeinc_cesu8(&(ptr), (duk_ucodepoint_t) (val)) 92 93 #define DUK_RAW_READ_U8(ptr) ((duk_uint8_t) (*(ptr))) 94 #define DUK_RAW_READ_U16_BE(ptr) duk_raw_read_u16_be((ptr)); 95 #define DUK_RAW_READ_U32_BE(ptr) duk_raw_read_u32_be((ptr)); 96 #define DUK_RAW_READ_DOUBLE_BE(ptr) duk_raw_read_double_be((ptr)); 97 98 #define DUK_RAW_READINC_U8(ptr) ((duk_uint8_t) (*(ptr)++)) 99 #define DUK_RAW_READINC_U16_BE(ptr) duk_raw_readinc_u16_be(&(ptr)); 100 #define DUK_RAW_READINC_U32_BE(ptr) duk_raw_readinc_u32_be(&(ptr)); 101 #define DUK_RAW_READINC_DOUBLE_BE(ptr) duk_raw_readinc_double_be(&(ptr)); 102 103 /* 104 * Double and float byte order operations. 105 */ 106 107 DUK_INTERNAL_DECL void duk_dblunion_host_to_little(duk_double_union *u); 108 DUK_INTERNAL_DECL void duk_dblunion_little_to_host(duk_double_union *u); 109 DUK_INTERNAL_DECL void duk_dblunion_host_to_big(duk_double_union *u); 110 DUK_INTERNAL_DECL void duk_dblunion_big_to_host(duk_double_union *u); 111 DUK_INTERNAL_DECL void duk_fltunion_host_to_big(duk_float_union *u); 112 DUK_INTERNAL_DECL void duk_fltunion_big_to_host(duk_float_union *u); 113 114 /* 115 * Buffer writer (dynamic buffer only) 116 * 117 * Helper for writing to a dynamic buffer with a concept of a "slack" area 118 * to reduce resizes. You can ensure there is enough space beforehand and 119 * then write for a while without further checks, relying on a stable data 120 * pointer. Slack handling is automatic so call sites only indicate how 121 * much data they need right now. 122 * 123 * There are several ways to write using bufwriter. The best approach 124 * depends mainly on how much performance matters over code footprint. 125 * The key issues are (1) ensuring there is space and (2) keeping the 126 * pointers consistent. Fast code should ensure space for multiple writes 127 * with one ensure call. Fastest inner loop code can temporarily borrow 128 * the 'p' pointer but must write it back eventually. 129 * 130 * Be careful to ensure all macro arguments (other than static pointers like 131 * 'thr' and 'bw_ctx') are evaluated exactly once, using temporaries if 132 * necessary (if that's not possible, there should be a note near the macro). 133 * Buffer write arguments often contain arithmetic etc so this is 134 * particularly important here. 135 */ 136 137 /* XXX: Migrate bufwriter and other read/write helpers to its own header? */ 138 139 struct duk_bufwriter_ctx { 140 duk_uint8_t *p; 141 duk_uint8_t *p_base; 142 duk_uint8_t *p_limit; 143 duk_hbuffer_dynamic *buf; 144 }; 145 146 #if defined(DUK_USE_PREFER_SIZE) 147 #define DUK_BW_SLACK_ADD 64 148 #define DUK_BW_SLACK_SHIFT 4 /* 2^4 -> 1/16 = 6.25% slack */ 149 #else 150 #define DUK_BW_SLACK_ADD 64 151 #define DUK_BW_SLACK_SHIFT 2 /* 2^2 -> 1/4 = 25% slack */ 152 #endif 153 154 /* Initialization and finalization (compaction), converting to other types. */ 155 156 #define DUK_BW_INIT_PUSHBUF(thr,bw_ctx,sz) do { \ 157 duk_bw_init_pushbuf((thr), (bw_ctx), (sz)); \ 158 } while (0) 159 #define DUK_BW_INIT_WITHBUF(thr,bw_ctx,buf) do { \ 160 duk_bw_init((thr), (bw_ctx), (buf)); \ 161 } while (0) 162 #define DUK_BW_COMPACT(thr,bw_ctx) do { \ 163 /* Make underlying buffer compact to match DUK_BW_GET_SIZE(). */ \ 164 duk_bw_compact((thr), (bw_ctx)); \ 165 } while (0) 166 #define DUK_BW_PUSH_AS_STRING(thr,bw_ctx) do { \ 167 duk_push_lstring((thr), \ 168 (const char *) (bw_ctx)->p_base, \ 169 (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \ 170 } while (0) 171 172 /* Pointers may be NULL for a while when 'buf' size is zero and before any 173 * ENSURE calls have been made. Once an ENSURE has been made, the pointers 174 * are required to be non-NULL so that it's always valid to use memcpy() and 175 * memmove(), even for zero size. 176 */ 177 #if defined(DUK_USE_ASSERTIONS) 178 DUK_INTERNAL_DECL void duk_bw_assert_valid(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx); 179 #define DUK_BW_ASSERT_VALID_EXPR(thr,bw_ctx) (duk_bw_assert_valid((thr), (bw_ctx))) 180 #define DUK_BW_ASSERT_VALID(thr,bw_ctx) do { duk_bw_assert_valid((thr), (bw_ctx)); } while (0) 181 #else 182 #define DUK_BW_ASSERT_VALID_EXPR(thr,bw_ctx) DUK_ASSERT_EXPR(1) 183 #define DUK_BW_ASSERT_VALID(thr,bw_ctx) do {} while (0) 184 #endif 185 186 /* Working with the pointer and current size. */ 187 188 #define DUK_BW_GET_PTR(thr,bw_ctx) \ 189 ((bw_ctx)->p) 190 #define DUK_BW_SET_PTR(thr,bw_ctx,ptr) do { \ 191 (bw_ctx)->p = (ptr); \ 192 } while (0) 193 #define DUK_BW_ADD_PTR(thr,bw_ctx,delta) do { \ 194 (bw_ctx)->p += (delta); \ 195 } while (0) 196 #define DUK_BW_GET_BASEPTR(thr,bw_ctx) \ 197 ((bw_ctx)->p_base) 198 #define DUK_BW_GET_LIMITPTR(thr,bw_ctx) \ 199 ((bw_ctx)->p_limit) 200 #define DUK_BW_GET_SIZE(thr,bw_ctx) \ 201 ((duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)) 202 #define DUK_BW_SET_SIZE(thr,bw_ctx,sz) do { \ 203 DUK_ASSERT((duk_size_t) (sz) <= (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \ 204 (bw_ctx)->p = (bw_ctx)->p_base + (sz); \ 205 } while (0) 206 #define DUK_BW_RESET_SIZE(thr,bw_ctx) do { \ 207 /* Reset to zero size, keep current limit. */ \ 208 (bw_ctx)->p = (bw_ctx)->p_base; \ 209 } while (0) 210 #define DUK_BW_GET_BUFFER(thr,bw_ctx) \ 211 ((bw_ctx)->buf) 212 213 /* Ensuring (reserving) space. */ 214 215 #define DUK_BW_ENSURE(thr,bw_ctx,sz) do { \ 216 duk_size_t duk__sz, duk__space; \ 217 DUK_BW_ASSERT_VALID((thr), (bw_ctx)); \ 218 duk__sz = (sz); \ 219 duk__space = (duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p); \ 220 if (duk__space < duk__sz) { \ 221 (void) duk_bw_resize((thr), (bw_ctx), duk__sz); \ 222 } \ 223 } while (0) 224 /* NOTE: Multiple evaluation of 'ptr' in this macro. */ 225 /* XXX: Rework to use an always-inline function? */ 226 #define DUK_BW_ENSURE_RAW(thr,bw_ctx,sz,ptr) \ 227 (((duk_size_t) ((bw_ctx)->p_limit - (ptr)) >= (sz)) ? \ 228 (ptr) : \ 229 ((bw_ctx)->p = (ptr), duk_bw_resize((thr),(bw_ctx),(sz)))) 230 #define DUK_BW_ENSURE_GETPTR(thr,bw_ctx,sz) \ 231 DUK_BW_ENSURE_RAW((thr), (bw_ctx), (sz), (bw_ctx)->p) 232 #define DUK_BW_ASSERT_SPACE_EXPR(thr,bw_ctx,sz) \ 233 (DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)), \ 234 DUK_ASSERT_EXPR((duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p) >= (duk_size_t) (sz))) 235 #define DUK_BW_ASSERT_SPACE(thr,bw_ctx,sz) do { \ 236 DUK_BW_ASSERT_SPACE_EXPR((thr), (bw_ctx), (sz)); \ 237 } while (0) 238 239 /* Miscellaneous. */ 240 241 #define DUK_BW_SETPTR_AND_COMPACT(thr,bw_ctx,ptr) do { \ 242 (bw_ctx)->p = (ptr); \ 243 duk_bw_compact((thr), (bw_ctx)); \ 244 } while (0) 245 246 /* Fast write calls which assume you control the slack beforehand. 247 * Multibyte write variants exist and use a temporary write pointer 248 * because byte writes alias with anything: with a stored pointer 249 * explicit pointer load/stores get generated (e.g. gcc -Os). 250 */ 251 252 #define DUK_BW_WRITE_RAW_U8(thr,bw_ctx,val) do { \ 253 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 1); \ 254 *(bw_ctx)->p++ = (duk_uint8_t) (val); \ 255 } while (0) 256 #define DUK_BW_WRITE_RAW_U8_2(thr,bw_ctx,val1,val2) do { \ 257 duk_uint8_t *duk__p; \ 258 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 2); \ 259 duk__p = (bw_ctx)->p; \ 260 *duk__p++ = (duk_uint8_t) (val1); \ 261 *duk__p++ = (duk_uint8_t) (val2); \ 262 (bw_ctx)->p = duk__p; \ 263 } while (0) 264 #define DUK_BW_WRITE_RAW_U8_3(thr,bw_ctx,val1,val2,val3) do { \ 265 duk_uint8_t *duk__p; \ 266 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 3); \ 267 duk__p = (bw_ctx)->p; \ 268 *duk__p++ = (duk_uint8_t) (val1); \ 269 *duk__p++ = (duk_uint8_t) (val2); \ 270 *duk__p++ = (duk_uint8_t) (val3); \ 271 (bw_ctx)->p = duk__p; \ 272 } while (0) 273 #define DUK_BW_WRITE_RAW_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \ 274 duk_uint8_t *duk__p; \ 275 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 4); \ 276 duk__p = (bw_ctx)->p; \ 277 *duk__p++ = (duk_uint8_t) (val1); \ 278 *duk__p++ = (duk_uint8_t) (val2); \ 279 *duk__p++ = (duk_uint8_t) (val3); \ 280 *duk__p++ = (duk_uint8_t) (val4); \ 281 (bw_ctx)->p = duk__p; \ 282 } while (0) 283 #define DUK_BW_WRITE_RAW_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \ 284 duk_uint8_t *duk__p; \ 285 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 5); \ 286 duk__p = (bw_ctx)->p; \ 287 *duk__p++ = (duk_uint8_t) (val1); \ 288 *duk__p++ = (duk_uint8_t) (val2); \ 289 *duk__p++ = (duk_uint8_t) (val3); \ 290 *duk__p++ = (duk_uint8_t) (val4); \ 291 *duk__p++ = (duk_uint8_t) (val5); \ 292 (bw_ctx)->p = duk__p; \ 293 } while (0) 294 #define DUK_BW_WRITE_RAW_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \ 295 duk_uint8_t *duk__p; \ 296 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 6); \ 297 duk__p = (bw_ctx)->p; \ 298 *duk__p++ = (duk_uint8_t) (val1); \ 299 *duk__p++ = (duk_uint8_t) (val2); \ 300 *duk__p++ = (duk_uint8_t) (val3); \ 301 *duk__p++ = (duk_uint8_t) (val4); \ 302 *duk__p++ = (duk_uint8_t) (val5); \ 303 *duk__p++ = (duk_uint8_t) (val6); \ 304 (bw_ctx)->p = duk__p; \ 305 } while (0) 306 #define DUK_BW_WRITE_RAW_XUTF8(thr,bw_ctx,cp) do { \ 307 duk_ucodepoint_t duk__cp; \ 308 duk_small_int_t duk__enc_len; \ 309 duk__cp = (duk_ucodepoint_t) (cp); \ 310 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_xutf8_length(duk__cp)); \ 311 duk__enc_len = duk_unicode_encode_xutf8(duk__cp, (bw_ctx)->p); \ 312 (bw_ctx)->p += duk__enc_len; \ 313 } while (0) 314 #define DUK_BW_WRITE_RAW_CESU8(thr,bw_ctx,cp) do { \ 315 duk_ucodepoint_t duk__cp; \ 316 duk_small_int_t duk__enc_len; \ 317 duk__cp = (duk_ucodepoint_t) (cp); \ 318 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_cesu8_length(duk__cp)); \ 319 duk__enc_len = duk_unicode_encode_cesu8(duk__cp, (bw_ctx)->p); \ 320 (bw_ctx)->p += duk__enc_len; \ 321 } while (0) 322 /* XXX: add temporary duk__p pointer here too; sharing */ 323 /* XXX: avoid unsafe variants */ 324 #define DUK_BW_WRITE_RAW_BYTES(thr,bw_ctx,valptr,valsz) do { \ 325 const void *duk__valptr; \ 326 duk_size_t duk__valsz; \ 327 duk__valptr = (const void *) (valptr); \ 328 duk__valsz = (duk_size_t) (valsz); \ 329 duk_memcpy_unsafe((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \ 330 (bw_ctx)->p += duk__valsz; \ 331 } while (0) 332 #define DUK_BW_WRITE_RAW_CSTRING(thr,bw_ctx,val) do { \ 333 const duk_uint8_t *duk__val; \ 334 duk_size_t duk__val_len; \ 335 duk__val = (const duk_uint8_t *) (val); \ 336 duk__val_len = DUK_STRLEN((const char *) duk__val); \ 337 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \ 338 (bw_ctx)->p += duk__val_len; \ 339 } while (0) 340 #define DUK_BW_WRITE_RAW_HSTRING(thr,bw_ctx,val) do { \ 341 duk_size_t duk__val_len; \ 342 duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \ 343 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \ 344 (bw_ctx)->p += duk__val_len; \ 345 } while (0) 346 #define DUK_BW_WRITE_RAW_HBUFFER(thr,bw_ctx,val) do { \ 347 duk_size_t duk__val_len; \ 348 duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \ 349 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ 350 (bw_ctx)->p += duk__val_len; \ 351 } while (0) 352 #define DUK_BW_WRITE_RAW_HBUFFER_FIXED(thr,bw_ctx,val) do { \ 353 duk_size_t duk__val_len; \ 354 duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \ 355 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ 356 (bw_ctx)->p += duk__val_len; \ 357 } while (0) 358 #define DUK_BW_WRITE_RAW_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \ 359 duk_size_t duk__val_len; \ 360 duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \ 361 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ 362 (bw_ctx)->p += duk__val_len; \ 363 } while (0) 364 365 /* Append bytes from a slice already in the buffer. */ 366 #define DUK_BW_WRITE_RAW_SLICE(thr,bw,dst_off,dst_len) \ 367 duk_bw_write_raw_slice((thr), (bw), (dst_off), (dst_len)) 368 369 /* Insert bytes in the middle of the buffer from an external buffer. */ 370 #define DUK_BW_INSERT_RAW_BYTES(thr,bw,dst_off,buf,len) \ 371 duk_bw_insert_raw_bytes((thr), (bw), (dst_off), (buf), (len)) 372 373 /* Insert bytes in the middle of the buffer from a slice already 374 * in the buffer. Source offset is interpreted "before" the operation. 375 */ 376 #define DUK_BW_INSERT_RAW_SLICE(thr,bw,dst_off,src_off,len) \ 377 duk_bw_insert_raw_slice((thr), (bw), (dst_off), (src_off), (len)) 378 379 /* Insert a reserved area somewhere in the buffer; caller fills it. 380 * Evaluates to a (duk_uint_t *) pointing to the start of the reserved 381 * area for convenience. 382 */ 383 #define DUK_BW_INSERT_RAW_AREA(thr,bw,off,len) \ 384 duk_bw_insert_raw_area((thr), (bw), (off), (len)) 385 386 /* Remove a slice from inside buffer. */ 387 #define DUK_BW_REMOVE_RAW_SLICE(thr,bw,off,len) \ 388 duk_bw_remove_raw_slice((thr), (bw), (off), (len)) 389 390 /* Safe write calls which will ensure space first. */ 391 392 #define DUK_BW_WRITE_ENSURE_U8(thr,bw_ctx,val) do { \ 393 DUK_BW_ENSURE((thr), (bw_ctx), 1); \ 394 DUK_BW_WRITE_RAW_U8((thr), (bw_ctx), (val)); \ 395 } while (0) 396 #define DUK_BW_WRITE_ENSURE_U8_2(thr,bw_ctx,val1,val2) do { \ 397 DUK_BW_ENSURE((thr), (bw_ctx), 2); \ 398 DUK_BW_WRITE_RAW_U8_2((thr), (bw_ctx), (val1), (val2)); \ 399 } while (0) 400 #define DUK_BW_WRITE_ENSURE_U8_3(thr,bw_ctx,val1,val2,val3) do { \ 401 DUK_BW_ENSURE((thr), (bw_ctx), 3); \ 402 DUK_BW_WRITE_RAW_U8_3((thr), (bw_ctx), (val1), (val2), (val3)); \ 403 } while (0) 404 #define DUK_BW_WRITE_ENSURE_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \ 405 DUK_BW_ENSURE((thr), (bw_ctx), 4); \ 406 DUK_BW_WRITE_RAW_U8_4((thr), (bw_ctx), (val1), (val2), (val3), (val4)); \ 407 } while (0) 408 #define DUK_BW_WRITE_ENSURE_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \ 409 DUK_BW_ENSURE((thr), (bw_ctx), 5); \ 410 DUK_BW_WRITE_RAW_U8_5((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5)); \ 411 } while (0) 412 #define DUK_BW_WRITE_ENSURE_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \ 413 DUK_BW_ENSURE((thr), (bw_ctx), 6); \ 414 DUK_BW_WRITE_RAW_U8_6((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5), (val6)); \ 415 } while (0) 416 #define DUK_BW_WRITE_ENSURE_XUTF8(thr,bw_ctx,cp) do { \ 417 DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_XUTF8_LENGTH); \ 418 DUK_BW_WRITE_RAW_XUTF8((thr), (bw_ctx), (cp)); \ 419 } while (0) 420 #define DUK_BW_WRITE_ENSURE_CESU8(thr,bw_ctx,cp) do { \ 421 DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_CESU8_LENGTH); \ 422 DUK_BW_WRITE_RAW_CESU8((thr), (bw_ctx), (cp)); \ 423 } while (0) 424 /* XXX: add temporary duk__p pointer here too; sharing */ 425 /* XXX: avoid unsafe */ 426 #define DUK_BW_WRITE_ENSURE_BYTES(thr,bw_ctx,valptr,valsz) do { \ 427 const void *duk__valptr; \ 428 duk_size_t duk__valsz; \ 429 duk__valptr = (const void *) (valptr); \ 430 duk__valsz = (duk_size_t) (valsz); \ 431 DUK_BW_ENSURE((thr), (bw_ctx), duk__valsz); \ 432 duk_memcpy_unsafe((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \ 433 (bw_ctx)->p += duk__valsz; \ 434 } while (0) 435 #define DUK_BW_WRITE_ENSURE_CSTRING(thr,bw_ctx,val) do { \ 436 const duk_uint8_t *duk__val; \ 437 duk_size_t duk__val_len; \ 438 duk__val = (const duk_uint8_t *) (val); \ 439 duk__val_len = DUK_STRLEN((const char *) duk__val); \ 440 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ 441 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \ 442 (bw_ctx)->p += duk__val_len; \ 443 } while (0) 444 #define DUK_BW_WRITE_ENSURE_HSTRING(thr,bw_ctx,val) do { \ 445 duk_size_t duk__val_len; \ 446 duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \ 447 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ 448 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \ 449 (bw_ctx)->p += duk__val_len; \ 450 } while (0) 451 #define DUK_BW_WRITE_ENSURE_HBUFFER(thr,bw_ctx,val) do { \ 452 duk_size_t duk__val_len; \ 453 duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \ 454 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ 455 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ 456 (bw_ctx)->p += duk__val_len; \ 457 } while (0) 458 #define DUK_BW_WRITE_ENSURE_HBUFFER_FIXED(thr,bw_ctx,val) do { \ 459 duk_size_t duk__val_len; \ 460 duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \ 461 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ 462 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ 463 (bw_ctx)->p += duk__val_len; \ 464 } while (0) 465 #define DUK_BW_WRITE_ENSURE_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \ 466 duk_size_t duk__val_len; \ 467 duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \ 468 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ 469 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ 470 (bw_ctx)->p += duk__val_len; \ 471 } while (0) 472 473 #define DUK_BW_WRITE_ENSURE_SLICE(thr,bw,dst_off,dst_len) \ 474 duk_bw_write_ensure_slice((thr), (bw), (dst_off), (dst_len)) 475 #define DUK_BW_INSERT_ENSURE_BYTES(thr,bw,dst_off,buf,len) \ 476 duk_bw_insert_ensure_bytes((thr), (bw), (dst_off), (buf), (len)) 477 #define DUK_BW_INSERT_ENSURE_SLICE(thr,bw,dst_off,src_off,len) \ 478 duk_bw_insert_ensure_slice((thr), (bw), (dst_off), (src_off), (len)) 479 #define DUK_BW_INSERT_ENSURE_AREA(thr,bw,off,len) \ 480 /* Evaluates to (duk_uint8_t *) pointing to start of area. */ \ 481 duk_bw_insert_ensure_area((thr), (bw), (off), (len)) 482 #define DUK_BW_REMOVE_ENSURE_SLICE(thr,bw,off,len) \ 483 /* No difference between raw/ensure because the buffer shrinks. */ \ 484 DUK_BW_REMOVE_RAW_SLICE((thr), (bw), (off), (len)) 485 486 /* 487 * Externs and prototypes 488 */ 489 490 #if !defined(DUK_SINGLE_FILE) 491 DUK_INTERNAL_DECL const duk_uint8_t duk_lc_digits[36]; 492 DUK_INTERNAL_DECL const duk_uint8_t duk_uc_nybbles[16]; 493 DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256]; 494 #if defined(DUK_USE_HEX_FASTPATH) 495 DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256]; 496 DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256]; 497 #endif 498 #endif /* !DUK_SINGLE_FILE */ 499 500 /* Note: assumes that duk_util_probe_steps size is 32 */ 501 #if defined(DUK_USE_HOBJECT_HASH_PART) 502 #if !defined(DUK_SINGLE_FILE) 503 DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32]; 504 #endif /* !DUK_SINGLE_FILE */ 505 #endif 506 507 #if defined(DUK_USE_STRHASH_DENSE) 508 DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed); 509 #endif 510 511 DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits); 512 DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx); 513 DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value); 514 DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value); 515 DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx); 516 DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out); 517 518 DUK_INTERNAL_DECL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits); 519 DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx); 520 521 #if !defined(DUK_USE_GET_RANDOM_DOUBLE) 522 DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr); 523 DUK_INTERNAL_DECL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr); 524 #endif 525 526 DUK_INTERNAL_DECL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf); 527 DUK_INTERNAL_DECL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size); 528 DUK_INTERNAL_DECL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz); 529 DUK_INTERNAL_DECL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx); 530 DUK_INTERNAL_DECL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len); 531 DUK_INTERNAL_DECL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len); 532 DUK_INTERNAL_DECL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len); 533 DUK_INTERNAL_DECL void duk_bw_insert_ensure_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len); 534 DUK_INTERNAL_DECL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len); 535 DUK_INTERNAL_DECL void duk_bw_insert_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len); 536 DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); 537 DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); 538 DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); 539 /* No duk_bw_remove_ensure_slice(), functionality would be identical. */ 540 541 DUK_INTERNAL_DECL duk_uint16_t duk_raw_read_u16_be(const duk_uint8_t *p); 542 DUK_INTERNAL_DECL duk_uint32_t duk_raw_read_u32_be(const duk_uint8_t *p); 543 DUK_INTERNAL_DECL duk_float_t duk_raw_read_float_be(const duk_uint8_t *p); 544 DUK_INTERNAL_DECL duk_double_t duk_raw_read_double_be(const duk_uint8_t *p); 545 DUK_INTERNAL_DECL duk_uint16_t duk_raw_readinc_u16_be(const duk_uint8_t **p); 546 DUK_INTERNAL_DECL duk_uint32_t duk_raw_readinc_u32_be(const duk_uint8_t **p); 547 DUK_INTERNAL_DECL duk_float_t duk_raw_readinc_float_be(const duk_uint8_t **p); 548 DUK_INTERNAL_DECL duk_double_t duk_raw_readinc_double_be(const duk_uint8_t **p); 549 DUK_INTERNAL_DECL void duk_raw_write_u16_be(duk_uint8_t *p, duk_uint16_t val); 550 DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t *p, duk_uint32_t val); 551 DUK_INTERNAL_DECL void duk_raw_write_float_be(duk_uint8_t *p, duk_float_t val); 552 DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t *p, duk_double_t val); 553 DUK_INTERNAL_DECL duk_small_int_t duk_raw_write_xutf8(duk_uint8_t *p, duk_ucodepoint_t val); 554 DUK_INTERNAL_DECL duk_small_int_t duk_raw_write_cesu8(duk_uint8_t *p, duk_ucodepoint_t val); 555 DUK_INTERNAL_DECL void duk_raw_writeinc_u16_be(duk_uint8_t **p, duk_uint16_t val); 556 DUK_INTERNAL_DECL void duk_raw_writeinc_u32_be(duk_uint8_t **p, duk_uint32_t val); 557 DUK_INTERNAL_DECL void duk_raw_writeinc_float_be(duk_uint8_t **p, duk_float_t val); 558 DUK_INTERNAL_DECL void duk_raw_writeinc_double_be(duk_uint8_t **p, duk_double_t val); 559 DUK_INTERNAL_DECL void duk_raw_writeinc_xutf8(duk_uint8_t **p, duk_ucodepoint_t val); 560 DUK_INTERNAL_DECL void duk_raw_writeinc_cesu8(duk_uint8_t **p, duk_ucodepoint_t val); 561 562 #if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */ 563 DUK_INTERNAL_DECL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len); 564 #endif 565 566 /* memcpy(), memmove() etc wrappers. The plain variants like duk_memcpy() 567 * assume C99+ and 'src' and 'dst' pointers must be non-NULL even when the 568 * operation size is zero. The unsafe variants like duk_memcpy_safe() deal 569 * with the zero size case explicitly, and allow NULL pointers in that case 570 * (which is undefined behavior in C99+). For the majority of actual targets 571 * a NULL pointer with a zero length is fine in practice. These wrappers are 572 * macros to force inlining; because there are hundreds of call sites, even a 573 * few extra bytes per call site adds up to ~1kB footprint. 574 */ 575 #if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) 576 #define duk_memcpy(dst,src,len) do { \ 577 void *duk__dst = (dst); \ 578 const void *duk__src = (src); \ 579 duk_size_t duk__len = (len); \ 580 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ 581 DUK_ASSERT(duk__src != NULL || duk__len == 0U); \ 582 (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \ 583 } while (0) 584 #define duk_memcpy_unsafe(dst,src,len) duk_memcpy((dst), (src), (len)) 585 #define duk_memmove(dst,src,len) do { \ 586 void *duk__dst = (dst); \ 587 const void *duk__src = (src); \ 588 duk_size_t duk__len = (len); \ 589 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ 590 DUK_ASSERT(duk__src != NULL || duk__len == 0U); \ 591 (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \ 592 } while (0) 593 #define duk_memmove_unsafe(dst,src,len) duk_memmove((dst), (src), (len)) 594 #define duk_memset(dst,val,len) do { \ 595 void *duk__dst = (dst); \ 596 duk_small_int_t duk__val = (val); \ 597 duk_size_t duk__len = (len); \ 598 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ 599 (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \ 600 } while (0) 601 #define duk_memset_unsafe(dst,val,len) duk_memset((dst), (val), (len)) 602 #define duk_memzero(dst,len) do { \ 603 void *duk__dst = (dst); \ 604 duk_size_t duk__len = (len); \ 605 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ 606 (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \ 607 } while (0) 608 #define duk_memzero_unsafe(dst,len) duk_memzero((dst), (len)) 609 #else /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */ 610 #define duk_memcpy(dst,src,len) do { \ 611 void *duk__dst = (dst); \ 612 const void *duk__src = (src); \ 613 duk_size_t duk__len = (len); \ 614 DUK_ASSERT(duk__dst != NULL); \ 615 DUK_ASSERT(duk__src != NULL); \ 616 (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \ 617 } while (0) 618 #define duk_memcpy_unsafe(dst,src,len) do { \ 619 void *duk__dst = (dst); \ 620 const void *duk__src = (src); \ 621 duk_size_t duk__len = (len); \ 622 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ 623 DUK_ASSERT(duk__src != NULL || duk__len == 0U); \ 624 if (DUK_LIKELY(duk__len > 0U)) { \ 625 DUK_ASSERT(duk__dst != NULL); \ 626 DUK_ASSERT(duk__src != NULL); \ 627 (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \ 628 } \ 629 } while (0) 630 #define duk_memmove(dst,src,len) do { \ 631 void *duk__dst = (dst); \ 632 const void *duk__src = (src); \ 633 duk_size_t duk__len = (len); \ 634 DUK_ASSERT(duk__dst != NULL); \ 635 DUK_ASSERT(duk__src != NULL); \ 636 (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \ 637 } while (0) 638 #define duk_memmove_unsafe(dst,src,len) do { \ 639 void *duk__dst = (dst); \ 640 const void *duk__src = (src); \ 641 duk_size_t duk__len = (len); \ 642 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ 643 DUK_ASSERT(duk__src != NULL || duk__len == 0U); \ 644 if (DUK_LIKELY(duk__len > 0U)) { \ 645 DUK_ASSERT(duk__dst != NULL); \ 646 DUK_ASSERT(duk__src != NULL); \ 647 (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \ 648 } \ 649 } while (0) 650 #define duk_memset(dst,val,len) do { \ 651 void *duk__dst = (dst); \ 652 duk_small_int_t duk__val = (val); \ 653 duk_size_t duk__len = (len); \ 654 DUK_ASSERT(duk__dst != NULL); \ 655 (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \ 656 } while (0) 657 #define duk_memset_unsafe(dst,val,len) do { \ 658 void *duk__dst = (dst); \ 659 duk_small_int_t duk__val = (val); \ 660 duk_size_t duk__len = (len); \ 661 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ 662 if (DUK_LIKELY(duk__len > 0U)) { \ 663 DUK_ASSERT(duk__dst != NULL); \ 664 (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \ 665 } \ 666 } while (0) 667 #define duk_memzero(dst,len) do { \ 668 void *duk__dst = (dst); \ 669 duk_size_t duk__len = (len); \ 670 DUK_ASSERT(duk__dst != NULL); \ 671 (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \ 672 } while (0) 673 #define duk_memzero_unsafe(dst,len) do { \ 674 void *duk__dst = (dst); \ 675 duk_size_t duk__len = (len); \ 676 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ 677 if (DUK_LIKELY(duk__len > 0U)) { \ 678 DUK_ASSERT(duk__dst != NULL); \ 679 (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \ 680 } \ 681 } while (0) 682 #endif /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */ 683 684 DUK_INTERNAL_DECL duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len); 685 DUK_INTERNAL_DECL duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len); 686 687 DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival); 688 DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival); 689 DUK_INTERNAL_DECL duk_bool_t duk_double_is_anyinf(duk_double_t x); 690 DUK_INTERNAL_DECL duk_bool_t duk_double_is_posinf(duk_double_t x); 691 DUK_INTERNAL_DECL duk_bool_t duk_double_is_neginf(duk_double_t x); 692 DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan(duk_double_t x); 693 DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x); 694 DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x); 695 DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x); 696 DUK_INTERNAL_DECL duk_small_uint_t duk_double_signbit(duk_double_t x); 697 DUK_INTERNAL_DECL duk_double_t duk_double_trunc_towards_zero(duk_double_t x); 698 DUK_INTERNAL_DECL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y); 699 DUK_INTERNAL_DECL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y); 700 DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y); 701 DUK_INTERNAL_DECL duk_bool_t duk_double_is_finite(duk_double_t x); 702 DUK_INTERNAL_DECL duk_bool_t duk_double_is_integer(duk_double_t x); 703 DUK_INTERNAL_DECL duk_bool_t duk_double_is_safe_integer(duk_double_t x); 704 705 DUK_INTERNAL_DECL duk_double_t duk_double_div(duk_double_t x, duk_double_t y); 706 DUK_INTERNAL_DECL duk_int_t duk_double_to_int_t(duk_double_t x); 707 DUK_INTERNAL_DECL duk_uint_t duk_double_to_uint_t(duk_double_t x); 708 DUK_INTERNAL_DECL duk_int32_t duk_double_to_int32_t(duk_double_t x); 709 DUK_INTERNAL_DECL duk_uint32_t duk_double_to_uint32_t(duk_double_t x); 710 DUK_INTERNAL_DECL duk_float_t duk_double_to_float_t(duk_double_t x); 711 DUK_INTERNAL_DECL duk_bool_t duk_double_equals(duk_double_t x, duk_double_t y); 712 DUK_INTERNAL_DECL duk_bool_t duk_float_equals(duk_float_t x, duk_float_t y); 713 714 /* 715 * Miscellaneous 716 */ 717 718 /* Example: x = 0x10 = 0b00010000 719 * x - 1 = 0x0f = 0b00001111 720 * x & (x - 1) == 0 721 * 722 * x = 0x07 = 0b00000111 723 * x - 1 = 0x06 = 0b00000110 724 * x & (x - 1) != 0 725 * 726 * However, incorrectly true for x == 0 so check for that explicitly. 727 */ 728 #define DUK_IS_POWER_OF_TWO(x) \ 729 ((x) != 0U && ((x) & ((x) - 1U)) == 0U) 730 731 #endif /* DUK_UTIL_H_INCLUDED */ 732