1 /*
2  *  Heap header definition and assorted macros, including ref counting.
3  *  Access all fields through the accessor macros.
4  */
5 
6 #ifndef DUK_HEAPHDR_H_INCLUDED
7 #define DUK_HEAPHDR_H_INCLUDED
8 
9 /*
10  *  Common heap header
11  *
12  *  All heap objects share the same flags and refcount fields.  Objects other
13  *  than strings also need to have a single or double linked list pointers
14  *  for insertion into the "heap allocated" list.  Strings are held in the
15  *  heap-wide string table so they don't need link pointers.
16  *
17  *  Technically, 'h_refcount' must be wide enough to guarantee that it cannot
18  *  wrap (otherwise objects might be freed incorrectly after wrapping).  This
19  *  means essentially that the refcount field must be as wide as data pointers.
20  *  On 64-bit platforms this means that the refcount needs to be 64 bits even
21  *  if an 'int' is 32 bits.  This is a bit unfortunate, and compromising on
22  *  this might be reasonable in the future.
23  *
24  *  Heap header size on 32-bit platforms: 8 bytes without reference counting,
25  *  16 bytes with reference counting.
26  */
27 
28 struct duk_heaphdr {
29 	duk_uint32_t h_flags;
30 
31 #if defined(DUK_USE_REFERENCE_COUNTING)
32 #if defined(DUK_USE_REFCOUNT16)
33 	duk_uint16_t h_refcount16;
34 #else
35 	duk_size_t h_refcount;
36 #endif
37 #endif
38 
39 #if defined(DUK_USE_HEAPPTR16)
40 	duk_uint16_t h_next16;
41 #else
42 	duk_heaphdr *h_next;
43 #endif
44 
45 #if defined(DUK_USE_DOUBLE_LINKED_HEAP)
46 	/* refcounting requires direct heap frees, which in turn requires a dual linked heap */
47 #if defined(DUK_USE_HEAPPTR16)
48 	duk_uint16_t h_prev16;
49 #else
50 	duk_heaphdr *h_prev;
51 #endif
52 #endif
53 
54 	/* When DUK_USE_HEAPPTR16 (and DUK_USE_REFCOUNT16) is in use, the
55 	 * struct won't align nicely to 4 bytes.  This 16-bit extra field
56 	 * is added to make the alignment clean; the field can be used by
57 	 * heap objects when 16-bit packing is used.  This field is now
58 	 * conditional to DUK_USE_HEAPPTR16 only, but it is intended to be
59 	 * used with DUK_USE_REFCOUNT16 and DUK_USE_DOUBLE_LINKED_HEAP;
60 	 * this only matter to low memory environments anyway.
61 	 */
62 #if defined(DUK_USE_HEAPPTR16)
63 	duk_uint16_t h_extra16;
64 #endif
65 };
66 
67 struct duk_heaphdr_string {
68 	/* 16 bits would be enough for shared heaphdr flags and duk_hstring
69 	 * flags.  The initial parts of duk_heaphdr_string and duk_heaphdr
70 	 * must match so changing the flags field size here would be quite
71 	 * awkward.  However, to minimize struct size, we can pack at least
72 	 * 16 bits of duk_hstring data into the flags field.
73 	 */
74 	duk_uint32_t h_flags;
75 
76 #if defined(DUK_USE_REFERENCE_COUNTING)
77 #if defined(DUK_USE_REFCOUNT16)
78 	duk_uint16_t h_refcount16;
79 	duk_uint16_t h_strextra16;  /* round out to 8 bytes */
80 #else
81 	duk_size_t h_refcount;
82 #endif
83 #else
84 	duk_uint16_t h_strextra16;
85 #endif
86 };
87 
88 #define DUK_HEAPHDR_FLAGS_TYPE_MASK      0x00000003UL
89 #define DUK_HEAPHDR_FLAGS_FLAG_MASK      (~DUK_HEAPHDR_FLAGS_TYPE_MASK)
90 
91                                              /* 2 bits for heap type */
92 #define DUK_HEAPHDR_FLAGS_HEAP_START     2   /* 5 heap flags */
93 #define DUK_HEAPHDR_FLAGS_USER_START     7   /* 25 user flags */
94 
95 #define DUK_HEAPHDR_HEAP_FLAG_NUMBER(n)  (DUK_HEAPHDR_FLAGS_HEAP_START + (n))
96 #define DUK_HEAPHDR_USER_FLAG_NUMBER(n)  (DUK_HEAPHDR_FLAGS_USER_START + (n))
97 #define DUK_HEAPHDR_HEAP_FLAG(n)         (1UL << (DUK_HEAPHDR_FLAGS_HEAP_START + (n)))
98 #define DUK_HEAPHDR_USER_FLAG(n)         (1UL << (DUK_HEAPHDR_FLAGS_USER_START + (n)))
99 
100 #define DUK_HEAPHDR_FLAG_REACHABLE       DUK_HEAPHDR_HEAP_FLAG(0)  /* mark-and-sweep: reachable */
101 #define DUK_HEAPHDR_FLAG_TEMPROOT        DUK_HEAPHDR_HEAP_FLAG(1)  /* mark-and-sweep: children not processed */
102 #define DUK_HEAPHDR_FLAG_FINALIZABLE     DUK_HEAPHDR_HEAP_FLAG(2)  /* mark-and-sweep: finalizable (on current pass) */
103 #define DUK_HEAPHDR_FLAG_FINALIZED       DUK_HEAPHDR_HEAP_FLAG(3)  /* mark-and-sweep: finalized (on previous pass) */
104 #define DUK_HEAPHDR_FLAG_READONLY        DUK_HEAPHDR_HEAP_FLAG(4)  /* read-only object, in code section */
105 
106 #define DUK_HTYPE_MIN                    1
107 #define DUK_HTYPE_STRING                 1
108 #define DUK_HTYPE_OBJECT                 2
109 #define DUK_HTYPE_BUFFER                 3
110 #define DUK_HTYPE_MAX                    3
111 
112 #if defined(DUK_USE_HEAPPTR16)
113 #define DUK_HEAPHDR_GET_NEXT(heap,h) \
114 	((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_next16))
115 #define DUK_HEAPHDR_SET_NEXT(heap,h,val)   do { \
116 		(h)->h_next16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) val); \
117 	} while (0)
118 #else
119 #define DUK_HEAPHDR_GET_NEXT(heap,h)  ((h)->h_next)
120 #define DUK_HEAPHDR_SET_NEXT(heap,h,val)   do { \
121 		(h)->h_next = (val); \
122 	} while (0)
123 #endif
124 
125 #if defined(DUK_USE_DOUBLE_LINKED_HEAP)
126 #if defined(DUK_USE_HEAPPTR16)
127 #define DUK_HEAPHDR_GET_PREV(heap,h) \
128 	((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_prev16))
129 #define DUK_HEAPHDR_SET_PREV(heap,h,val)   do { \
130 		(h)->h_prev16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (val)); \
131 	} while (0)
132 #else
133 #define DUK_HEAPHDR_GET_PREV(heap,h)       ((h)->h_prev)
134 #define DUK_HEAPHDR_SET_PREV(heap,h,val)   do { \
135 		(h)->h_prev = (val); \
136 	} while (0)
137 #endif
138 #endif
139 
140 #if defined(DUK_USE_REFERENCE_COUNTING)
141 #if defined(DUK_USE_REFCOUNT16)
142 #define DUK_HEAPHDR_GET_REFCOUNT(h)   ((h)->h_refcount16)
143 #define DUK_HEAPHDR_SET_REFCOUNT(h,val)  do { \
144 		(h)->h_refcount16 = (val); \
145 	} while (0)
146 #define DUK_HEAPHDR_PREINC_REFCOUNT(h)  (++(h)->h_refcount16)  /* result: updated refcount */
147 #define DUK_HEAPHDR_PREDEC_REFCOUNT(h)  (--(h)->h_refcount16)  /* result: updated refcount */
148 #else
149 #define DUK_HEAPHDR_GET_REFCOUNT(h)   ((h)->h_refcount)
150 #define DUK_HEAPHDR_SET_REFCOUNT(h,val)  do { \
151 		(h)->h_refcount = (val); \
152 	} while (0)
153 #define DUK_HEAPHDR_PREINC_REFCOUNT(h)  (++(h)->h_refcount)  /* result: updated refcount */
154 #define DUK_HEAPHDR_PREDEC_REFCOUNT(h)  (--(h)->h_refcount)  /* result: updated refcount */
155 #endif
156 #else
157 /* refcount macros not defined without refcounting, caller must #ifdef now */
158 #endif  /* DUK_USE_REFERENCE_COUNTING */
159 
160 /*
161  *  Note: type is treated as a field separate from flags, so some masking is
162  *  involved in the macros below.
163  */
164 
165 #define DUK_HEAPHDR_GET_FLAGS_RAW(h)  ((h)->h_flags)
166 
167 #define DUK_HEAPHDR_GET_FLAGS(h)      ((h)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK)
168 #define DUK_HEAPHDR_SET_FLAGS(h,val)  do { \
169 		(h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) | (val); \
170 	} while (0)
171 
172 #define DUK_HEAPHDR_GET_TYPE(h)       ((h)->h_flags & DUK_HEAPHDR_FLAGS_TYPE_MASK)
173 #define DUK_HEAPHDR_SET_TYPE(h,val)   do { \
174 		(h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_TYPE_MASK)) | (val); \
175 	} while (0)
176 
177 #define DUK_HEAPHDR_HTYPE_VALID(h)    ( \
178 	DUK_HEAPHDR_GET_TYPE((h)) >= DUK_HTYPE_MIN && \
179 	DUK_HEAPHDR_GET_TYPE((h)) <= DUK_HTYPE_MAX \
180 	)
181 
182 #define DUK_HEAPHDR_SET_TYPE_AND_FLAGS(h,tval,fval)  do { \
183 		(h)->h_flags = ((tval) & DUK_HEAPHDR_FLAGS_TYPE_MASK) | \
184 		               ((fval) & DUK_HEAPHDR_FLAGS_FLAG_MASK); \
185 	} while (0)
186 
187 #define DUK_HEAPHDR_SET_FLAG_BITS(h,bits)  do { \
188 		DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
189 		(h)->h_flags |= (bits); \
190 	} while (0)
191 
192 #define DUK_HEAPHDR_CLEAR_FLAG_BITS(h,bits)  do { \
193 		DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
194 		(h)->h_flags &= ~((bits)); \
195 	} while (0)
196 
197 #define DUK_HEAPHDR_CHECK_FLAG_BITS(h,bits)  (((h)->h_flags & (bits)) != 0)
198 
199 #define DUK_HEAPHDR_SET_REACHABLE(h)      DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
200 #define DUK_HEAPHDR_CLEAR_REACHABLE(h)    DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
201 #define DUK_HEAPHDR_HAS_REACHABLE(h)      DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
202 
203 #define DUK_HEAPHDR_SET_TEMPROOT(h)       DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
204 #define DUK_HEAPHDR_CLEAR_TEMPROOT(h)     DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
205 #define DUK_HEAPHDR_HAS_TEMPROOT(h)       DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
206 
207 #define DUK_HEAPHDR_SET_FINALIZABLE(h)    DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
208 #define DUK_HEAPHDR_CLEAR_FINALIZABLE(h)  DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
209 #define DUK_HEAPHDR_HAS_FINALIZABLE(h)    DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
210 
211 #define DUK_HEAPHDR_SET_FINALIZED(h)      DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
212 #define DUK_HEAPHDR_CLEAR_FINALIZED(h)    DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
213 #define DUK_HEAPHDR_HAS_FINALIZED(h)      DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
214 
215 #define DUK_HEAPHDR_SET_READONLY(h)       DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
216 #define DUK_HEAPHDR_CLEAR_READONLY(h)     DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
217 #define DUK_HEAPHDR_HAS_READONLY(h)       DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
218 
219 /* get or set a range of flags; m=first bit number, n=number of bits */
220 #define DUK_HEAPHDR_GET_FLAG_RANGE(h,m,n)  (((h)->h_flags >> (m)) & ((1UL << (n)) - 1UL))
221 
222 #define DUK_HEAPHDR_SET_FLAG_RANGE(h,m,n,v)  do { \
223 		(h)->h_flags = \
224 			((h)->h_flags & (~(((1UL << (n)) - 1UL) << (m)))) \
225 			| ((v) << (m)); \
226 	} while (0)
227 
228 /* init pointer fields to null */
229 #if defined(DUK_USE_DOUBLE_LINKED_HEAP)
230 #define DUK_HEAPHDR_INIT_NULLS(h)       do { \
231 		DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
232 		DUK_HEAPHDR_SET_PREV((h), (void *) NULL); \
233 	} while (0)
234 #else
235 #define DUK_HEAPHDR_INIT_NULLS(h)       do { \
236 		DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
237 	} while (0)
238 #endif
239 
240 #define DUK_HEAPHDR_STRING_INIT_NULLS(h)  /* currently nop */
241 
242 /*
243  *  Assert helpers
244  */
245 
246 /* Check that prev/next links are consistent: if e.g. h->prev is != NULL,
247  * h->prev->next should point back to h.
248  */
249 #if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_ASSERTIONS)
250 #define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do { \
251 		if ((h) != NULL) { \
252 			duk_heaphdr *h__prev, *h__next; \
253 			h__prev = DUK_HEAPHDR_GET_PREV((heap), (h)); \
254 			h__next = DUK_HEAPHDR_GET_NEXT((heap), (h)); \
255 			DUK_ASSERT(h__prev == NULL || (DUK_HEAPHDR_GET_NEXT((heap), h__prev) == (h))); \
256 			DUK_ASSERT(h__next == NULL || (DUK_HEAPHDR_GET_PREV((heap), h__next) == (h))); \
257 		} \
258 	} while (0)
259 #else
260 #define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do {} while (0)
261 #endif
262 
263 /*
264  *  Reference counting helper macros.  The macros take a thread argument
265  *  and must thus always be executed in a specific thread context.  The
266  *  thread argument is needed for features like finalization.  Currently
267  *  it is not required for INCREF, but it is included just in case.
268  *
269  *  Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not
270  *  defined without DUK_USE_REFERENCE_COUNTING, so caller must #ifdef
271  *  around them.
272  */
273 
274 #if defined(DUK_USE_REFERENCE_COUNTING)
275 
276 #if defined(DUK_USE_ROM_OBJECTS)
277 /* With ROM objects "needs refcount update" is true when the value is
278  * heap allocated and is not a ROM object.
279  */
280 /* XXX: double evaluation for 'tv' argument. */
281 #define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) \
282 	(DUK_TVAL_IS_HEAP_ALLOCATED((tv)) && !DUK_HEAPHDR_HAS_READONLY(DUK_TVAL_GET_HEAPHDR((tv))))
283 #define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h)  (!DUK_HEAPHDR_HAS_READONLY((h)))
284 #else  /* DUK_USE_ROM_OBJECTS */
285 /* Without ROM objects "needs refcount update" == is heap allocated. */
286 #define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)    DUK_TVAL_IS_HEAP_ALLOCATED((tv))
287 #define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h)  1
288 #endif  /* DUK_USE_ROM_OBJECTS */
289 
290 /* Fast variants, inline refcount operations except for refzero handling.
291  * Can be used explicitly when speed is always more important than size.
292  * For a good compiler and a single file build, these are basically the
293  * same as a forced inline.
294  */
295 #define DUK_TVAL_INCREF_FAST(thr,tv) do { \
296 		duk_tval *duk__tv = (tv); \
297 		DUK_ASSERT(duk__tv != NULL); \
298 		if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
299 			duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
300 			DUK_ASSERT(duk__h != NULL); \
301 			DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
302 			DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
303 		} \
304 	} while (0)
305 #define DUK_TVAL_DECREF_FAST(thr,tv) do { \
306 		duk_tval *duk__tv = (tv); \
307 		DUK_ASSERT(duk__tv != NULL); \
308 		if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
309 			duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
310 			DUK_ASSERT(duk__h != NULL); \
311 			DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
312 			DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
313 			if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
314 				duk_heaphdr_refzero((thr), duk__h); \
315 			} \
316 		} \
317 	} while (0)
318 #define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \
319 		duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
320 		DUK_ASSERT(duk__h != NULL); \
321 		DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
322 		if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
323 			DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
324 		} \
325 	} while (0)
326 #define DUK_HEAPHDR_DECREF_FAST(thr,h) do { \
327 		duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
328 		DUK_ASSERT(duk__h != NULL); \
329 		DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
330 		DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
331 		if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
332 			if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
333 				duk_heaphdr_refzero((thr), duk__h); \
334 			} \
335 		} \
336 	} while (0)
337 
338 /* Slow variants, call to a helper to reduce code size.
339  * Can be used explicitly when size is always more important than speed.
340  */
341 #define DUK_TVAL_INCREF_SLOW(thr,tv) do { \
342 		duk_tval_incref((tv)); \
343 	} while (0)
344 #define DUK_TVAL_DECREF_SLOW(thr,tv) do { \
345 		duk_tval_decref((thr), (tv)); \
346 	} while (0)
347 #define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { \
348 		duk_heaphdr_incref((duk_heaphdr *) (h)); \
349 	} while (0)
350 #define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { \
351 		duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); \
352 	} while (0)
353 
354 /* Default variants.  Selection depends on speed/size preference.
355  * Concretely: with gcc 4.8.1 -Os x64 the difference in final binary
356  * is about +1kB for _FAST variants.
357  */
358 #if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
359 #define DUK_TVAL_INCREF(thr,tv)                DUK_TVAL_INCREF_FAST((thr),(tv))
360 #define DUK_TVAL_DECREF(thr,tv)                DUK_TVAL_DECREF_FAST((thr),(tv))
361 #define DUK_HEAPHDR_INCREF(thr,h)              DUK_HEAPHDR_INCREF_FAST((thr),(h))
362 #define DUK_HEAPHDR_DECREF(thr,h)              DUK_HEAPHDR_DECREF_FAST((thr),(h))
363 #else
364 #define DUK_TVAL_INCREF(thr,tv)                DUK_TVAL_INCREF_SLOW((thr),(tv))
365 #define DUK_TVAL_DECREF(thr,tv)                DUK_TVAL_DECREF_SLOW((thr),(tv))
366 #define DUK_HEAPHDR_INCREF(thr,h)              DUK_HEAPHDR_INCREF_SLOW((thr),(h))
367 #define DUK_HEAPHDR_DECREF(thr,h)              DUK_HEAPHDR_DECREF_SLOW((thr),(h))
368 #endif
369 
370 /* Casting convenience. */
371 #define DUK_HSTRING_INCREF(thr,h)              DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
372 #define DUK_HSTRING_DECREF(thr,h)              DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
373 #define DUK_HOBJECT_INCREF(thr,h)              DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
374 #define DUK_HOBJECT_DECREF(thr,h)              DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
375 #define DUK_HBUFFER_INCREF(thr,h)              DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
376 #define DUK_HBUFFER_DECREF(thr,h)              DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
377 #define DUK_HCOMPILEDFUNCTION_INCREF(thr,h)    DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
378 #define DUK_HCOMPILEDFUNCTION_DECREF(thr,h)    DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
379 #define DUK_HNATIVEFUNCTION_INCREF(thr,h)      DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
380 #define DUK_HNATIVEFUNCTION_DECREF(thr,h)      DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
381 #define DUK_HBUFFEROBJECT_INCREF(thr,h)        DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
382 #define DUK_HBUFFEROBJECT_DECREF(thr,h)        DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
383 #define DUK_HTHREAD_INCREF(thr,h)              DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
384 #define DUK_HTHREAD_DECREF(thr,h)              DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
385 
386 /* Convenience for some situations; the above macros don't allow NULLs
387  * for performance reasons.
388  */
389 #define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \
390 		if ((h) != NULL) { \
391 			DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \
392 		} \
393 	} while (0)
394 #define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \
395 		if ((h) != NULL) { \
396 			DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \
397 		} \
398 	} while (0)
399 
400 /*
401  *  Macros to set a duk_tval and update refcount of the target (decref the
402  *  old value and incref the new value if necessary).  This is both performance
403  *  and footprint critical; any changes made should be measured for size/speed.
404  */
405 
406 #define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
407 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
408 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
409 		DUK_TVAL_SET_UNDEFINED(tv__dst); \
410 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
411 	} while (0)
412 
413 #define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
414 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
415 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
416 		DUK_TVAL_SET_UNUSED(tv__dst); \
417 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
418 	} while (0)
419 
420 #define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \
421 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
422 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
423 		DUK_TVAL_SET_NULL(tv__dst); \
424 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
425 	} while (0)
426 
427 #define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
428 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
429 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
430 		DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \
431 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
432 	} while (0)
433 
434 #define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
435 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
436 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
437 		DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \
438 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
439 	} while (0)
440 #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
441 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
442 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
443 		DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \
444 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
445 	} while (0)
446 #define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
447 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
448 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
449 		DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \
450 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
451 	} while (0)
452 #define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \
453 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
454 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
455 		DUK_TVAL_SET_NAN(tv__dst); \
456 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
457 	} while (0)
458 #if defined(DUK_USE_FASTINT)
459 #define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
460 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
461 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
462 		DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \
463 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
464 	} while (0)
465 #define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
466 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
467 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
468 		DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \
469 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
470 	} while (0)
471 #define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
472 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
473 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
474 		DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \
475 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
476 	} while (0)
477 #else
478 #define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \
479 	DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval))
480 #endif  /* DUK_USE_FASTINT */
481 
482 #define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \
483 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
484 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
485 		DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \
486 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
487 	} while (0)
488 
489 #define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
490 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
491 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
492 		DUK_TVAL_SET_STRING(tv__dst, (newval)); \
493 		DUK_HSTRING_INCREF((thr), (newval)); \
494 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
495 	} while (0)
496 
497 #define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
498 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
499 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
500 		DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \
501 		DUK_HOBJECT_INCREF((thr), (newval)); \
502 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
503 	} while (0)
504 
505 #define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
506 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
507 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
508 		DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \
509 		DUK_HBUFFER_INCREF((thr), (newval)); \
510 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
511 	} while (0)
512 
513 #define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
514 		duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
515 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
516 		DUK_TVAL_SET_POINTER(tv__dst, (newval)); \
517 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
518 	} while (0)
519 
520 /* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups,
521  * etc, so it's very important for performance.  Measure when changing.
522  *
523  * NOTE: the source and destination duk_tval pointers may be the same, and
524  * the macros MUST deal with that correctly.
525  */
526 
527 /* Original idiom used, minimal code size. */
528 #define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \
529 		duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \
530 		tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
531 		DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
532 		DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
533 		DUK_TVAL_INCREF((thr), tv__src); \
534 		DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
535 	} while (0)
536 
537 /* Faster alternative: avoid making a temporary copy of tvptr_dst and use
538  * fast incref/decref macros.
539  */
540 #define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \
541 		duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \
542 		tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
543 		DUK_TVAL_INCREF_FAST((thr), tv__src); \
544 		if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv__dst)) { \
545 			h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \
546 			DUK_ASSERT(h__obj != NULL); \
547 			DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
548 			DUK_HEAPHDR_DECREF_FAST((thr), h__obj);  /* side effects */ \
549 		} else { \
550 			DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
551 		} \
552 	} while (0)
553 
554 /* XXX: no optimized variants yet */
555 #define DUK_TVAL_SET_UNDEFINED_UPDREF         DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
556 #define DUK_TVAL_SET_UNUSED_UPDREF            DUK_TVAL_SET_UNUSED_UPDREF_ALT0
557 #define DUK_TVAL_SET_NULL_UPDREF              DUK_TVAL_SET_NULL_UPDREF_ALT0
558 #define DUK_TVAL_SET_BOOLEAN_UPDREF           DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
559 #define DUK_TVAL_SET_NUMBER_UPDREF            DUK_TVAL_SET_NUMBER_UPDREF_ALT0
560 #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF    DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0
561 #define DUK_TVAL_SET_DOUBLE_UPDREF            DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
562 #define DUK_TVAL_SET_NAN_UPDREF               DUK_TVAL_SET_NAN_UPDREF_ALT0
563 #if defined(DUK_USE_FASTINT)
564 #define DUK_TVAL_SET_FASTINT_UPDREF           DUK_TVAL_SET_FASTINT_UPDREF_ALT0
565 #define DUK_TVAL_SET_FASTINT_I32_UPDREF       DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0
566 #define DUK_TVAL_SET_FASTINT_U32_UPDREF       DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0
567 #else
568 #define DUK_TVAL_SET_FASTINT_UPDREF           DUK_TVAL_SET_DOUBLE_CAST_UPDREF  /* XXX: fast int-to-double */
569 #define DUK_TVAL_SET_FASTINT_I32_UPDREF       DUK_TVAL_SET_DOUBLE_CAST_UPDREF
570 #define DUK_TVAL_SET_FASTINT_U32_UPDREF       DUK_TVAL_SET_DOUBLE_CAST_UPDREF
571 #endif  /* DUK_USE_FASTINT */
572 #define DUK_TVAL_SET_LIGHTFUNC_UPDREF         DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
573 #define DUK_TVAL_SET_STRING_UPDREF            DUK_TVAL_SET_STRING_UPDREF_ALT0
574 #define DUK_TVAL_SET_OBJECT_UPDREF            DUK_TVAL_SET_OBJECT_UPDREF_ALT0
575 #define DUK_TVAL_SET_BUFFER_UPDREF            DUK_TVAL_SET_BUFFER_UPDREF_ALT0
576 #define DUK_TVAL_SET_POINTER_UPDREF           DUK_TVAL_SET_POINTER_UPDREF_ALT0
577 
578 #if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
579 /* Optimized for speed. */
580 #define DUK_TVAL_SET_TVAL_UPDREF              DUK_TVAL_SET_TVAL_UPDREF_ALT1
581 #define DUK_TVAL_SET_TVAL_UPDREF_FAST         DUK_TVAL_SET_TVAL_UPDREF_ALT1
582 #define DUK_TVAL_SET_TVAL_UPDREF_SLOW         DUK_TVAL_SET_TVAL_UPDREF_ALT0
583 #else
584 /* Optimized for size. */
585 #define DUK_TVAL_SET_TVAL_UPDREF              DUK_TVAL_SET_TVAL_UPDREF_ALT0
586 #define DUK_TVAL_SET_TVAL_UPDREF_FAST         DUK_TVAL_SET_TVAL_UPDREF_ALT0
587 #define DUK_TVAL_SET_TVAL_UPDREF_SLOW         DUK_TVAL_SET_TVAL_UPDREF_ALT0
588 #endif
589 
590 #else  /* DUK_USE_REFERENCE_COUNTING */
591 
592 #define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)     0
593 #define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h)   0
594 
595 #define DUK_TVAL_INCREF_FAST(thr,v)            do {} while (0) /* nop */
596 #define DUK_TVAL_DECREF_FAST(thr,v)            do {} while (0) /* nop */
597 #define DUK_TVAL_INCREF_SLOW(thr,v)            do {} while (0) /* nop */
598 #define DUK_TVAL_DECREF_SLOW(thr,v)            do {} while (0) /* nop */
599 #define DUK_TVAL_INCREF(thr,v)                 do {} while (0) /* nop */
600 #define DUK_TVAL_DECREF(thr,v)                 do {} while (0) /* nop */
601 #define DUK_HEAPHDR_INCREF_FAST(thr,h)         do {} while (0) /* nop */
602 #define DUK_HEAPHDR_DECREF_FAST(thr,h)         do {} while (0) /* nop */
603 #define DUK_HEAPHDR_INCREF_SLOW(thr,h)         do {} while (0) /* nop */
604 #define DUK_HEAPHDR_DECREF_SLOW(thr,h)         do {} while (0) /* nop */
605 #define DUK_HEAPHDR_INCREF(thr,h)              do {} while (0) /* nop */
606 #define DUK_HEAPHDR_DECREF(thr,h)              do {} while (0) /* nop */
607 #define DUK_HSTRING_INCREF(thr,h)              do {} while (0) /* nop */
608 #define DUK_HSTRING_DECREF(thr,h)              do {} while (0) /* nop */
609 #define DUK_HOBJECT_INCREF(thr,h)              do {} while (0) /* nop */
610 #define DUK_HOBJECT_DECREF(thr,h)              do {} while (0) /* nop */
611 #define DUK_HBUFFER_INCREF(thr,h)              do {} while (0) /* nop */
612 #define DUK_HBUFFER_DECREF(thr,h)              do {} while (0) /* nop */
613 #define DUK_HCOMPILEDFUNCTION_INCREF(thr,h)    do {} while (0) /* nop */
614 #define DUK_HCOMPILEDFUNCTION_DECREF(thr,h)    do {} while (0) /* nop */
615 #define DUK_HNATIVEFUNCTION_INCREF(thr,h)      do {} while (0) /* nop */
616 #define DUK_HNATIVEFUNCTION_DECREF(thr,h)      do {} while (0) /* nop */
617 #define DUK_HBUFFEROBJECT_INCREF(thr,h)        do {} while (0) /* nop */
618 #define DUK_HBUFFEROBJECT_DECREF(thr,h)        do {} while (0) /* nop */
619 #define DUK_HTHREAD_INCREF(thr,h)              do {} while (0) /* nop */
620 #define DUK_HTHREAD_DECREF(thr,h)              do {} while (0) /* nop */
621 #define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h)    do {} while (0) /* nop */
622 #define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h)    do {} while (0) /* nop */
623 
624 #define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
625 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
626 		DUK_TVAL_SET_UNDEFINED(tv__dst); \
627 		DUK_UNREF((thr)); \
628 	} while (0)
629 
630 #define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
631 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
632 		DUK_TVAL_SET_UNUSED(tv__dst); \
633 		DUK_UNREF((thr)); \
634 	} while (0)
635 
636 #define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \
637 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
638 		DUK_TVAL_SET_NULL(tv__dst); \
639 		DUK_UNREF((thr)); \
640 	} while (0)
641 
642 #define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
643 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
644 		DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \
645 		DUK_UNREF((thr)); \
646 	} while (0)
647 
648 #define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
649 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
650 		DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \
651 		DUK_UNREF((thr)); \
652 	} while (0)
653 #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
654 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
655 		DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \
656 		DUK_UNREF((thr)); \
657 	} while (0)
658 #define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
659 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
660 		DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \
661 		DUK_UNREF((thr)); \
662 	} while (0)
663 #define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \
664 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
665 		DUK_TVAL_SET_NAN(tv__dst); \
666 		DUK_UNREF((thr)); \
667 	} while (0)
668 #if defined(DUK_USE_FASTINT)
669 #define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
670 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
671 		DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \
672 		DUK_UNREF((thr)); \
673 	} while (0)
674 #define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
675 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
676 		DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \
677 		DUK_UNREF((thr)); \
678 	} while (0)
679 #define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
680 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
681 		DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \
682 		DUK_UNREF((thr)); \
683 	} while (0)
684 #else
685 #define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \
686 	DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval))
687 #endif  /* DUK_USE_FASTINT */
688 
689 #define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \
690 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
691 		DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \
692 		DUK_UNREF((thr)); \
693 	} while (0)
694 
695 #define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
696 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
697 		DUK_TVAL_SET_STRING(tv__dst, (newval)); \
698 		DUK_UNREF((thr)); \
699 	} while (0)
700 
701 #define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
702 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
703 		DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \
704 		DUK_UNREF((thr)); \
705 	} while (0)
706 
707 #define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
708 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
709 		DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \
710 		DUK_UNREF((thr)); \
711 	} while (0)
712 
713 #define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
714 		duk_tval *tv__dst; tv__dst = (tvptr_dst); \
715 		DUK_TVAL_SET_POINTER(tv__dst, (newval)); \
716 		DUK_UNREF((thr)); \
717 	} while (0)
718 
719 #define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \
720 		duk_tval *tv__dst, *tv__src; \
721 		tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
722 		DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
723 		DUK_UNREF((thr)); \
724 	} while (0)
725 
726 #define DUK_TVAL_SET_UNDEFINED_UPDREF         DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
727 #define DUK_TVAL_SET_UNUSED_UPDREF            DUK_TVAL_SET_UNUSED_UPDREF_ALT0
728 #define DUK_TVAL_SET_NULL_UPDREF              DUK_TVAL_SET_NULL_UPDREF_ALT0
729 #define DUK_TVAL_SET_BOOLEAN_UPDREF           DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
730 #define DUK_TVAL_SET_NUMBER_UPDREF            DUK_TVAL_SET_NUMBER_UPDREF_ALT0
731 #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF    DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0
732 #define DUK_TVAL_SET_DOUBLE_UPDREF            DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
733 #define DUK_TVAL_SET_NAN_UPDREF               DUK_TVAL_SET_NAN_UPDREF_ALT0
734 #if defined(DUK_USE_FASTINT)
735 #define DUK_TVAL_SET_FASTINT_UPDREF           DUK_TVAL_SET_FASTINT_UPDREF_ALT0
736 #define DUK_TVAL_SET_FASTINT_I32_UPDREF       DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0
737 #define DUK_TVAL_SET_FASTINT_U32_UPDREF       DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0
738 #else
739 #define DUK_TVAL_SET_FASTINT_UPDREF           DUK_TVAL_SET_DOUBLE_CAST_UPDREF  /* XXX: fast-int-to-double */
740 #define DUK_TVAL_SET_FASTINT_I32_UPDREF       DUK_TVAL_SET_DOUBLE_CAST_UPDREF
741 #define DUK_TVAL_SET_FASTINT_U32_UPDREF       DUK_TVAL_SET_DOUBLE_CAST_UPDREF
742 #endif  /* DUK_USE_FASTINT */
743 #define DUK_TVAL_SET_LIGHTFUNC_UPDREF         DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
744 #define DUK_TVAL_SET_STRING_UPDREF            DUK_TVAL_SET_STRING_UPDREF_ALT0
745 #define DUK_TVAL_SET_OBJECT_UPDREF            DUK_TVAL_SET_OBJECT_UPDREF_ALT0
746 #define DUK_TVAL_SET_BUFFER_UPDREF            DUK_TVAL_SET_BUFFER_UPDREF_ALT0
747 #define DUK_TVAL_SET_POINTER_UPDREF           DUK_TVAL_SET_POINTER_UPDREF_ALT0
748 
749 #define DUK_TVAL_SET_TVAL_UPDREF              DUK_TVAL_SET_TVAL_UPDREF_ALT0
750 #define DUK_TVAL_SET_TVAL_UPDREF_FAST         DUK_TVAL_SET_TVAL_UPDREF_ALT0
751 #define DUK_TVAL_SET_TVAL_UPDREF_SLOW         DUK_TVAL_SET_TVAL_UPDREF_ALT0
752 
753 #endif  /* DUK_USE_REFERENCE_COUNTING */
754 
755 #endif  /* DUK_HEAPHDR_H_INCLUDED */
756