]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | * see doc/types.rst for a detailed discussion (especially of how the | |
15 | * IEEE double format is used to pack tagged values). | |
16 | * | |
17 | * NB: because macro arguments are often expressions, macros should | |
18 | * avoid evaluating their argument more than once. | |
19 | */ | |
20 | ||
21 | #ifndef DUK_TVAL_H_INCLUDED | |
22 | #define DUK_TVAL_H_INCLUDED | |
23 | ||
24 | /* sanity */ | |
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 | |
27 | #endif | |
28 | ||
29 | #ifdef DUK_USE_PACKED_TVAL | |
30 | /* ======================================================================== */ | |
31 | ||
32 | /* | |
33 | * Packed 8-byte representation | |
34 | */ | |
35 | ||
36 | /* sanity */ | |
37 | #if !defined(DUK_USE_PACKED_TVAL_POSSIBLE) | |
38 | #error packed representation not supported | |
39 | #endif | |
40 | ||
41 | /* use duk_double_union as duk_tval directly */ | |
42 | typedef union duk_double_union duk_tval; | |
43 | ||
44 | /* tags */ | |
45 | #define DUK_TAG_NORMALIZED_NAN 0x7ff8UL /* the NaN variant we use */ | |
46 | /* avoid tag 0xfff0, no risk of confusion with negative infinity */ | |
47 | #if defined(DUK_USE_FASTINT) | |
48 | #define DUK_TAG_FASTINT 0xfff1UL /* embed: integer value */ | |
49 | #endif | |
50 | #define DUK_TAG_UNDEFINED 0xfff2UL /* embed: 0 or 1 (normal or unused) */ | |
51 | #define DUK_TAG_NULL 0xfff3UL /* embed: nothing */ | |
52 | #define DUK_TAG_BOOLEAN 0xfff4UL /* embed: 0 or 1 (false or true) */ | |
53 | /* DUK_TAG_NUMBER would logically go here, but it has multiple 'tags' */ | |
54 | #define DUK_TAG_POINTER 0xfff5UL /* embed: void ptr */ | |
55 | #define DUK_TAG_LIGHTFUNC 0xfff6UL /* embed: func ptr */ | |
56 | #define DUK_TAG_STRING 0xfff7UL /* embed: duk_hstring ptr */ | |
57 | #define DUK_TAG_OBJECT 0xfff8UL /* embed: duk_hobject ptr */ | |
58 | #define DUK_TAG_BUFFER 0xfff9UL /* embed: duk_hbuffer ptr */ | |
59 | ||
60 | /* for convenience */ | |
61 | #define DUK_XTAG_UNDEFINED_ACTUAL 0xfff20000UL | |
62 | #define DUK_XTAG_UNDEFINED_UNUSED 0xfff20001UL | |
63 | #define DUK_XTAG_NULL 0xfff30000UL | |
64 | #define DUK_XTAG_BOOLEAN_FALSE 0xfff40000UL | |
65 | #define DUK_XTAG_BOOLEAN_TRUE 0xfff40001UL | |
66 | ||
67 | /* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */ | |
68 | #ifdef DUK_USE_64BIT_OPS | |
69 | #ifdef DUK_USE_DOUBLE_ME | |
70 | #define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \ | |
71 | (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \ | |
72 | } while (0) | |
73 | #else | |
74 | #define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \ | |
75 | (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \ | |
76 | } while (0) | |
77 | #endif | |
78 | #else /* DUK_USE_64BIT_OPS */ | |
79 | #define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \ | |
80 | (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \ | |
81 | (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \ | |
82 | } while (0) | |
83 | #endif /* DUK_USE_64BIT_OPS */ | |
84 | ||
85 | #ifdef DUK_USE_64BIT_OPS | |
86 | /* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */ | |
87 | #ifdef DUK_USE_DOUBLE_ME | |
88 | #define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \ | |
89 | (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \ | |
90 | ((duk_uint64_t) (flags)) | \ | |
91 | (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \ | |
92 | } while (0) | |
93 | #else | |
94 | #define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \ | |
95 | (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \ | |
96 | (((duk_uint64_t) (flags)) << 32) | \ | |
97 | ((duk_uint64_t) (duk_uint32_t) (fp)); \ | |
98 | } while (0) | |
99 | #endif | |
100 | #else /* DUK_USE_64BIT_OPS */ | |
101 | #define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \ | |
102 | (v)->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \ | |
103 | (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \ | |
104 | } while (0) | |
105 | #endif /* DUK_USE_64BIT_OPS */ | |
106 | ||
107 | #if defined(DUK_USE_FASTINT) | |
108 | /* Note: masking is done for 'i' to deal with negative numbers correctly */ | |
109 | #ifdef DUK_USE_DOUBLE_ME | |
110 | #define DUK__TVAL_SET_FASTINT(v,i) do { \ | |
111 | (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \ | |
112 | (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ | |
113 | } while (0) | |
114 | #define DUK__TVAL_SET_FASTINT_U32(v,i) do { \ | |
115 | (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \ | |
116 | (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ | |
117 | } while (0) | |
118 | #else | |
119 | #define DUK__TVAL_SET_FASTINT(v,i) do { \ | |
120 | (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & 0x0000ffffffffffffULL); \ | |
121 | } while (0) | |
122 | #define DUK__TVAL_SET_FASTINT_U32(v,i) do { \ | |
123 | (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \ | |
124 | } while (0) | |
125 | #endif | |
126 | ||
127 | #define DUK__TVAL_SET_FASTINT_I32(v,i) do { \ | |
128 | duk_int64_t duk__tmp = (duk_int64_t) (i); \ | |
129 | DUK_TVAL_SET_FASTINT((v), duk__tmp); \ | |
130 | } while (0) | |
131 | ||
132 | /* XXX: clumsy sign extend and masking of 16 topmost bits */ | |
133 | #ifdef DUK_USE_DOUBLE_ME | |
134 | #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) | |
135 | #else | |
136 | #define DUK__TVAL_GET_FASTINT(v) ((((duk_int64_t) (v)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16) | |
137 | #endif | |
138 | #define DUK__TVAL_GET_FASTINT_U32(v) ((v)->ui[DUK_DBL_IDX_UI1]) | |
139 | #define DUK__TVAL_GET_FASTINT_I32(v) ((duk_int32_t) (v)->ui[DUK_DBL_IDX_UI1]) | |
140 | #endif /* DUK_USE_FASTINT */ | |
141 | ||
142 | #define DUK_TVAL_SET_UNDEFINED_ACTUAL(v) DUK_DBLUNION_SET_HIGH32((v), DUK_XTAG_UNDEFINED_ACTUAL) | |
143 | #define DUK_TVAL_SET_UNDEFINED_UNUSED(v) DUK_DBLUNION_SET_HIGH32((v), DUK_XTAG_UNDEFINED_UNUSED) | |
144 | ||
145 | /* Note: 16-bit initializer suffices (unlike for undefined/boolean) */ | |
146 | #define DUK_TVAL_SET_NULL(v) do { \ | |
147 | (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \ | |
148 | } while (0) | |
149 | ||
150 | #define DUK_TVAL_SET_BOOLEAN(v,val) DUK_DBLUNION_SET_HIGH32((v), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val))) | |
151 | ||
152 | #define DUK_TVAL_SET_NAN(v) DUK_DBLUNION_SET_NAN_FULL((v)) | |
153 | ||
154 | /* Assumes that caller has normalized NaNs, otherwise trouble ahead. */ | |
155 | #if defined(DUK_USE_FASTINT) | |
156 | #define DUK_TVAL_SET_DOUBLE(v,d) do { \ | |
157 | duk_double_t duk__dblval; \ | |
158 | duk__dblval = (d); \ | |
159 | DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \ | |
160 | DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \ | |
161 | } while (0) | |
162 | #define DUK_TVAL_SET_FASTINT(v,i) DUK__TVAL_SET_FASTINT((v), (i)) | |
163 | #define DUK_TVAL_SET_FASTINT_I32(v,i) DUK__TVAL_SET_FASTINT_I32((v), (i)) | |
164 | #define DUK_TVAL_SET_FASTINT_U32(v,i) DUK__TVAL_SET_FASTINT_U32((v), (i)) | |
165 | #define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) duk_tval_set_number_chkfast((v), (d)) | |
166 | #define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d)) | |
167 | #define DUK_TVAL_CHKFAST_INPLACE(v) do { \ | |
168 | duk_tval *duk__tv; \ | |
169 | duk_double_t duk__d; \ | |
170 | duk__tv = (v); \ | |
171 | if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ | |
172 | duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ | |
173 | DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \ | |
174 | } \ | |
175 | } while (0) | |
176 | #else | |
177 | #define DUK_TVAL_SET_DOUBLE(v,d) do { \ | |
178 | duk_double_t duk__dblval; \ | |
179 | duk__dblval = (d); \ | |
180 | DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \ | |
181 | DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \ | |
182 | } while (0) | |
183 | #define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) DUK_TVAL_SET_DOUBLE((v), (d)) | |
184 | #define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d)) | |
185 | #define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0) | |
186 | #endif | |
187 | ||
188 | #define DUK_TVAL_SET_LIGHTFUNC(v,fp,flags) DUK__TVAL_SET_LIGHTFUNC((v), (fp), (flags)) | |
189 | #define DUK_TVAL_SET_STRING(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_STRING) | |
190 | #define DUK_TVAL_SET_OBJECT(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_OBJECT) | |
191 | #define DUK_TVAL_SET_BUFFER(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_BUFFER) | |
192 | #define DUK_TVAL_SET_POINTER(v,p) DUK__TVAL_SET_TAGGEDPOINTER((v), (p), DUK_TAG_POINTER) | |
193 | ||
194 | #define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0) | |
195 | ||
196 | /* getters */ | |
197 | #define DUK_TVAL_GET_BOOLEAN(v) ((int) (v)->us[DUK_DBL_IDX_US1]) | |
198 | #if defined(DUK_USE_FASTINT) | |
199 | #define DUK_TVAL_GET_DOUBLE(v) ((v)->d) | |
200 | #define DUK_TVAL_GET_FASTINT(v) DUK__TVAL_GET_FASTINT((v)) | |
201 | #define DUK_TVAL_GET_FASTINT_U32(v) DUK__TVAL_GET_FASTINT_U32((v)) | |
202 | #define DUK_TVAL_GET_FASTINT_I32(v) DUK__TVAL_GET_FASTINT_I32((v)) | |
203 | #define DUK_TVAL_GET_NUMBER(v) duk_tval_get_number_packed((v)) | |
204 | #else | |
205 | #define DUK_TVAL_GET_NUMBER(v) ((v)->d) | |
206 | #define DUK_TVAL_GET_DOUBLE(v) ((v)->d) | |
207 | #endif | |
208 | #define DUK_TVAL_GET_LIGHTFUNC(v,out_fp,out_flags) do { \ | |
209 | (out_flags) = (v)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \ | |
210 | (out_fp) = (duk_c_function) (v)->ui[DUK_DBL_IDX_UI1]; \ | |
211 | } while (0) | |
212 | #define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(v) ((duk_c_function) ((v)->ui[DUK_DBL_IDX_UI1])) | |
213 | #define DUK_TVAL_GET_LIGHTFUNC_FLAGS(v) (((int) (v)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL) | |
214 | #define DUK_TVAL_GET_STRING(v) ((duk_hstring *) (v)->vp[DUK_DBL_IDX_VP1]) | |
215 | #define DUK_TVAL_GET_OBJECT(v) ((duk_hobject *) (v)->vp[DUK_DBL_IDX_VP1]) | |
216 | #define DUK_TVAL_GET_BUFFER(v) ((duk_hbuffer *) (v)->vp[DUK_DBL_IDX_VP1]) | |
217 | #define DUK_TVAL_GET_POINTER(v) ((void *) (v)->vp[DUK_DBL_IDX_VP1]) | |
218 | #define DUK_TVAL_GET_HEAPHDR(v) ((duk_heaphdr *) (v)->vp[DUK_DBL_IDX_VP1]) | |
219 | ||
220 | /* decoding */ | |
221 | #define DUK_TVAL_GET_TAG(v) ((duk_small_uint_t) (v)->us[DUK_DBL_IDX_US0]) | |
222 | ||
223 | #define DUK_TVAL_IS_UNDEFINED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNDEFINED) | |
224 | #define DUK_TVAL_IS_UNDEFINED_ACTUAL(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_UNDEFINED_ACTUAL) | |
225 | #define DUK_TVAL_IS_UNDEFINED_UNUSED(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_UNDEFINED_UNUSED) | |
226 | #define DUK_TVAL_IS_NULL(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_NULL) | |
227 | #define DUK_TVAL_IS_BOOLEAN(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BOOLEAN) | |
228 | #define DUK_TVAL_IS_BOOLEAN_TRUE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE) | |
229 | #define DUK_TVAL_IS_BOOLEAN_FALSE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE) | |
230 | #define DUK_TVAL_IS_LIGHTFUNC(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_LIGHTFUNC) | |
231 | #define DUK_TVAL_IS_STRING(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_STRING) | |
232 | #define DUK_TVAL_IS_OBJECT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_OBJECT) | |
233 | #define DUK_TVAL_IS_BUFFER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BUFFER) | |
234 | #define DUK_TVAL_IS_POINTER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_POINTER) | |
235 | #if defined(DUK_USE_FASTINT) | |
236 | /* 0xfff0 is -Infinity */ | |
237 | #define DUK_TVAL_IS_DOUBLE(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL) | |
238 | #define DUK_TVAL_IS_FASTINT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_FASTINT) | |
239 | #define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff1UL) | |
240 | #else | |
241 | #define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL) | |
242 | #define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v)) | |
243 | #endif | |
244 | ||
245 | #define DUK_TVAL_IS_HEAP_ALLOCATED(v) (DUK_TVAL_GET_TAG((v)) >= DUK_TAG_STRING) | |
246 | ||
247 | #if defined(DUK_USE_FASTINT) | |
248 | DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_packed(duk_tval *tv); | |
249 | #endif | |
250 | ||
251 | #else /* DUK_USE_PACKED_TVAL */ | |
252 | /* ======================================================================== */ | |
253 | ||
254 | /* | |
255 | * Portable 12-byte representation | |
256 | */ | |
257 | ||
258 | /* Note: not initializing all bytes is normally not an issue: Duktape won't | |
259 | * read or use the uninitialized bytes so valgrind won't issue warnings. | |
260 | * In some special cases a harmless valgrind warning may be issued though. | |
261 | * For example, the DumpHeap debugger command writes out a compiled function's | |
262 | * 'data' area as is, including any uninitialized bytes, which causes a | |
263 | * valgrind warning. | |
264 | */ | |
265 | ||
266 | typedef struct duk_tval_struct duk_tval; | |
267 | ||
268 | struct duk_tval_struct { | |
269 | duk_small_uint_t t; | |
270 | duk_small_uint_t v_extra; | |
271 | union { | |
272 | duk_double_t d; | |
273 | duk_small_int_t i; | |
274 | #if defined(DUK_USE_FASTINT) | |
275 | duk_int64_t fi; /* if present, forces 16-byte duk_tval */ | |
276 | #endif | |
277 | void *voidptr; | |
278 | duk_hstring *hstring; | |
279 | duk_hobject *hobject; | |
280 | duk_hcompiledfunction *hcompiledfunction; | |
281 | duk_hnativefunction *hnativefunction; | |
282 | duk_hthread *hthread; | |
283 | duk_hbuffer *hbuffer; | |
284 | duk_heaphdr *heaphdr; | |
285 | duk_c_function lightfunc; | |
286 | } v; | |
287 | }; | |
288 | ||
289 | #define DUK__TAG_NUMBER 0 /* not exposed */ | |
290 | #if defined(DUK_USE_FASTINT) | |
291 | #define DUK_TAG_FASTINT 1 | |
292 | #endif | |
293 | #define DUK_TAG_UNDEFINED 2 | |
294 | #define DUK_TAG_NULL 3 | |
295 | #define DUK_TAG_BOOLEAN 4 | |
296 | #define DUK_TAG_POINTER 5 | |
297 | #define DUK_TAG_LIGHTFUNC 6 | |
298 | #define DUK_TAG_STRING 7 | |
299 | #define DUK_TAG_OBJECT 8 | |
300 | #define DUK_TAG_BUFFER 9 | |
301 | ||
302 | /* DUK__TAG_NUMBER is intentionally first, as it is the default clause in code | |
303 | * to support the 8-byte representation. Further, it is a non-heap-allocated | |
304 | * type so it should come before DUK_TAG_STRING. Finally, it should not break | |
305 | * the tag value ranges covered by case-clauses in a switch-case. | |
306 | */ | |
307 | ||
308 | /* setters */ | |
309 | #define DUK_TVAL_SET_UNDEFINED_ACTUAL(tv) do { \ | |
310 | (tv)->t = DUK_TAG_UNDEFINED; \ | |
311 | (tv)->v.i = 0; \ | |
312 | } while (0) | |
313 | ||
314 | #define DUK_TVAL_SET_UNDEFINED_UNUSED(tv) do { \ | |
315 | (tv)->t = DUK_TAG_UNDEFINED; \ | |
316 | (tv)->v.i = 1; \ | |
317 | } while (0) | |
318 | ||
319 | #define DUK_TVAL_SET_NULL(tv) do { \ | |
320 | (tv)->t = DUK_TAG_NULL; \ | |
321 | } while (0) | |
322 | ||
323 | #define DUK_TVAL_SET_BOOLEAN(tv,val) do { \ | |
324 | (tv)->t = DUK_TAG_BOOLEAN; \ | |
325 | (tv)->v.i = (val); \ | |
326 | } while (0) | |
327 | ||
328 | #if defined(DUK_USE_FASTINT) | |
329 | #define DUK_TVAL_SET_DOUBLE(tv,val) do { \ | |
330 | (tv)->t = DUK__TAG_NUMBER; \ | |
331 | (tv)->v.d = (val); \ | |
332 | } while (0) | |
333 | #define DUK_TVAL_SET_FASTINT(tv,val) do { \ | |
334 | (tv)->t = DUK_TAG_FASTINT; \ | |
335 | (tv)->v.fi = (val); \ | |
336 | } while (0) | |
337 | #define DUK_TVAL_SET_FASTINT_U32(tv,val) do { \ | |
338 | (tv)->t = DUK_TAG_FASTINT; \ | |
339 | (tv)->v.fi = (duk_int64_t) (val); \ | |
340 | } while (0) | |
341 | #define DUK_TVAL_SET_FASTINT_I32(tv,val) do { \ | |
342 | (tv)->t = DUK_TAG_FASTINT; \ | |
343 | (tv)->v.fi = (duk_int64_t) (val); \ | |
344 | } while (0) | |
345 | #define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \ | |
346 | duk_tval_set_number_chkfast((tv), (d)) | |
347 | #define DUK_TVAL_SET_NUMBER(tv,val) \ | |
348 | DUK_TVAL_SET_DOUBLE((tv), (val)) | |
349 | #define DUK_TVAL_CHKFAST_INPLACE(v) do { \ | |
350 | duk_tval *duk__tv; \ | |
351 | duk_double_t duk__d; \ | |
352 | duk__tv = (v); \ | |
353 | if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ | |
354 | duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ | |
355 | DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \ | |
356 | } \ | |
357 | } while (0) | |
358 | #else | |
359 | #define DUK_TVAL_SET_NUMBER(tv,val) do { \ | |
360 | (tv)->t = DUK__TAG_NUMBER; \ | |
361 | (tv)->v.d = (val); \ | |
362 | } while (0) | |
363 | #define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \ | |
364 | DUK_TVAL_SET_NUMBER((tv), (d)) | |
365 | #define DUK_TVAL_SET_DOUBLE(v,d) \ | |
366 | DUK_TVAL_SET_NUMBER((tv), (d)) | |
367 | #define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0) | |
368 | #endif /* DUK_USE_FASTINT */ | |
369 | ||
370 | #define DUK_TVAL_SET_POINTER(tv,hptr) do { \ | |
371 | (tv)->t = DUK_TAG_POINTER; \ | |
372 | (tv)->v.voidptr = (hptr); \ | |
373 | } while (0) | |
374 | ||
375 | #define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ | |
376 | (tv)->t = DUK_TAG_LIGHTFUNC; \ | |
377 | (tv)->v_extra = (flags); \ | |
378 | (tv)->v.lightfunc = (duk_c_function) (fp); \ | |
379 | } while (0) | |
380 | ||
381 | #define DUK_TVAL_SET_STRING(tv,hptr) do { \ | |
382 | (tv)->t = DUK_TAG_STRING; \ | |
383 | (tv)->v.hstring = (hptr); \ | |
384 | } while (0) | |
385 | ||
386 | #define DUK_TVAL_SET_OBJECT(tv,hptr) do { \ | |
387 | (tv)->t = DUK_TAG_OBJECT; \ | |
388 | (tv)->v.hobject = (hptr); \ | |
389 | } while (0) | |
390 | ||
391 | #define DUK_TVAL_SET_BUFFER(tv,hptr) do { \ | |
392 | (tv)->t = DUK_TAG_BUFFER; \ | |
393 | (tv)->v.hbuffer = (hptr); \ | |
394 | } while (0) | |
395 | ||
396 | #define DUK_TVAL_SET_NAN(tv) do { \ | |
397 | /* in non-packed representation we don't care about which NaN is used */ \ | |
398 | (tv)->t = DUK__TAG_NUMBER; \ | |
399 | (tv)->v.d = DUK_DOUBLE_NAN; \ | |
400 | } while (0) | |
401 | ||
402 | #define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0) | |
403 | ||
404 | /* getters */ | |
405 | #define DUK_TVAL_GET_BOOLEAN(tv) ((tv)->v.i) | |
406 | #if defined(DUK_USE_FASTINT) | |
407 | #define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d) | |
408 | #define DUK_TVAL_GET_FASTINT(tv) ((tv)->v.fi) | |
409 | #define DUK_TVAL_GET_FASTINT_U32(tv) ((duk_uint32_t) ((tv)->v.fi)) | |
410 | #define DUK_TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) ((tv)->v.fi)) | |
411 | #if 0 | |
412 | #define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \ | |
413 | (duk_double_t) DUK_TVAL_GET_FASTINT((tv)) : \ | |
414 | DUK_TVAL_GET_DOUBLE((tv))) | |
415 | #define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_unpacked((tv)) | |
416 | #else | |
417 | /* This seems reasonable overall. */ | |
418 | #define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \ | |
419 | duk_tval_get_number_unpacked_fastint((tv)) : \ | |
420 | DUK_TVAL_GET_DOUBLE((tv))) | |
421 | #endif | |
422 | #else | |
423 | #define DUK_TVAL_GET_NUMBER(tv) ((tv)->v.d) | |
424 | #define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d) | |
425 | #endif /* DUK_USE_FASTINT */ | |
426 | #define DUK_TVAL_GET_POINTER(tv) ((tv)->v.voidptr) | |
427 | #define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \ | |
428 | (out_flags) = (duk_uint32_t) (tv)->v_extra; \ | |
429 | (out_fp) = (tv)->v.lightfunc; \ | |
430 | } while (0) | |
431 | #define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc) | |
432 | #define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_uint32_t) ((tv)->v_extra)) | |
433 | #define DUK_TVAL_GET_STRING(tv) ((tv)->v.hstring) | |
434 | #define DUK_TVAL_GET_OBJECT(tv) ((tv)->v.hobject) | |
435 | #define DUK_TVAL_GET_BUFFER(tv) ((tv)->v.hbuffer) | |
436 | #define DUK_TVAL_GET_HEAPHDR(tv) ((tv)->v.heaphdr) | |
437 | ||
438 | /* decoding */ | |
439 | #define DUK_TVAL_GET_TAG(tv) ((tv)->t) | |
440 | #define DUK_TVAL_IS_UNDEFINED(tv) ((tv)->t == DUK_TAG_UNDEFINED) | |
441 | #define DUK_TVAL_IS_UNDEFINED_ACTUAL(tv) (((tv)->t == DUK_TAG_UNDEFINED) && ((tv)->v.i == 0)) | |
442 | #define DUK_TVAL_IS_UNDEFINED_UNUSED(tv) (((tv)->t == DUK_TAG_UNDEFINED) && ((tv)->v.i != 0)) | |
443 | #define DUK_TVAL_IS_NULL(tv) ((tv)->t == DUK_TAG_NULL) | |
444 | #define DUK_TVAL_IS_BOOLEAN(tv) ((tv)->t == DUK_TAG_BOOLEAN) | |
445 | #define DUK_TVAL_IS_BOOLEAN_TRUE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0)) | |
446 | #define DUK_TVAL_IS_BOOLEAN_FALSE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0)) | |
447 | #if defined(DUK_USE_FASTINT) | |
448 | #define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK__TAG_NUMBER) | |
449 | #define DUK_TVAL_IS_FASTINT(tv) ((tv)->t == DUK_TAG_FASTINT) | |
450 | #define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER || \ | |
451 | (tv)->t == DUK_TAG_FASTINT) | |
452 | #else | |
453 | #define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER) | |
454 | #define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v)) | |
455 | #endif /* DUK_USE_FASTINT */ | |
456 | #define DUK_TVAL_IS_POINTER(tv) ((tv)->t == DUK_TAG_POINTER) | |
457 | #define DUK_TVAL_IS_LIGHTFUNC(tv) ((tv)->t == DUK_TAG_LIGHTFUNC) | |
458 | #define DUK_TVAL_IS_STRING(tv) ((tv)->t == DUK_TAG_STRING) | |
459 | #define DUK_TVAL_IS_OBJECT(tv) ((tv)->t == DUK_TAG_OBJECT) | |
460 | #define DUK_TVAL_IS_BUFFER(tv) ((tv)->t == DUK_TAG_BUFFER) | |
461 | ||
462 | #define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t >= DUK_TAG_STRING) | |
463 | ||
464 | #if defined(DUK_USE_FASTINT) | |
465 | #if 0 | |
466 | DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked(duk_tval *tv); | |
467 | #endif | |
468 | DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv); | |
469 | #endif | |
470 | ||
471 | #endif /* DUK_USE_PACKED_TVAL */ | |
472 | ||
473 | /* | |
474 | * Convenience (independent of representation) | |
475 | */ | |
476 | ||
477 | #define DUK_TVAL_SET_BOOLEAN_TRUE(v) DUK_TVAL_SET_BOOLEAN(v, 1) | |
478 | #define DUK_TVAL_SET_BOOLEAN_FALSE(v) DUK_TVAL_SET_BOOLEAN(v, 0) | |
479 | ||
480 | /* Lightfunc flags packing and unpacking. */ | |
481 | /* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss## */ | |
482 | #define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \ | |
483 | ((((duk_int32_t) (lf_flags)) << 16) >> 24) | |
484 | #define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \ | |
485 | (((lf_flags) >> 4) & 0x0f) | |
486 | #define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \ | |
487 | ((lf_flags) & 0x0f) | |
488 | #define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \ | |
489 | (((magic) & 0xff) << 8) | ((length) << 4) | (nargs) | |
490 | ||
491 | #define DUK_LFUNC_NARGS_VARARGS 0x0f /* varargs marker */ | |
492 | #define DUK_LFUNC_NARGS_MIN 0x00 | |
493 | #define DUK_LFUNC_NARGS_MAX 0x0e /* max, excl. varargs marker */ | |
494 | #define DUK_LFUNC_LENGTH_MIN 0x00 | |
495 | #define DUK_LFUNC_LENGTH_MAX 0x0f | |
496 | #define DUK_LFUNC_MAGIC_MIN (-0x80) | |
497 | #define DUK_LFUNC_MAGIC_MAX 0x7f | |
498 | ||
499 | /* fastint constants etc */ | |
500 | #if defined(DUK_USE_FASTINT) | |
501 | #define DUK_FASTINT_MIN (-0x800000000000LL) | |
502 | #define DUK_FASTINT_MAX 0x7fffffffffffLL | |
503 | #define DUK_FASTINT_BITS 48 | |
504 | ||
505 | DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x); | |
506 | #endif | |
507 | ||
508 | #endif /* DUK_TVAL_H_INCLUDED */ |