2 * Tagged type definition (duk_tval) and accessor macros.
4 * Access all fields through the accessor macros, as the representation
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).
12 * Selecting the tagged type format involves many trade-offs (memory
13 * use, size and performance of generated code, portability, etc),
14 * see doc/types.rst for a detailed discussion (especially of how the
15 * IEEE double format is used to pack tagged values).
17 * NB: because macro arguments are often expressions, macros should
18 * avoid evaluating their argument more than once.
21 #ifndef DUK_TVAL_H_INCLUDED
22 #define DUK_TVAL_H_INCLUDED
25 #if !defined(DUK_USE_DOUBLE_LE) && !defined(DUK_USE_DOUBLE_ME) && !defined(DUK_USE_DOUBLE_BE)
26 #error unsupported: cannot determine byte order variant
29 #if defined(DUK_USE_PACKED_TVAL)
30 /* ======================================================================== */
33 * Packed 8-byte representation
36 /* use duk_double_union as duk_tval directly */
37 typedef union duk_double_union duk_tval
;
40 #define DUK_TAG_NORMALIZED_NAN 0x7ff8UL /* the NaN variant we use */
41 /* avoid tag 0xfff0, no risk of confusion with negative infinity */
42 #if defined(DUK_USE_FASTINT)
43 #define DUK_TAG_FASTINT 0xfff1UL /* embed: integer value */
45 #define DUK_TAG_UNUSED 0xfff2UL /* marker; not actual tagged value */
46 #define DUK_TAG_UNDEFINED 0xfff3UL /* embed: nothing */
47 #define DUK_TAG_NULL 0xfff4UL /* embed: nothing */
48 #define DUK_TAG_BOOLEAN 0xfff5UL /* embed: 0 or 1 (false or true) */
49 /* DUK_TAG_NUMBER would logically go here, but it has multiple 'tags' */
50 #define DUK_TAG_POINTER 0xfff6UL /* embed: void ptr */
51 #define DUK_TAG_LIGHTFUNC 0xfff7UL /* embed: func ptr */
52 #define DUK_TAG_STRING 0xfff8UL /* embed: duk_hstring ptr */
53 #define DUK_TAG_OBJECT 0xfff9UL /* embed: duk_hobject ptr */
54 #define DUK_TAG_BUFFER 0xfffaUL /* embed: duk_hbuffer ptr */
57 #define DUK_XTAG_BOOLEAN_FALSE 0xfff50000UL
58 #define DUK_XTAG_BOOLEAN_TRUE 0xfff50001UL
60 /* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */
61 #if defined(DUK_USE_64BIT_OPS)
62 #if defined(DUK_USE_DOUBLE_ME)
63 #define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
64 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \
67 #define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
68 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \
71 #else /* DUK_USE_64BIT_OPS */
72 #define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
73 (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \
74 (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \
76 #endif /* DUK_USE_64BIT_OPS */
78 #if defined(DUK_USE_64BIT_OPS)
79 /* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */
80 #if defined(DUK_USE_DOUBLE_ME)
81 #define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
82 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \
83 ((duk_uint64_t) (flags)) | \
84 (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \
87 #define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
88 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \
89 (((duk_uint64_t) (flags)) << 32) | \
90 ((duk_uint64_t) (duk_uint32_t) (fp)); \
93 #else /* DUK_USE_64BIT_OPS */
94 #define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
95 (v)->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \
96 (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \
98 #endif /* DUK_USE_64BIT_OPS */
100 #if defined(DUK_USE_FASTINT)
101 /* Note: masking is done for 'i' to deal with negative numbers correctly */
102 #if defined(DUK_USE_DOUBLE_ME)
103 #define DUK__TVAL_SET_FASTINT(v,i) do { \
104 (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \
105 (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
107 #define DUK__TVAL_SET_FASTINT_U32(v,i) do { \
108 (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \
109 (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
112 #define DUK__TVAL_SET_FASTINT(v,i) do { \
113 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & 0x0000ffffffffffffULL); \
115 #define DUK__TVAL_SET_FASTINT_U32(v,i) do { \
116 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \
120 #define DUK__TVAL_SET_FASTINT_I32(v,i) do { \
121 duk_int64_t duk__tmp = (duk_int64_t) (i); \
122 DUK_TVAL_SET_FASTINT((v), duk__tmp); \
125 /* XXX: clumsy sign extend and masking of 16 topmost bits */
126 #if defined(DUK_USE_DOUBLE_ME)
127 #define DUK__TVAL_GET_FASTINT(v) (((duk_int64_t) ((((duk_uint64_t) (v)->ui[DUK_DBL_IDX_UI0]) << 32) | ((duk_uint64_t) (v)->ui[DUK_DBL_IDX_UI1]))) << 16 >> 16)
129 #define DUK__TVAL_GET_FASTINT(v) ((((duk_int64_t) (v)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16)
131 #define DUK__TVAL_GET_FASTINT_U32(v) ((v)->ui[DUK_DBL_IDX_UI1])
132 #define DUK__TVAL_GET_FASTINT_I32(v) ((duk_int32_t) (v)->ui[DUK_DBL_IDX_UI1])
133 #endif /* DUK_USE_FASTINT */
135 #define DUK_TVAL_SET_UNDEFINED(v) do { \
136 (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \
138 #define DUK_TVAL_SET_UNUSED(v) do { \
139 (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \
141 #define DUK_TVAL_SET_NULL(v) do { \
142 (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \
145 #define DUK_TVAL_SET_BOOLEAN(v,val) DUK_DBLUNION_SET_HIGH32((v), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val)))
147 #define DUK_TVAL_SET_NAN(v) DUK_DBLUNION_SET_NAN_FULL((v))
149 /* Assumes that caller has normalized NaNs, otherwise trouble ahead. */
150 #if defined(DUK_USE_FASTINT)
151 #define DUK_TVAL_SET_DOUBLE(v,d) do { \
152 duk_double_t duk__dblval; \
154 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
155 DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \
157 #define DUK_TVAL_SET_FASTINT(v,i) DUK__TVAL_SET_FASTINT((v), (i))
158 #define DUK_TVAL_SET_FASTINT_I32(v,i) DUK__TVAL_SET_FASTINT_I32((v), (i))
159 #define DUK_TVAL_SET_FASTINT_U32(v,i) DUK__TVAL_SET_FASTINT_U32((v), (i))
160 #define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) duk_tval_set_number_chkfast((v), (d))
161 #define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
162 #define DUK_TVAL_CHKFAST_INPLACE(v) do { \
164 duk_double_t duk__d; \
166 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
167 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
168 DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \
172 #define DUK_TVAL_SET_DOUBLE(v,d) do { \
173 duk_double_t duk__dblval; \
175 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
176 DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \
178 #define DUK_TVAL_SET_FASTINT(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i)) /* XXX: fast int-to-double */
179 #define DUK_TVAL_SET_FASTINT_I32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i))
180 #define DUK_TVAL_SET_FASTINT_U32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i))
181 #define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
182 #define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
183 #define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0)
186 #define DUK_TVAL_SET_LIGHTFUNC(v,fp,flags) DUK__TVAL_SET_LIGHTFUNC((v), (fp), (flags))
187 #define DUK_TVAL_SET_STRING(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_STRING)
188 #define DUK_TVAL_SET_OBJECT(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_OBJECT)
189 #define DUK_TVAL_SET_BUFFER(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_BUFFER)
190 #define DUK_TVAL_SET_POINTER(v,p) DUK__TVAL_SET_TAGGEDPOINTER((v), (p), DUK_TAG_POINTER)
192 #define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0)
195 #define DUK_TVAL_GET_BOOLEAN(v) ((int) (v)->us[DUK_DBL_IDX_US1])
196 #if defined(DUK_USE_FASTINT)
197 #define DUK_TVAL_GET_DOUBLE(v) ((v)->d)
198 #define DUK_TVAL_GET_FASTINT(v) DUK__TVAL_GET_FASTINT((v))
199 #define DUK_TVAL_GET_FASTINT_U32(v) DUK__TVAL_GET_FASTINT_U32((v))
200 #define DUK_TVAL_GET_FASTINT_I32(v) DUK__TVAL_GET_FASTINT_I32((v))
201 #define DUK_TVAL_GET_NUMBER(v) duk_tval_get_number_packed((v))
203 #define DUK_TVAL_GET_NUMBER(v) ((v)->d)
204 #define DUK_TVAL_GET_DOUBLE(v) ((v)->d)
206 #define DUK_TVAL_GET_LIGHTFUNC(v,out_fp,out_flags) do { \
207 (out_flags) = (v)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \
208 (out_fp) = (duk_c_function) (v)->ui[DUK_DBL_IDX_UI1]; \
210 #define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(v) ((duk_c_function) ((v)->ui[DUK_DBL_IDX_UI1]))
211 #define DUK_TVAL_GET_LIGHTFUNC_FLAGS(v) (((int) (v)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL)
212 #define DUK_TVAL_GET_STRING(v) ((duk_hstring *) (v)->vp[DUK_DBL_IDX_VP1])
213 #define DUK_TVAL_GET_OBJECT(v) ((duk_hobject *) (v)->vp[DUK_DBL_IDX_VP1])
214 #define DUK_TVAL_GET_BUFFER(v) ((duk_hbuffer *) (v)->vp[DUK_DBL_IDX_VP1])
215 #define DUK_TVAL_GET_POINTER(v) ((void *) (v)->vp[DUK_DBL_IDX_VP1])
216 #define DUK_TVAL_GET_HEAPHDR(v) ((duk_heaphdr *) (v)->vp[DUK_DBL_IDX_VP1])
219 #define DUK_TVAL_GET_TAG(v) ((duk_small_uint_t) (v)->us[DUK_DBL_IDX_US0])
221 #define DUK_TVAL_IS_UNDEFINED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNDEFINED)
222 #define DUK_TVAL_IS_UNUSED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNUSED)
223 #define DUK_TVAL_IS_NULL(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_NULL)
224 #define DUK_TVAL_IS_BOOLEAN(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BOOLEAN)
225 #define DUK_TVAL_IS_BOOLEAN_TRUE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE)
226 #define DUK_TVAL_IS_BOOLEAN_FALSE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE)
227 #define DUK_TVAL_IS_LIGHTFUNC(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_LIGHTFUNC)
228 #define DUK_TVAL_IS_STRING(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_STRING)
229 #define DUK_TVAL_IS_OBJECT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_OBJECT)
230 #define DUK_TVAL_IS_BUFFER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BUFFER)
231 #define DUK_TVAL_IS_POINTER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_POINTER)
232 #if defined(DUK_USE_FASTINT)
233 /* 0xfff0 is -Infinity */
234 #define DUK_TVAL_IS_DOUBLE(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL)
235 #define DUK_TVAL_IS_FASTINT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_FASTINT)
236 #define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff1UL)
238 #define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL)
239 #define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v))
242 /* This is performance critical because it appears in every DECREF. */
243 #define DUK_TVAL_IS_HEAP_ALLOCATED(v) (DUK_TVAL_GET_TAG((v)) >= DUK_TAG_STRING)
245 #if defined(DUK_USE_FASTINT)
246 DUK_INTERNAL_DECL duk_double_t
duk_tval_get_number_packed(duk_tval
*tv
);
249 #else /* DUK_USE_PACKED_TVAL */
250 /* ======================================================================== */
253 * Portable 12-byte representation
256 /* Note: not initializing all bytes is normally not an issue: Duktape won't
257 * read or use the uninitialized bytes so valgrind won't issue warnings.
258 * In some special cases a harmless valgrind warning may be issued though.
259 * For example, the DumpHeap debugger command writes out a compiled function's
260 * 'data' area as is, including any uninitialized bytes, which causes a
264 typedef struct duk_tval_struct duk_tval
;
266 struct duk_tval_struct
{
268 duk_small_uint_t v_extra
;
272 #if defined(DUK_USE_FASTINT)
273 duk_int64_t fi
; /* if present, forces 16-byte duk_tval */
276 duk_hstring
*hstring
;
277 duk_hobject
*hobject
;
278 duk_hcompiledfunction
*hcompiledfunction
;
279 duk_hnativefunction
*hnativefunction
;
280 duk_hthread
*hthread
;
281 duk_hbuffer
*hbuffer
;
282 duk_heaphdr
*heaphdr
;
283 duk_c_function lightfunc
;
287 #define DUK__TAG_NUMBER 0 /* not exposed */
288 #if defined(DUK_USE_FASTINT)
289 #define DUK_TAG_FASTINT 1
291 #define DUK_TAG_UNDEFINED 2
292 #define DUK_TAG_NULL 3
293 #define DUK_TAG_BOOLEAN 4
294 #define DUK_TAG_POINTER 5
295 #define DUK_TAG_LIGHTFUNC 6
296 #define DUK_TAG_UNUSED 7 /* marker; not actual tagged type */
297 #define DUK_TAG_STRING 8 /* first heap allocated, match bit boundary */
298 #define DUK_TAG_OBJECT 9
299 #define DUK_TAG_BUFFER 10
301 /* DUK__TAG_NUMBER is intentionally first, as it is the default clause in code
302 * to support the 8-byte representation. Further, it is a non-heap-allocated
303 * type so it should come before DUK_TAG_STRING. Finally, it should not break
304 * the tag value ranges covered by case-clauses in a switch-case.
308 #define DUK_TVAL_SET_UNDEFINED(tv) do { \
309 (tv)->t = DUK_TAG_UNDEFINED; \
312 #define DUK_TVAL_SET_UNUSED(tv) do { \
313 (tv)->t = DUK_TAG_UNUSED; \
316 #define DUK_TVAL_SET_NULL(tv) do { \
317 (tv)->t = DUK_TAG_NULL; \
320 #define DUK_TVAL_SET_BOOLEAN(tv,val) do { \
321 (tv)->t = DUK_TAG_BOOLEAN; \
325 #if defined(DUK_USE_FASTINT)
326 #define DUK_TVAL_SET_DOUBLE(tv,val) do { \
327 (tv)->t = DUK__TAG_NUMBER; \
330 #define DUK_TVAL_SET_FASTINT(tv,val) do { \
331 (tv)->t = DUK_TAG_FASTINT; \
332 (tv)->v.fi = (val); \
334 #define DUK_TVAL_SET_FASTINT_U32(tv,val) do { \
335 (tv)->t = DUK_TAG_FASTINT; \
336 (tv)->v.fi = (duk_int64_t) (val); \
338 #define DUK_TVAL_SET_FASTINT_I32(tv,val) do { \
339 (tv)->t = DUK_TAG_FASTINT; \
340 (tv)->v.fi = (duk_int64_t) (val); \
342 #define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \
343 duk_tval_set_number_chkfast((tv), (d))
344 #define DUK_TVAL_SET_NUMBER(tv,val) \
345 DUK_TVAL_SET_DOUBLE((tv), (val))
346 #define DUK_TVAL_CHKFAST_INPLACE(v) do { \
348 duk_double_t duk__d; \
350 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
351 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
352 DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \
356 #define DUK_TVAL_SET_DOUBLE(tv,d) \
357 DUK_TVAL_SET_NUMBER((tv), (d))
358 #define DUK_TVAL_SET_FASTINT(tv,val) \
359 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) /* XXX: fast int-to-double */
360 #define DUK_TVAL_SET_FASTINT_U32(tv,val) \
361 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
362 #define DUK_TVAL_SET_FASTINT_I32(tv,val) \
363 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
364 #define DUK_TVAL_SET_NUMBER(tv,val) do { \
365 (tv)->t = DUK__TAG_NUMBER; \
368 #define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \
369 DUK_TVAL_SET_NUMBER((tv), (d))
370 #define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0)
371 #endif /* DUK_USE_FASTINT */
373 #define DUK_TVAL_SET_POINTER(tv,hptr) do { \
374 (tv)->t = DUK_TAG_POINTER; \
375 (tv)->v.voidptr = (hptr); \
378 #define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
379 (tv)->t = DUK_TAG_LIGHTFUNC; \
380 (tv)->v_extra = (flags); \
381 (tv)->v.lightfunc = (duk_c_function) (fp); \
384 #define DUK_TVAL_SET_STRING(tv,hptr) do { \
385 (tv)->t = DUK_TAG_STRING; \
386 (tv)->v.hstring = (hptr); \
389 #define DUK_TVAL_SET_OBJECT(tv,hptr) do { \
390 (tv)->t = DUK_TAG_OBJECT; \
391 (tv)->v.hobject = (hptr); \
394 #define DUK_TVAL_SET_BUFFER(tv,hptr) do { \
395 (tv)->t = DUK_TAG_BUFFER; \
396 (tv)->v.hbuffer = (hptr); \
399 #define DUK_TVAL_SET_NAN(tv) do { \
400 /* in non-packed representation we don't care about which NaN is used */ \
401 (tv)->t = DUK__TAG_NUMBER; \
402 (tv)->v.d = DUK_DOUBLE_NAN; \
405 #define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0)
408 #define DUK_TVAL_GET_BOOLEAN(tv) ((tv)->v.i)
409 #if defined(DUK_USE_FASTINT)
410 #define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d)
411 #define DUK_TVAL_GET_FASTINT(tv) ((tv)->v.fi)
412 #define DUK_TVAL_GET_FASTINT_U32(tv) ((duk_uint32_t) ((tv)->v.fi))
413 #define DUK_TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) ((tv)->v.fi))
415 #define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \
416 (duk_double_t) DUK_TVAL_GET_FASTINT((tv)) : \
417 DUK_TVAL_GET_DOUBLE((tv)))
418 #define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_unpacked((tv))
420 /* This seems reasonable overall. */
421 #define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \
422 duk_tval_get_number_unpacked_fastint((tv)) : \
423 DUK_TVAL_GET_DOUBLE((tv)))
426 #define DUK_TVAL_GET_NUMBER(tv) ((tv)->v.d)
427 #define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d)
428 #endif /* DUK_USE_FASTINT */
429 #define DUK_TVAL_GET_POINTER(tv) ((tv)->v.voidptr)
430 #define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \
431 (out_flags) = (duk_uint32_t) (tv)->v_extra; \
432 (out_fp) = (tv)->v.lightfunc; \
434 #define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc)
435 #define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_uint32_t) ((tv)->v_extra))
436 #define DUK_TVAL_GET_STRING(tv) ((tv)->v.hstring)
437 #define DUK_TVAL_GET_OBJECT(tv) ((tv)->v.hobject)
438 #define DUK_TVAL_GET_BUFFER(tv) ((tv)->v.hbuffer)
439 #define DUK_TVAL_GET_HEAPHDR(tv) ((tv)->v.heaphdr)
442 #define DUK_TVAL_GET_TAG(tv) ((tv)->t)
443 #define DUK_TVAL_IS_UNDEFINED(tv) ((tv)->t == DUK_TAG_UNDEFINED)
444 #define DUK_TVAL_IS_UNUSED(tv) ((tv)->t == DUK_TAG_UNUSED)
445 #define DUK_TVAL_IS_NULL(tv) ((tv)->t == DUK_TAG_NULL)
446 #define DUK_TVAL_IS_BOOLEAN(tv) ((tv)->t == DUK_TAG_BOOLEAN)
447 #define DUK_TVAL_IS_BOOLEAN_TRUE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0))
448 #define DUK_TVAL_IS_BOOLEAN_FALSE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0))
449 #if defined(DUK_USE_FASTINT)
450 #define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK__TAG_NUMBER)
451 #define DUK_TVAL_IS_FASTINT(tv) ((tv)->t == DUK_TAG_FASTINT)
452 #define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER || \
453 (tv)->t == DUK_TAG_FASTINT)
455 #define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER)
456 #define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v))
457 #endif /* DUK_USE_FASTINT */
458 #define DUK_TVAL_IS_POINTER(tv) ((tv)->t == DUK_TAG_POINTER)
459 #define DUK_TVAL_IS_LIGHTFUNC(tv) ((tv)->t == DUK_TAG_LIGHTFUNC)
460 #define DUK_TVAL_IS_STRING(tv) ((tv)->t == DUK_TAG_STRING)
461 #define DUK_TVAL_IS_OBJECT(tv) ((tv)->t == DUK_TAG_OBJECT)
462 #define DUK_TVAL_IS_BUFFER(tv) ((tv)->t == DUK_TAG_BUFFER)
464 /* This is performance critical because it's needed for every DECREF.
465 * Take advantage of the fact that the first heap allocated tag is 8,
466 * so that bit 3 is set for all heap allocated tags (and never set for
467 * non-heap-allocated tags).
470 #define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t >= DUK_TAG_STRING)
472 #define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t & 0x08)
474 #if defined(DUK_USE_FASTINT)
476 DUK_INTERNAL_DECL duk_double_t
duk_tval_get_number_unpacked(duk_tval
*tv
);
478 DUK_INTERNAL_DECL duk_double_t
duk_tval_get_number_unpacked_fastint(duk_tval
*tv
);
481 #endif /* DUK_USE_PACKED_TVAL */
484 * Convenience (independent of representation)
487 #define DUK_TVAL_SET_BOOLEAN_TRUE(v) DUK_TVAL_SET_BOOLEAN(v, 1)
488 #define DUK_TVAL_SET_BOOLEAN_FALSE(v) DUK_TVAL_SET_BOOLEAN(v, 0)
490 /* Lightfunc flags packing and unpacking. */
491 /* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss## */
492 #define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \
493 ((((duk_int32_t) (lf_flags)) << 16) >> 24)
494 #define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \
495 (((lf_flags) >> 4) & 0x0f)
496 #define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \
498 #define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \
499 (((magic) & 0xff) << 8) | ((length) << 4) | (nargs)
501 #define DUK_LFUNC_NARGS_VARARGS 0x0f /* varargs marker */
502 #define DUK_LFUNC_NARGS_MIN 0x00
503 #define DUK_LFUNC_NARGS_MAX 0x0e /* max, excl. varargs marker */
504 #define DUK_LFUNC_LENGTH_MIN 0x00
505 #define DUK_LFUNC_LENGTH_MAX 0x0f
506 #define DUK_LFUNC_MAGIC_MIN (-0x80)
507 #define DUK_LFUNC_MAGIC_MAX 0x7f
509 /* fastint constants etc */
510 #if defined(DUK_USE_FASTINT)
511 #define DUK_FASTINT_MIN (-0x800000000000LL)
512 #define DUK_FASTINT_MAX 0x7fffffffffffLL
513 #define DUK_FASTINT_BITS 48
515 DUK_INTERNAL_DECL
void duk_tval_set_number_chkfast(duk_tval
*tv
, duk_double_t x
);
518 #endif /* DUK_TVAL_H_INCLUDED */