Github User Fetcher 1.0.0
C Application with Server and GUI
Loading...
Searching...
No Matches
duk_heap_markandsweep.c File Reference
#include "duk_internal.h"

Go to the source code of this file.

Functions

DUK_LOCAL_DECL void duk__mark_heaphdr (duk_heap *heap, duk_heaphdr *h)
 
DUK_LOCAL_DECL void duk__mark_tval (duk_heap *heap, duk_tval *tv)
 
DUK_LOCAL duk_hthreadduk__get_temp_hthread (duk_heap *heap)
 
DUK_LOCAL void duk__mark_hstring (duk_heap *heap, duk_hstring *h)
 
DUK_LOCAL void duk__mark_hobject (duk_heap *heap, duk_hobject *h)
 
DUK_LOCAL void duk__mark_roots_heap (duk_heap *heap)
 
DUK_LOCAL void duk__mark_refzero_list (duk_heap *heap)
 
DUK_LOCAL void duk__mark_finalizable (duk_heap *heap)
 
DUK_LOCAL void duk__mark_finalize_list (duk_heap *heap)
 
DUK_LOCAL void duk__handle_temproot (duk_heap *heap, duk_heaphdr *hdr)
 
DUK_LOCAL void duk__mark_temproots_by_heap_scan (duk_heap *heap)
 
DUK_LOCAL void duk__finalize_refcounts (duk_heap *heap)
 
DUK_LOCAL void duk__clear_refzero_list_flags (duk_heap *heap)
 
DUK_LOCAL void duk__clear_finalize_list_flags (duk_heap *heap)
 
DUK_LOCAL void duk__sweep_stringtable_probe (duk_heap *heap, duk_size_t *out_count_keep)
 
DUK_LOCAL void duk__sweep_heap (duk_heap *heap, duk_int_t flags, duk_size_t *out_count_keep)
 
DUK_LOCAL void duk__run_object_finalizers (duk_heap *heap, duk_small_uint_t flags)
 
DUK_LOCAL int duk__protected_compact_object (duk_context *ctx)
 
DUK_LOCAL void duk__compact_object_list (duk_heap *heap, duk_hthread *thr, duk_heaphdr *start)
 
DUK_LOCAL void duk__compact_objects (duk_heap *heap)
 
DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep (duk_heap *heap, duk_small_uint_t flags)
 

Function Documentation

◆ duk__clear_finalize_list_flags()

DUK_LOCAL void duk__clear_finalize_list_flags ( duk_heap * heap)

Definition at line 509 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

509 {
510 duk_heaphdr *hdr;
511
512 DUK_DD(DUK_DDPRINT("duk__clear_finalize_list_flags: %p", (void *) heap));
513
514 hdr = heap->finalize_list;
515 while (hdr) {
520 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
521 }
522}
#define DUK_HEAPHDR_HAS_TEMPROOT(h)
#define DUK_HEAPHDR_HAS_FINALIZED(h)
#define DUK_HEAPHDR_CLEAR_REACHABLE(h)
#define DUK_HEAPHDR_HAS_FINALIZABLE(h)
#define DUK_HEAPHDR_GET_NEXT(heap, h)

References DUK_ASSERT, DUK_DD, DUK_DDPRINT, DUK_HEAPHDR_CLEAR_REACHABLE, DUK_HEAPHDR_GET_NEXT, DUK_HEAPHDR_HAS_FINALIZABLE, DUK_HEAPHDR_HAS_FINALIZED, DUK_HEAPHDR_HAS_TEMPROOT, and duk_heap::finalize_list.

Referenced by duk_heap_mark_and_sweep().

◆ duk__clear_refzero_list_flags()

DUK_LOCAL void duk__clear_refzero_list_flags ( duk_heap * heap)

◆ duk__compact_object_list()

DUK_LOCAL void duk__compact_object_list ( duk_heap * heap,
duk_hthread * thr,
duk_heaphdr * start )

Definition at line 952 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

952 {
953#endif
954 duk_heaphdr *curr;
955#ifdef DUK_USE_DEBUG
956 duk_size_t old_size, new_size;
957#endif
958 duk_hobject *obj;
959
960 DUK_UNREF(heap);
961
962 curr = start;
963 while (curr) {
964 DUK_DDD(DUK_DDDPRINT("mark-and-sweep compact: %p", (void *) curr));
965
967 goto next;
968 }
969 obj = (duk_hobject *) curr;
970
971#ifdef DUK_USE_DEBUG
975#endif
976
977 DUK_DD(DUK_DDPRINT("compact object: %p", (void *) obj));
978 duk_push_hobject((duk_context *) thr, obj);
979 /* XXX: disable error handlers for duration of compaction? */
981
982#ifdef DUK_USE_DEBUG
986#endif
987
988#ifdef DUK_USE_DEBUG
989 (*p_count_compact)++;
990 (*p_count_bytes_saved) += (duk_size_t) (old_size - new_size);
991#endif
992
993 next:
994 curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
995#ifdef DUK_USE_DEBUG
996 (*p_count_check)++;
997#endif
998 }
999}
#define DUK_HEAPHDR_GET_TYPE(h)
#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent, n_arr, n_hash)
#define DUK_HOBJECT_GET_ASIZE(h)
#define DUK_HOBJECT_GET_HSIZE(h)
DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, duk_idx_t nargs, duk_idx_t nrets)
DUK_INTERNAL_DECL void duk_push_hobject(duk_context *ctx, duk_hobject *h)
#define DUK_HOBJECT_GET_ESIZE(h)
DUK_LOCAL int duk__protected_compact_object(duk_context *ctx)
#define next(ls)

References duk__protected_compact_object(), DUK_DD, DUK_DDD, DUK_DDDPRINT, DUK_DDPRINT, DUK_HEAPHDR_GET_NEXT, DUK_HEAPHDR_GET_TYPE, DUK_HOBJECT_GET_ASIZE, DUK_HOBJECT_GET_ESIZE, DUK_HOBJECT_GET_HSIZE, DUK_HOBJECT_P_COMPUTE_SIZE, DUK_HTYPE_OBJECT, duk_push_hobject(), duk_safe_call(), DUK_UNREF, and next.

Referenced by duk__compact_objects().

◆ duk__compact_objects()

DUK_LOCAL void duk__compact_objects ( duk_heap * heap)

Definition at line 1001 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

1001 {
1002 /* XXX: which lists should participate? to be finalized? */
1003#ifdef DUK_USE_DEBUG
1004 duk_size_t count_check = 0;
1005 duk_size_t count_compact = 0;
1006 duk_size_t count_bytes_saved = 0;
1007#endif
1008 duk_hthread *thr;
1009
1010 DUK_DD(DUK_DDPRINT("duk__compact_objects: %p", (void *) heap));
1011
1012 thr = duk__get_temp_hthread(heap);
1013 DUK_ASSERT(thr != NULL);
1014
1015#ifdef DUK_USE_DEBUG
1016 duk__compact_object_list(heap, thr, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved);
1017 duk__compact_object_list(heap, thr, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved);
1018#ifdef DUK_USE_REFERENCE_COUNTING
1019 duk__compact_object_list(heap, thr, heap->refzero_list, &count_check, &count_compact, &count_bytes_saved);
1020#endif
1021#else
1022 duk__compact_object_list(heap, thr, heap->heap_allocated);
1023 duk__compact_object_list(heap, thr, heap->finalize_list);
1024#ifdef DUK_USE_REFERENCE_COUNTING
1025 duk__compact_object_list(heap, thr, heap->refzero_list);
1026#endif
1027#endif
1028
1029#ifdef DUK_USE_DEBUG
1030 DUK_D(DUK_DPRINT("mark-and-sweep compact objects: %ld checked, %ld compaction attempts, %ld bytes saved by compaction",
1031 (long) count_check, (long) count_compact, (long) count_bytes_saved));
1032#endif
1033}
DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start)
DUK_LOCAL duk_hthread * duk__get_temp_hthread(duk_heap *heap)
#define NULL
Definition gmacros.h:924

References duk__compact_object_list(), duk__get_temp_hthread(), DUK_ASSERT, DUK_D, DUK_DD, DUK_DDPRINT, DUK_DPRINT, duk_heap::finalize_list, duk_heap::heap_allocated, NULL, and duk_heap::refzero_list.

Referenced by duk_heap_mark_and_sweep().

◆ duk__finalize_refcounts()

DUK_LOCAL void duk__finalize_refcounts ( duk_heap * heap)

Definition at line 445 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

445 {
446 duk_hthread *thr;
447 duk_heaphdr *hdr;
448
449 thr = duk__get_temp_hthread(heap);
450 DUK_ASSERT(thr != NULL);
451
452 DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p, hthread=%p",
453 (void *) heap, (void *) thr));
454
455 hdr = heap->heap_allocated;
456 while (hdr) {
457 if (!DUK_HEAPHDR_HAS_REACHABLE(hdr)) {
458 /*
459 * Unreachable object about to be swept. Finalize target refcounts
460 * (objects which the unreachable object points to) without doing
461 * refzero processing. Recursive decrefs are also prevented when
462 * refzero processing is disabled.
463 *
464 * Value cannot be a finalizable object, as they have been made
465 * temporarily reachable for this round.
466 */
467
468 DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr));
470 }
471
472 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
473 }
474}
#define DUK_HEAPHDR_HAS_REACHABLE(h)
DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr)

References duk__get_temp_hthread(), DUK_ASSERT, DUK_DD, DUK_DDD, DUK_DDDPRINT, DUK_DDPRINT, DUK_HEAPHDR_GET_NEXT, DUK_HEAPHDR_HAS_REACHABLE, duk_heaphdr_refcount_finalize(), duk_heap::heap_allocated, and NULL.

Referenced by duk_heap_mark_and_sweep().

◆ duk__get_temp_hthread()

DUK_LOCAL duk_hthread * duk__get_temp_hthread ( duk_heap * heap)

◆ duk__handle_temproot()

DUK_LOCAL void duk__handle_temproot ( duk_heap * heap,
duk_heaphdr * hdr )

Definition at line 373 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

373 {
374#endif
375 if (!DUK_HEAPHDR_HAS_TEMPROOT(hdr)) {
376 DUK_DDD(DUK_DDDPRINT("not a temp root: %p", (void *) hdr));
377 return;
378 }
379
380 DUK_DDD(DUK_DDDPRINT("found a temp root: %p", (void *) hdr));
382 DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* done so that duk__mark_heaphdr() works correctly */
383 duk__mark_heaphdr(heap, hdr);
384
385#ifdef DUK_USE_DEBUG
386 (*count)++;
387#endif
388}
#define DUK_HEAPHDR_CLEAR_TEMPROOT(h)
DUK_LOCAL_DECL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h)

References duk__mark_heaphdr(), DUK_DDD, DUK_DDDPRINT, DUK_HEAPHDR_CLEAR_REACHABLE, DUK_HEAPHDR_CLEAR_TEMPROOT, and DUK_HEAPHDR_HAS_TEMPROOT.

Referenced by duk__mark_temproots_by_heap_scan().

◆ duk__mark_finalizable()

DUK_LOCAL void duk__mark_finalizable ( duk_heap * heap)

Definition at line 265 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

265 {
266 duk_hthread *thr;
267 duk_heaphdr *hdr;
268 duk_size_t count_finalizable = 0;
269
270 DUK_DD(DUK_DDPRINT("duk__mark_finalizable: %p", (void *) heap));
271
272 thr = duk__get_temp_hthread(heap);
273 DUK_ASSERT(thr != NULL);
274
275 hdr = heap->heap_allocated;
276 while (hdr) {
277 /* A finalizer is looked up from the object and up its prototype chain
278 * (which allows inherited finalizers). A prototype loop must not cause
279 * an error to be thrown here; duk_hobject_hasprop_raw() will ignore a
280 * prototype loop silently and indicate that the property doesn't exist.
281 */
282
283 if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) &&
287
288 /* heaphdr:
289 * - is not reachable
290 * - is an object
291 * - is not a finalized object
292 * - has a finalizer
293 */
294
295 DUK_DD(DUK_DDPRINT("unreachable heap object will be "
296 "finalized -> mark as finalizable "
297 "and treat as a reachability root: %p",
298 (void *) hdr));
301 count_finalizable ++;
302 }
303
304 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
305 }
306
307 if (count_finalizable == 0) {
308 return;
309 }
310
311 DUK_DD(DUK_DDPRINT("marked %ld heap objects as finalizable, now mark them reachable",
312 (long) count_finalizable));
313
314 hdr = heap->heap_allocated;
315 while (hdr) {
317 duk__mark_heaphdr(heap, hdr);
318 }
319
320 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
321 }
322
323 /* Caller will finish the marking process if we hit a recursion limit. */
324}
#define DUK_HEAPHDR_SET_FINALIZABLE(h)
#define DUK_HEAPHDR_HAS_READONLY(h)
DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key)
#define DUK_HTHREAD_STRING_INT_FINALIZER(thr)

References duk__get_temp_hthread(), duk__mark_heaphdr(), DUK_ASSERT, DUK_DD, DUK_DDPRINT, DUK_HEAPHDR_GET_NEXT, DUK_HEAPHDR_GET_TYPE, DUK_HEAPHDR_HAS_FINALIZABLE, DUK_HEAPHDR_HAS_FINALIZED, DUK_HEAPHDR_HAS_REACHABLE, DUK_HEAPHDR_HAS_READONLY, DUK_HEAPHDR_SET_FINALIZABLE, duk_hobject_hasprop_raw(), DUK_HTHREAD_STRING_INT_FINALIZER, DUK_HTYPE_OBJECT, duk_heap::heap_allocated, and NULL.

Referenced by duk_heap_mark_and_sweep().

◆ duk__mark_finalize_list()

DUK_LOCAL void duk__mark_finalize_list ( duk_heap * heap)

Definition at line 331 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

331 {
332 duk_heaphdr *hdr;
333#ifdef DUK_USE_DEBUG
334 duk_size_t count_finalize_list = 0;
335#endif
336
337 DUK_DD(DUK_DDPRINT("duk__mark_finalize_list: %p", (void *) heap));
338
339 hdr = heap->finalize_list;
340 while (hdr) {
341 duk__mark_heaphdr(heap, hdr);
342 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
343#ifdef DUK_USE_DEBUG
344 count_finalize_list++;
345#endif
346 }
347
348#ifdef DUK_USE_DEBUG
349 if (count_finalize_list > 0) {
350 DUK_D(DUK_DPRINT("marked %ld objects on the finalize_list as reachable (previous finalizer run skipped)",
351 (long) count_finalize_list));
352 }
353#endif
354}

References duk__mark_heaphdr(), DUK_D, DUK_DD, DUK_DDPRINT, DUK_DPRINT, DUK_HEAPHDR_GET_NEXT, and duk_heap::finalize_list.

Referenced by duk_heap_mark_and_sweep().

◆ duk__mark_heaphdr()

DUK_LOCAL_DECL void duk__mark_heaphdr ( duk_heap * heap,
duk_heaphdr * h )

Definition at line 144 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

144 {
145 DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld",
146 (void *) h,
147 (h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1)));
148 if (!h) {
149 return;
150 }
151#if defined(DUK_USE_ROM_OBJECTS)
153 DUK_DDD(DUK_DDDPRINT("readonly object %p, skip", (void *) h));
154 return;
155 }
156#endif
158 DUK_DDD(DUK_DDDPRINT("already marked reachable, skip"));
159 return;
160 }
162
164 /* log this with a normal debug level because this should be relatively rare */
165 DUK_D(DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p", (void *) h));
168 return;
169 }
170
172
173 switch ((int) DUK_HEAPHDR_GET_TYPE(h)) {
174 case DUK_HTYPE_STRING:
175 duk__mark_hstring(heap, (duk_hstring *) h);
176 break;
177 case DUK_HTYPE_OBJECT:
178 duk__mark_hobject(heap, (duk_hobject *) h);
179 break;
180 case DUK_HTYPE_BUFFER:
181 /* nothing to mark */
182 break;
183 default:
184 DUK_D(DUK_DPRINT("attempt to mark heaphdr %p with invalid htype %ld", (void *) h, (long) DUK_HEAPHDR_GET_TYPE(h)));
186 }
187
189}
#define DUK_USE_MARK_AND_SWEEP_RECLIMIT
#define DUK_HEAPHDR_SET_REACHABLE(h)
#define DUK_HEAPHDR_SET_TEMPROOT(h)
#define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap)
DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h)
DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h)

References duk__mark_hobject(), duk__mark_hstring(), DUK_D, DUK_DDD, DUK_DDDPRINT, DUK_DPRINT, DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED, DUK_HEAPHDR_GET_TYPE, DUK_HEAPHDR_HAS_REACHABLE, DUK_HEAPHDR_HAS_READONLY, DUK_HEAPHDR_SET_REACHABLE, DUK_HEAPHDR_SET_TEMPROOT, DUK_HTYPE_BUFFER, DUK_HTYPE_OBJECT, DUK_HTYPE_STRING, DUK_UNREACHABLE, DUK_USE_MARK_AND_SWEEP_RECLIMIT, duk_heap::mark_and_sweep_recursion_depth, and NULL.

Referenced by duk__handle_temproot(), duk__mark_finalizable(), duk__mark_finalize_list(), duk__mark_hobject(), duk__mark_refzero_list(), duk__mark_roots_heap(), and duk__mark_tval().

◆ duk__mark_hobject()

DUK_LOCAL void duk__mark_hobject ( duk_heap * heap,
duk_hobject * h )

Definition at line 41 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

41 {
43
44 DUK_DDD(DUK_DDDPRINT("duk__mark_hobject: %p", (void *) h));
45
46 DUK_ASSERT(h);
47
48 /* XXX: use advancing pointers instead of index macros -> faster and smaller? */
49
50 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
51 duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i);
52 if (!key) {
53 continue;
54 }
55 duk__mark_heaphdr(heap, (duk_heaphdr *) key);
56 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
59 } else {
60 duk__mark_tval(heap, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v);
61 }
62 }
63
64 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
66 }
67
68 /* hash part is a 'weak reference' and does not contribute */
69
71
74 duk_tval *tv, *tv_end;
75 duk_hobject **fn, **fn_end;
76
77 /* 'data' is reachable through every compiled function which
78 * contains a reference.
79 */
80
82
83 if (DUK_HCOMPILEDFUNCTION_GET_DATA(heap, f) != NULL) {
86 while (tv < tv_end) {
87 duk__mark_tval(heap, tv);
88 tv++;
89 }
90
93 while (fn < fn_end) {
94 duk__mark_heaphdr(heap, (duk_heaphdr *) *fn);
95 fn++;
96 }
97 } else {
98 /* May happen in some out-of-memory corner cases. */
99 DUK_D(DUK_DPRINT("duk_hcompiledfunction 'data' is NULL, skipping marking"));
100 }
101 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
103 DUK_UNREF(f);
104 /* nothing to mark */
105 } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
107 duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf);
108 } else if (DUK_HOBJECT_IS_THREAD(h)) {
109 duk_hthread *t = (duk_hthread *) h;
110 duk_tval *tv;
111
112 tv = t->valstack;
113 while (tv < t->valstack_top) {
114 duk__mark_tval(heap, tv);
115 tv++;
116 }
117
118 for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
119 duk_activation *act = t->callstack + i;
121 duk__mark_heaphdr(heap, (duk_heaphdr *) act->var_env);
122 duk__mark_heaphdr(heap, (duk_heaphdr *) act->lex_env);
123#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
124 duk__mark_heaphdr(heap, (duk_heaphdr *) act->prev_caller);
125#endif
126 }
127
128#if 0 /* nothing now */
129 for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
130 duk_catcher *cat = t->catchstack + i;
131 }
132#endif
133
135
136 /* XXX: duk_small_uint_t would be enough for this loop */
137 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
138 duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]);
139 }
140 }
141}
duk_uint32_t duk_uint_fast32_t
#define DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i)
#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap, h)
#define DUK_HOBJECT_GET_PROTOTYPE(heap, h)
#define DUK_HOBJECT_GET_ENEXT(h)
#define DUK_HOBJECT_IS_COMPILEDFUNCTION(h)
#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap, h)
#define DUK_HOBJECT_E_GET_KEY(heap, h, i)
#define DUK_HOBJECT_IS_THREAD(h)
#define DUK_HOBJECT_IS_NATIVEFUNCTION(h)
#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap, h)
#define DUK_HOBJECT_IS_BUFFEROBJECT(h)
#define DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)
#define DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)
#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap, h)
#define DUK_ACT_GET_FUNC(act)
#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap, h)
DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv)
duk_hobject * builtins[DUK_NUM_BUILTINS]

References duk_hbufferobject::buf, duk_hthread::builtins, duk_hthread::callstack, duk_hthread::callstack_top, duk_hthread::catchstack, duk_hthread::catchstack_top, duk__mark_heaphdr(), duk__mark_tval(), DUK_ACT_GET_FUNC, DUK_ASSERT, DUK_D, DUK_DDD, DUK_DDDPRINT, DUK_DPRINT, DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE, DUK_HCOMPILEDFUNCTION_GET_CONSTS_END, DUK_HCOMPILEDFUNCTION_GET_DATA, DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE, DUK_HCOMPILEDFUNCTION_GET_FUNCS_END, DUK_HOBJECT_A_GET_VALUE_PTR, DUK_HOBJECT_E_GET_KEY, DUK_HOBJECT_E_GET_VALUE_PTR, DUK_HOBJECT_E_SLOT_IS_ACCESSOR, DUK_HOBJECT_GET_ASIZE, DUK_HOBJECT_GET_ENEXT, DUK_HOBJECT_GET_PROTOTYPE, DUK_HOBJECT_IS_BUFFEROBJECT, DUK_HOBJECT_IS_COMPILEDFUNCTION, DUK_HOBJECT_IS_NATIVEFUNCTION, DUK_HOBJECT_IS_THREAD, DUK_NUM_BUILTINS, DUK_UNREF, duk_activation::lex_env, NULL, duk_hthread::resumer, duk_hthread::valstack, and duk_activation::var_env.

Referenced by duk__mark_heaphdr().

◆ duk__mark_hstring()

DUK_LOCAL void duk__mark_hstring ( duk_heap * heap,
duk_hstring * h )

Definition at line 31 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

31 {
32 DUK_UNREF(heap);
33 DUK_UNREF(h);
34
35 DUK_DDD(DUK_DDDPRINT("duk__mark_hstring: %p", (void *) h));
36 DUK_ASSERT(h);
37
38 /* nothing to process */
39}

References DUK_ASSERT, DUK_DDD, DUK_DDDPRINT, and DUK_UNREF.

Referenced by duk__mark_heaphdr().

◆ duk__mark_refzero_list()

DUK_LOCAL void duk__mark_refzero_list ( duk_heap * heap)

Definition at line 240 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

240 {
241 duk_heaphdr *hdr;
242
243 DUK_DD(DUK_DDPRINT("duk__mark_refzero_list: %p", (void *) heap));
244
245 hdr = heap->refzero_list;
246 while (hdr) {
247 duk__mark_heaphdr(heap, hdr);
248 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
249 }
250}

References duk__mark_heaphdr(), DUK_DD, DUK_DDPRINT, DUK_HEAPHDR_GET_NEXT, and duk_heap::refzero_list.

Referenced by duk_heap_mark_and_sweep().

◆ duk__mark_roots_heap()

DUK_LOCAL void duk__mark_roots_heap ( duk_heap * heap)

Definition at line 205 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

205 {
207
208 DUK_DD(DUK_DDPRINT("duk__mark_roots_heap: %p", (void *) heap));
209
212
213 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
214 duk_hstring *h = DUK_HEAP_GET_STRING(heap, i);
215 duk__mark_heaphdr(heap, (duk_heaphdr *) h);
216 }
217
218 duk__mark_tval(heap, &heap->lj.value1);
219 duk__mark_tval(heap, &heap->lj.value2);
220
221#if defined(DUK_USE_DEBUGGER_SUPPORT)
222 for (i = 0; i < heap->dbg_breakpoint_count; i++) {
223 duk__mark_heaphdr(heap, (duk_heaphdr *) heap->dbg_breakpoints[i].filename);
224 }
225#endif
226}
unsigned int duk_small_uint_t
#define DUK_HEAP_GET_STRING(heap, idx)

References duk__mark_heaphdr(), duk__mark_tval(), DUK_DD, DUK_DDPRINT, DUK_HEAP_GET_STRING, DUK_HEAP_NUM_STRINGS, duk_heap::heap_object, duk_heap::heap_thread, duk_heap::lj, duk_ljstate::value1, and duk_ljstate::value2.

Referenced by duk_heap_mark_and_sweep().

◆ duk__mark_temproots_by_heap_scan()

DUK_LOCAL void duk__mark_temproots_by_heap_scan ( duk_heap * heap)

Definition at line 390 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

390 {
391 duk_heaphdr *hdr;
392#ifdef DUK_USE_DEBUG
393 duk_size_t count;
394#endif
395
396 DUK_DD(DUK_DDPRINT("duk__mark_temproots_by_heap_scan: %p", (void *) heap));
397
399 DUK_DD(DUK_DDPRINT("recursion limit reached, doing heap scan to continue from temproots"));
400
401#ifdef DUK_USE_DEBUG
402 count = 0;
403#endif
405
406 hdr = heap->heap_allocated;
407 while (hdr) {
408#ifdef DUK_USE_DEBUG
409 duk__handle_temproot(heap, hdr, &count);
410#else
411 duk__handle_temproot(heap, hdr);
412#endif
413 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
414 }
415
416 /* must also check refzero_list */
417#ifdef DUK_USE_REFERENCE_COUNTING
418 hdr = heap->refzero_list;
419 while (hdr) {
420#ifdef DUK_USE_DEBUG
421 duk__handle_temproot(heap, hdr, &count);
422#else
423 duk__handle_temproot(heap, hdr);
424#endif
425 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
426 }
427#endif /* DUK_USE_REFERENCE_COUNTING */
428
429#ifdef DUK_USE_DEBUG
430 DUK_DD(DUK_DDPRINT("temproot mark heap scan processed %ld temp roots", (long) count));
431#endif
432 }
433}
#define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)
#define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap)
DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr)

References duk__handle_temproot(), DUK_DD, DUK_DDPRINT, DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED, DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED, DUK_HEAPHDR_GET_NEXT, duk_heap::heap_allocated, and duk_heap::refzero_list.

Referenced by duk_heap_mark_and_sweep().

◆ duk__mark_tval()

DUK_LOCAL_DECL void duk__mark_tval ( duk_heap * heap,
duk_tval * tv )

Definition at line 191 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

191 {
192 DUK_DDD(DUK_DDDPRINT("duk__mark_tval %p", (void *) tv));
193 if (!tv) {
194 return;
195 }
198 }
199}
#define DUK_TVAL_IS_HEAP_ALLOCATED(tv)
#define DUK_TVAL_GET_HEAPHDR(tv)

References duk__mark_heaphdr(), DUK_DDD, DUK_DDDPRINT, DUK_TVAL_GET_HEAPHDR, and DUK_TVAL_IS_HEAP_ALLOCATED.

Referenced by duk__mark_hobject(), and duk__mark_roots_heap().

◆ duk__protected_compact_object()

DUK_LOCAL int duk__protected_compact_object ( duk_context * ctx)

Definition at line 940 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

940 {
941 /* XXX: for threads, compact value stack, call stack, catch stack? */
942
943 duk_hobject *obj = duk_get_hobject(ctx, -1);
944 DUK_ASSERT(obj != NULL);
946 return 0;
947}
DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj)
DUK_INTERNAL_DECL duk_hobject * duk_get_hobject(duk_context *ctx, duk_idx_t index)

References DUK_ASSERT, duk_get_hobject(), duk_hobject_compact_props(), and NULL.

Referenced by duk__compact_object_list().

◆ duk__run_object_finalizers()

DUK_LOCAL void duk__run_object_finalizers ( duk_heap * heap,
duk_small_uint_t flags )

Definition at line 875 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

875 {
876 duk_heaphdr *curr;
878#ifdef DUK_USE_DEBUG
879 duk_size_t count = 0;
880#endif
881 duk_hthread *thr;
882
883 DUK_DD(DUK_DDPRINT("duk__run_object_finalizers: %p", (void *) heap));
884
885 thr = duk__get_temp_hthread(heap);
886 DUK_ASSERT(thr != NULL);
887
888 curr = heap->finalize_list;
889 while (curr) {
890 DUK_DDD(DUK_DDDPRINT("mark-and-sweep finalize: %p", (void *) curr));
891
892 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* only objects have finalizers */
893 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); /* flags have been already cleared */
897 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* No finalizers for ROM objects */
898
899 if (DUK_LIKELY((flags & DUK_MS_FLAG_SKIP_FINALIZERS) == 0)) {
900 /* Run the finalizer, duk_hobject_run_finalizer() sets FINALIZED.
901 * Next mark-and-sweep will collect the object unless it has
902 * become reachable (i.e. rescued). FINALIZED prevents the
903 * finalizer from being executed again before that.
904 */
905 duk_hobject_run_finalizer(thr, (duk_hobject *) curr); /* must never longjmp */
907 } else {
908 /* Used during heap destruction: don't actually run finalizers
909 * because we're heading into forced finalization. Instead,
910 * queue finalizable objects back to the heap_allocated list.
911 */
912 DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing"));
914 }
915
916 /* queue back to heap_allocated */
917 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
919
920 curr = next;
921#ifdef DUK_USE_DEBUG
922 count++;
923#endif
924 }
925
926 /* finalize_list will always be processed completely */
927 heap->finalize_list = NULL;
928
929#ifdef DUK_USE_DEBUG
930 DUK_D(DUK_DPRINT("mark-and-sweep finalize objects: %ld finalizers called", (long) count));
931#endif
932}
#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, hdr)
DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj)
#define DUK_MS_FLAG_SKIP_FINALIZERS

References duk__get_temp_hthread(), DUK_ASSERT, DUK_D, DUK_DD, DUK_DDD, DUK_DDDPRINT, DUK_DDPRINT, DUK_DPRINT, DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED, DUK_HEAPHDR_GET_NEXT, DUK_HEAPHDR_GET_TYPE, DUK_HEAPHDR_HAS_FINALIZABLE, DUK_HEAPHDR_HAS_FINALIZED, DUK_HEAPHDR_HAS_REACHABLE, DUK_HEAPHDR_HAS_READONLY, DUK_HEAPHDR_HAS_TEMPROOT, duk_hobject_run_finalizer(), DUK_HTYPE_OBJECT, DUK_LIKELY, DUK_MS_FLAG_SKIP_FINALIZERS, duk_heap::finalize_list, next, and NULL.

Referenced by duk_heap_mark_and_sweep().

◆ duk__sweep_heap()

DUK_LOCAL void duk__sweep_heap ( duk_heap * heap,
duk_int_t flags,
duk_size_t * out_count_keep )

Definition at line 717 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

717 {
718 duk_heaphdr *prev; /* last element that was left in the heap */
719 duk_heaphdr *curr;
721#ifdef DUK_USE_DEBUG
722 duk_size_t count_free = 0;
723 duk_size_t count_finalize = 0;
724 duk_size_t count_rescue = 0;
725#endif
726 duk_size_t count_keep = 0;
727
728 DUK_UNREF(flags);
729 DUK_DD(DUK_DDPRINT("duk__sweep_heap: %p", (void *) heap));
730
731 prev = NULL;
732 curr = heap->heap_allocated;
733 heap->heap_allocated = NULL;
734 while (curr) {
735 /* Strings and ROM objects are never placed on the heap allocated list. */
738
739 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
740
741 if (DUK_HEAPHDR_HAS_REACHABLE(curr)) {
742 /*
743 * Reachable object, keep
744 */
745
746 DUK_DDD(DUK_DDDPRINT("sweep, reachable: %p", (void *) curr));
747
748 if (DUK_HEAPHDR_HAS_FINALIZABLE(curr)) {
749 /*
750 * If object has been marked finalizable, move it to the
751 * "to be finalized" work list. It will be collected on
752 * the next mark-and-sweep if it is still unreachable
753 * after running the finalizer.
754 */
755
758 DUK_DDD(DUK_DDDPRINT("object has finalizer, move to finalization work list: %p", (void *) curr));
759
760#ifdef DUK_USE_DOUBLE_LINKED_HEAP
761 if (heap->finalize_list) {
762 DUK_HEAPHDR_SET_PREV(heap, heap->finalize_list, curr);
763 }
764 DUK_HEAPHDR_SET_PREV(heap, curr, NULL);
765#endif
766 DUK_HEAPHDR_SET_NEXT(heap, curr, heap->finalize_list);
767 DUK_ASSERT_HEAPHDR_LINKS(heap, curr);
768 heap->finalize_list = curr;
769#ifdef DUK_USE_DEBUG
770 count_finalize++;
771#endif
772 } else {
773 /*
774 * Object will be kept; queue object back to heap_allocated (to tail)
775 */
776
777 if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
778 /*
779 * Object's finalizer was executed on last round, and
780 * object has been happily rescued.
781 */
782
785 DUK_DD(DUK_DDPRINT("object rescued during mark-and-sweep finalization: %p", (void *) curr));
786#ifdef DUK_USE_DEBUG
787 count_rescue++;
788#endif
789 } else {
790 /*
791 * Plain, boring reachable object.
792 */
793 DUK_DD(DUK_DDPRINT("keep object: %!iO", curr));
794 count_keep++;
795 }
796
797 if (!heap->heap_allocated) {
798 heap->heap_allocated = curr;
799 }
800 if (prev) {
801 DUK_HEAPHDR_SET_NEXT(heap, prev, curr);
802 }
803#ifdef DUK_USE_DOUBLE_LINKED_HEAP
804 DUK_HEAPHDR_SET_PREV(heap, curr, prev);
805#endif
806 DUK_ASSERT_HEAPHDR_LINKS(heap, prev);
807 DUK_ASSERT_HEAPHDR_LINKS(heap, curr);
808 prev = curr;
809 }
810
814
818
819 curr = next;
820 } else {
821 /*
822 * Unreachable object, free
823 */
824
825 DUK_DDD(DUK_DDDPRINT("sweep, not reachable: %p", (void *) curr));
826
827#if defined(DUK_USE_REFERENCE_COUNTING)
828 /* Non-zero refcounts should not happen because we refcount
829 * finalize all unreachable objects which should cancel out
830 * refcounts (even for cycles).
831 */
833#endif
835
836 if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
837 DUK_DDD(DUK_DDDPRINT("finalized object not rescued: %p", (void *) curr));
838 }
839
840 /* Note: object cannot be a finalizable unreachable object, as
841 * they have been marked temporarily reachable for this round,
842 * and are handled above.
843 */
844
845#ifdef DUK_USE_DEBUG
846 count_free++;
847#endif
848
849 /* weak refs should be handled here, but no weak refs for
850 * any non-string objects exist right now.
851 */
852
853 /* free object and all auxiliary (non-heap) allocs */
854 duk_heap_free_heaphdr_raw(heap, curr);
855
856 curr = next;
857 }
858 }
859 if (prev) {
860 DUK_HEAPHDR_SET_NEXT(heap, prev, NULL);
861 }
862 DUK_ASSERT_HEAPHDR_LINKS(heap, prev);
863
864#ifdef DUK_USE_DEBUG
865 DUK_D(DUK_DPRINT("mark-and-sweep sweep objects (non-string): %ld freed, %ld kept, %ld rescued, %ld queued for finalization",
866 (long) count_free, (long) count_keep, (long) count_rescue, (long) count_finalize));
867#endif
868 *out_count_keep = count_keep;
869}
#define DUK_HEAPHDR_CLEAR_FINALIZED(h)
#define DUK_HEAPHDR_SET_NEXT(heap, h, val)
#define DUK_HEAPHDR_SET_PREV(heap, h, val)
#define DUK_HEAPHDR_CLEAR_FINALIZABLE(h)
#define DUK_HEAPHDR_GET_REFCOUNT(h)
#define DUK_ASSERT_HEAPHDR_LINKS(heap, h)
DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr)

References DUK_ASSERT, DUK_ASSERT_HEAPHDR_LINKS, DUK_D, DUK_DD, DUK_DDD, DUK_DDDPRINT, DUK_DDPRINT, DUK_DPRINT, duk_heap_free_heaphdr_raw(), DUK_HEAPHDR_CLEAR_FINALIZABLE, DUK_HEAPHDR_CLEAR_FINALIZED, DUK_HEAPHDR_CLEAR_REACHABLE, DUK_HEAPHDR_GET_NEXT, DUK_HEAPHDR_GET_REFCOUNT, DUK_HEAPHDR_GET_TYPE, DUK_HEAPHDR_HAS_FINALIZABLE, DUK_HEAPHDR_HAS_FINALIZED, DUK_HEAPHDR_HAS_REACHABLE, DUK_HEAPHDR_HAS_READONLY, DUK_HEAPHDR_SET_NEXT, DUK_HEAPHDR_SET_PREV, DUK_HTYPE_OBJECT, DUK_HTYPE_STRING, DUK_UNREF, duk_heap::finalize_list, duk_heap::heap_allocated, next, and NULL.

Referenced by duk_heap_mark_and_sweep().

◆ duk__sweep_stringtable_probe()

DUK_LOCAL void duk__sweep_stringtable_probe ( duk_heap * heap,
duk_size_t * out_count_keep )

Definition at line 644 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

644 {
645 duk_hstring *h;
647#ifdef DUK_USE_DEBUG
648 duk_size_t count_free = 0;
649#endif
650 duk_size_t count_keep = 0;
651
652 DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap));
653
654 for (i = 0; i < heap->st_size; i++) {
655#if defined(DUK_USE_HEAPPTR16)
656 h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
657#else
658 h = heap->strtable[i];
659#endif
660 if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
661 continue;
662 } else if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
664 count_keep++;
665 continue;
666 }
667
668#ifdef DUK_USE_DEBUG
669 count_free++;
670#endif
671
672#if defined(DUK_USE_REFERENCE_COUNTING)
673 /* Non-zero refcounts should not happen for unreachable strings,
674 * because we refcount finalize all unreachable objects which
675 * should have decreased unreachable string refcounts to zero
676 * (even for cycles).
677 */
679#endif
680
681 DUK_DDD(DUK_DDDPRINT("sweep string, not reachable: %p", (void *) h));
682
683 /* deal with weak references first */
685
686 /* remove the string (mark DELETED), could also call
687 * duk_heap_string_remove() but that would be slow and
688 * pointless because we already know the slot.
689 */
690#if defined(DUK_USE_HEAPPTR16)
691 heap->strtable16[i] = heap->heapptr_deleted16;
692#else
693 heap->strtable[i] = DUK_STRTAB_DELETED_MARKER(heap);
694#endif
695
696 /* free inner references (these exist e.g. when external
697 * strings are enabled)
698 */
700
701 /* finally free the struct itself */
702 DUK_FREE(heap, h);
703 }
704
705#ifdef DUK_USE_DEBUG
706 DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept",
707 (long) count_free, (long) count_keep));
708#endif
709 *out_count_keep = count_keep;
710}
#define DUK_STRTAB_DELETED_MARKER(heap)
#define DUK_FREE(heap, ptr)
DUK_INTERNAL_DECL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h)
DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h)

References DUK_ASSERT, DUK_D, DUK_DD, DUK_DDD, DUK_DDDPRINT, DUK_DDPRINT, DUK_DPRINT, DUK_FREE, duk_free_hstring_inner(), duk_heap_strcache_string_remove(), DUK_HEAPHDR_CLEAR_REACHABLE, DUK_HEAPHDR_GET_REFCOUNT, DUK_HEAPHDR_HAS_REACHABLE, DUK_STRTAB_DELETED_MARKER, duk_heap::heap_udata, NULL, duk_heap::st_size, and duk_heap::strtable.

Referenced by duk_heap_mark_and_sweep().

◆ duk_heap_mark_and_sweep()

DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep ( duk_heap * heap,
duk_small_uint_t flags )

Definition at line 1151 of file duktape-1.5.2/src-separate/duk_heap_markandsweep.c.

1151 {
1152 duk_hthread *thr;
1153 duk_size_t count_keep_obj;
1154 duk_size_t count_keep_str;
1155#ifdef DUK_USE_VOLUNTARY_GC
1156 duk_size_t tmp;
1157#endif
1158
1159 /* XXX: thread selection for mark-and-sweep is currently a hack.
1160 * If we don't have a thread, the entire mark-and-sweep is now
1161 * skipped (although we could just skip finalizations).
1162 */
1163
1164 /* If thr != NULL, the thr may still be in the middle of
1165 * initialization.
1166 * XXX: Improve the thread viability test.
1167 */
1168 thr = duk__get_temp_hthread(heap);
1169 if (thr == NULL) {
1170 DUK_D(DUK_DPRINT("gc skipped because we don't have a temp thread"));
1171
1172 /* reset voluntary gc trigger count */
1173#ifdef DUK_USE_VOLUNTARY_GC
1175#endif
1176 return 0; /* OK */
1177 }
1178
1179 /* If debugger is paused, garbage collection is disabled by default. */
1180 /* XXX: will need a force flag if garbage collection is triggered
1181 * explicitly during paused state.
1182 */
1183#if defined(DUK_USE_DEBUGGER_SUPPORT)
1184 if (DUK_HEAP_IS_PAUSED(heap)) {
1185 /* Checking this here rather that in memory alloc primitives
1186 * reduces checking code there but means a failed allocation
1187 * will go through a few retries before giving up. That's
1188 * fine because this only happens during debugging.
1189 */
1190 DUK_D(DUK_DPRINT("gc skipped because debugger is paused"));
1191 return 0;
1192 }
1193#endif
1194
1195 DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx",
1196 (unsigned long) flags, (unsigned long) (flags | heap->mark_and_sweep_base_flags)));
1197
1198 flags |= heap->mark_and_sweep_base_flags;
1199
1200 /*
1201 * Assertions before
1202 */
1203
1204#ifdef DUK_USE_ASSERTIONS
1208 duk__assert_heaphdr_flags(heap);
1209#ifdef DUK_USE_REFERENCE_COUNTING
1210 /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount
1211 * finalizer may trigger a mark-and-sweep.
1212 */
1213 duk__assert_valid_refcounts(heap);
1214#endif /* DUK_USE_REFERENCE_COUNTING */
1215#endif /* DUK_USE_ASSERTIONS */
1216
1217 /*
1218 * Begin
1219 */
1220
1222
1223 /*
1224 * Mark roots, hoping that recursion limit is not normally hit.
1225 * If recursion limit is hit, run additional reachability rounds
1226 * starting from "temproots" until marking is complete.
1227 *
1228 * Marking happens in two phases: first we mark actual reachability
1229 * roots (and run "temproots" to complete the process). Then we
1230 * check which objects are unreachable and are finalizable; such
1231 * objects are marked as FINALIZABLE and marked as reachability
1232 * (and "temproots" is run again to complete the process).
1233 *
1234 * The heap finalize_list must also be marked as a reachability root.
1235 * There may be objects on the list from a previous round if the
1236 * previous run had finalizer skip flag.
1237 */
1238
1239 duk__mark_roots_heap(heap); /* main reachability roots */
1240#ifdef DUK_USE_REFERENCE_COUNTING
1241 duk__mark_refzero_list(heap); /* refzero_list treated as reachability roots */
1242#endif
1243 duk__mark_temproots_by_heap_scan(heap); /* temproots */
1244
1245 duk__mark_finalizable(heap); /* mark finalizable as reachability roots */
1246 duk__mark_finalize_list(heap); /* mark finalizer work list as reachability roots */
1247 duk__mark_temproots_by_heap_scan(heap); /* temproots */
1248
1249 /*
1250 * Sweep garbage and remove marking flags, and move objects with
1251 * finalizers to the finalizer work list.
1252 *
1253 * Objects to be swept need to get their refcounts finalized before
1254 * they are swept. In other words, their target object refcounts
1255 * need to be decreased. This has to be done before freeing any
1256 * objects to avoid decref'ing dangling pointers (which may happen
1257 * even without bugs, e.g. with reference loops)
1258 *
1259 * Because strings don't point to other heap objects, similar
1260 * finalization is not necessary for strings.
1261 */
1262
1263 /* XXX: more emergency behavior, e.g. find smaller hash sizes etc */
1264
1265#ifdef DUK_USE_REFERENCE_COUNTING
1267#endif
1268 duk__sweep_heap(heap, flags, &count_keep_obj);
1269#if defined(DUK_USE_STRTAB_CHAIN)
1270 duk__sweep_stringtable_chain(heap, &count_keep_str);
1271#elif defined(DUK_USE_STRTAB_PROBE)
1272 duk__sweep_stringtable_probe(heap, &count_keep_str);
1273#else
1274#error internal error, invalid strtab options
1275#endif
1276#ifdef DUK_USE_REFERENCE_COUNTING
1278#endif
1280
1281 /*
1282 * Object compaction (emergency only).
1283 *
1284 * Object compaction is a separate step after sweeping, as there is
1285 * more free memory for it to work with. Also, currently compaction
1286 * may insert new objects into the heap allocated list and the string
1287 * table which we don't want to do during a sweep (the reachability
1288 * flags of such objects would be incorrect). The objects inserted
1289 * are currently:
1290 *
1291 * - a temporary duk_hbuffer for a new properties allocation
1292 * - if array part is abandoned, string keys are interned
1293 *
1294 * The object insertions go to the front of the list, so they do not
1295 * cause an infinite loop (they are not compacted).
1296 */
1297
1298 if ((flags & DUK_MS_FLAG_EMERGENCY) &&
1301 }
1302
1303 /*
1304 * String table resize check.
1305 *
1306 * Note: this may silently (and safely) fail if GC is caused by an
1307 * allocation call in stringtable resize_hash(). Resize_hash()
1308 * will prevent a recursive call to itself by setting the
1309 * DUK_MS_FLAG_NO_STRINGTABLE_RESIZE in heap->mark_and_sweep_base_flags.
1310 */
1311
1312 /* XXX: stringtable emergency compaction? */
1313
1314 /* XXX: remove this feature entirely? it would only matter for
1315 * emergency GC. Disable for lowest memory builds.
1316 */
1317#if defined(DUK_USE_MS_STRINGTABLE_RESIZE)
1318 if (!(flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE)) {
1319 DUK_DD(DUK_DDPRINT("resize stringtable: %p", (void *) heap));
1321 } else {
1322 DUK_D(DUK_DPRINT("stringtable resize skipped because DUK_MS_FLAG_NO_STRINGTABLE_RESIZE is set"));
1323 }
1324#endif
1325
1326 /*
1327 * Finalize objects in the finalization work list. Finalized
1328 * objects are queued back to heap_allocated with FINALIZED set.
1329 *
1330 * Since finalizers may cause arbitrary side effects, they are
1331 * prevented during string table and object property allocation
1332 * resizing using the DUK_MS_FLAG_NO_FINALIZERS flag in
1333 * heap->mark_and_sweep_base_flags. In this case the objects
1334 * remain in the finalization work list after mark-and-sweep
1335 * exits and they may be finalized on the next pass.
1336 *
1337 * Finalization currently happens inside "MARKANDSWEEP_RUNNING"
1338 * protection (no mark-and-sweep may be triggered by the
1339 * finalizers). As a side effect:
1340 *
1341 * 1) an out-of-memory error inside a finalizer will not
1342 * cause a mark-and-sweep and may cause the finalizer
1343 * to fail unnecessarily
1344 *
1345 * 2) any temporary objects whose refcount decreases to zero
1346 * during finalization will not be put into refzero_list;
1347 * they can only be collected by another mark-and-sweep
1348 *
1349 * This is not optimal, but since the sweep for this phase has
1350 * already happened, this is probably good enough for now.
1351 */
1352
1353#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE)
1354 /* Cannot simulate individual finalizers because finalize_list only
1355 * contains objects with actual finalizers. But simulate side effects
1356 * from finalization by doing a bogus function call and resizing the
1357 * stacks.
1358 */
1359 if (flags & DUK_MS_FLAG_NO_FINALIZERS) {
1360 DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, DUK_MS_FLAG_NO_FINALIZERS is set"));
1361 } else if (!(thr->valstack != NULL && thr->callstack != NULL && thr->catchstack != NULL)) {
1362 DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, thread not yet viable"));
1363 } else {
1364 DUK_D(DUK_DPRINT("run mark-and-sweep torture finalizer"));
1365 duk__markandsweep_torture_finalizer(thr);
1366 }
1367#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */
1368
1369 if (flags & DUK_MS_FLAG_NO_FINALIZERS) {
1370 DUK_D(DUK_DPRINT("finalizer run skipped because DUK_MS_FLAG_NO_FINALIZERS is set"));
1371 } else {
1372 duk__run_object_finalizers(heap, flags);
1373 }
1374
1375 /*
1376 * Finish
1377 */
1378
1380
1381 /*
1382 * Assertions after
1383 */
1384
1385#ifdef DUK_USE_ASSERTIONS
1389 duk__assert_heaphdr_flags(heap);
1390#ifdef DUK_USE_REFERENCE_COUNTING
1391 /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount
1392 * finalizer may trigger a mark-and-sweep.
1393 */
1394 duk__assert_valid_refcounts(heap);
1395#endif /* DUK_USE_REFERENCE_COUNTING */
1396#endif /* DUK_USE_ASSERTIONS */
1397
1398 /*
1399 * Reset trigger counter
1400 */
1401
1402#ifdef DUK_USE_VOLUNTARY_GC
1403 tmp = (count_keep_obj + count_keep_str) / 256;
1407 DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, trigger reset to %ld",
1408 (long) count_keep_obj, (long) count_keep_str, (long) heap->mark_and_sweep_trigger_counter));
1409#else
1410 DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, no voluntary trigger",
1411 (long) count_keep_obj, (long) count_keep_str));
1412#endif
1413
1414 return 0; /* OK */
1415}
duk_int_fast32_t duk_int_t
#define DUK_MS_FLAG_EMERGENCY
#define DUK_MS_FLAG_NO_OBJECT_COMPACTION
#define DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap)
#define DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap)
#define DUK_MS_FLAG_NO_FINALIZERS
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD
#define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)
#define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP
DUK_INTERNAL_DECL void duk_heap_force_strtab_resize(duk_heap *heap)
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT
DUK_LOCAL void duk__clear_refzero_list_flags(duk_heap *heap)
DUK_LOCAL void duk__mark_temproots_by_heap_scan(duk_heap *heap)
DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap)
DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_count_keep)
DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags)
DUK_LOCAL void duk__mark_roots_heap(duk_heap *heap)
DUK_LOCAL void duk__mark_finalizable(duk_heap *heap)
DUK_LOCAL void duk__mark_finalize_list(duk_heap *heap)
DUK_LOCAL void duk__mark_refzero_list(duk_heap *heap)
DUK_LOCAL void duk__clear_finalize_list_flags(duk_heap *heap)
DUK_LOCAL void duk__compact_objects(duk_heap *heap)
DUK_LOCAL void duk__sweep_stringtable_probe(duk_heap *heap, duk_size_t *out_count_keep)
duk_small_uint_t mark_and_sweep_base_flags

References duk_hthread::callstack, duk_hthread::catchstack, duk__clear_finalize_list_flags(), duk__clear_refzero_list_flags(), duk__compact_objects(), duk__finalize_refcounts(), duk__get_temp_hthread(), duk__mark_finalizable(), duk__mark_finalize_list(), duk__mark_refzero_list(), duk__mark_roots_heap(), duk__mark_temproots_by_heap_scan(), duk__run_object_finalizers(), duk__sweep_heap(), duk__sweep_stringtable_probe(), DUK_ASSERT, DUK_D, DUK_DD, DUK_DDPRINT, DUK_DPRINT, DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING, duk_heap_force_strtab_resize(), DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED, DUK_HEAP_HAS_MARKANDSWEEP_RUNNING, DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD, DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT, DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP, DUK_HEAP_SET_MARKANDSWEEP_RUNNING, DUK_MS_FLAG_EMERGENCY, DUK_MS_FLAG_NO_FINALIZERS, DUK_MS_FLAG_NO_OBJECT_COMPACTION, DUK_MS_FLAG_NO_STRINGTABLE_RESIZE, duk_heap::mark_and_sweep_base_flags, duk_heap::mark_and_sweep_recursion_depth, duk_heap::mark_and_sweep_trigger_counter, NULL, and duk_hthread::valstack.