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