]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* |
2 | * Heap structure. | |
3 | * | |
4 | * Heap contains allocated heap objects, interned strings, and built-in | |
5 | * strings for one or more threads. | |
6 | */ | |
7 | ||
8 | #ifndef DUK_HEAP_H_INCLUDED | |
9 | #define DUK_HEAP_H_INCLUDED | |
10 | ||
11 | /* alloc function typedefs in duktape.h */ | |
12 | ||
13 | /* | |
14 | * Heap flags | |
15 | */ | |
16 | ||
17 | #define DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING (1 << 0) /* mark-and-sweep is currently running */ | |
18 | #define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 1) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */ | |
19 | #define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING (1 << 2) /* refcount code is processing refzero list */ | |
20 | #define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 3) /* an error handler (user callback to augment/replace error) is running */ | |
21 | #define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 4) /* executor interrupt running (used to avoid nested interrupts) */ | |
11fdf7f2 | 22 | #define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 5) /* heap destruction ongoing, finalizer rescue no longer possible */ |
7c673cae FG |
23 | |
24 | #define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits)) | |
25 | #define DUK__HEAP_SET_FLAGS(heap,bits) do { \ | |
26 | (heap)->flags |= (bits); \ | |
27 | } while (0) | |
28 | #define DUK__HEAP_CLEAR_FLAGS(heap,bits) do { \ | |
29 | (heap)->flags &= ~(bits); \ | |
30 | } while (0) | |
31 | ||
32 | #define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) | |
33 | #define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) | |
34 | #define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) | |
35 | #define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) | |
36 | #define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) | |
11fdf7f2 | 37 | #define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) |
7c673cae FG |
38 | |
39 | #define DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) | |
40 | #define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) | |
41 | #define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) | |
42 | #define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) | |
43 | #define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) | |
11fdf7f2 | 44 | #define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) |
7c673cae FG |
45 | |
46 | #define DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) | |
47 | #define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) | |
48 | #define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) | |
49 | #define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) | |
50 | #define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) | |
11fdf7f2 | 51 | #define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) |
7c673cae FG |
52 | |
53 | /* | |
54 | * Longjmp types, also double as identifying continuation type for a rethrow (in 'finally') | |
55 | */ | |
56 | ||
57 | #define DUK_LJ_TYPE_UNKNOWN 0 /* unused */ | |
11fdf7f2 TL |
58 | #define DUK_LJ_TYPE_THROW 1 /* value1 -> error object */ |
59 | #define DUK_LJ_TYPE_YIELD 2 /* value1 -> yield value, iserror -> error / normal */ | |
60 | #define DUK_LJ_TYPE_RESUME 3 /* value1 -> resume value, value2 -> resumee thread, iserror -> error/normal */ | |
61 | #define DUK_LJ_TYPE_BREAK 4 /* value1 -> label number, pseudo-type to indicate a break continuation (for ENDFIN) */ | |
62 | #define DUK_LJ_TYPE_CONTINUE 5 /* value1 -> label number, pseudo-type to indicate a continue continuation (for ENDFIN) */ | |
63 | #define DUK_LJ_TYPE_RETURN 6 /* value1 -> return value, pseudo-type to indicate a return continuation (for ENDFIN) */ | |
64 | #define DUK_LJ_TYPE_NORMAL 7 /* no value, pseudo-type to indicate a normal continuation (for ENDFIN) */ | |
7c673cae FG |
65 | |
66 | /* | |
67 | * Mark-and-sweep flags | |
68 | * | |
69 | * These are separate from heap level flags now but could be merged. | |
70 | * The heap structure only contains a 'base mark-and-sweep flags' | |
71 | * field and the GC caller can impose further flags. | |
72 | */ | |
73 | ||
74 | #define DUK_MS_FLAG_EMERGENCY (1 << 0) /* emergency mode: try extra hard */ | |
75 | #define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE (1 << 1) /* don't resize stringtable (but may sweep it); needed during stringtable resize */ | |
11fdf7f2 TL |
76 | #define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2) /* don't compact objects; needed during object property allocation resize */ |
77 | #define DUK_MS_FLAG_NO_FINALIZERS (1 << 3) /* don't run finalizers; leave finalizable objects in finalize_list for next round */ | |
78 | #define DUK_MS_FLAG_SKIP_FINALIZERS (1 << 4) /* don't run finalizers; queue finalizable objects back to heap_allocated */ | |
7c673cae FG |
79 | |
80 | /* | |
81 | * Thread switching | |
82 | * | |
83 | * To switch heap->curr_thread, use the macro below so that interrupt counters | |
84 | * get updated correctly. The macro allows a NULL target thread because that | |
85 | * happens e.g. in call handling. | |
86 | */ | |
87 | ||
88 | #if defined(DUK_USE_INTERRUPT_COUNTER) | |
89 | #define DUK_HEAP_SWITCH_THREAD(heap,newthr) duk_heap_switch_thread((heap), (newthr)) | |
90 | #else | |
91 | #define DUK_HEAP_SWITCH_THREAD(heap,newthr) do { \ | |
92 | (heap)->curr_thread = (newthr); \ | |
93 | } while (0) | |
94 | #endif | |
95 | ||
96 | /* | |
97 | * Other heap related defines | |
98 | */ | |
99 | ||
100 | /* Mark-and-sweep interval is relative to combined count of objects and | |
101 | * strings kept in the heap during the latest mark-and-sweep pass. | |
102 | * Fixed point .8 multiplier and .0 adder. Trigger count (interval) is | |
103 | * decreased by each (re)allocation attempt (regardless of size), and each | |
104 | * refzero processed object. | |
105 | * | |
106 | * 'SKIP' indicates how many (re)allocations to wait until a retry if | |
107 | * GC is skipped because there is no thread do it with yet (happens | |
108 | * only during init phases). | |
109 | */ | |
110 | #if defined(DUK_USE_MARK_AND_SWEEP) | |
111 | #if defined(DUK_USE_REFERENCE_COUNTING) | |
112 | #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 12800L /* 50x heap size */ | |
113 | #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L | |
114 | #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L | |
115 | #else | |
116 | #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 256L /* 1x heap size */ | |
117 | #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L | |
118 | #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L | |
119 | #endif | |
120 | #endif | |
121 | ||
122 | /* Stringcache is used for speeding up char-offset-to-byte-offset | |
123 | * translations for non-ASCII strings. | |
124 | */ | |
125 | #define DUK_HEAP_STRCACHE_SIZE 4 | |
126 | #define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT 16 /* strings up to the this length are not cached */ | |
127 | ||
128 | /* helper to insert a (non-string) heap object into heap allocated list */ | |
129 | #define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap),(hdr)) | |
130 | ||
131 | /* | |
132 | * Stringtable | |
133 | */ | |
134 | ||
135 | /* initial stringtable size, must be prime and higher than DUK_UTIL_MIN_HASH_PRIME */ | |
136 | #define DUK_STRTAB_INITIAL_SIZE 17 | |
137 | ||
138 | /* indicates a deleted string; any fixed non-NULL, non-hstring pointer works */ | |
139 | #define DUK_STRTAB_DELETED_MARKER(heap) ((duk_hstring *) heap) | |
140 | ||
141 | /* resizing parameters */ | |
142 | #define DUK_STRTAB_MIN_FREE_DIVISOR 4 /* load factor max 75% */ | |
143 | #define DUK_STRTAB_MIN_USED_DIVISOR 4 /* load factor min 25% */ | |
144 | #define DUK_STRTAB_GROW_ST_SIZE(n) ((n) + (n)) /* used entries + approx 100% -> reset load to 50% */ | |
145 | ||
146 | #define DUK_STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */ | |
147 | #define DUK_STRTAB_HIGHEST_32BIT_PRIME 0xfffffffbUL | |
148 | ||
149 | /* probe sequence (open addressing) */ | |
150 | #define DUK_STRTAB_HASH_INITIAL(hash,h_size) ((hash) % (h_size)) | |
151 | #define DUK_STRTAB_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash)) | |
152 | ||
153 | /* fixed top level hashtable size (separate chaining) */ | |
154 | #define DUK_STRTAB_CHAIN_SIZE DUK_USE_STRTAB_CHAIN_SIZE | |
155 | ||
156 | /* | |
157 | * Built-in strings | |
158 | */ | |
159 | ||
160 | /* heap string indices are autogenerated in duk_strings.h */ | |
11fdf7f2 TL |
161 | #if defined(DUK_USE_ROM_STRINGS) |
162 | #define DUK_HEAP_GET_STRING(heap,idx) \ | |
163 | ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)])) | |
164 | #else /* DUK_USE_ROM_STRINGS */ | |
7c673cae FG |
165 | #if defined(DUK_USE_HEAPPTR16) |
166 | #define DUK_HEAP_GET_STRING(heap,idx) \ | |
167 | ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (heap)->strs16[(idx)])) | |
168 | #else | |
169 | #define DUK_HEAP_GET_STRING(heap,idx) \ | |
170 | ((heap)->strs[(idx)]) | |
171 | #endif | |
11fdf7f2 | 172 | #endif /* DUK_USE_ROM_STRINGS */ |
7c673cae FG |
173 | |
174 | /* | |
175 | * Raw memory calls: relative to heap, but no GC interaction | |
176 | */ | |
177 | ||
178 | #define DUK_ALLOC_RAW(heap,size) \ | |
179 | ((heap)->alloc_func((heap)->heap_udata, (size))) | |
180 | ||
181 | #define DUK_REALLOC_RAW(heap,ptr,newsize) \ | |
182 | ((heap)->realloc_func((heap)->heap_udata, (void *) (ptr), (newsize))) | |
183 | ||
184 | #define DUK_FREE_RAW(heap,ptr) \ | |
185 | ((heap)->free_func((heap)->heap_udata, (void *) (ptr))) | |
186 | ||
187 | /* | |
188 | * Memory calls: relative to heap, GC interaction, but no error throwing. | |
189 | * | |
190 | * XXX: Currently a mark-and-sweep triggered by memory allocation will run | |
191 | * using the heap->heap_thread. This thread is also used for running | |
192 | * mark-and-sweep finalization; this is not ideal because it breaks the | |
193 | * isolation between multiple global environments. | |
194 | * | |
195 | * Notes: | |
196 | * | |
197 | * - DUK_FREE() is required to ignore NULL and any other possible return | |
198 | * value of a zero-sized alloc/realloc (same as ANSI C free()). | |
199 | * | |
200 | * - There is no DUK_REALLOC_ZEROED because we don't assume to know the | |
201 | * old size. Caller must zero the reallocated memory. | |
202 | * | |
203 | * - DUK_REALLOC_INDIRECT() must be used when a mark-and-sweep triggered | |
204 | * by an allocation failure might invalidate the original 'ptr', thus | |
205 | * causing a realloc retry to use an invalid pointer. Example: we're | |
206 | * reallocating the value stack and a finalizer resizes the same value | |
207 | * stack during mark-and-sweep. The indirect variant requests for the | |
208 | * current location of the pointer being reallocated using a callback | |
209 | * right before every realloc attempt; this circuitous approach is used | |
210 | * to avoid strict aliasing issues in a more straightforward indirect | |
211 | * pointer (void **) approach. Note: the pointer in the storage | |
212 | * location is read but is NOT updated; the caller must do that. | |
213 | */ | |
214 | ||
215 | /* callback for indirect reallocs, request for current pointer */ | |
216 | typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud); | |
217 | ||
218 | #define DUK_ALLOC(heap,size) duk_heap_mem_alloc((heap), (size)) | |
219 | #define DUK_ALLOC_ZEROED(heap,size) duk_heap_mem_alloc_zeroed((heap), (size)) | |
220 | #define DUK_REALLOC(heap,ptr,newsize) duk_heap_mem_realloc((heap), (ptr), (newsize)) | |
221 | #define DUK_REALLOC_INDIRECT(heap,cb,ud,newsize) duk_heap_mem_realloc_indirect((heap), (cb), (ud), (newsize)) | |
222 | #define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr)) | |
223 | ||
224 | /* | |
225 | * Memory constants | |
226 | */ | |
227 | ||
228 | #define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 5 /* Retry allocation after mark-and-sweep for this | |
229 | * many times. A single mark-and-sweep round is | |
230 | * not guaranteed to free all unreferenced memory | |
231 | * because of finalization (in fact, ANY number of | |
232 | * rounds is strictly not enough). | |
233 | */ | |
234 | ||
235 | #define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT 3 /* Starting from this round, use emergency mode | |
236 | * for mark-and-sweep. | |
237 | */ | |
238 | ||
239 | /* | |
240 | * Debugger support | |
241 | */ | |
242 | ||
243 | /* Maximum number of breakpoints. Only breakpoints that are set are | |
244 | * consulted so increasing this has no performance impact. | |
245 | */ | |
246 | #define DUK_HEAP_MAX_BREAKPOINTS 16 | |
247 | ||
248 | /* Opcode interval for a Date-based status/peek rate limit check. Only | |
249 | * relevant when debugger is attached. Requesting a timestamp may be a | |
250 | * slow operation on some platforms so this shouldn't be too low. On the | |
251 | * other hand a high value makes Duktape react to a pause request slowly. | |
252 | */ | |
253 | #define DUK_HEAP_DBG_RATELIMIT_OPCODES 4000 | |
254 | ||
255 | /* Milliseconds between status notify and transport peeks. */ | |
256 | #define DUK_HEAP_DBG_RATELIMIT_MILLISECS 200 | |
257 | ||
258 | /* Step types */ | |
259 | #define DUK_STEP_TYPE_NONE 0 | |
260 | #define DUK_STEP_TYPE_INTO 1 | |
261 | #define DUK_STEP_TYPE_OVER 2 | |
262 | #define DUK_STEP_TYPE_OUT 3 | |
263 | ||
264 | struct duk_breakpoint { | |
265 | duk_hstring *filename; | |
266 | duk_uint32_t line; | |
267 | }; | |
268 | ||
269 | #if defined(DUK_USE_DEBUGGER_SUPPORT) | |
270 | #define DUK_HEAP_IS_DEBUGGER_ATTACHED(heap) ((heap)->dbg_read_cb != NULL) | |
271 | #define DUK_HEAP_CLEAR_STEP_STATE(heap) do { \ | |
272 | (heap)->dbg_step_type = DUK_STEP_TYPE_NONE; \ | |
273 | (heap)->dbg_step_thread = NULL; \ | |
274 | (heap)->dbg_step_csindex = 0; \ | |
275 | (heap)->dbg_step_startline = 0; \ | |
276 | } while (0) | |
277 | #define DUK_HEAP_SET_PAUSED(heap) do { \ | |
278 | (heap)->dbg_paused = 1; \ | |
279 | (heap)->dbg_state_dirty = 1; \ | |
280 | DUK_HEAP_CLEAR_STEP_STATE((heap)); \ | |
281 | } while (0) | |
282 | #define DUK_HEAP_CLEAR_PAUSED(heap) do { \ | |
283 | (heap)->dbg_paused = 0; \ | |
284 | (heap)->dbg_state_dirty = 1; \ | |
285 | DUK_HEAP_CLEAR_STEP_STATE((heap)); \ | |
286 | } while (0) | |
11fdf7f2 | 287 | #define DUK_HEAP_IS_PAUSED(heap) ((heap)->dbg_paused) |
7c673cae FG |
288 | #endif /* DUK_USE_DEBUGGER_SUPPORT */ |
289 | ||
290 | /* | |
291 | * String cache should ideally be at duk_hthread level, but that would | |
292 | * cause string finalization to slow down relative to the number of | |
293 | * threads; string finalization must check the string cache for "weak" | |
294 | * references to the string being finalized to avoid dead pointers. | |
295 | * | |
296 | * Thus, string caches are now at the heap level now. | |
297 | */ | |
298 | ||
299 | struct duk_strcache { | |
300 | duk_hstring *h; | |
301 | duk_uint32_t bidx; | |
302 | duk_uint32_t cidx; | |
303 | }; | |
304 | ||
305 | /* | |
306 | * Longjmp state, contains the information needed to perform a longjmp. | |
307 | * Longjmp related values are written to value1, value2, and iserror. | |
308 | */ | |
309 | ||
310 | struct duk_ljstate { | |
311 | duk_jmpbuf *jmpbuf_ptr; /* current setjmp() catchpoint */ | |
312 | duk_small_uint_t type; /* longjmp type */ | |
313 | duk_bool_t iserror; /* isError flag for yield */ | |
314 | duk_tval value1; /* 1st related value (type specific) */ | |
315 | duk_tval value2; /* 2nd related value (type specific) */ | |
316 | }; | |
317 | ||
318 | /* | |
319 | * Stringtable entry for fixed size stringtable | |
320 | */ | |
321 | ||
322 | struct duk_strtab_entry { | |
323 | #if defined(DUK_USE_HEAPPTR16) | |
324 | /* A 16-bit listlen makes sense with 16-bit heap pointers: there | |
325 | * won't be space for 64k strings anyway. | |
326 | */ | |
327 | duk_uint16_t listlen; /* if 0, 'str16' used, if > 0, 'strlist16' used */ | |
328 | union { | |
329 | duk_uint16_t strlist16; | |
330 | duk_uint16_t str16; | |
331 | } u; | |
332 | #else | |
333 | duk_size_t listlen; /* if 0, 'str' used, if > 0, 'strlist' used */ | |
334 | union { | |
335 | duk_hstring **strlist; | |
336 | duk_hstring *str; | |
337 | } u; | |
338 | #endif | |
339 | }; | |
340 | ||
341 | /* | |
342 | * Main heap structure | |
343 | */ | |
344 | ||
345 | struct duk_heap { | |
346 | duk_small_uint_t flags; | |
347 | ||
348 | /* Allocator functions. */ | |
349 | duk_alloc_function alloc_func; | |
350 | duk_realloc_function realloc_func; | |
351 | duk_free_function free_func; | |
352 | ||
353 | /* Heap udata, used for allocator functions but also for other heap | |
354 | * level callbacks like pointer compression, etc. | |
355 | */ | |
356 | void *heap_udata; | |
357 | ||
358 | /* Precomputed pointers when using 16-bit heap pointer packing. */ | |
359 | #if defined(DUK_USE_HEAPPTR16) | |
360 | duk_uint16_t heapptr_null16; | |
361 | duk_uint16_t heapptr_deleted16; | |
362 | #endif | |
363 | ||
364 | /* Fatal error handling, called e.g. when a longjmp() is needed but | |
365 | * lj.jmpbuf_ptr is NULL. fatal_func must never return; it's not | |
366 | * declared as "noreturn" because doing that for typedefs is a bit | |
367 | * challenging portability-wise. | |
368 | */ | |
369 | duk_fatal_function fatal_func; | |
370 | ||
371 | /* allocated heap objects */ | |
372 | duk_heaphdr *heap_allocated; | |
373 | ||
374 | /* work list for objects whose refcounts are zero but which have not been | |
375 | * "finalized"; avoids recursive C calls when refcounts go to zero in a | |
376 | * chain of objects. | |
377 | */ | |
378 | #if defined(DUK_USE_REFERENCE_COUNTING) | |
379 | duk_heaphdr *refzero_list; | |
380 | duk_heaphdr *refzero_list_tail; | |
381 | #endif | |
382 | ||
383 | #if defined(DUK_USE_MARK_AND_SWEEP) | |
384 | /* mark-and-sweep control */ | |
385 | #if defined(DUK_USE_VOLUNTARY_GC) | |
386 | duk_int_t mark_and_sweep_trigger_counter; | |
387 | #endif | |
388 | duk_int_t mark_and_sweep_recursion_depth; | |
389 | ||
390 | /* mark-and-sweep flags automatically active (used for critical sections) */ | |
391 | duk_small_uint_t mark_and_sweep_base_flags; | |
392 | ||
393 | /* work list for objects to be finalized (by mark-and-sweep) */ | |
394 | duk_heaphdr *finalize_list; | |
395 | #endif | |
396 | ||
397 | /* longjmp state */ | |
398 | duk_ljstate lj; | |
399 | ||
400 | /* marker for detecting internal "double faults", see duk_error_throw.c */ | |
401 | duk_bool_t handling_error; | |
402 | ||
403 | /* heap thread, used internally and for finalization */ | |
404 | duk_hthread *heap_thread; | |
405 | ||
406 | /* current thread */ | |
407 | duk_hthread *curr_thread; /* currently running thread */ | |
408 | ||
409 | /* heap level "stash" object (e.g., various reachability roots) */ | |
410 | duk_hobject *heap_object; | |
411 | ||
412 | /* duk_handle_call / duk_handle_safe_call recursion depth limiting */ | |
413 | duk_int_t call_recursion_depth; | |
414 | duk_int_t call_recursion_limit; | |
415 | ||
416 | /* mix-in value for computing string hashes; should be reasonably unpredictable */ | |
417 | duk_uint32_t hash_seed; | |
418 | ||
419 | /* rnd_state for duk_util_tinyrandom.c */ | |
420 | duk_uint32_t rnd_state; | |
421 | ||
422 | /* For manual debugging: instruction count based on executor and | |
423 | * interrupt counter book-keeping. Inspect debug logs to see how | |
424 | * they match up. | |
425 | */ | |
426 | #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) | |
427 | duk_int_t inst_count_exec; | |
428 | duk_int_t inst_count_interrupt; | |
429 | #endif | |
430 | ||
431 | /* debugger */ | |
432 | ||
433 | #if defined(DUK_USE_DEBUGGER_SUPPORT) | |
434 | /* callbacks and udata; dbg_read_cb != NULL is used to indicate attached state */ | |
435 | duk_debug_read_function dbg_read_cb; /* required, NULL implies detached */ | |
436 | duk_debug_write_function dbg_write_cb; /* required */ | |
437 | duk_debug_peek_function dbg_peek_cb; | |
438 | duk_debug_read_flush_function dbg_read_flush_cb; | |
439 | duk_debug_write_flush_function dbg_write_flush_cb; | |
11fdf7f2 | 440 | duk_debug_request_function dbg_request_cb; |
7c673cae FG |
441 | duk_debug_detached_function dbg_detached_cb; |
442 | void *dbg_udata; | |
443 | ||
444 | /* debugger state, only relevant when attached */ | |
445 | duk_bool_t dbg_processing; /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */ | |
446 | duk_bool_t dbg_paused; /* currently paused: talk with debug client until step/resume */ | |
447 | duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */ | |
448 | duk_bool_t dbg_force_restart; /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */ | |
11fdf7f2 | 449 | duk_bool_t dbg_detaching; /* debugger detaching; used to avoid calling detach handler recursively */ |
7c673cae FG |
450 | duk_small_uint_t dbg_step_type; /* step type: none, step into, step over, step out */ |
451 | duk_hthread *dbg_step_thread; /* borrowed; NULL if no step state (NULLed in unwind) */ | |
452 | duk_size_t dbg_step_csindex; /* callstack index */ | |
453 | duk_uint32_t dbg_step_startline; /* starting line number */ | |
454 | duk_breakpoint dbg_breakpoints[DUK_HEAP_MAX_BREAKPOINTS]; /* breakpoints: [0,breakpoint_count[ gc reachable */ | |
455 | duk_small_uint_t dbg_breakpoint_count; | |
456 | duk_breakpoint *dbg_breakpoints_active[DUK_HEAP_MAX_BREAKPOINTS + 1]; /* currently active breakpoints: NULL term, borrowed pointers */ | |
457 | /* XXX: make active breakpoints actual copies instead of pointers? */ | |
458 | ||
459 | /* These are for rate limiting Status notifications and transport peeking. */ | |
460 | duk_uint32_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */ | |
461 | duk_uint32_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */ | |
462 | duk_double_t dbg_last_time; /* time when status/peek was last done (Date-based rate limit) */ | |
11fdf7f2 TL |
463 | |
464 | /* Used to support single-byte stream lookahead. */ | |
465 | duk_bool_t dbg_have_next_byte; | |
466 | duk_uint8_t dbg_next_byte; | |
7c673cae FG |
467 | #endif |
468 | ||
469 | /* string intern table (weak refs) */ | |
470 | #if defined(DUK_USE_STRTAB_PROBE) | |
471 | #if defined(DUK_USE_HEAPPTR16) | |
472 | duk_uint16_t *strtable16; | |
473 | #else | |
474 | duk_hstring **strtable; | |
475 | #endif | |
476 | duk_uint32_t st_size; /* alloc size in elements */ | |
477 | duk_uint32_t st_used; /* used elements (includes DELETED) */ | |
478 | #endif | |
479 | ||
480 | /* XXX: static alloc is OK until separate chaining stringtable | |
481 | * resizing is implemented. | |
482 | */ | |
483 | #if defined(DUK_USE_STRTAB_CHAIN) | |
484 | duk_strtab_entry strtable[DUK_STRTAB_CHAIN_SIZE]; | |
485 | #endif | |
486 | ||
487 | /* string access cache (codepoint offset -> byte offset) for fast string | |
488 | * character looping; 'weak' reference which needs special handling in GC. | |
489 | */ | |
490 | duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE]; | |
491 | ||
492 | /* built-in strings */ | |
11fdf7f2 TL |
493 | #if defined(DUK_USE_ROM_STRINGS) |
494 | /* No field needed when strings are in ROM. */ | |
495 | #else | |
7c673cae FG |
496 | #if defined(DUK_USE_HEAPPTR16) |
497 | duk_uint16_t strs16[DUK_HEAP_NUM_STRINGS]; | |
498 | #else | |
499 | duk_hstring *strs[DUK_HEAP_NUM_STRINGS]; | |
500 | #endif | |
11fdf7f2 | 501 | #endif |
7c673cae FG |
502 | }; |
503 | ||
504 | /* | |
505 | * Prototypes | |
506 | */ | |
507 | ||
508 | DUK_INTERNAL_DECL | |
509 | duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, | |
510 | duk_realloc_function realloc_func, | |
511 | duk_free_function free_func, | |
512 | void *heap_udata, | |
513 | duk_fatal_function fatal_func); | |
514 | DUK_INTERNAL_DECL void duk_heap_free(duk_heap *heap); | |
515 | DUK_INTERNAL_DECL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h); | |
516 | DUK_INTERNAL_DECL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h); | |
517 | DUK_INTERNAL_DECL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h); | |
518 | DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr); | |
519 | ||
520 | DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr); | |
521 | #if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING) | |
522 | DUK_INTERNAL_DECL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr); | |
523 | #endif | |
524 | #if defined(DUK_USE_INTERRUPT_COUNTER) | |
525 | DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr); | |
526 | #endif | |
527 | ||
528 | #if 0 /*unused*/ | |
529 | DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); | |
530 | #endif | |
531 | DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); | |
532 | DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len); | |
533 | #if 0 /*unused*/ | |
534 | DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val); | |
535 | #endif | |
536 | DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val); | |
537 | DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val); | |
11fdf7f2 | 538 | #if defined(DUK_USE_REFERENCE_COUNTING) |
7c673cae | 539 | DUK_INTERNAL_DECL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h); |
11fdf7f2 | 540 | #endif |
7c673cae FG |
541 | #if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_MS_STRINGTABLE_RESIZE) |
542 | DUK_INTERNAL_DECL void duk_heap_force_strtab_resize(duk_heap *heap); | |
543 | #endif | |
544 | DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap); | |
545 | #if defined(DUK_USE_DEBUG) | |
546 | DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap); | |
547 | #endif | |
548 | ||
549 | ||
550 | DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h); | |
551 | DUK_INTERNAL_DECL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset); | |
552 | ||
553 | #if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS) | |
554 | DUK_INTERNAL_DECL void *duk_default_alloc_function(void *udata, duk_size_t size); | |
555 | DUK_INTERNAL_DECL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize); | |
556 | DUK_INTERNAL_DECL void duk_default_free_function(void *udata, void *ptr); | |
557 | #endif | |
558 | ||
559 | DUK_INTERNAL_DECL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size); | |
560 | DUK_INTERNAL_DECL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size); | |
561 | DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize); | |
562 | DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize); | |
563 | DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr); | |
564 | ||
565 | #ifdef DUK_USE_REFERENCE_COUNTING | |
566 | #if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT) | |
567 | DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv); | |
568 | #endif | |
569 | #if 0 /* unused */ | |
570 | DUK_INTERNAL_DECL void duk_tval_incref_allownull(duk_tval *tv); | |
571 | #endif | |
572 | DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv); | |
573 | #if 0 /* unused */ | |
574 | DUK_INTERNAL_DECL void duk_tval_decref_allownull(duk_hthread *thr, duk_tval *tv); | |
575 | #endif | |
576 | #if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT) | |
577 | DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h); | |
578 | #endif | |
579 | #if 0 /* unused */ | |
580 | DUK_INTERNAL_DECL void duk_heaphdr_incref_allownull(duk_heaphdr *h); | |
581 | #endif | |
582 | DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h); | |
583 | DUK_INTERNAL_DECL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h); | |
584 | DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h); | |
585 | DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr); | |
586 | #else | |
587 | /* no refcounting */ | |
588 | #endif | |
589 | ||
590 | #if defined(DUK_USE_MARK_AND_SWEEP) | |
591 | DUK_INTERNAL_DECL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags); | |
592 | #endif | |
593 | ||
594 | DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len); | |
595 | ||
596 | #endif /* DUK_HEAP_H_INCLUDED */ |