xref: /plan9/sys/src/cmd/gs/src/igc.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1993, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: igc.c,v 1.15 2005/09/05 13:58:55 leonardo Exp $ */
187dd7cddfSDavid du Colombier /* Garbage collector for Ghostscript */
197dd7cddfSDavid du Colombier #include "memory_.h"
207dd7cddfSDavid du Colombier #include "ghost.h"
21*593dc095SDavid du Colombier #include "ierrors.h"
227dd7cddfSDavid du Colombier #include "gsexit.h"
237dd7cddfSDavid du Colombier #include "gsmdebug.h"
247dd7cddfSDavid du Colombier #include "gsstruct.h"
257dd7cddfSDavid du Colombier #include "gsutil.h"
267dd7cddfSDavid du Colombier #include "iastate.h"
277dd7cddfSDavid du Colombier #include "isave.h"
287dd7cddfSDavid du Colombier #include "isstate.h"
297dd7cddfSDavid du Colombier #include "idict.h"
307dd7cddfSDavid du Colombier #include "ipacked.h"
317dd7cddfSDavid du Colombier #include "istruct.h"
327dd7cddfSDavid du Colombier #include "igc.h"
337dd7cddfSDavid du Colombier #include "igcstr.h"
347dd7cddfSDavid du Colombier #include "inamedef.h"
357dd7cddfSDavid du Colombier #include "opdef.h"		/* for marking oparray names */
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier /* Define whether to force all garbage collections to be global. */
383ff48bf5SDavid du Colombier private const bool I_FORCE_GLOBAL_GC = false;
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier /* Define whether to bypass the collector entirely. */
413ff48bf5SDavid du Colombier private const bool I_BYPASS_GC = false;
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier /* Define an entry on the mark stack. */
447dd7cddfSDavid du Colombier typedef struct {
457dd7cddfSDavid du Colombier     void *ptr;
467dd7cddfSDavid du Colombier     uint index;
477dd7cddfSDavid du Colombier     bool is_refs;
487dd7cddfSDavid du Colombier } ms_entry;
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier /* Define (a segment of) the mark stack. */
517dd7cddfSDavid du Colombier /* entries[0] has ptr = 0 to indicate the bottom of the stack. */
527dd7cddfSDavid du Colombier /* count additional entries follow this structure. */
537dd7cddfSDavid du Colombier typedef struct gc_mark_stack_s gc_mark_stack;
547dd7cddfSDavid du Colombier struct gc_mark_stack_s {
557dd7cddfSDavid du Colombier     gc_mark_stack *prev;
567dd7cddfSDavid du Colombier     gc_mark_stack *next;
577dd7cddfSDavid du Colombier     uint count;
587dd7cddfSDavid du Colombier     bool on_heap;		/* if true, allocated during GC */
597dd7cddfSDavid du Colombier     ms_entry entries[1];
607dd7cddfSDavid du Colombier };
617dd7cddfSDavid du Colombier 
627dd7cddfSDavid du Colombier /* Define the mark stack sizing parameters. */
637dd7cddfSDavid du Colombier #define ms_size_default 100	/* default, allocated on C stack */
647dd7cddfSDavid du Colombier /* This should probably be defined as a parameter somewhere.... */
657dd7cddfSDavid du Colombier #define ms_size_desired		/* for additional allocation */\
667dd7cddfSDavid du Colombier  ((max_ushort - sizeof(gc_mark_stack)) / sizeof(ms_entry) - 10)
677dd7cddfSDavid du Colombier #define ms_size_min 50		/* min size for segment in free block */
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier /* Forward references */
70*593dc095SDavid du Colombier 
71*593dc095SDavid du Colombier private void gc_init_mark_stack(gc_mark_stack *, uint);
72*593dc095SDavid du Colombier private void gc_objects_clear_marks(const gs_memory_t *mem, chunk_t *);
73*593dc095SDavid du Colombier private void gc_unmark_names(name_table *);
74*593dc095SDavid du Colombier private int gc_trace(gs_gc_root_t *, gc_state_t *, gc_mark_stack *);
75*593dc095SDavid du Colombier private int gc_rescan_chunk(chunk_t *, gc_state_t *, gc_mark_stack *);
76*593dc095SDavid du Colombier private int gc_trace_chunk(const gs_memory_t *mem, chunk_t *, gc_state_t *, gc_mark_stack *);
77*593dc095SDavid du Colombier private bool gc_trace_finish(gc_state_t *);
78*593dc095SDavid du Colombier private void gc_clear_reloc(chunk_t *);
79*593dc095SDavid du Colombier private void gc_objects_set_reloc(chunk_t *);
80*593dc095SDavid du Colombier private void gc_do_reloc(chunk_t *, gs_ref_memory_t *, gc_state_t *);
81*593dc095SDavid du Colombier private void gc_objects_compact(chunk_t *, gc_state_t *);
82*593dc095SDavid du Colombier private void gc_free_empty_chunks(gs_ref_memory_t *);
837dd7cddfSDavid du Colombier 
847dd7cddfSDavid du Colombier /* Forward references for pointer types */
857dd7cddfSDavid du Colombier private ptr_proc_unmark(ptr_struct_unmark);
867dd7cddfSDavid du Colombier private ptr_proc_mark(ptr_struct_mark);
877dd7cddfSDavid du Colombier private ptr_proc_unmark(ptr_string_unmark);
887dd7cddfSDavid du Colombier private ptr_proc_mark(ptr_string_mark);
897dd7cddfSDavid du Colombier /*ptr_proc_unmark(ptr_ref_unmark); *//* in igc.h */
907dd7cddfSDavid du Colombier /*ptr_proc_mark(ptr_ref_mark); *//* in igc.h */
917dd7cddfSDavid du Colombier private ptr_proc_reloc(igc_reloc_struct_ptr, void);
927dd7cddfSDavid du Colombier 
937dd7cddfSDavid du Colombier ptr_proc_reloc(igc_reloc_ref_ptr, ref_packed);	/* in igcref.c */
947dd7cddfSDavid du Colombier refs_proc_reloc(igc_reloc_refs);	/* in igcref.c */
957dd7cddfSDavid du Colombier 
967dd7cddfSDavid du Colombier /* Define this GC's procedure vector. */
977dd7cddfSDavid du Colombier private const gc_procs_with_refs_t igc_procs = {
987dd7cddfSDavid du Colombier     igc_reloc_struct_ptr, igc_reloc_string, igc_reloc_const_string,
99*593dc095SDavid du Colombier     igc_reloc_param_string, igc_reloc_ref_ptr, igc_reloc_refs
1007dd7cddfSDavid du Colombier };
1017dd7cddfSDavid du Colombier 
1027dd7cddfSDavid du Colombier /* Pointer type descriptors. */
1037dd7cddfSDavid du Colombier /* Note that the trace/mark routine has special knowledge of ptr_ref_type */
1047dd7cddfSDavid du Colombier /* and ptr_struct_type -- it assumes that no other types have embedded */
1057dd7cddfSDavid du Colombier /* pointers.  Note also that the reloc procedures for string and ref */
1067dd7cddfSDavid du Colombier /* pointers are never called. */
1077dd7cddfSDavid du Colombier typedef ptr_proc_reloc((*ptr_proc_reloc_t), void);
1087dd7cddfSDavid du Colombier const gs_ptr_procs_t ptr_struct_procs =
1097dd7cddfSDavid du Colombier {ptr_struct_unmark, ptr_struct_mark, (ptr_proc_reloc_t) igc_reloc_struct_ptr};
1107dd7cddfSDavid du Colombier const gs_ptr_procs_t ptr_string_procs =
1117dd7cddfSDavid du Colombier {ptr_string_unmark, ptr_string_mark, NULL};
1127dd7cddfSDavid du Colombier const gs_ptr_procs_t ptr_const_string_procs =
1137dd7cddfSDavid du Colombier {ptr_string_unmark, ptr_string_mark, NULL};
1147dd7cddfSDavid du Colombier const gs_ptr_procs_t ptr_ref_procs =
1157dd7cddfSDavid du Colombier {ptr_ref_unmark, ptr_ref_mark, NULL};
1167dd7cddfSDavid du Colombier 
1177dd7cddfSDavid du Colombier /* ------ Main program ------ */
1187dd7cddfSDavid du Colombier 
1197dd7cddfSDavid du Colombier /* Top level of garbage collector. */
1207dd7cddfSDavid du Colombier #ifdef DEBUG
1217dd7cddfSDavid du Colombier private void
end_phase(const char * str)1227dd7cddfSDavid du Colombier end_phase(const char *str)
1237dd7cddfSDavid du Colombier {
1247dd7cddfSDavid du Colombier     if (gs_debug_c('6')) {
1257dd7cddfSDavid du Colombier 	dlprintf1("[6]---------------- end %s ----------------\n",
1267dd7cddfSDavid du Colombier 		  (const char *)str);
1273ff48bf5SDavid du Colombier 	dflush();
1287dd7cddfSDavid du Colombier     }
1297dd7cddfSDavid du Colombier }
1307dd7cddfSDavid du Colombier static const char *const depth_dots_string = "..........";
1317dd7cddfSDavid du Colombier private const char *
depth_dots(const ms_entry * sp,const gc_mark_stack * pms)1327dd7cddfSDavid du Colombier depth_dots(const ms_entry * sp, const gc_mark_stack * pms)
1337dd7cddfSDavid du Colombier {
1347dd7cddfSDavid du Colombier     int depth = sp - pms->entries - 1;
1357dd7cddfSDavid du Colombier     const gc_mark_stack *pss = pms;
1367dd7cddfSDavid du Colombier 
1377dd7cddfSDavid du Colombier     while ((pss = pss->prev) != 0)
1387dd7cddfSDavid du Colombier 	depth += pss->count - 1;
1397dd7cddfSDavid du Colombier     return depth_dots_string + (depth >= 10 ? 0 : 10 - depth);
1407dd7cddfSDavid du Colombier }
1417dd7cddfSDavid du Colombier private void
gc_validate_spaces(gs_ref_memory_t ** spaces,int max_space,gc_state_t * gcst)1427dd7cddfSDavid du Colombier gc_validate_spaces(gs_ref_memory_t **spaces, int max_space, gc_state_t *gcst)
1437dd7cddfSDavid du Colombier {
1447dd7cddfSDavid du Colombier     int i;
1457dd7cddfSDavid du Colombier     gs_ref_memory_t *mem;
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier     for (i = 1; i <= max_space; ++i)
1487dd7cddfSDavid du Colombier 	if ((mem = spaces[i]) != 0)
1497dd7cddfSDavid du Colombier 	    ialloc_validate_memory(mem, gcst);
1507dd7cddfSDavid du Colombier }
1517dd7cddfSDavid du Colombier #else  /* !DEBUG */
1527dd7cddfSDavid du Colombier #  define end_phase(str) DO_NOTHING
1537dd7cddfSDavid du Colombier #endif /* DEBUG */
1547dd7cddfSDavid du Colombier void
gs_gc_reclaim(vm_spaces * pspaces,bool global)1557dd7cddfSDavid du Colombier gs_gc_reclaim(vm_spaces * pspaces, bool global)
1567dd7cddfSDavid du Colombier {
1577dd7cddfSDavid du Colombier #define nspaces ((i_vm_max + 1) * 2) /* * 2 for stable allocators */
1587dd7cddfSDavid du Colombier 
1597dd7cddfSDavid du Colombier     vm_spaces spaces;
1607dd7cddfSDavid du Colombier     gs_ref_memory_t *space_memories[nspaces];
1617dd7cddfSDavid du Colombier     gs_gc_root_t space_roots[nspaces];
1627dd7cddfSDavid du Colombier     int max_trace;		/* max space_ to trace */
1637dd7cddfSDavid du Colombier     int min_collect;		/* min space_ to collect */
1647dd7cddfSDavid du Colombier     int min_collect_vm_space;	/* min VM space to collect */
1657dd7cddfSDavid du Colombier     int ispace;
1667dd7cddfSDavid du Colombier     gs_ref_memory_t *mem;
1677dd7cddfSDavid du Colombier     chunk_t *cp;
1687dd7cddfSDavid du Colombier     gs_gc_root_t *rp;
1697dd7cddfSDavid du Colombier     gc_state_t state;
1707dd7cddfSDavid du Colombier     struct _msd {
1717dd7cddfSDavid du Colombier 	gc_mark_stack stack;
1727dd7cddfSDavid du Colombier 	ms_entry body[ms_size_default];
1737dd7cddfSDavid du Colombier     } ms_default;
1747dd7cddfSDavid du Colombier     gc_mark_stack *mark_stack = &ms_default.stack;
175*593dc095SDavid du Colombier     const gs_memory_t *cmem;
1767dd7cddfSDavid du Colombier 
1777dd7cddfSDavid du Colombier     /* Optionally force global GC for debugging. */
1787dd7cddfSDavid du Colombier 
1797dd7cddfSDavid du Colombier     if (I_FORCE_GLOBAL_GC)
1807dd7cddfSDavid du Colombier 	global = true;
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier     /* Determine which spaces we are tracing and collecting. */
1837dd7cddfSDavid du Colombier 
1847dd7cddfSDavid du Colombier     spaces = *pspaces;
185*593dc095SDavid du Colombier     cmem = space_system->stable_memory;
1867dd7cddfSDavid du Colombier     space_memories[1] = space_system;
1877dd7cddfSDavid du Colombier     space_memories[2] = space_global;
1887dd7cddfSDavid du Colombier     min_collect = max_trace = 2;
1897dd7cddfSDavid du Colombier     min_collect_vm_space = i_vm_global;
1907dd7cddfSDavid du Colombier     if (space_global->stable_memory != (gs_memory_t *)space_global)
1917dd7cddfSDavid du Colombier 	space_memories[++max_trace] =
1927dd7cddfSDavid du Colombier 	    (gs_ref_memory_t *)space_global->stable_memory;
1937dd7cddfSDavid du Colombier     if (space_global != space_local) {
1947dd7cddfSDavid du Colombier 	space_memories[++max_trace] = space_local;
1957dd7cddfSDavid du Colombier 	min_collect = max_trace;
1967dd7cddfSDavid du Colombier 	min_collect_vm_space = i_vm_local;
1977dd7cddfSDavid du Colombier 	if (space_local->stable_memory != (gs_memory_t *)space_local)
1987dd7cddfSDavid du Colombier 	    space_memories[++max_trace] =
1997dd7cddfSDavid du Colombier 		(gs_ref_memory_t *)space_local->stable_memory;
2007dd7cddfSDavid du Colombier     }
2017dd7cddfSDavid du Colombier     if (global)
2027dd7cddfSDavid du Colombier 	min_collect = min_collect_vm_space = 1;
2037dd7cddfSDavid du Colombier 
2047dd7cddfSDavid du Colombier #define for_spaces(i, n)\
2057dd7cddfSDavid du Colombier   for (i = 1; i <= n; ++i)
2067dd7cddfSDavid du Colombier #define for_collected_spaces(i)\
2077dd7cddfSDavid du Colombier   for (i = min_collect; i <= max_trace; ++i)
2087dd7cddfSDavid du Colombier #define for_space_mems(i, mem)\
2097dd7cddfSDavid du Colombier   for (mem = space_memories[i]; mem != 0; mem = &mem->saved->state)
2107dd7cddfSDavid du Colombier #define for_mem_chunks(mem, cp)\
2117dd7cddfSDavid du Colombier   for (cp = (mem)->cfirst; cp != 0; cp = cp->cnext)
2127dd7cddfSDavid du Colombier #define for_space_chunks(i, mem, cp)\
2137dd7cddfSDavid du Colombier   for_space_mems(i, mem) for_mem_chunks(mem, cp)
2147dd7cddfSDavid du Colombier #define for_chunks(n, mem, cp)\
2157dd7cddfSDavid du Colombier   for_spaces(ispace, n) for_space_chunks(ispace, mem, cp)
2167dd7cddfSDavid du Colombier #define for_collected_chunks(mem, cp)\
2177dd7cddfSDavid du Colombier   for_collected_spaces(ispace) for_space_chunks(ispace, mem, cp)
2187dd7cddfSDavid du Colombier #define for_roots(n, mem, rp)\
2197dd7cddfSDavid du Colombier   for_spaces(ispace, n)\
2207dd7cddfSDavid du Colombier     for (mem = space_memories[ispace], rp = mem->roots; rp != 0; rp = rp->next)
2217dd7cddfSDavid du Colombier 
2227dd7cddfSDavid du Colombier     /* Initialize the state. */
2237dd7cddfSDavid du Colombier 
2247dd7cddfSDavid du Colombier     state.procs = &igc_procs;
2257dd7cddfSDavid du Colombier     state.loc.memory = space_global;	/* any one will do */
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier     state.loc.cp = 0;
2287dd7cddfSDavid du Colombier     state.spaces = spaces;
2297dd7cddfSDavid du Colombier     state.min_collect = min_collect_vm_space << r_space_shift;
2307dd7cddfSDavid du Colombier     state.relocating_untraced = false;
231*593dc095SDavid du Colombier     state.heap = state.loc.memory->non_gc_memory;
232*593dc095SDavid du Colombier     state.ntable = state.heap->gs_lib_ctx->gs_name_table;
2337dd7cddfSDavid du Colombier 
2347dd7cddfSDavid du Colombier     /* Register the allocators themselves as roots, */
2357dd7cddfSDavid du Colombier     /* so we mark and relocate the change and save lists properly. */
2367dd7cddfSDavid du Colombier 
2377dd7cddfSDavid du Colombier     for_spaces(ispace, max_trace)
2387dd7cddfSDavid du Colombier 	gs_register_struct_root((gs_memory_t *)space_memories[ispace],
2397dd7cddfSDavid du Colombier 				&space_roots[ispace],
2407dd7cddfSDavid du Colombier 				(void **)&space_memories[ispace],
2417dd7cddfSDavid du Colombier 				"gc_top_level");
2427dd7cddfSDavid du Colombier 
2437dd7cddfSDavid du Colombier     end_phase("register space roots");
2447dd7cddfSDavid du Colombier 
2457dd7cddfSDavid du Colombier #ifdef DEBUG
2467dd7cddfSDavid du Colombier 
2477dd7cddfSDavid du Colombier     /* Pre-validate the state.  This shouldn't be necessary.... */
2487dd7cddfSDavid du Colombier 
2497dd7cddfSDavid du Colombier     gc_validate_spaces(space_memories, max_trace, &state);
2507dd7cddfSDavid du Colombier 
2517dd7cddfSDavid du Colombier     end_phase("pre-validate pointers");
2527dd7cddfSDavid du Colombier 
2537dd7cddfSDavid du Colombier #endif
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier     if (I_BYPASS_GC) {		/* Don't collect at all. */
2567dd7cddfSDavid du Colombier 	goto no_collect;
2577dd7cddfSDavid du Colombier     }
2587dd7cddfSDavid du Colombier 
2597dd7cddfSDavid du Colombier     /* Clear marks in spaces to be collected. */
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier     for_collected_spaces(ispace)
2627dd7cddfSDavid du Colombier 	for_space_chunks(ispace, mem, cp) {
263*593dc095SDavid du Colombier         gc_objects_clear_marks((const gs_memory_t *)mem, cp);
2647dd7cddfSDavid du Colombier 	gc_strings_set_marks(cp, false);
2657dd7cddfSDavid du Colombier     }
2667dd7cddfSDavid du Colombier 
2677dd7cddfSDavid du Colombier     end_phase("clear chunk marks");
2687dd7cddfSDavid du Colombier 
2697dd7cddfSDavid du Colombier     /* Clear the marks of roots.  We must do this explicitly, */
2707dd7cddfSDavid du Colombier     /* since some roots are not in any chunk. */
2717dd7cddfSDavid du Colombier 
2727dd7cddfSDavid du Colombier     for_roots(max_trace, mem, rp) {
2737dd7cddfSDavid du Colombier 	enum_ptr_t eptr;
2747dd7cddfSDavid du Colombier 
2757dd7cddfSDavid du Colombier 	eptr.ptr = *rp->p;
2767dd7cddfSDavid du Colombier 	if_debug_root('6', "[6]unmarking root", rp);
2777dd7cddfSDavid du Colombier 	(*rp->ptype->unmark)(&eptr, &state);
2787dd7cddfSDavid du Colombier     }
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier     end_phase("clear root marks");
2817dd7cddfSDavid du Colombier 
2827dd7cddfSDavid du Colombier     if (global)
2837dd7cddfSDavid du Colombier 	gc_unmark_names(state.ntable);
2847dd7cddfSDavid du Colombier 
2857dd7cddfSDavid du Colombier     /* Initialize the (default) mark stack. */
2867dd7cddfSDavid du Colombier 
2877dd7cddfSDavid du Colombier     gc_init_mark_stack(&ms_default.stack, ms_size_default);
2887dd7cddfSDavid du Colombier     ms_default.stack.prev = 0;
2897dd7cddfSDavid du Colombier     ms_default.stack.on_heap = false;
2907dd7cddfSDavid du Colombier 
2917dd7cddfSDavid du Colombier     /* Add all large-enough free blocks to the mark stack. */
2927dd7cddfSDavid du Colombier     /* Also initialize the rescan pointers. */
2937dd7cddfSDavid du Colombier 
2947dd7cddfSDavid du Colombier     {
2957dd7cddfSDavid du Colombier 	gc_mark_stack *end = mark_stack;
2967dd7cddfSDavid du Colombier 
2977dd7cddfSDavid du Colombier 	for_chunks(max_trace, mem, cp) {
2987dd7cddfSDavid du Colombier 	    uint avail = cp->ctop - cp->cbot;
2997dd7cddfSDavid du Colombier 
3007dd7cddfSDavid du Colombier 	    if (avail >= sizeof(gc_mark_stack) + sizeof(ms_entry) *
3017dd7cddfSDavid du Colombier 		ms_size_min &&
3027dd7cddfSDavid du Colombier 		!cp->inner_count
3037dd7cddfSDavid du Colombier 		) {
3047dd7cddfSDavid du Colombier 		gc_mark_stack *pms = (gc_mark_stack *) cp->cbot;
3057dd7cddfSDavid du Colombier 
3067dd7cddfSDavid du Colombier 		gc_init_mark_stack(pms, (avail - sizeof(gc_mark_stack)) /
3077dd7cddfSDavid du Colombier 				   sizeof(ms_entry));
3087dd7cddfSDavid du Colombier 		end->next = pms;
3097dd7cddfSDavid du Colombier 		pms->prev = end;
3107dd7cddfSDavid du Colombier 		pms->on_heap = false;
3117dd7cddfSDavid du Colombier 		if_debug2('6', "[6]adding free 0x%lx(%u) to mark stack\n",
3127dd7cddfSDavid du Colombier 			  (ulong) pms, pms->count);
3137dd7cddfSDavid du Colombier 	    }
3147dd7cddfSDavid du Colombier 	    cp->rescan_bot = cp->cend;
3157dd7cddfSDavid du Colombier 	    cp->rescan_top = cp->cbase;
3167dd7cddfSDavid du Colombier 	}
3177dd7cddfSDavid du Colombier     }
3187dd7cddfSDavid du Colombier 
3197dd7cddfSDavid du Colombier     /* Mark reachable objects. */
3207dd7cddfSDavid du Colombier 
3217dd7cddfSDavid du Colombier     {
3227dd7cddfSDavid du Colombier 	int more = 0;
3237dd7cddfSDavid du Colombier 
3247dd7cddfSDavid du Colombier 	/* Mark from roots. */
3257dd7cddfSDavid du Colombier 
3267dd7cddfSDavid du Colombier 	for_roots(max_trace, mem, rp) {
3277dd7cddfSDavid du Colombier 	    if_debug_root('6', "[6]marking root", rp);
3287dd7cddfSDavid du Colombier 	    more |= gc_trace(rp, &state, mark_stack);
3297dd7cddfSDavid du Colombier 	}
3307dd7cddfSDavid du Colombier 
3317dd7cddfSDavid du Colombier 	end_phase("mark");
3327dd7cddfSDavid du Colombier 
3337dd7cddfSDavid du Colombier 	/* If this is a local GC, mark from non-local chunks. */
3347dd7cddfSDavid du Colombier 
3357dd7cddfSDavid du Colombier 	if (!global)
3367dd7cddfSDavid du Colombier 	    for_chunks(min_collect - 1, mem, cp)
337*593dc095SDavid du Colombier 		more |= gc_trace_chunk((const gs_memory_t *)mem, cp, &state, mark_stack);
3387dd7cddfSDavid du Colombier 
3397dd7cddfSDavid du Colombier 	/* Handle mark stack overflow. */
3407dd7cddfSDavid du Colombier 
3417dd7cddfSDavid du Colombier 	while (more < 0) {	/* stack overflowed */
3427dd7cddfSDavid du Colombier 	    more = 0;
3437dd7cddfSDavid du Colombier 	    for_chunks(max_trace, mem, cp)
3447dd7cddfSDavid du Colombier 		more |= gc_rescan_chunk(cp, &state, mark_stack);
3457dd7cddfSDavid du Colombier 	}
3467dd7cddfSDavid du Colombier 
3477dd7cddfSDavid du Colombier 	end_phase("mark overflow");
3487dd7cddfSDavid du Colombier     }
3497dd7cddfSDavid du Colombier 
3507dd7cddfSDavid du Colombier     /* Free the mark stack. */
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier     {
3537dd7cddfSDavid du Colombier 	gc_mark_stack *pms = mark_stack;
3547dd7cddfSDavid du Colombier 
3557dd7cddfSDavid du Colombier 	while (pms->next)
3567dd7cddfSDavid du Colombier 	    pms = pms->next;
3577dd7cddfSDavid du Colombier 	while (pms) {
3587dd7cddfSDavid du Colombier 	    gc_mark_stack *prev = pms->prev;
3597dd7cddfSDavid du Colombier 
3607dd7cddfSDavid du Colombier 	    if (pms->on_heap)
3617dd7cddfSDavid du Colombier 		gs_free_object(state.heap, pms, "gc mark stack");
3627dd7cddfSDavid du Colombier 	    else
3637dd7cddfSDavid du Colombier 		gs_alloc_fill(pms, gs_alloc_fill_free,
3647dd7cddfSDavid du Colombier 			      sizeof(*pms) + sizeof(ms_entry) * pms->count);
3657dd7cddfSDavid du Colombier 	    pms = prev;
3667dd7cddfSDavid du Colombier 	}
3677dd7cddfSDavid du Colombier     }
3687dd7cddfSDavid du Colombier 
3697dd7cddfSDavid du Colombier     end_phase("free mark stack");
3707dd7cddfSDavid du Colombier 
3717dd7cddfSDavid du Colombier     if (global) {
3727dd7cddfSDavid du Colombier 	gc_trace_finish(&state);
3737dd7cddfSDavid du Colombier 	names_trace_finish(state.ntable, &state);
3747dd7cddfSDavid du Colombier 
3757dd7cddfSDavid du Colombier 	end_phase("finish trace");
3767dd7cddfSDavid du Colombier     }
3777dd7cddfSDavid du Colombier     /* Clear marks and relocation in spaces that are only being traced. */
3787dd7cddfSDavid du Colombier     /* We have to clear the marks first, because we want the */
3797dd7cddfSDavid du Colombier     /* relocation to wind up as o_untraced, not o_unmarked. */
3807dd7cddfSDavid du Colombier 
3817dd7cddfSDavid du Colombier     for_chunks(min_collect - 1, mem, cp)
382*593dc095SDavid du Colombier         gc_objects_clear_marks((const gs_memory_t *)mem, cp);
3837dd7cddfSDavid du Colombier 
3847dd7cddfSDavid du Colombier     end_phase("post-clear marks");
3857dd7cddfSDavid du Colombier 
3867dd7cddfSDavid du Colombier     for_chunks(min_collect - 1, mem, cp)
3877dd7cddfSDavid du Colombier 	gc_clear_reloc(cp);
3887dd7cddfSDavid du Colombier 
3897dd7cddfSDavid du Colombier     end_phase("clear reloc");
3907dd7cddfSDavid du Colombier 
3917dd7cddfSDavid du Colombier     /* Set the relocation of roots outside any chunk to o_untraced, */
3927dd7cddfSDavid du Colombier     /* so we won't try to relocate pointers to them. */
3937dd7cddfSDavid du Colombier     /* (Currently, there aren't any.) */
3947dd7cddfSDavid du Colombier 
3957dd7cddfSDavid du Colombier     /* Disable freeing in the allocators of the spaces we are */
3967dd7cddfSDavid du Colombier     /* collecting, so finalization procedures won't cause problems. */
3977dd7cddfSDavid du Colombier     {
3987dd7cddfSDavid du Colombier 	int i;
3997dd7cddfSDavid du Colombier 
4007dd7cddfSDavid du Colombier 	for_collected_spaces(i)
4017dd7cddfSDavid du Colombier 	    gs_enable_free((gs_memory_t *)space_memories[i], false);
4027dd7cddfSDavid du Colombier     }
4037dd7cddfSDavid du Colombier 
4047dd7cddfSDavid du Colombier     /* Compute relocation based on marks, in the spaces */
4057dd7cddfSDavid du Colombier     /* we are going to compact.  Also finalize freed objects. */
4067dd7cddfSDavid du Colombier 
4077dd7cddfSDavid du Colombier     for_collected_chunks(mem, cp) {
4087dd7cddfSDavid du Colombier 	gc_objects_set_reloc(cp);
4097dd7cddfSDavid du Colombier 	gc_strings_set_reloc(cp);
4107dd7cddfSDavid du Colombier     }
4117dd7cddfSDavid du Colombier 
4127dd7cddfSDavid du Colombier     /* Re-enable freeing. */
4137dd7cddfSDavid du Colombier     {
4147dd7cddfSDavid du Colombier 	int i;
4157dd7cddfSDavid du Colombier 
4167dd7cddfSDavid du Colombier 	for_collected_spaces(i)
4177dd7cddfSDavid du Colombier 	    gs_enable_free((gs_memory_t *)space_memories[i], true);
4187dd7cddfSDavid du Colombier     }
4197dd7cddfSDavid du Colombier 
4207dd7cddfSDavid du Colombier     end_phase("set reloc");
4217dd7cddfSDavid du Colombier 
4227dd7cddfSDavid du Colombier     /* Relocate pointers. */
4237dd7cddfSDavid du Colombier 
4247dd7cddfSDavid du Colombier     state.relocating_untraced = true;
4257dd7cddfSDavid du Colombier     for_chunks(min_collect - 1, mem, cp)
4267dd7cddfSDavid du Colombier 	gc_do_reloc(cp, mem, &state);
4277dd7cddfSDavid du Colombier     state.relocating_untraced = false;
4287dd7cddfSDavid du Colombier     for_collected_chunks(mem, cp)
4297dd7cddfSDavid du Colombier 	gc_do_reloc(cp, mem, &state);
4307dd7cddfSDavid du Colombier 
4317dd7cddfSDavid du Colombier     end_phase("relocate chunks");
4327dd7cddfSDavid du Colombier 
4337dd7cddfSDavid du Colombier     for_roots(max_trace, mem, rp) {
4347dd7cddfSDavid du Colombier 	if_debug3('6', "[6]relocating root 0x%lx: 0x%lx -> 0x%lx\n",
4357dd7cddfSDavid du Colombier 		  (ulong) rp, (ulong) rp->p, (ulong) * rp->p);
4367dd7cddfSDavid du Colombier 	if (rp->ptype == ptr_ref_type) {
4377dd7cddfSDavid du Colombier 	    ref *pref = (ref *) * rp->p;
4387dd7cddfSDavid du Colombier 
4397dd7cddfSDavid du Colombier 	    igc_reloc_refs((ref_packed *) pref,
4407dd7cddfSDavid du Colombier 			   (ref_packed *) (pref + 1),
4417dd7cddfSDavid du Colombier 			   &state);
4427dd7cddfSDavid du Colombier 	} else
4437dd7cddfSDavid du Colombier 	    *rp->p = (*rp->ptype->reloc) (*rp->p, &state);
4447dd7cddfSDavid du Colombier 	if_debug3('6', "[6]relocated root 0x%lx: 0x%lx -> 0x%lx\n",
4457dd7cddfSDavid du Colombier 		  (ulong) rp, (ulong) rp->p, (ulong) * rp->p);
4467dd7cddfSDavid du Colombier     }
4477dd7cddfSDavid du Colombier 
4487dd7cddfSDavid du Colombier     end_phase("relocate roots");
4497dd7cddfSDavid du Colombier 
4507dd7cddfSDavid du Colombier     /* Compact data.  We only do this for spaces we are collecting. */
4517dd7cddfSDavid du Colombier 
4527dd7cddfSDavid du Colombier     for_collected_spaces(ispace) {
4537dd7cddfSDavid du Colombier 	for_space_mems(ispace, mem) {
4547dd7cddfSDavid du Colombier 	    for_mem_chunks(mem, cp) {
4557dd7cddfSDavid du Colombier 		if_debug_chunk('6', "[6]compacting chunk", cp);
4567dd7cddfSDavid du Colombier 		gc_objects_compact(cp, &state);
4577dd7cddfSDavid du Colombier 		gc_strings_compact(cp);
4587dd7cddfSDavid du Colombier 		if_debug_chunk('6', "[6]after compaction:", cp);
4597dd7cddfSDavid du Colombier 		if (mem->pcc == cp)
4607dd7cddfSDavid du Colombier 		    mem->cc = *cp;
4617dd7cddfSDavid du Colombier 	    }
4627dd7cddfSDavid du Colombier 	    mem->saved = mem->reloc_saved;
4637dd7cddfSDavid du Colombier 	    ialloc_reset_free(mem);
4647dd7cddfSDavid du Colombier 	}
4657dd7cddfSDavid du Colombier     }
4667dd7cddfSDavid du Colombier 
4677dd7cddfSDavid du Colombier     end_phase("compact");
4687dd7cddfSDavid du Colombier 
4697dd7cddfSDavid du Colombier     /* Free empty chunks. */
4707dd7cddfSDavid du Colombier 
4717dd7cddfSDavid du Colombier     for_collected_spaces(ispace) {
4727dd7cddfSDavid du Colombier 	for_space_mems(ispace, mem) {
4737dd7cddfSDavid du Colombier 	    gc_free_empty_chunks(mem);
4747dd7cddfSDavid du Colombier         }
4757dd7cddfSDavid du Colombier     }
4767dd7cddfSDavid du Colombier 
4777dd7cddfSDavid du Colombier     end_phase("free empty chunks");
4787dd7cddfSDavid du Colombier 
4797dd7cddfSDavid du Colombier     /*
4807dd7cddfSDavid du Colombier      * Update previous_status to reflect any freed chunks,
4817dd7cddfSDavid du Colombier      * and set inherited to the negative of allocated,
4827dd7cddfSDavid du Colombier      * so it has no effect.  We must update previous_status by
4837dd7cddfSDavid du Colombier      * working back-to-front along the save chain, using pointer reversal.
4847dd7cddfSDavid du Colombier      * (We could update inherited in any order, since it only uses
4857dd7cddfSDavid du Colombier      * information local to the individual save level.)
4867dd7cddfSDavid du Colombier      */
4877dd7cddfSDavid du Colombier 
4887dd7cddfSDavid du Colombier     for_collected_spaces(ispace) {	/* Reverse the pointers. */
4897dd7cddfSDavid du Colombier 	alloc_save_t *curr;
4907dd7cddfSDavid du Colombier 	alloc_save_t *prev = 0;
4917dd7cddfSDavid du Colombier 	alloc_save_t *next;
4927dd7cddfSDavid du Colombier 	gs_memory_status_t total;
4937dd7cddfSDavid du Colombier 
4947dd7cddfSDavid du Colombier 	for (curr = space_memories[ispace]->saved; curr != 0;
4957dd7cddfSDavid du Colombier 	     prev = curr, curr = next
4967dd7cddfSDavid du Colombier 	    ) {
4977dd7cddfSDavid du Colombier 	    next = curr->state.saved;
4987dd7cddfSDavid du Colombier 	    curr->state.saved = prev;
4997dd7cddfSDavid du Colombier 	}
5007dd7cddfSDavid du Colombier 	/* Now work the other way, accumulating the values. */
5017dd7cddfSDavid du Colombier 	total.allocated = 0, total.used = 0;
5027dd7cddfSDavid du Colombier 	for (curr = prev, prev = 0; curr != 0;
5037dd7cddfSDavid du Colombier 	     prev = curr, curr = next
5047dd7cddfSDavid du Colombier 	    ) {
5057dd7cddfSDavid du Colombier 	    mem = &curr->state;
5067dd7cddfSDavid du Colombier 	    next = mem->saved;
5077dd7cddfSDavid du Colombier 	    mem->saved = prev;
5087dd7cddfSDavid du Colombier 	    mem->previous_status = total;
5097dd7cddfSDavid du Colombier 	    if_debug3('6',
5107dd7cddfSDavid du Colombier 		      "[6]0x%lx previous allocated=%lu, used=%lu\n",
5117dd7cddfSDavid du Colombier 		      (ulong) mem, total.allocated, total.used);
5127dd7cddfSDavid du Colombier 	    gs_memory_status((gs_memory_t *) mem, &total);
5137dd7cddfSDavid du Colombier 	    mem->gc_allocated = mem->allocated + total.allocated;
514*593dc095SDavid du Colombier 	    mem->inherited = -(int)mem->allocated;
5157dd7cddfSDavid du Colombier 	}
5167dd7cddfSDavid du Colombier 	mem = space_memories[ispace];
5177dd7cddfSDavid du Colombier 	mem->previous_status = total;
5187dd7cddfSDavid du Colombier 	mem->gc_allocated = mem->allocated + total.allocated;
5197dd7cddfSDavid du Colombier 	if_debug3('6', "[6]0x%lx previous allocated=%lu, used=%lu\n",
5207dd7cddfSDavid du Colombier 		  (ulong) mem, total.allocated, total.used);
5217dd7cddfSDavid du Colombier     }
5227dd7cddfSDavid du Colombier 
5237dd7cddfSDavid du Colombier     end_phase("update stats");
5247dd7cddfSDavid du Colombier 
5257dd7cddfSDavid du Colombier   no_collect:
5267dd7cddfSDavid du Colombier 
5277dd7cddfSDavid du Colombier     /* Unregister the allocator roots. */
5287dd7cddfSDavid du Colombier 
5297dd7cddfSDavid du Colombier     for_spaces(ispace, max_trace)
5307dd7cddfSDavid du Colombier 	gs_unregister_root((gs_memory_t *)space_memories[ispace],
5317dd7cddfSDavid du Colombier 			   &space_roots[ispace], "gc_top_level");
5327dd7cddfSDavid du Colombier 
5337dd7cddfSDavid du Colombier     end_phase("unregister space roots");
5347dd7cddfSDavid du Colombier 
5357dd7cddfSDavid du Colombier #ifdef DEBUG
5367dd7cddfSDavid du Colombier 
5377dd7cddfSDavid du Colombier     /* Validate the state.  This shouldn't be necessary.... */
5387dd7cddfSDavid du Colombier 
5397dd7cddfSDavid du Colombier     gc_validate_spaces(space_memories, max_trace, &state);
5407dd7cddfSDavid du Colombier 
5417dd7cddfSDavid du Colombier     end_phase("validate pointers");
5427dd7cddfSDavid du Colombier 
5437dd7cddfSDavid du Colombier #endif
5447dd7cddfSDavid du Colombier }
5457dd7cddfSDavid du Colombier 
5467dd7cddfSDavid du Colombier /* ------ Debugging utilities ------ */
5477dd7cddfSDavid du Colombier 
5487dd7cddfSDavid du Colombier /* Validate a pointer to an object header. */
5497dd7cddfSDavid du Colombier #ifdef DEBUG
5507dd7cddfSDavid du Colombier #  define debug_check_object(pre, cp, gcst)\
5517dd7cddfSDavid du Colombier      ialloc_validate_object((pre) + 1, cp, gcst)
5527dd7cddfSDavid du Colombier #else
5537dd7cddfSDavid du Colombier #  define debug_check_object(pre, cp, gcst) DO_NOTHING
5547dd7cddfSDavid du Colombier #endif
5557dd7cddfSDavid du Colombier 
5567dd7cddfSDavid du Colombier /* ------ Unmarking phase ------ */
5577dd7cddfSDavid du Colombier 
5587dd7cddfSDavid du Colombier /* Unmark a single struct. */
5597dd7cddfSDavid du Colombier private void
ptr_struct_unmark(enum_ptr_t * pep,gc_state_t * ignored)5607dd7cddfSDavid du Colombier ptr_struct_unmark(enum_ptr_t *pep, gc_state_t * ignored)
5617dd7cddfSDavid du Colombier {
5627dd7cddfSDavid du Colombier     void *const vptr = (void *)pep->ptr; /* break const */
5637dd7cddfSDavid du Colombier 
5647dd7cddfSDavid du Colombier     if (vptr != 0)
5657dd7cddfSDavid du Colombier 	o_set_unmarked(((obj_header_t *) vptr - 1));
5667dd7cddfSDavid du Colombier }
5677dd7cddfSDavid du Colombier 
5687dd7cddfSDavid du Colombier /* Unmark a single string. */
5697dd7cddfSDavid du Colombier private void
ptr_string_unmark(enum_ptr_t * pep,gc_state_t * gcst)5707dd7cddfSDavid du Colombier ptr_string_unmark(enum_ptr_t *pep, gc_state_t * gcst)
5717dd7cddfSDavid du Colombier {
5727dd7cddfSDavid du Colombier     discard(gc_string_mark(pep->ptr, pep->size, false, gcst));
5737dd7cddfSDavid du Colombier }
5747dd7cddfSDavid du Colombier 
5757dd7cddfSDavid du Colombier /* Unmark the objects in a chunk. */
5767dd7cddfSDavid du Colombier private void
gc_objects_clear_marks(const gs_memory_t * mem,chunk_t * cp)577*593dc095SDavid du Colombier gc_objects_clear_marks(const gs_memory_t *mem, chunk_t * cp)
5787dd7cddfSDavid du Colombier {
5797dd7cddfSDavid du Colombier     if_debug_chunk('6', "[6]unmarking chunk", cp);
5807dd7cddfSDavid du Colombier     SCAN_CHUNK_OBJECTS(cp)
5817dd7cddfSDavid du Colombier 	DO_ALL
5827dd7cddfSDavid du Colombier 	struct_proc_clear_marks((*proc)) =
5837dd7cddfSDavid du Colombier 	pre->o_type->clear_marks;
5847dd7cddfSDavid du Colombier #ifdef DEBUG
5857dd7cddfSDavid du Colombier     if (pre->o_type != &st_free)
5867dd7cddfSDavid du Colombier 	debug_check_object(pre, cp, NULL);
5877dd7cddfSDavid du Colombier #endif
5887dd7cddfSDavid du Colombier     if_debug3('7', " [7](un)marking %s(%lu) 0x%lx\n",
5897dd7cddfSDavid du Colombier 	      struct_type_name_string(pre->o_type),
5907dd7cddfSDavid du Colombier 	      (ulong) size, (ulong) pre);
5917dd7cddfSDavid du Colombier     o_set_unmarked(pre);
5927dd7cddfSDavid du Colombier     if (proc != 0)
593*593dc095SDavid du Colombier         (*proc) (mem, pre + 1, size, pre->o_type);
5947dd7cddfSDavid du Colombier     END_OBJECTS_SCAN
5957dd7cddfSDavid du Colombier }
5967dd7cddfSDavid du Colombier 
5977dd7cddfSDavid du Colombier /* Mark 0- and 1-character names, and those referenced from the */
5987dd7cddfSDavid du Colombier /* op_array_nx_table, and unmark all the rest. */
5997dd7cddfSDavid du Colombier private void
gc_unmark_names(name_table * nt)6007dd7cddfSDavid du Colombier gc_unmark_names(name_table * nt)
6017dd7cddfSDavid du Colombier {
6027dd7cddfSDavid du Colombier     uint i;
6037dd7cddfSDavid du Colombier 
6047dd7cddfSDavid du Colombier     names_unmark_all(nt);
6057dd7cddfSDavid du Colombier     for (i = 0; i < op_array_table_global.count; i++) {
6067dd7cddfSDavid du Colombier 	name_index_t nidx = op_array_table_global.nx_table[i];
6077dd7cddfSDavid du Colombier 
6087dd7cddfSDavid du Colombier 	names_mark_index(nt, nidx);
6097dd7cddfSDavid du Colombier     }
6107dd7cddfSDavid du Colombier     for (i = 0; i < op_array_table_local.count; i++) {
6117dd7cddfSDavid du Colombier 	name_index_t nidx = op_array_table_local.nx_table[i];
6127dd7cddfSDavid du Colombier 
6137dd7cddfSDavid du Colombier 	names_mark_index(nt, nidx);
6147dd7cddfSDavid du Colombier     }
6157dd7cddfSDavid du Colombier }
6167dd7cddfSDavid du Colombier 
6177dd7cddfSDavid du Colombier /* ------ Marking phase ------ */
6187dd7cddfSDavid du Colombier 
6197dd7cddfSDavid du Colombier /* Initialize (a segment of) the mark stack. */
6207dd7cddfSDavid du Colombier private void
gc_init_mark_stack(gc_mark_stack * pms,uint count)6217dd7cddfSDavid du Colombier gc_init_mark_stack(gc_mark_stack * pms, uint count)
6227dd7cddfSDavid du Colombier {
6237dd7cddfSDavid du Colombier     pms->next = 0;
6247dd7cddfSDavid du Colombier     pms->count = count;
6257dd7cddfSDavid du Colombier     pms->entries[0].ptr = 0;
6267dd7cddfSDavid du Colombier     pms->entries[0].index = 0;
6277dd7cddfSDavid du Colombier     pms->entries[0].is_refs = false;
6287dd7cddfSDavid du Colombier }
6297dd7cddfSDavid du Colombier 
6307dd7cddfSDavid du Colombier /* Mark starting from all marked objects in the interval of a chunk */
6317dd7cddfSDavid du Colombier /* needing rescanning. */
6327dd7cddfSDavid du Colombier private int
gc_rescan_chunk(chunk_t * cp,gc_state_t * pstate,gc_mark_stack * pmstack)6337dd7cddfSDavid du Colombier gc_rescan_chunk(chunk_t * cp, gc_state_t * pstate, gc_mark_stack * pmstack)
6347dd7cddfSDavid du Colombier {
6357dd7cddfSDavid du Colombier     byte *sbot = cp->rescan_bot;
6367dd7cddfSDavid du Colombier     byte *stop = cp->rescan_top;
6377dd7cddfSDavid du Colombier     gs_gc_root_t root;
6387dd7cddfSDavid du Colombier     void *comp;
6397dd7cddfSDavid du Colombier     int more = 0;
640*593dc095SDavid du Colombier     const gs_memory_t *mem = gcst_get_memory_ptr( pstate );
6417dd7cddfSDavid du Colombier 
6427dd7cddfSDavid du Colombier     if (sbot > stop)
6437dd7cddfSDavid du Colombier 	return 0;
6447dd7cddfSDavid du Colombier     root.p = &comp;
6457dd7cddfSDavid du Colombier     if_debug_chunk('6', "[6]rescanning chunk", cp);
6467dd7cddfSDavid du Colombier     cp->rescan_bot = cp->cend;
6477dd7cddfSDavid du Colombier     cp->rescan_top = cp->cbase;
6487dd7cddfSDavid du Colombier     SCAN_CHUNK_OBJECTS(cp)
6497dd7cddfSDavid du Colombier 	DO_ALL
6507dd7cddfSDavid du Colombier 	if ((byte *) (pre + 1) + size < sbot);
6517dd7cddfSDavid du Colombier     else if ((byte *) (pre + 1) > stop)
6527dd7cddfSDavid du Colombier 	return more;		/* 'break' won't work here */
6537dd7cddfSDavid du Colombier     else {
6547dd7cddfSDavid du Colombier 	if_debug2('7', " [7]scanning/marking 0x%lx(%lu)\n",
6557dd7cddfSDavid du Colombier 		  (ulong) pre, (ulong) size);
6567dd7cddfSDavid du Colombier 	if (pre->o_type == &st_refs) {
6577dd7cddfSDavid du Colombier 	    ref_packed *rp = (ref_packed *) (pre + 1);
6587dd7cddfSDavid du Colombier 	    char *end = (char *)rp + size;
6597dd7cddfSDavid du Colombier 
6607dd7cddfSDavid du Colombier 	    root.ptype = ptr_ref_type;
6617dd7cddfSDavid du Colombier 	    while ((char *)rp < end) {
6627dd7cddfSDavid du Colombier 		comp = rp;
6637dd7cddfSDavid du Colombier 		if (r_is_packed(rp)) {
6647dd7cddfSDavid du Colombier 		    if (r_has_pmark(rp)) {
6657dd7cddfSDavid du Colombier 			r_clear_pmark(rp);
6667dd7cddfSDavid du Colombier 			more |= gc_trace(&root, pstate,
6677dd7cddfSDavid du Colombier 					 pmstack);
6687dd7cddfSDavid du Colombier 		    }
6697dd7cddfSDavid du Colombier 		    rp++;
6707dd7cddfSDavid du Colombier 		} else {
6717dd7cddfSDavid du Colombier 		    ref *const pref = (ref *)rp;
6727dd7cddfSDavid du Colombier 
6737dd7cddfSDavid du Colombier 		    if (r_has_attr(pref, l_mark)) {
6747dd7cddfSDavid du Colombier 			r_clear_attrs(pref, l_mark);
6757dd7cddfSDavid du Colombier 			more |= gc_trace(&root, pstate, pmstack);
6767dd7cddfSDavid du Colombier 		    }
6777dd7cddfSDavid du Colombier 		    rp += packed_per_ref;
6787dd7cddfSDavid du Colombier 		}
6797dd7cddfSDavid du Colombier 	    }
6807dd7cddfSDavid du Colombier 	} else if (!o_is_unmarked(pre)) {
6817dd7cddfSDavid du Colombier 	    struct_proc_clear_marks((*proc)) =
6827dd7cddfSDavid du Colombier 		pre->o_type->clear_marks;
6837dd7cddfSDavid du Colombier 	    root.ptype = ptr_struct_type;
6847dd7cddfSDavid du Colombier 	    comp = pre + 1;
6857dd7cddfSDavid du Colombier 	    if (!o_is_untraced(pre))
6867dd7cddfSDavid du Colombier 		o_set_unmarked(pre);
6877dd7cddfSDavid du Colombier 	    if (proc != 0)
688*593dc095SDavid du Colombier 	        (*proc) (mem, comp, size, pre->o_type);
6897dd7cddfSDavid du Colombier 	    more |= gc_trace(&root, pstate, pmstack);
6907dd7cddfSDavid du Colombier 	}
6917dd7cddfSDavid du Colombier     }
6927dd7cddfSDavid du Colombier     END_OBJECTS_SCAN
6937dd7cddfSDavid du Colombier 	return more;
6947dd7cddfSDavid du Colombier }
6957dd7cddfSDavid du Colombier 
6967dd7cddfSDavid du Colombier /* Mark starting from all the objects in a chunk. */
6977dd7cddfSDavid du Colombier /* We assume that pstate->min_collect > avm_system, */
6987dd7cddfSDavid du Colombier /* so we don't have to trace names. */
6997dd7cddfSDavid du Colombier private int
gc_trace_chunk(const gs_memory_t * mem,chunk_t * cp,gc_state_t * pstate,gc_mark_stack * pmstack)700*593dc095SDavid du Colombier gc_trace_chunk(const gs_memory_t *mem, chunk_t * cp, gc_state_t * pstate, gc_mark_stack * pmstack)
7017dd7cddfSDavid du Colombier {
7027dd7cddfSDavid du Colombier     gs_gc_root_t root;
7037dd7cddfSDavid du Colombier     void *comp;
7047dd7cddfSDavid du Colombier     int more = 0;
7057dd7cddfSDavid du Colombier     int min_trace = pstate->min_collect;
7067dd7cddfSDavid du Colombier 
7077dd7cddfSDavid du Colombier     root.p = &comp;
7087dd7cddfSDavid du Colombier     if_debug_chunk('6', "[6]marking from chunk", cp);
7097dd7cddfSDavid du Colombier     SCAN_CHUNK_OBJECTS(cp)
7107dd7cddfSDavid du Colombier 	DO_ALL
7117dd7cddfSDavid du Colombier     {
7127dd7cddfSDavid du Colombier 	if_debug2('7', " [7]scanning/marking 0x%lx(%lu)\n",
7137dd7cddfSDavid du Colombier 		  (ulong) pre, (ulong) size);
7147dd7cddfSDavid du Colombier 	if (pre->o_type == &st_refs) {
7157dd7cddfSDavid du Colombier 	    ref_packed *rp = (ref_packed *) (pre + 1);
7167dd7cddfSDavid du Colombier 	    char *end = (char *)rp + size;
7177dd7cddfSDavid du Colombier 
7187dd7cddfSDavid du Colombier 	    root.ptype = ptr_ref_type;
7197dd7cddfSDavid du Colombier 	    while ((char *)rp < end) {
7207dd7cddfSDavid du Colombier 		comp = rp;
7217dd7cddfSDavid du Colombier 		if (r_is_packed(rp)) {	/* No packed refs need tracing. */
7227dd7cddfSDavid du Colombier 		    rp++;
7237dd7cddfSDavid du Colombier 		} else {
7247dd7cddfSDavid du Colombier 		    ref *const pref = (ref *)rp;
7257dd7cddfSDavid du Colombier 
7267dd7cddfSDavid du Colombier 		    if (r_space(pref) >= min_trace) {
7277dd7cddfSDavid du Colombier 			r_clear_attrs(pref, l_mark);
7287dd7cddfSDavid du Colombier 			more |= gc_trace(&root, pstate, pmstack);
7297dd7cddfSDavid du Colombier 		    }
7307dd7cddfSDavid du Colombier 		    rp += packed_per_ref;
7317dd7cddfSDavid du Colombier 		}
7327dd7cddfSDavid du Colombier 	    }
7337dd7cddfSDavid du Colombier 	} else if (!o_is_unmarked(pre)) {
7347dd7cddfSDavid du Colombier 	    if (!o_is_untraced(pre))
7357dd7cddfSDavid du Colombier 		o_set_unmarked(pre);
7367dd7cddfSDavid du Colombier 	    if (pre->o_type != &st_free) {
7377dd7cddfSDavid du Colombier 		struct_proc_clear_marks((*proc)) =
7387dd7cddfSDavid du Colombier 		    pre->o_type->clear_marks;
7397dd7cddfSDavid du Colombier 
7407dd7cddfSDavid du Colombier 		root.ptype = ptr_struct_type;
7417dd7cddfSDavid du Colombier 		comp = pre + 1;
7427dd7cddfSDavid du Colombier 		if (proc != 0)
743*593dc095SDavid du Colombier 		    (*proc) (mem, comp, size, pre->o_type);
7447dd7cddfSDavid du Colombier 		more |= gc_trace(&root, pstate, pmstack);
7457dd7cddfSDavid du Colombier 	    }
7467dd7cddfSDavid du Colombier 	}
7477dd7cddfSDavid du Colombier     }
7487dd7cddfSDavid du Colombier     END_OBJECTS_SCAN
7497dd7cddfSDavid du Colombier 	return more;
7507dd7cddfSDavid du Colombier }
7517dd7cddfSDavid du Colombier 
7527dd7cddfSDavid du Colombier /* Recursively mark from a (root) pointer. */
7537dd7cddfSDavid du Colombier /* Return -1 if we overflowed the mark stack, */
7547dd7cddfSDavid du Colombier /* 0 if we completed successfully without marking any new objects, */
7557dd7cddfSDavid du Colombier /* 1 if we completed and marked some new objects. */
756*593dc095SDavid du Colombier private int gc_extend_stack(gc_mark_stack *, gc_state_t *);
7577dd7cddfSDavid du Colombier private int
gc_trace(gs_gc_root_t * rp,gc_state_t * pstate,gc_mark_stack * pmstack)7587dd7cddfSDavid du Colombier gc_trace(gs_gc_root_t * rp, gc_state_t * pstate, gc_mark_stack * pmstack)
7597dd7cddfSDavid du Colombier {
7607dd7cddfSDavid du Colombier     int min_trace = pstate->min_collect;
7617dd7cddfSDavid du Colombier     gc_mark_stack *pms = pmstack;
7627dd7cddfSDavid du Colombier     ms_entry *sp = pms->entries + 1;
7637dd7cddfSDavid du Colombier 
7647dd7cddfSDavid du Colombier     /* We stop the mark stack 1 entry early, because we store into */
7657dd7cddfSDavid du Colombier     /* the entry beyond the top. */
7667dd7cddfSDavid du Colombier     ms_entry *stop = sp + pms->count - 2;
7677dd7cddfSDavid du Colombier     int new = 0;
7687dd7cddfSDavid du Colombier     enum_ptr_t nep;
7697dd7cddfSDavid du Colombier     void *nptr;
7707dd7cddfSDavid du Colombier     name_table *nt = pstate->ntable;
7717dd7cddfSDavid du Colombier 
7727dd7cddfSDavid du Colombier #define mark_name(nidx)\
7737dd7cddfSDavid du Colombier   BEGIN\
7747dd7cddfSDavid du Colombier     if (names_mark_index(nt, nidx)) {\
7757dd7cddfSDavid du Colombier 	new |= 1;\
7767dd7cddfSDavid du Colombier 	if_debug2('8', "  [8]marked name 0x%lx(%u)\n",\
7777dd7cddfSDavid du Colombier 		  (ulong)names_index_ptr(nt, nidx), nidx);\
7787dd7cddfSDavid du Colombier     }\
7797dd7cddfSDavid du Colombier   END
7807dd7cddfSDavid du Colombier 
7817dd7cddfSDavid du Colombier     nptr = *rp->p;
7827dd7cddfSDavid du Colombier     if (nptr == 0)
7837dd7cddfSDavid du Colombier 	return 0;
7847dd7cddfSDavid du Colombier 
7857dd7cddfSDavid du Colombier     /* Initialize the stack */
7867dd7cddfSDavid du Colombier     sp->ptr = nptr;
7877dd7cddfSDavid du Colombier     if (rp->ptype == ptr_ref_type)
7887dd7cddfSDavid du Colombier 	sp->index = 1, sp->is_refs = true;
7897dd7cddfSDavid du Colombier     else {
7907dd7cddfSDavid du Colombier 	sp->index = 0, sp->is_refs = false;
7917dd7cddfSDavid du Colombier 	nep.ptr = nptr;
7927dd7cddfSDavid du Colombier 	if ((*rp->ptype->mark) (&nep, pstate))
7937dd7cddfSDavid du Colombier 	    new |= 1;
7947dd7cddfSDavid du Colombier     }
7957dd7cddfSDavid du Colombier     for (;;) {
7967dd7cddfSDavid du Colombier 	gs_ptr_type_t ptp;
7977dd7cddfSDavid du Colombier 
7987dd7cddfSDavid du Colombier 	/*
7997dd7cddfSDavid du Colombier 	 * The following should really be an if..else, but that
8007dd7cddfSDavid du Colombier 	 * would force unnecessary is_refs tests.
8017dd7cddfSDavid du Colombier 	 */
8027dd7cddfSDavid du Colombier 	if (sp->is_refs)
8037dd7cddfSDavid du Colombier 	    goto do_refs;
8047dd7cddfSDavid du Colombier 
8057dd7cddfSDavid du Colombier 	/* ---------------- Structure ---------------- */
8067dd7cddfSDavid du Colombier 
8077dd7cddfSDavid du Colombier       do_struct:
8087dd7cddfSDavid du Colombier 	{
8097dd7cddfSDavid du Colombier 	    obj_header_t *ptr = sp->ptr;
8107dd7cddfSDavid du Colombier 
8117dd7cddfSDavid du Colombier 	    struct_proc_enum_ptrs((*mproc));
8127dd7cddfSDavid du Colombier 
8137dd7cddfSDavid du Colombier 	    if (ptr == 0) {	/* We've reached the bottom of a stack segment. */
8147dd7cddfSDavid du Colombier 		pms = pms->prev;
8157dd7cddfSDavid du Colombier 		if (pms == 0)
8167dd7cddfSDavid du Colombier 		    break;	/* all done */
8177dd7cddfSDavid du Colombier 		stop = pms->entries + pms->count - 1;
8187dd7cddfSDavid du Colombier 		sp = stop;
8197dd7cddfSDavid du Colombier 		continue;
8207dd7cddfSDavid du Colombier 	    }
8217dd7cddfSDavid du Colombier 	    debug_check_object(ptr - 1, NULL, NULL);
8227dd7cddfSDavid du Colombier 	  ts:if_debug4('7', " [7]%smarking %s 0x%lx[%u]",
8237dd7cddfSDavid du Colombier 		      depth_dots(sp, pms),
8247dd7cddfSDavid du Colombier 		      struct_type_name_string(ptr[-1].o_type),
8257dd7cddfSDavid du Colombier 		      (ulong) ptr, sp->index);
8267dd7cddfSDavid du Colombier 	    mproc = ptr[-1].o_type->enum_ptrs;
8277dd7cddfSDavid du Colombier 	    if (mproc == gs_no_struct_enum_ptrs ||
8287dd7cddfSDavid du Colombier 		(ptp = (*mproc)
829*593dc095SDavid du Colombier 		 (gcst_get_memory_ptr(pstate), ptr, pre_obj_contents_size(ptr - 1),
8307dd7cddfSDavid du Colombier 		  sp->index, &nep, ptr[-1].o_type, pstate)) == 0
8317dd7cddfSDavid du Colombier 		) {
8327dd7cddfSDavid du Colombier 		if_debug0('7', " - done\n");
8337dd7cddfSDavid du Colombier 		sp--;
8347dd7cddfSDavid du Colombier 		continue;
8357dd7cddfSDavid du Colombier 	    }
8367dd7cddfSDavid du Colombier 	    /* The cast in the following statement is the one */
8377dd7cddfSDavid du Colombier 	    /* place we need to break 'const' to make the */
8387dd7cddfSDavid du Colombier 	    /* template for pointer enumeration work. */
8397dd7cddfSDavid du Colombier 	    nptr = (void *)nep.ptr;
8407dd7cddfSDavid du Colombier 	    sp->index++;
8417dd7cddfSDavid du Colombier 	    if_debug1('7', " = 0x%lx\n", (ulong) nptr);
8427dd7cddfSDavid du Colombier 	    /* Descend into nep.ptr, whose pointer type is ptp. */
8437dd7cddfSDavid du Colombier 	    if (ptp == ptr_struct_type) {
8447dd7cddfSDavid du Colombier 		sp[1].index = 0;
8457dd7cddfSDavid du Colombier 		sp[1].is_refs = false;
8467dd7cddfSDavid du Colombier 		if (sp == stop)
8477dd7cddfSDavid du Colombier 		    goto push;
8487dd7cddfSDavid du Colombier 		if (!ptr_struct_mark(&nep, pstate))
8497dd7cddfSDavid du Colombier 		    goto ts;
8507dd7cddfSDavid du Colombier 		new |= 1;
8517dd7cddfSDavid du Colombier 		(++sp)->ptr = nptr;
8527dd7cddfSDavid du Colombier 		goto do_struct;
8537dd7cddfSDavid du Colombier 	    } else if (ptp == ptr_ref_type) {
8547dd7cddfSDavid du Colombier 		sp[1].index = 1;
8557dd7cddfSDavid du Colombier 		sp[1].is_refs = true;
8567dd7cddfSDavid du Colombier 		if (sp == stop)
8577dd7cddfSDavid du Colombier 		    goto push;
8587dd7cddfSDavid du Colombier 		new |= 1;
8597dd7cddfSDavid du Colombier 		(++sp)->ptr = nptr;
8607dd7cddfSDavid du Colombier 		goto do_refs;
8617dd7cddfSDavid du Colombier 	    } else {		/* We assume this is some non-pointer- */
8627dd7cddfSDavid du Colombier 		/* containing type. */
8637dd7cddfSDavid du Colombier 		if ((*ptp->mark) (&nep, pstate))
8647dd7cddfSDavid du Colombier 		    new |= 1;
8657dd7cddfSDavid du Colombier 		goto ts;
8667dd7cddfSDavid du Colombier 	    }
8677dd7cddfSDavid du Colombier 	}
8687dd7cddfSDavid du Colombier 
8697dd7cddfSDavid du Colombier 	/* ---------------- Refs ---------------- */
8707dd7cddfSDavid du Colombier 
8717dd7cddfSDavid du Colombier       do_refs:
8727dd7cddfSDavid du Colombier 	{
8737dd7cddfSDavid du Colombier 	    ref_packed *pptr = sp->ptr;
8747dd7cddfSDavid du Colombier 	    ref *rptr;
8757dd7cddfSDavid du Colombier 
8767dd7cddfSDavid du Colombier 	  tr:if (!sp->index) {
8777dd7cddfSDavid du Colombier 		--sp;
8787dd7cddfSDavid du Colombier 		continue;
8797dd7cddfSDavid du Colombier 	    }
8807dd7cddfSDavid du Colombier 	    --(sp->index);
8817dd7cddfSDavid du Colombier 	    if_debug3('8', "  [8]%smarking refs 0x%lx[%u]\n",
8827dd7cddfSDavid du Colombier 		      depth_dots(sp, pms), (ulong) pptr, sp->index);
8837dd7cddfSDavid du Colombier 	    if (r_is_packed(pptr)) {
8847dd7cddfSDavid du Colombier 		if (!r_has_pmark(pptr)) {
8857dd7cddfSDavid du Colombier 		    r_set_pmark(pptr);
8867dd7cddfSDavid du Colombier 		    new |= 1;
8877dd7cddfSDavid du Colombier 		    if (r_packed_is_name(pptr)) {
8887dd7cddfSDavid du Colombier 			name_index_t nidx = packed_name_index(pptr);
8897dd7cddfSDavid du Colombier 
8907dd7cddfSDavid du Colombier 			mark_name(nidx);
8917dd7cddfSDavid du Colombier 		    }
8927dd7cddfSDavid du Colombier 		}
8937dd7cddfSDavid du Colombier 		++pptr;
8947dd7cddfSDavid du Colombier 		goto tr;
8957dd7cddfSDavid du Colombier 	    }
8967dd7cddfSDavid du Colombier 	    rptr = (ref *) pptr;	/* * const beyond here */
8977dd7cddfSDavid du Colombier 	    if (r_has_attr(rptr, l_mark)) {
8987dd7cddfSDavid du Colombier 		pptr = (ref_packed *)(rptr + 1);
8997dd7cddfSDavid du Colombier 		goto tr;
9007dd7cddfSDavid du Colombier 	    }
9017dd7cddfSDavid du Colombier 	    r_set_attrs(rptr, l_mark);
9027dd7cddfSDavid du Colombier 	    new |= 1;
9037dd7cddfSDavid du Colombier 	    if (r_space(rptr) < min_trace) {	/* Note that this always picks up all scalars. */
9047dd7cddfSDavid du Colombier 		pptr = (ref_packed *) (rptr + 1);
9057dd7cddfSDavid du Colombier 		goto tr;
9067dd7cddfSDavid du Colombier 	    }
9077dd7cddfSDavid du Colombier 	    sp->ptr = rptr + 1;
9087dd7cddfSDavid du Colombier 	    switch (r_type(rptr)) {
9097dd7cddfSDavid du Colombier 		    /* Struct cases */
9107dd7cddfSDavid du Colombier 		case t_file:
9117dd7cddfSDavid du Colombier 		    nptr = rptr->value.pfile;
9127dd7cddfSDavid du Colombier 		  rs:sp[1].is_refs = false;
9137dd7cddfSDavid du Colombier 		    sp[1].index = 0;
9147dd7cddfSDavid du Colombier 		    if (sp == stop) {
9157dd7cddfSDavid du Colombier 			ptp = ptr_struct_type;
9167dd7cddfSDavid du Colombier 			break;
9177dd7cddfSDavid du Colombier 		    }
9187dd7cddfSDavid du Colombier 		    nep.ptr = nptr;
9197dd7cddfSDavid du Colombier 		    if (!ptr_struct_mark(&nep, pstate))
9207dd7cddfSDavid du Colombier 			goto nr;
9217dd7cddfSDavid du Colombier 		    new |= 1;
9227dd7cddfSDavid du Colombier 		    (++sp)->ptr = nptr;
9237dd7cddfSDavid du Colombier 		    goto do_struct;
9247dd7cddfSDavid du Colombier 		case t_device:
9257dd7cddfSDavid du Colombier 		    nptr = rptr->value.pdevice;
9267dd7cddfSDavid du Colombier 		    goto rs;
9277dd7cddfSDavid du Colombier 		case t_fontID:
9287dd7cddfSDavid du Colombier 		case t_struct:
9297dd7cddfSDavid du Colombier 		case t_astruct:
9307dd7cddfSDavid du Colombier 		    nptr = rptr->value.pstruct;
9317dd7cddfSDavid du Colombier 		    goto rs;
9327dd7cddfSDavid du Colombier 		    /* Non-trivial non-struct cases */
9337dd7cddfSDavid du Colombier 		case t_dictionary:
9347dd7cddfSDavid du Colombier 		    nptr = rptr->value.pdict;
9357dd7cddfSDavid du Colombier 		    sp[1].index = sizeof(dict) / sizeof(ref);
9367dd7cddfSDavid du Colombier 		    goto rrp;
9377dd7cddfSDavid du Colombier 		case t_array:
9387dd7cddfSDavid du Colombier 		    nptr = rptr->value.refs;
9397dd7cddfSDavid du Colombier 		  rr:if ((sp[1].index = r_size(rptr)) == 0) {	/* Set the base pointer to 0, */
9407dd7cddfSDavid du Colombier 			/* so we never try to relocate it. */
9417dd7cddfSDavid du Colombier 			rptr->value.refs = 0;
9427dd7cddfSDavid du Colombier 			goto nr;
9437dd7cddfSDavid du Colombier 		    }
9447dd7cddfSDavid du Colombier 		  rrp:
9457dd7cddfSDavid du Colombier 		  rrc:sp[1].is_refs = true;
9467dd7cddfSDavid du Colombier 		    if (sp == stop) {
9477dd7cddfSDavid du Colombier 			/*
9487dd7cddfSDavid du Colombier 			 * The following initialization is unnecessary:
9497dd7cddfSDavid du Colombier 			 * ptp will not be used if sp[1].is_refs = true.
9507dd7cddfSDavid du Colombier 			 * We put this here solely to get rid of bogus
9517dd7cddfSDavid du Colombier 			 * "possibly uninitialized variable" warnings
9527dd7cddfSDavid du Colombier 			 * from certain compilers.
9537dd7cddfSDavid du Colombier 			 */
9547dd7cddfSDavid du Colombier 			ptp = ptr_ref_type;
9557dd7cddfSDavid du Colombier 			break;
9567dd7cddfSDavid du Colombier 		    }
9577dd7cddfSDavid du Colombier 		    new |= 1;
9587dd7cddfSDavid du Colombier 		    (++sp)->ptr = nptr;
9597dd7cddfSDavid du Colombier 		    goto do_refs;
9607dd7cddfSDavid du Colombier 		case t_mixedarray:
9617dd7cddfSDavid du Colombier 		case t_shortarray:
9627dd7cddfSDavid du Colombier 		    nptr = rptr->value.writable_packed;
9637dd7cddfSDavid du Colombier 		    goto rr;
9647dd7cddfSDavid du Colombier 		case t_name:
9657dd7cddfSDavid du Colombier 		    mark_name(names_index(nt, rptr));
9667dd7cddfSDavid du Colombier 		  nr:pptr = (ref_packed *) (rptr + 1);
9677dd7cddfSDavid du Colombier 		    goto tr;
9687dd7cddfSDavid du Colombier 		case t_string:
9697dd7cddfSDavid du Colombier 		    if (gc_string_mark(rptr->value.bytes, r_size(rptr), true, pstate))
9707dd7cddfSDavid du Colombier 			new |= 1;
9717dd7cddfSDavid du Colombier 		    goto nr;
9727dd7cddfSDavid du Colombier 		case t_oparray:
9737dd7cddfSDavid du Colombier 		    nptr = rptr->value.refs;	/* discard const */
9747dd7cddfSDavid du Colombier 		    sp[1].index = 1;
9757dd7cddfSDavid du Colombier 		    goto rrc;
9767dd7cddfSDavid du Colombier 		default:
9777dd7cddfSDavid du Colombier 		    goto nr;
9787dd7cddfSDavid du Colombier 	    }
9797dd7cddfSDavid du Colombier 	}
9807dd7cddfSDavid du Colombier 
9817dd7cddfSDavid du Colombier 	/* ---------------- Recursion ---------------- */
9827dd7cddfSDavid du Colombier 
9837dd7cddfSDavid du Colombier       push:
9847dd7cddfSDavid du Colombier 	if (sp == stop) {	/* The current segment is full. */
9857dd7cddfSDavid du Colombier 	    int new_added = gc_extend_stack(pms, pstate);
9867dd7cddfSDavid du Colombier 
9877dd7cddfSDavid du Colombier 	    if (new_added) {
9887dd7cddfSDavid du Colombier 		new |= new_added;
9897dd7cddfSDavid du Colombier 		continue;
9907dd7cddfSDavid du Colombier 	    }
9917dd7cddfSDavid du Colombier 	    pms = pms->next;
9927dd7cddfSDavid du Colombier 	    stop = pms->entries + pms->count - 1;
9937dd7cddfSDavid du Colombier 	    pms->entries[1] = sp[1];
9947dd7cddfSDavid du Colombier 	    sp = pms->entries;
9957dd7cddfSDavid du Colombier 	}
9967dd7cddfSDavid du Colombier 	/* index and is_refs are already set */
9977dd7cddfSDavid du Colombier 	if (!sp[1].is_refs) {
9987dd7cddfSDavid du Colombier 	    nep.ptr = nptr;
9997dd7cddfSDavid du Colombier 	    if (!(*ptp->mark) (&nep, pstate))
10007dd7cddfSDavid du Colombier 		continue;
10017dd7cddfSDavid du Colombier 	    new |= 1;
10027dd7cddfSDavid du Colombier 	}
10037dd7cddfSDavid du Colombier 	(++sp)->ptr = nptr;
10047dd7cddfSDavid du Colombier     }
10057dd7cddfSDavid du Colombier     return new;
10067dd7cddfSDavid du Colombier }
10077dd7cddfSDavid du Colombier /* Link to, attempting to allocate if necessary, */
10087dd7cddfSDavid du Colombier /* another chunk of mark stack. */
10097dd7cddfSDavid du Colombier private int
gc_extend_stack(gc_mark_stack * pms,gc_state_t * pstate)10107dd7cddfSDavid du Colombier gc_extend_stack(gc_mark_stack * pms, gc_state_t * pstate)
10117dd7cddfSDavid du Colombier {
10127dd7cddfSDavid du Colombier     if (pms->next == 0) {	/* Try to allocate another segment. */
10137dd7cddfSDavid du Colombier 	uint count;
10147dd7cddfSDavid du Colombier 
10157dd7cddfSDavid du Colombier 	for (count = ms_size_desired; count >= ms_size_min; count >>= 1) {
10167dd7cddfSDavid du Colombier 	    pms->next = (gc_mark_stack *)
10177dd7cddfSDavid du Colombier 		gs_alloc_bytes_immovable(pstate->heap,
10187dd7cddfSDavid du Colombier 					 sizeof(gc_mark_stack) +
10197dd7cddfSDavid du Colombier 					 sizeof(ms_entry) * count,
10207dd7cddfSDavid du Colombier 					 "gc mark stack");
10217dd7cddfSDavid du Colombier 	    if (pms->next != 0)
10227dd7cddfSDavid du Colombier 		break;
10237dd7cddfSDavid du Colombier 	}
10247dd7cddfSDavid du Colombier 	if (pms->next == 0) {	/* The mark stack overflowed. */
10257dd7cddfSDavid du Colombier 	    ms_entry *sp = pms->entries + pms->count - 1;
10267dd7cddfSDavid du Colombier 	    byte *cptr = sp->ptr;	/* container */
10277dd7cddfSDavid du Colombier 	    chunk_t *cp = gc_locate(cptr, pstate);
10287dd7cddfSDavid du Colombier 	    int new = 1;
10297dd7cddfSDavid du Colombier 
10307dd7cddfSDavid du Colombier 	    if (cp == 0) {	/* We were tracing outside collectible */
10317dd7cddfSDavid du Colombier 		/* storage.  This can't happen. */
10327dd7cddfSDavid du Colombier 		lprintf1("mark stack overflowed while outside collectible space at 0x%lx!\n",
10337dd7cddfSDavid du Colombier 			 (ulong) cptr);
1034*593dc095SDavid du Colombier 		gs_abort(pstate->heap);
10357dd7cddfSDavid du Colombier 	    }
10367dd7cddfSDavid du Colombier 	    if (cptr < cp->rescan_bot)
10377dd7cddfSDavid du Colombier 		cp->rescan_bot = cptr, new = -1;
10387dd7cddfSDavid du Colombier 	    if (cptr > cp->rescan_top)
10397dd7cddfSDavid du Colombier 		cp->rescan_top = cptr, new = -1;
10407dd7cddfSDavid du Colombier 	    return new;
10417dd7cddfSDavid du Colombier 	}
10427dd7cddfSDavid du Colombier 	gc_init_mark_stack(pms->next, count);
10437dd7cddfSDavid du Colombier 	pms->next->prev = pms;
10447dd7cddfSDavid du Colombier 	pms->next->on_heap = true;
10457dd7cddfSDavid du Colombier     }
10467dd7cddfSDavid du Colombier     return 0;
10477dd7cddfSDavid du Colombier }
10487dd7cddfSDavid du Colombier 
10497dd7cddfSDavid du Colombier /* Mark a struct.  Return true if new mark. */
10507dd7cddfSDavid du Colombier private bool
ptr_struct_mark(enum_ptr_t * pep,gc_state_t * ignored)10517dd7cddfSDavid du Colombier ptr_struct_mark(enum_ptr_t *pep, gc_state_t * ignored)
10527dd7cddfSDavid du Colombier {
10537dd7cddfSDavid du Colombier     obj_header_t *ptr = (obj_header_t *)pep->ptr;
10547dd7cddfSDavid du Colombier 
10557dd7cddfSDavid du Colombier     if (ptr == 0)
10567dd7cddfSDavid du Colombier 	return false;
10577dd7cddfSDavid du Colombier     ptr--;			/* point to header */
10587dd7cddfSDavid du Colombier     if (!o_is_unmarked(ptr))
10597dd7cddfSDavid du Colombier 	return false;
10607dd7cddfSDavid du Colombier     o_mark(ptr);
10617dd7cddfSDavid du Colombier     return true;
10627dd7cddfSDavid du Colombier }
10637dd7cddfSDavid du Colombier 
10647dd7cddfSDavid du Colombier /* Mark a string.  Return true if new mark. */
10657dd7cddfSDavid du Colombier private bool
ptr_string_mark(enum_ptr_t * pep,gc_state_t * gcst)10667dd7cddfSDavid du Colombier ptr_string_mark(enum_ptr_t *pep, gc_state_t * gcst)
10677dd7cddfSDavid du Colombier {
10687dd7cddfSDavid du Colombier     return gc_string_mark(pep->ptr, pep->size, true, gcst);
10697dd7cddfSDavid du Colombier }
10707dd7cddfSDavid du Colombier 
10717dd7cddfSDavid du Colombier /* Finish tracing by marking names. */
10727dd7cddfSDavid du Colombier private bool
gc_trace_finish(gc_state_t * pstate)10737dd7cddfSDavid du Colombier gc_trace_finish(gc_state_t * pstate)
10747dd7cddfSDavid du Colombier {
10757dd7cddfSDavid du Colombier     name_table *nt = pstate->ntable;
10767dd7cddfSDavid du Colombier     name_index_t nidx = 0;
10777dd7cddfSDavid du Colombier     bool marked = false;
10787dd7cddfSDavid du Colombier 
10797dd7cddfSDavid du Colombier     while ((nidx = names_next_valid_index(nt, nidx)) != 0) {
10807dd7cddfSDavid du Colombier 	name_string_t *pnstr = names_index_string_inline(nt, nidx);
10817dd7cddfSDavid du Colombier 
10827dd7cddfSDavid du Colombier 	if (pnstr->mark) {
10837dd7cddfSDavid du Colombier 	    enum_ptr_t enst, ensst;
10847dd7cddfSDavid du Colombier 
10857dd7cddfSDavid du Colombier 	    if (!pnstr->foreign_string &&
10867dd7cddfSDavid du Colombier 		gc_string_mark(pnstr->string_bytes, pnstr->string_size,
10877dd7cddfSDavid du Colombier 			       true, pstate)
10887dd7cddfSDavid du Colombier 		)
10897dd7cddfSDavid du Colombier 		marked = true;
10907dd7cddfSDavid du Colombier 	    enst.ptr = names_index_sub_table(nt, nidx);
10917dd7cddfSDavid du Colombier 	    ensst.ptr = names_index_string_sub_table(nt, nidx);
10927dd7cddfSDavid du Colombier 	    marked |=
10937dd7cddfSDavid du Colombier 		ptr_struct_mark(&enst, pstate) |
10947dd7cddfSDavid du Colombier 		ptr_struct_mark(&ensst, pstate);
10957dd7cddfSDavid du Colombier 	}
10967dd7cddfSDavid du Colombier     }
10977dd7cddfSDavid du Colombier     return marked;
10987dd7cddfSDavid du Colombier }
10997dd7cddfSDavid du Colombier 
11007dd7cddfSDavid du Colombier /* ------ Relocation planning phase ------ */
11017dd7cddfSDavid du Colombier 
11027dd7cddfSDavid du Colombier /* Initialize the relocation information in the chunk header. */
11037dd7cddfSDavid du Colombier private void
gc_init_reloc(chunk_t * cp)11047dd7cddfSDavid du Colombier gc_init_reloc(chunk_t * cp)
11057dd7cddfSDavid du Colombier {
11067dd7cddfSDavid du Colombier     chunk_head_t *chead = cp->chead;
11077dd7cddfSDavid du Colombier 
11087dd7cddfSDavid du Colombier     chead->dest = cp->cbase;
11097dd7cddfSDavid du Colombier     chead->free.o_back =
11107dd7cddfSDavid du Colombier 	offset_of(chunk_head_t, free) >> obj_back_shift;
11117dd7cddfSDavid du Colombier     chead->free.o_size = sizeof(obj_header_t);
11127dd7cddfSDavid du Colombier     chead->free.o_nreloc = 0;
11137dd7cddfSDavid du Colombier }
11147dd7cddfSDavid du Colombier 
11157dd7cddfSDavid du Colombier /* Set marks and clear relocation for chunks that won't be compacted. */
11167dd7cddfSDavid du Colombier private void
gc_clear_reloc(chunk_t * cp)11177dd7cddfSDavid du Colombier gc_clear_reloc(chunk_t * cp)
11187dd7cddfSDavid du Colombier {
11197dd7cddfSDavid du Colombier     byte *pfree = (byte *) & cp->chead->free;
11207dd7cddfSDavid du Colombier 
11217dd7cddfSDavid du Colombier     gc_init_reloc(cp);
11227dd7cddfSDavid du Colombier     SCAN_CHUNK_OBJECTS(cp)
11237dd7cddfSDavid du Colombier 	DO_ALL
11247dd7cddfSDavid du Colombier 	const struct_shared_procs_t *procs =
11257dd7cddfSDavid du Colombier     pre->o_type->shared;
11267dd7cddfSDavid du Colombier 
11277dd7cddfSDavid du Colombier     if (procs != 0)
11287dd7cddfSDavid du Colombier 	(*procs->clear_reloc) (pre, size);
11297dd7cddfSDavid du Colombier     o_set_untraced(pre);
11307dd7cddfSDavid du Colombier     pre->o_back = ((byte *) pre - pfree) >> obj_back_shift;
11317dd7cddfSDavid du Colombier     END_OBJECTS_SCAN
11327dd7cddfSDavid du Colombier 	gc_strings_set_marks(cp, true);
11337dd7cddfSDavid du Colombier     gc_strings_clear_reloc(cp);
11347dd7cddfSDavid du Colombier }
11357dd7cddfSDavid du Colombier 
11367dd7cddfSDavid du Colombier /* Set the relocation for the objects in a chunk. */
11377dd7cddfSDavid du Colombier /* This will never be called for a chunk with any o_untraced objects. */
11387dd7cddfSDavid du Colombier private void
gc_objects_set_reloc(chunk_t * cp)11397dd7cddfSDavid du Colombier gc_objects_set_reloc(chunk_t * cp)
11407dd7cddfSDavid du Colombier {
11417dd7cddfSDavid du Colombier     uint reloc = 0;
11427dd7cddfSDavid du Colombier     chunk_head_t *chead = cp->chead;
11437dd7cddfSDavid du Colombier     byte *pfree = (byte *) & chead->free;	/* most recent free object */
11447dd7cddfSDavid du Colombier 
11457dd7cddfSDavid du Colombier     if_debug_chunk('6', "[6]setting reloc for chunk", cp);
11467dd7cddfSDavid du Colombier     gc_init_reloc(cp);
11477dd7cddfSDavid du Colombier     SCAN_CHUNK_OBJECTS(cp)
11487dd7cddfSDavid du Colombier 	DO_ALL
11497dd7cddfSDavid du Colombier 	struct_proc_finalize((*finalize));
11507dd7cddfSDavid du Colombier     const struct_shared_procs_t *procs =
11517dd7cddfSDavid du Colombier     pre->o_type->shared;
11527dd7cddfSDavid du Colombier 
11537dd7cddfSDavid du Colombier     if ((procs == 0 ? o_is_unmarked(pre) :
11547dd7cddfSDavid du Colombier 	 !(*procs->set_reloc) (pre, reloc, size))
11557dd7cddfSDavid du Colombier 	) {			/* Free object */
11567dd7cddfSDavid du Colombier 	reloc += sizeof(obj_header_t) + obj_align_round(size);
11577dd7cddfSDavid du Colombier 	if ((finalize = pre->o_type->finalize) != 0) {
11587dd7cddfSDavid du Colombier 	    if_debug2('u', "[u]GC finalizing %s 0x%lx\n",
11597dd7cddfSDavid du Colombier 		      struct_type_name_string(pre->o_type),
11607dd7cddfSDavid du Colombier 		      (ulong) (pre + 1));
11617dd7cddfSDavid du Colombier 	    (*finalize) (pre + 1);
11627dd7cddfSDavid du Colombier 	}
11637dd7cddfSDavid du Colombier 	pfree = (byte *) pre;
11647dd7cddfSDavid du Colombier 	pre->o_back = (pfree - (byte *) chead) >> obj_back_shift;
11657dd7cddfSDavid du Colombier 	pre->o_nreloc = reloc;
11667dd7cddfSDavid du Colombier 	if_debug3('7', " [7]at 0x%lx, unmarked %lu, new reloc = %u\n",
11677dd7cddfSDavid du Colombier 		  (ulong) pre, (ulong) size, reloc);
11687dd7cddfSDavid du Colombier     } else {			/* Useful object */
11697dd7cddfSDavid du Colombier 	debug_check_object(pre, cp, NULL);
11707dd7cddfSDavid du Colombier 	pre->o_back = ((byte *) pre - pfree) >> obj_back_shift;
11717dd7cddfSDavid du Colombier     }
11727dd7cddfSDavid du Colombier     END_OBJECTS_SCAN
11737dd7cddfSDavid du Colombier #ifdef DEBUG
11747dd7cddfSDavid du Colombier 	if (reloc != 0) {
11757dd7cddfSDavid du Colombier 	if_debug1('6', "[6]freed %u", reloc);
11767dd7cddfSDavid du Colombier 	if_debug_chunk('6', " in", cp);
11777dd7cddfSDavid du Colombier     }
11787dd7cddfSDavid du Colombier #endif
11797dd7cddfSDavid du Colombier }
11807dd7cddfSDavid du Colombier 
11817dd7cddfSDavid du Colombier /* ------ Relocation phase ------ */
11827dd7cddfSDavid du Colombier 
11837dd7cddfSDavid du Colombier /* Relocate the pointers in all the objects in a chunk. */
11847dd7cddfSDavid du Colombier private void
gc_do_reloc(chunk_t * cp,gs_ref_memory_t * mem,gc_state_t * pstate)11857dd7cddfSDavid du Colombier gc_do_reloc(chunk_t * cp, gs_ref_memory_t * mem, gc_state_t * pstate)
11867dd7cddfSDavid du Colombier {
11877dd7cddfSDavid du Colombier     chunk_head_t *chead = cp->chead;
11887dd7cddfSDavid du Colombier 
11897dd7cddfSDavid du Colombier     if_debug_chunk('6', "[6]relocating in chunk", cp);
11907dd7cddfSDavid du Colombier     SCAN_CHUNK_OBJECTS(cp)
11917dd7cddfSDavid du Colombier 	DO_ALL
1192*593dc095SDavid du Colombier #ifdef DEBUG
1193*593dc095SDavid du Colombier 	pstate->container = cp;
1194*593dc095SDavid du Colombier #endif
11957dd7cddfSDavid du Colombier     /* We need to relocate the pointers in an object iff */
11967dd7cddfSDavid du Colombier     /* it is o_untraced, or it is a useful object. */
11977dd7cddfSDavid du Colombier     /* An object is free iff its back pointer points to */
11987dd7cddfSDavid du Colombier     /* the chunk_head structure. */
11997dd7cddfSDavid du Colombier 	if (o_is_untraced(pre) ||
12007dd7cddfSDavid du Colombier 	    pre->o_back << obj_back_shift != (byte *) pre - (byte *) chead
12017dd7cddfSDavid du Colombier 	    ) {
12027dd7cddfSDavid du Colombier 	    struct_proc_reloc_ptrs((*proc)) =
12037dd7cddfSDavid du Colombier 		pre->o_type->reloc_ptrs;
12047dd7cddfSDavid du Colombier 
12057dd7cddfSDavid du Colombier 	    if_debug3('7',
12067dd7cddfSDavid du Colombier 		      " [7]relocating ptrs in %s(%lu) 0x%lx\n",
12077dd7cddfSDavid du Colombier 		      struct_type_name_string(pre->o_type),
12087dd7cddfSDavid du Colombier 		      (ulong) size, (ulong) pre);
12097dd7cddfSDavid du Colombier 	    if (proc != 0)
12107dd7cddfSDavid du Colombier 		(*proc) (pre + 1, size, pre->o_type, pstate);
12117dd7cddfSDavid du Colombier 	}
1212*593dc095SDavid du Colombier #ifdef DEBUG
1213*593dc095SDavid du Colombier 	pstate->container = 0;
1214*593dc095SDavid du Colombier #endif
12157dd7cddfSDavid du Colombier     END_OBJECTS_SCAN
12167dd7cddfSDavid du Colombier }
12177dd7cddfSDavid du Colombier 
12187dd7cddfSDavid du Colombier /* Print pointer relocation if debugging. */
12197dd7cddfSDavid du Colombier /* We have to provide this procedure even if DEBUG is not defined, */
12207dd7cddfSDavid du Colombier /* in case one of the other GC modules was compiled with DEBUG. */
12217dd7cddfSDavid du Colombier const void *
print_reloc_proc(const void * obj,const char * cname,const void * robj)12227dd7cddfSDavid du Colombier print_reloc_proc(const void *obj, const char *cname, const void *robj)
12237dd7cddfSDavid du Colombier {
12247dd7cddfSDavid du Colombier     if_debug3('9', "  [9]relocate %s * 0x%lx to 0x%lx\n",
12257dd7cddfSDavid du Colombier 	      cname, (ulong)obj, (ulong)robj);
12267dd7cddfSDavid du Colombier     return robj;
12277dd7cddfSDavid du Colombier }
12287dd7cddfSDavid du Colombier 
12297dd7cddfSDavid du Colombier /* Relocate a pointer to an (aligned) object. */
12307dd7cddfSDavid du Colombier /* See gsmemory.h for why the argument is const and the result is not. */
12317dd7cddfSDavid du Colombier private void /*obj_header_t */ *
igc_reloc_struct_ptr(const void * obj,gc_state_t * gcst)12327dd7cddfSDavid du Colombier igc_reloc_struct_ptr(const void /*obj_header_t */ *obj, gc_state_t * gcst)
12337dd7cddfSDavid du Colombier {
12347dd7cddfSDavid du Colombier     const obj_header_t *const optr = (const obj_header_t *)obj;
12357dd7cddfSDavid du Colombier     const void *robj;
12367dd7cddfSDavid du Colombier 
12377dd7cddfSDavid du Colombier     if (obj == 0) {
12387dd7cddfSDavid du Colombier 	discard(print_reloc(obj, "NULL", 0));
12397dd7cddfSDavid du Colombier 	return 0;
12407dd7cddfSDavid du Colombier     }
12417dd7cddfSDavid du Colombier     debug_check_object(optr - 1, NULL, gcst);
12427dd7cddfSDavid du Colombier     {
12437dd7cddfSDavid du Colombier 	uint back = optr[-1].o_back;
12447dd7cddfSDavid du Colombier 
12457dd7cddfSDavid du Colombier 	if (back == o_untraced)
12467dd7cddfSDavid du Colombier 	    robj = obj;
12477dd7cddfSDavid du Colombier 	else {
12487dd7cddfSDavid du Colombier #ifdef DEBUG
12497dd7cddfSDavid du Colombier 	    /* Do some sanity checking. */
1250*593dc095SDavid du Colombier 	    chunk_t *cp = gcst->container;
1251*593dc095SDavid du Colombier 
1252*593dc095SDavid du Colombier 	    if (cp != 0 && cp->cbase <= (byte *)obj && (byte *)obj <cp->ctop) {
1253*593dc095SDavid du Colombier 		if (back > (cp->ctop - cp->cbase) >> obj_back_shift) {
12547dd7cddfSDavid du Colombier 		    lprintf2("Invalid back pointer %u at 0x%lx!\n",
12557dd7cddfSDavid du Colombier 			     back, (ulong) obj);
1256*593dc095SDavid du Colombier 		    gs_abort(NULL);
1257*593dc095SDavid du Colombier 		}
1258*593dc095SDavid du Colombier 	    } else {
1259*593dc095SDavid du Colombier 		/* Pointed to unknown chunk. Can't check it, sorry. */
12607dd7cddfSDavid du Colombier 	    }
12617dd7cddfSDavid du Colombier #endif
12627dd7cddfSDavid du Colombier 	    {
12637dd7cddfSDavid du Colombier 		const obj_header_t *pfree = (const obj_header_t *)
12647dd7cddfSDavid du Colombier 		((const char *)(optr - 1) -
12657dd7cddfSDavid du Colombier 		 (back << obj_back_shift));
12667dd7cddfSDavid du Colombier 		const chunk_head_t *chead = (const chunk_head_t *)
12677dd7cddfSDavid du Colombier 		((const char *)pfree -
12687dd7cddfSDavid du Colombier 		 (pfree->o_back << obj_back_shift));
12697dd7cddfSDavid du Colombier 
12707dd7cddfSDavid du Colombier 		robj = chead->dest +
12717dd7cddfSDavid du Colombier 		    ((const char *)obj - (const char *)(chead + 1) -
12727dd7cddfSDavid du Colombier 		     pfree->o_nreloc);
12737dd7cddfSDavid du Colombier 	    }
12747dd7cddfSDavid du Colombier 	}
12757dd7cddfSDavid du Colombier     }
12767dd7cddfSDavid du Colombier     /* Use a severely deprecated pun to remove the const property. */
12777dd7cddfSDavid du Colombier     {
12787dd7cddfSDavid du Colombier 	union { const void *r; void *w; } u;
12797dd7cddfSDavid du Colombier 
12807dd7cddfSDavid du Colombier 	u.r = print_reloc(obj, struct_type_name_string(optr[-1].o_type), robj);
12817dd7cddfSDavid du Colombier 	return u.w;
12827dd7cddfSDavid du Colombier     }
12837dd7cddfSDavid du Colombier }
12847dd7cddfSDavid du Colombier 
12857dd7cddfSDavid du Colombier /* ------ Compaction phase ------ */
12867dd7cddfSDavid du Colombier 
12877dd7cddfSDavid du Colombier /* Compact the objects in a chunk. */
12887dd7cddfSDavid du Colombier /* This will never be called for a chunk with any o_untraced objects. */
12897dd7cddfSDavid du Colombier private void
gc_objects_compact(chunk_t * cp,gc_state_t * gcst)12907dd7cddfSDavid du Colombier gc_objects_compact(chunk_t * cp, gc_state_t * gcst)
12917dd7cddfSDavid du Colombier {
12927dd7cddfSDavid du Colombier     chunk_head_t *chead = cp->chead;
12937dd7cddfSDavid du Colombier     obj_header_t *dpre = (obj_header_t *) chead->dest;
1294*593dc095SDavid du Colombier     const gs_memory_t *cmem = gcst->spaces.memories.named.system->stable_memory;
12957dd7cddfSDavid du Colombier 
12967dd7cddfSDavid du Colombier     SCAN_CHUNK_OBJECTS(cp)
12977dd7cddfSDavid du Colombier 	DO_ALL
12987dd7cddfSDavid du Colombier     /* An object is free iff its back pointer points to */
12997dd7cddfSDavid du Colombier     /* the chunk_head structure. */
13007dd7cddfSDavid du Colombier 	if (pre->o_back << obj_back_shift != (byte *) pre - (byte *) chead) {
13017dd7cddfSDavid du Colombier 	const struct_shared_procs_t *procs = pre->o_type->shared;
13027dd7cddfSDavid du Colombier 
13037dd7cddfSDavid du Colombier 	debug_check_object(pre, cp, gcst);
13047dd7cddfSDavid du Colombier 	if_debug4('7',
13057dd7cddfSDavid du Colombier 		  " [7]compacting %s 0x%lx(%lu) to 0x%lx\n",
13067dd7cddfSDavid du Colombier 		  struct_type_name_string(pre->o_type),
13077dd7cddfSDavid du Colombier 		  (ulong) pre, (ulong) size, (ulong) dpre);
13087dd7cddfSDavid du Colombier 	if (procs == 0) {
13097dd7cddfSDavid du Colombier 	    if (dpre != pre)
13107dd7cddfSDavid du Colombier 		memmove(dpre, pre,
13117dd7cddfSDavid du Colombier 			sizeof(obj_header_t) + size);
13127dd7cddfSDavid du Colombier 	} else
1313*593dc095SDavid du Colombier 	    (*procs->compact) (cmem, pre, dpre, size);
13147dd7cddfSDavid du Colombier 	dpre = (obj_header_t *)
13157dd7cddfSDavid du Colombier 	    ((byte *) dpre + obj_size_round(size));
13167dd7cddfSDavid du Colombier     }
13177dd7cddfSDavid du Colombier     END_OBJECTS_SCAN
13187dd7cddfSDavid du Colombier 	if (cp->outer == 0 && chead->dest != cp->cbase)
13197dd7cddfSDavid du Colombier 	dpre = (obj_header_t *) cp->cbase;	/* compacted this chunk into another */
13207dd7cddfSDavid du Colombier     gs_alloc_fill(dpre, gs_alloc_fill_collected, cp->cbot - (byte *) dpre);
13217dd7cddfSDavid du Colombier     cp->cbot = (byte *) dpre;
13227dd7cddfSDavid du Colombier     cp->rcur = 0;
13237dd7cddfSDavid du Colombier     cp->rtop = 0;		/* just to be sure */
13247dd7cddfSDavid du Colombier }
13257dd7cddfSDavid du Colombier 
13267dd7cddfSDavid du Colombier /* ------ Cleanup ------ */
13277dd7cddfSDavid du Colombier 
13287dd7cddfSDavid du Colombier /* Free empty chunks. */
13297dd7cddfSDavid du Colombier private void
gc_free_empty_chunks(gs_ref_memory_t * mem)13307dd7cddfSDavid du Colombier gc_free_empty_chunks(gs_ref_memory_t * mem)
13317dd7cddfSDavid du Colombier {
13327dd7cddfSDavid du Colombier     chunk_t *cp;
13337dd7cddfSDavid du Colombier     chunk_t *csucc;
13347dd7cddfSDavid du Colombier 
13357dd7cddfSDavid du Colombier     /* Free the chunks in reverse order, */
13367dd7cddfSDavid du Colombier     /* to encourage LIFO behavior. */
13377dd7cddfSDavid du Colombier     for (cp = mem->clast; cp != 0; cp = csucc) {	/* Make sure this isn't an inner chunk, */
13387dd7cddfSDavid du Colombier 	/* or a chunk that has inner chunks. */
13397dd7cddfSDavid du Colombier 	csucc = cp->cprev;	/* save before freeing */
13407dd7cddfSDavid du Colombier 	if (cp->cbot == cp->cbase && cp->ctop == cp->climit &&
13417dd7cddfSDavid du Colombier 	    cp->outer == 0 && cp->inner_count == 0
13427dd7cddfSDavid du Colombier 	    ) {
13437dd7cddfSDavid du Colombier 	    alloc_free_chunk(cp, mem);
13447dd7cddfSDavid du Colombier 	    if (mem->pcc == cp)
13457dd7cddfSDavid du Colombier 		mem->pcc = 0;
13467dd7cddfSDavid du Colombier 	}
13477dd7cddfSDavid du Colombier     }
13487dd7cddfSDavid du Colombier }
1349*593dc095SDavid du Colombier 
1350*593dc095SDavid du Colombier 
gcst_get_memory_ptr(gc_state_t * gcst)1351*593dc095SDavid du Colombier const gs_memory_t * gcst_get_memory_ptr(gc_state_t *gcst)
1352*593dc095SDavid du Colombier {
1353*593dc095SDavid du Colombier     vm_spaces spaces = gcst->spaces;
1354*593dc095SDavid du Colombier     const gs_memory_t *cmem = space_system->stable_memory;
1355*593dc095SDavid du Colombier     return cmem;
1356*593dc095SDavid du Colombier }
1357