1 /* 2 * Tagged type definition (duk_tval) and accessor macros. 3 * 4 * Access all fields through the accessor macros, as the representation 5 * is quite tricky. 6 * 7 * There are two packed type alternatives: an 8-byte representation 8 * based on an IEEE double (preferred for compactness), and a 12-byte 9 * representation (portability). The latter is needed also in e.g. 10 * 64-bit environments (it usually pads to 16 bytes per value). 11 * 12 * Selecting the tagged type format involves many trade-offs (memory 13 * use, size and performance of generated code, portability, etc). 14 * 15 * NB: because macro arguments are often expressions, macros should 16 * avoid evaluating their argument more than once. 17 */ 18 19 #if !defined(DUK_TVAL_H_INCLUDED) 20 #define DUK_TVAL_H_INCLUDED 21 22 /* sanity */ 23 #if !defined(DUK_USE_DOUBLE_LE) && !defined(DUK_USE_DOUBLE_ME) && !defined(DUK_USE_DOUBLE_BE) 24 #error unsupported: cannot determine byte order variant 25 #endif 26 27 #if defined(DUK_USE_PACKED_TVAL) 28 /* ======================================================================== */ 29 30 /* 31 * Packed 8-byte representation 32 */ 33 34 /* use duk_double_union as duk_tval directly */ 35 typedef union duk_double_union duk_tval; 36 typedef struct { 37 duk_uint16_t a; 38 duk_uint16_t b; 39 duk_uint16_t c; 40 duk_uint16_t d; 41 } duk_tval_unused; 42 43 /* tags */ 44 #define DUK_TAG_NORMALIZED_NAN 0x7ff8UL /* the NaN variant we use */ 45 /* avoid tag 0xfff0, no risk of confusion with negative infinity */ 46 #define DUK_TAG_MIN 0xfff1UL 47 #if defined(DUK_USE_FASTINT) 48 #define DUK_TAG_FASTINT 0xfff1UL /* embed: integer value */ 49 #endif 50 #define DUK_TAG_UNUSED 0xfff2UL /* marker; not actual tagged value */ 51 #define DUK_TAG_UNDEFINED 0xfff3UL /* embed: nothing */ 52 #define DUK_TAG_NULL 0xfff4UL /* embed: nothing */ 53 #define DUK_TAG_BOOLEAN 0xfff5UL /* embed: 0 or 1 (false or true) */ 54 /* DUK_TAG_NUMBER would logically go here, but it has multiple 'tags' */ 55 #define DUK_TAG_POINTER 0xfff6UL /* embed: void ptr */ 56 #define DUK_TAG_LIGHTFUNC 0xfff7UL /* embed: func ptr */ 57 #define DUK_TAG_STRING 0xfff8UL /* embed: duk_hstring ptr */ 58 #define DUK_TAG_OBJECT 0xfff9UL /* embed: duk_hobject ptr */ 59 #define DUK_TAG_BUFFER 0xfffaUL /* embed: duk_hbuffer ptr */ 60 #define DUK_TAG_MAX 0xfffaUL 61 62 /* for convenience */ 63 #define DUK_XTAG_BOOLEAN_FALSE 0xfff50000UL 64 #define DUK_XTAG_BOOLEAN_TRUE 0xfff50001UL 65 66 #define DUK_TVAL_IS_VALID_TAG(tv) \ 67 (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN) 68 69 /* DUK_TVAL_UNUSED initializer for duk_tval_unused, works for any endianness. */ 70 #define DUK_TVAL_UNUSED_INITIALIZER() \ 71 { DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED } 72 73 /* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */ 74 #if defined(DUK_USE_64BIT_OPS) 75 #if defined(DUK_USE_DOUBLE_ME) 76 #define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \ 77 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \ 78 } while (0) 79 #else 80 #define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \ 81 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \ 82 } while (0) 83 #endif 84 #else /* DUK_USE_64BIT_OPS */ 85 #define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \ 86 duk_tval *duk__tv; \ 87 duk__tv = (tv); \ 88 duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \ 89 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \ 90 } while (0) 91 #endif /* DUK_USE_64BIT_OPS */ 92 93 #if defined(DUK_USE_64BIT_OPS) 94 /* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */ 95 #if defined(DUK_USE_DOUBLE_ME) 96 #define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ 97 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \ 98 ((duk_uint64_t) (flags)) | \ 99 (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \ 100 } while (0) 101 #else 102 #define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ 103 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \ 104 (((duk_uint64_t) (flags)) << 32) | \ 105 ((duk_uint64_t) (duk_uint32_t) (fp)); \ 106 } while (0) 107 #endif 108 #else /* DUK_USE_64BIT_OPS */ 109 #define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ 110 duk_tval *duk__tv; \ 111 duk__tv = (tv); \ 112 duk__tv->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \ 113 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \ 114 } while (0) 115 #endif /* DUK_USE_64BIT_OPS */ 116 117 #if defined(DUK_USE_FASTINT) 118 /* Note: masking is done for 'i' to deal with negative numbers correctly */ 119 #if defined(DUK_USE_DOUBLE_ME) 120 #define DUK__TVAL_SET_I48(tv,i) do { \ 121 duk_tval *duk__tv; \ 122 duk__tv = (tv); \ 123 duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \ 124 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ 125 } while (0) 126 #define DUK__TVAL_SET_U32(tv,i) do { \ 127 duk_tval *duk__tv; \ 128 duk__tv = (tv); \ 129 duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \ 130 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ 131 } while (0) 132 #else 133 #define DUK__TVAL_SET_I48(tv,i) do { \ 134 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & DUK_U64_CONSTANT(0x0000ffffffffffff)); \ 135 } while (0) 136 #define DUK__TVAL_SET_U32(tv,i) do { \ 137 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \ 138 } while (0) 139 #endif 140 141 /* This needs to go through a cast because sign extension is needed. */ 142 #define DUK__TVAL_SET_I32(tv,i) do { \ 143 duk_int64_t duk__tmp = (duk_int64_t) (i); \ 144 DUK_TVAL_SET_I48((tv), duk__tmp); \ 145 } while (0) 146 147 /* XXX: Clumsy sign extend and masking of 16 topmost bits. */ 148 #if defined(DUK_USE_DOUBLE_ME) 149 #define DUK__TVAL_GET_FASTINT(tv) (((duk_int64_t) ((((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI0]) << 32) | ((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI1]))) << 16 >> 16) 150 #else 151 #define DUK__TVAL_GET_FASTINT(tv) ((((duk_int64_t) (tv)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16) 152 #endif 153 #define DUK__TVAL_GET_FASTINT_U32(tv) ((tv)->ui[DUK_DBL_IDX_UI1]) 154 #define DUK__TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) (tv)->ui[DUK_DBL_IDX_UI1]) 155 #endif /* DUK_USE_FASTINT */ 156 157 #define DUK_TVAL_SET_UNDEFINED(tv) do { \ 158 (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \ 159 } while (0) 160 #define DUK_TVAL_SET_UNUSED(tv) do { \ 161 (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \ 162 } while (0) 163 #define DUK_TVAL_SET_NULL(tv) do { \ 164 (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \ 165 } while (0) 166 167 #define DUK_TVAL_SET_BOOLEAN(tv,val) DUK_DBLUNION_SET_HIGH32((tv), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val))) 168 169 #define DUK_TVAL_SET_NAN(tv) DUK_DBLUNION_SET_NAN_FULL((tv)) 170 171 /* Assumes that caller has normalized NaNs, otherwise trouble ahead. */ 172 #if defined(DUK_USE_FASTINT) 173 #define DUK_TVAL_SET_DOUBLE(tv,d) do { \ 174 duk_double_t duk__dblval; \ 175 duk__dblval = (d); \ 176 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \ 177 DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \ 178 } while (0) 179 #define DUK_TVAL_SET_I48(tv,i) DUK__TVAL_SET_I48((tv), (i)) 180 #define DUK_TVAL_SET_I32(tv,i) DUK__TVAL_SET_I32((tv), (i)) 181 #define DUK_TVAL_SET_U32(tv,i) DUK__TVAL_SET_U32((tv), (i)) 182 #define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) duk_tval_set_number_chkfast_fast((tv), (d)) 183 #define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) duk_tval_set_number_chkfast_slow((tv), (d)) 184 #define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) 185 #define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \ 186 duk_tval *duk__tv; \ 187 duk_double_t duk__d; \ 188 duk__tv = (tv); \ 189 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ 190 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ 191 DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \ 192 } \ 193 } while (0) 194 #define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \ 195 duk_tval *duk__tv; \ 196 duk_double_t duk__d; \ 197 duk__tv = (tv); \ 198 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ 199 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ 200 DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \ 201 } \ 202 } while (0) 203 #else /* DUK_USE_FASTINT */ 204 #define DUK_TVAL_SET_DOUBLE(tv,d) do { \ 205 duk_double_t duk__dblval; \ 206 duk__dblval = (d); \ 207 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \ 208 DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \ 209 } while (0) 210 #define DUK_TVAL_SET_I48(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) /* XXX: fast int-to-double */ 211 #define DUK_TVAL_SET_I32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) 212 #define DUK_TVAL_SET_U32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) 213 #define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) 214 #define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) 215 #define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) 216 #define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0) 217 #define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0) 218 #endif /* DUK_USE_FASTINT */ 219 220 #define DUK_TVAL_SET_FASTINT(tv,i) DUK_TVAL_SET_I48((tv), (i)) /* alias */ 221 222 #define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) DUK__TVAL_SET_LIGHTFUNC((tv), (fp), (flags)) 223 #define DUK_TVAL_SET_STRING(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_STRING) 224 #define DUK_TVAL_SET_OBJECT(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_OBJECT) 225 #define DUK_TVAL_SET_BUFFER(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_BUFFER) 226 #define DUK_TVAL_SET_POINTER(tv,p) DUK__TVAL_SET_TAGGEDPOINTER((tv), (p), DUK_TAG_POINTER) 227 228 #define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0) 229 230 /* getters */ 231 #define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US1]) 232 #if defined(DUK_USE_FASTINT) 233 #define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d) 234 #define DUK_TVAL_GET_FASTINT(tv) DUK__TVAL_GET_FASTINT((tv)) 235 #define DUK_TVAL_GET_FASTINT_U32(tv) DUK__TVAL_GET_FASTINT_U32((tv)) 236 #define DUK_TVAL_GET_FASTINT_I32(tv) DUK__TVAL_GET_FASTINT_I32((tv)) 237 #define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_packed((tv)) 238 #else 239 #define DUK_TVAL_GET_NUMBER(tv) ((tv)->d) 240 #define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d) 241 #endif 242 #define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \ 243 (out_flags) = (tv)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \ 244 (out_fp) = (duk_c_function) (tv)->ui[DUK_DBL_IDX_UI1]; \ 245 } while (0) 246 #define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((duk_c_function) ((tv)->ui[DUK_DBL_IDX_UI1])) 247 #define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) (((duk_small_uint_t) (tv)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL) 248 #define DUK_TVAL_GET_STRING(tv) ((duk_hstring *) (tv)->vp[DUK_DBL_IDX_VP1]) 249 #define DUK_TVAL_GET_OBJECT(tv) ((duk_hobject *) (tv)->vp[DUK_DBL_IDX_VP1]) 250 #define DUK_TVAL_GET_BUFFER(tv) ((duk_hbuffer *) (tv)->vp[DUK_DBL_IDX_VP1]) 251 #define DUK_TVAL_GET_POINTER(tv) ((void *) (tv)->vp[DUK_DBL_IDX_VP1]) 252 #define DUK_TVAL_GET_HEAPHDR(tv) ((duk_heaphdr *) (tv)->vp[DUK_DBL_IDX_VP1]) 253 254 /* decoding */ 255 #define DUK_TVAL_GET_TAG(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US0]) 256 257 #define DUK_TVAL_IS_UNDEFINED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNDEFINED) 258 #define DUK_TVAL_IS_UNUSED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNUSED) 259 #define DUK_TVAL_IS_NULL(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_NULL) 260 #define DUK_TVAL_IS_BOOLEAN(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BOOLEAN) 261 #define DUK_TVAL_IS_BOOLEAN_TRUE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE) 262 #define DUK_TVAL_IS_BOOLEAN_FALSE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE) 263 #define DUK_TVAL_IS_LIGHTFUNC(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_LIGHTFUNC) 264 #define DUK_TVAL_IS_STRING(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_STRING) 265 #define DUK_TVAL_IS_OBJECT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_OBJECT) 266 #define DUK_TVAL_IS_BUFFER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BUFFER) 267 #define DUK_TVAL_IS_POINTER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_POINTER) 268 #if defined(DUK_USE_FASTINT) 269 /* 0xfff0 is -Infinity */ 270 #define DUK_TVAL_IS_DOUBLE(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL) 271 #define DUK_TVAL_IS_FASTINT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_FASTINT) 272 #define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff1UL) 273 #else 274 #define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL) 275 #define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv)) 276 #endif 277 278 /* This is performance critical because it appears in every DECREF. */ 279 #define DUK_TVAL_IS_HEAP_ALLOCATED(tv) (DUK_TVAL_GET_TAG((tv)) >= DUK_TAG_STRING) 280 281 #if defined(DUK_USE_FASTINT) 282 DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_packed(duk_tval *tv); 283 #endif 284 285 #else /* DUK_USE_PACKED_TVAL */ 286 /* ======================================================================== */ 287 288 /* 289 * Portable 12-byte representation 290 */ 291 292 /* Note: not initializing all bytes is normally not an issue: Duktape won't 293 * read or use the uninitialized bytes so valgrind won't issue warnings. 294 * In some special cases a harmless valgrind warning may be issued though. 295 * For example, the DumpHeap debugger command writes out a compiled function's 296 * 'data' area as is, including any uninitialized bytes, which causes a 297 * valgrind warning. 298 */ 299 300 typedef struct duk_tval_struct duk_tval; 301 302 struct duk_tval_struct { 303 duk_small_uint_t t; 304 duk_small_uint_t v_extra; 305 union { 306 duk_double_t d; 307 duk_small_int_t i; 308 #if defined(DUK_USE_FASTINT) 309 duk_int64_t fi; /* if present, forces 16-byte duk_tval */ 310 #endif 311 void *voidptr; 312 duk_hstring *hstring; 313 duk_hobject *hobject; 314 duk_hcompfunc *hcompfunc; 315 duk_hnatfunc *hnatfunc; 316 duk_hthread *hthread; 317 duk_hbuffer *hbuffer; 318 duk_heaphdr *heaphdr; 319 duk_c_function lightfunc; 320 } v; 321 }; 322 323 typedef struct { 324 duk_small_uint_t t; 325 duk_small_uint_t v_extra; 326 /* The rest of the fields don't matter except for debug dumps and such 327 * for which a partial initializer may trigger out-ot-bounds memory 328 * reads. Include a double field which is usually as large or larger 329 * than pointers (not always however). 330 */ 331 duk_double_t d; 332 } duk_tval_unused; 333 334 #define DUK_TVAL_UNUSED_INITIALIZER() \ 335 { DUK_TAG_UNUSED, 0, 0.0 } 336 337 #define DUK_TAG_MIN 0 338 #define DUK_TAG_NUMBER 0 /* DUK_TAG_NUMBER only defined for non-packed duk_tval */ 339 #if defined(DUK_USE_FASTINT) 340 #define DUK_TAG_FASTINT 1 341 #endif 342 #define DUK_TAG_UNDEFINED 2 343 #define DUK_TAG_NULL 3 344 #define DUK_TAG_BOOLEAN 4 345 #define DUK_TAG_POINTER 5 346 #define DUK_TAG_LIGHTFUNC 6 347 #define DUK_TAG_UNUSED 7 /* marker; not actual tagged type */ 348 #define DUK_TAG_STRING 8 /* first heap allocated, match bit boundary */ 349 #define DUK_TAG_OBJECT 9 350 #define DUK_TAG_BUFFER 10 351 #define DUK_TAG_MAX 10 352 353 #define DUK_TVAL_IS_VALID_TAG(tv) \ 354 (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN) 355 356 /* DUK_TAG_NUMBER is intentionally first, as it is the default clause in code 357 * to support the 8-byte representation. Further, it is a non-heap-allocated 358 * type so it should come before DUK_TAG_STRING. Finally, it should not break 359 * the tag value ranges covered by case-clauses in a switch-case. 360 */ 361 362 /* setters */ 363 #define DUK_TVAL_SET_UNDEFINED(tv) do { \ 364 duk_tval *duk__tv; \ 365 duk__tv = (tv); \ 366 duk__tv->t = DUK_TAG_UNDEFINED; \ 367 } while (0) 368 369 #define DUK_TVAL_SET_UNUSED(tv) do { \ 370 duk_tval *duk__tv; \ 371 duk__tv = (tv); \ 372 duk__tv->t = DUK_TAG_UNUSED; \ 373 } while (0) 374 375 #define DUK_TVAL_SET_NULL(tv) do { \ 376 duk_tval *duk__tv; \ 377 duk__tv = (tv); \ 378 duk__tv->t = DUK_TAG_NULL; \ 379 } while (0) 380 381 #define DUK_TVAL_SET_BOOLEAN(tv,val) do { \ 382 duk_tval *duk__tv; \ 383 duk__tv = (tv); \ 384 duk__tv->t = DUK_TAG_BOOLEAN; \ 385 duk__tv->v.i = (duk_small_int_t) (val); \ 386 } while (0) 387 388 #if defined(DUK_USE_FASTINT) 389 #define DUK_TVAL_SET_DOUBLE(tv,val) do { \ 390 duk_tval *duk__tv; \ 391 duk_double_t duk__dblval; \ 392 duk__dblval = (val); \ 393 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \ 394 duk__tv = (tv); \ 395 duk__tv->t = DUK_TAG_NUMBER; \ 396 duk__tv->v.d = duk__dblval; \ 397 } while (0) 398 #define DUK_TVAL_SET_I48(tv,val) do { \ 399 duk_tval *duk__tv; \ 400 duk__tv = (tv); \ 401 duk__tv->t = DUK_TAG_FASTINT; \ 402 duk__tv->v.fi = (val); \ 403 } while (0) 404 #define DUK_TVAL_SET_U32(tv,val) do { \ 405 duk_tval *duk__tv; \ 406 duk__tv = (tv); \ 407 duk__tv->t = DUK_TAG_FASTINT; \ 408 duk__tv->v.fi = (duk_int64_t) (val); \ 409 } while (0) 410 #define DUK_TVAL_SET_I32(tv,val) do { \ 411 duk_tval *duk__tv; \ 412 duk__tv = (tv); \ 413 duk__tv->t = DUK_TAG_FASTINT; \ 414 duk__tv->v.fi = (duk_int64_t) (val); \ 415 } while (0) 416 #define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \ 417 duk_tval_set_number_chkfast_fast((tv), (d)) 418 #define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \ 419 duk_tval_set_number_chkfast_slow((tv), (d)) 420 #define DUK_TVAL_SET_NUMBER(tv,val) \ 421 DUK_TVAL_SET_DOUBLE((tv), (val)) 422 #define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \ 423 duk_tval *duk__tv; \ 424 duk_double_t duk__d; \ 425 duk__tv = (tv); \ 426 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ 427 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ 428 DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \ 429 } \ 430 } while (0) 431 #define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \ 432 duk_tval *duk__tv; \ 433 duk_double_t duk__d; \ 434 duk__tv = (tv); \ 435 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ 436 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ 437 DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \ 438 } \ 439 } while (0) 440 #else /* DUK_USE_FASTINT */ 441 #define DUK_TVAL_SET_DOUBLE(tv,d) \ 442 DUK_TVAL_SET_NUMBER((tv), (d)) 443 #define DUK_TVAL_SET_I48(tv,val) \ 444 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) /* XXX: fast int-to-double */ 445 #define DUK_TVAL_SET_U32(tv,val) \ 446 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) 447 #define DUK_TVAL_SET_I32(tv,val) \ 448 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) 449 #define DUK_TVAL_SET_NUMBER(tv,val) do { \ 450 duk_tval *duk__tv; \ 451 duk_double_t duk__dblval; \ 452 duk__dblval = (val); \ 453 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \ 454 duk__tv = (tv); \ 455 duk__tv->t = DUK_TAG_NUMBER; \ 456 duk__tv->v.d = duk__dblval; \ 457 } while (0) 458 #define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \ 459 DUK_TVAL_SET_NUMBER((tv), (d)) 460 #define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \ 461 DUK_TVAL_SET_NUMBER((tv), (d)) 462 #define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0) 463 #define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0) 464 #endif /* DUK_USE_FASTINT */ 465 466 #define DUK_TVAL_SET_FASTINT(tv,i) \ 467 DUK_TVAL_SET_I48((tv), (i)) /* alias */ 468 469 #define DUK_TVAL_SET_POINTER(tv,hptr) do { \ 470 duk_tval *duk__tv; \ 471 duk__tv = (tv); \ 472 duk__tv->t = DUK_TAG_POINTER; \ 473 duk__tv->v.voidptr = (hptr); \ 474 } while (0) 475 476 #define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ 477 duk_tval *duk__tv; \ 478 duk__tv = (tv); \ 479 duk__tv->t = DUK_TAG_LIGHTFUNC; \ 480 duk__tv->v_extra = (flags); \ 481 duk__tv->v.lightfunc = (duk_c_function) (fp); \ 482 } while (0) 483 484 #define DUK_TVAL_SET_STRING(tv,hptr) do { \ 485 duk_tval *duk__tv; \ 486 duk__tv = (tv); \ 487 duk__tv->t = DUK_TAG_STRING; \ 488 duk__tv->v.hstring = (hptr); \ 489 } while (0) 490 491 #define DUK_TVAL_SET_OBJECT(tv,hptr) do { \ 492 duk_tval *duk__tv; \ 493 duk__tv = (tv); \ 494 duk__tv->t = DUK_TAG_OBJECT; \ 495 duk__tv->v.hobject = (hptr); \ 496 } while (0) 497 498 #define DUK_TVAL_SET_BUFFER(tv,hptr) do { \ 499 duk_tval *duk__tv; \ 500 duk__tv = (tv); \ 501 duk__tv->t = DUK_TAG_BUFFER; \ 502 duk__tv->v.hbuffer = (hptr); \ 503 } while (0) 504 505 #define DUK_TVAL_SET_NAN(tv) do { \ 506 /* in non-packed representation we don't care about which NaN is used */ \ 507 duk_tval *duk__tv; \ 508 duk__tv = (tv); \ 509 duk__tv->t = DUK_TAG_NUMBER; \ 510 duk__tv->v.d = DUK_DOUBLE_NAN; \ 511 } while (0) 512 513 #define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0) 514 515 /* getters */ 516 #define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->v.i) 517 #if defined(DUK_USE_FASTINT) 518 #define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d) 519 #define DUK_TVAL_GET_FASTINT(tv) ((tv)->v.fi) 520 #define DUK_TVAL_GET_FASTINT_U32(tv) ((duk_uint32_t) ((tv)->v.fi)) 521 #define DUK_TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) ((tv)->v.fi)) 522 #if 0 523 #define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \ 524 (duk_double_t) DUK_TVAL_GET_FASTINT((tv)) : \ 525 DUK_TVAL_GET_DOUBLE((tv))) 526 #define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_unpacked((tv)) 527 #else 528 /* This seems reasonable overall. */ 529 #define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \ 530 duk_tval_get_number_unpacked_fastint((tv)) : \ 531 DUK_TVAL_GET_DOUBLE((tv))) 532 #endif 533 #else 534 #define DUK_TVAL_GET_NUMBER(tv) ((tv)->v.d) 535 #define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d) 536 #endif /* DUK_USE_FASTINT */ 537 #define DUK_TVAL_GET_POINTER(tv) ((tv)->v.voidptr) 538 #define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \ 539 (out_flags) = (duk_uint32_t) (tv)->v_extra; \ 540 (out_fp) = (tv)->v.lightfunc; \ 541 } while (0) 542 #define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc) 543 #define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_small_uint_t) ((tv)->v_extra)) 544 #define DUK_TVAL_GET_STRING(tv) ((tv)->v.hstring) 545 #define DUK_TVAL_GET_OBJECT(tv) ((tv)->v.hobject) 546 #define DUK_TVAL_GET_BUFFER(tv) ((tv)->v.hbuffer) 547 #define DUK_TVAL_GET_HEAPHDR(tv) ((tv)->v.heaphdr) 548 549 /* decoding */ 550 #define DUK_TVAL_GET_TAG(tv) ((tv)->t) 551 #define DUK_TVAL_IS_UNDEFINED(tv) ((tv)->t == DUK_TAG_UNDEFINED) 552 #define DUK_TVAL_IS_UNUSED(tv) ((tv)->t == DUK_TAG_UNUSED) 553 #define DUK_TVAL_IS_NULL(tv) ((tv)->t == DUK_TAG_NULL) 554 #define DUK_TVAL_IS_BOOLEAN(tv) ((tv)->t == DUK_TAG_BOOLEAN) 555 #define DUK_TVAL_IS_BOOLEAN_TRUE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0)) 556 #define DUK_TVAL_IS_BOOLEAN_FALSE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0)) 557 #if defined(DUK_USE_FASTINT) 558 #define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK_TAG_NUMBER) 559 #define DUK_TVAL_IS_FASTINT(tv) ((tv)->t == DUK_TAG_FASTINT) 560 #define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER || \ 561 (tv)->t == DUK_TAG_FASTINT) 562 #else 563 #define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER) 564 #define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv)) 565 #endif /* DUK_USE_FASTINT */ 566 #define DUK_TVAL_IS_POINTER(tv) ((tv)->t == DUK_TAG_POINTER) 567 #define DUK_TVAL_IS_LIGHTFUNC(tv) ((tv)->t == DUK_TAG_LIGHTFUNC) 568 #define DUK_TVAL_IS_STRING(tv) ((tv)->t == DUK_TAG_STRING) 569 #define DUK_TVAL_IS_OBJECT(tv) ((tv)->t == DUK_TAG_OBJECT) 570 #define DUK_TVAL_IS_BUFFER(tv) ((tv)->t == DUK_TAG_BUFFER) 571 572 /* This is performance critical because it's needed for every DECREF. 573 * Take advantage of the fact that the first heap allocated tag is 8, 574 * so that bit 3 is set for all heap allocated tags (and never set for 575 * non-heap-allocated tags). 576 */ 577 #if 0 578 #define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t >= DUK_TAG_STRING) 579 #endif 580 #define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t & 0x08) 581 582 #if defined(DUK_USE_FASTINT) 583 #if 0 584 DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked(duk_tval *tv); 585 #endif 586 DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv); 587 #endif 588 589 #endif /* DUK_USE_PACKED_TVAL */ 590 591 /* 592 * Convenience (independent of representation) 593 */ 594 595 #define DUK_TVAL_SET_BOOLEAN_TRUE(tv) DUK_TVAL_SET_BOOLEAN((tv), 1) 596 #define DUK_TVAL_SET_BOOLEAN_FALSE(tv) DUK_TVAL_SET_BOOLEAN((tv), 0) 597 598 #define DUK_TVAL_STRING_IS_SYMBOL(tv) \ 599 DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING((tv))) 600 601 /* Lightfunc flags packing and unpacking. */ 602 /* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss##. 603 * Avoid signed shifts due to portability limitations. 604 */ 605 #define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \ 606 ((duk_int32_t) (duk_int8_t) (((duk_uint16_t) (lf_flags)) >> 8)) 607 #define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \ 608 (((lf_flags) >> 4) & 0x0fU) 609 #define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \ 610 ((lf_flags) & 0x0fU) 611 #define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \ 612 ((((duk_small_uint_t) (magic)) & 0xffU) << 8) | ((length) << 4) | (nargs) 613 614 #define DUK_LFUNC_NARGS_VARARGS 0x0f /* varargs marker */ 615 #define DUK_LFUNC_NARGS_MIN 0x00 616 #define DUK_LFUNC_NARGS_MAX 0x0e /* max, excl. varargs marker */ 617 #define DUK_LFUNC_LENGTH_MIN 0x00 618 #define DUK_LFUNC_LENGTH_MAX 0x0f 619 #define DUK_LFUNC_MAGIC_MIN (-0x80) 620 #define DUK_LFUNC_MAGIC_MAX 0x7f 621 622 /* fastint constants etc */ 623 #if defined(DUK_USE_FASTINT) 624 #define DUK_FASTINT_MIN (DUK_I64_CONSTANT(-0x800000000000)) 625 #define DUK_FASTINT_MAX (DUK_I64_CONSTANT(0x7fffffffffff)) 626 #define DUK_FASTINT_BITS 48 627 628 DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x); 629 DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x); 630 #endif 631 632 #if defined(DUK_USE_ASSERTIONS) 633 DUK_INTERNAL_DECL void duk_tval_assert_valid(duk_tval *tv); 634 #define DUK_TVAL_ASSERT_VALID(tv) do { duk_tval_assert_valid((tv)); } while (0) 635 #else 636 #define DUK_TVAL_ASSERT_VALID(tv) do {} while (0) 637 #endif 638 639 #endif /* DUK_TVAL_H_INCLUDED */ 640