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