diff options
author | Henry Stiles <henry.stiles@artifex.com> | 1998-07-28 06:22:20 +0000 |
---|---|---|
committer | Henry Stiles <henry.stiles@artifex.com> | 1998-07-28 06:22:20 +0000 |
commit | 5fbdbaab7335a147a3a7890b5c6fc123926815db (patch) | |
tree | 154edc89b06c38333fd6d4b9abaf0ee8740ddf6a /gs/src/igc.c | |
parent | 14cf10e3738f95f7864978c5a4778b50fb39524b (diff) | |
download | ghostpdl-5fbdbaab7335a147a3a7890b5c6fc123926815db.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r257,
which included commits to RCS files with non-trunk default branches.
git-svn-id: http://svn.ghostscript.com/ghostpcl/trunk/ghostpcl@258 06663e23-700e-0410-b217-a244a6096597
Diffstat (limited to 'gs/src/igc.c')
-rw-r--r-- | gs/src/igc.c | 1883 |
1 files changed, 961 insertions, 922 deletions
diff --git a/gs/src/igc.c b/gs/src/igc.c index f1a365e36..9bc083aa3 100644 --- a/gs/src/igc.c +++ b/gs/src/igc.c @@ -1,20 +1,20 @@ /* Copyright (C) 1993, 1996, 1997 Aladdin Enterprises. All rights reserved. - - This file is part of Aladdin Ghostscript. - - Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author - or distributor accepts any responsibility for the consequences of using it, - or for whether it serves any particular purpose or works at all, unless he - or she says so in writing. Refer to the Aladdin Ghostscript Free Public - License (the "License") for full details. - - Every copy of Aladdin Ghostscript must include a copy of the License, - normally in a plain ASCII text file named PUBLIC. The License grants you - the right to copy, modify and redistribute Aladdin Ghostscript, but only - under certain conditions described in the License. Among other things, the - License requires that the copyright notice and this notice be preserved on - all copies. -*/ + + This file is part of Aladdin Ghostscript. + + Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author + or distributor accepts any responsibility for the consequences of using it, + or for whether it serves any particular purpose or works at all, unless he + or she says so in writing. Refer to the Aladdin Ghostscript Free Public + License (the "License") for full details. + + Every copy of Aladdin Ghostscript must include a copy of the License, + normally in a plain ASCII text file named PUBLIC. The License grants you + the right to copy, modify and redistribute Aladdin Ghostscript, but only + under certain conditions described in the License. Among other things, the + License requires that the copyright notice and this notice be preserved on + all copies. + */ /* igc.c */ /* Garbage collector for Ghostscript */ @@ -34,7 +34,7 @@ #include "igc.h" #include "igcstr.h" #include "inamedef.h" -#include "opdef.h" /* for marking oparray names */ +#include "opdef.h" /* for marking oparray names */ /* Define whether to force all garbage collections to be global. */ private bool force_global_gc = false; @@ -43,19 +43,24 @@ private bool force_global_gc = false; private bool bypass_gc = false; /* Define an entry on the mark stack. */ -typedef struct { void *ptr; uint index; bool is_refs; } ms_entry; +typedef struct { + void *ptr; + uint index; + bool is_refs; +} ms_entry; /* Define (a segment of) the mark stack. */ /* entries[0] has ptr = 0 to indicate the bottom of the stack. */ /* count additional entries follow this structure. */ typedef struct gc_mark_stack_s gc_mark_stack; struct gc_mark_stack_s { - gc_mark_stack *prev; - gc_mark_stack *next; - uint count; - bool on_heap; /* if true, allocated with gs_malloc */ - ms_entry entries[1]; + gc_mark_stack *prev; + gc_mark_stack *next; + uint count; + bool on_heap; /* if true, allocated with gs_malloc */ + ms_entry entries[1]; }; + /* Define the mark stack sizing parameters. */ #define ms_size_default 100 /* default, allocated on C stack */ /* This should probably be defined as a parameter somewhere.... */ @@ -82,10 +87,11 @@ private ptr_proc_unmark(ptr_struct_unmark); private ptr_proc_mark(ptr_struct_mark); private ptr_proc_unmark(ptr_string_unmark); private ptr_proc_mark(ptr_string_mark); -/*ptr_proc_unmark(ptr_ref_unmark);*/ /* in igc.h */ -/*ptr_proc_mark(ptr_ref_mark);*/ /* in igc.h */ -/*ptr_proc_reloc(gs_reloc_struct_ptr, void);*/ /* in gsstruct.h */ -/*ptr_proc_reloc(gs_reloc_ref_ptr, ref_packed);*/ /* in istruct.h */ + + /*ptr_proc_unmark(ptr_ref_unmark); *//* in igc.h */ + /*ptr_proc_mark(ptr_ref_mark); *//* in igc.h */ + /*ptr_proc_reloc(gs_reloc_struct_ptr, void); *//* in gsstruct.h */ + /*ptr_proc_reloc(gs_reloc_ref_ptr, ref_packed); *//* in istruct.h */ /* Pointer type descriptors. */ /* Note that the trace/mark routine has special knowledge of ptr_ref_type */ @@ -94,68 +100,72 @@ private ptr_proc_mark(ptr_string_mark); /* pointers are never called. */ typedef ptr_proc_reloc((*ptr_proc_reloc_t), void); const gs_ptr_procs_t ptr_struct_procs = - { ptr_struct_unmark, ptr_struct_mark, (ptr_proc_reloc_t)gs_reloc_struct_ptr }; +{ptr_struct_unmark, ptr_struct_mark, (ptr_proc_reloc_t) gs_reloc_struct_ptr}; const gs_ptr_procs_t ptr_string_procs = - { ptr_string_unmark, ptr_string_mark, NULL }; +{ptr_string_unmark, ptr_string_mark, NULL}; const gs_ptr_procs_t ptr_const_string_procs = - { ptr_string_unmark, ptr_string_mark, NULL }; +{ptr_string_unmark, ptr_string_mark, NULL}; const gs_ptr_procs_t ptr_ref_procs = - { ptr_ref_unmark, ptr_ref_mark, NULL }; +{ptr_ref_unmark, ptr_ref_mark, NULL}; /* ------ Main program ------ */ /* Top level of garbage collector. */ #ifdef DEBUG private void -end_phase(const char _ds *str) -{ if ( gs_debug_c('6') ) - { dprintf1("[6]---------------- end %s ----------------\n", - (const char *)str); - fflush(dstderr); - } +end_phase(const char _ds * str) +{ + if (gs_debug_c('6')) { + dprintf1("[6]---------------- end %s ----------------\n", + (const char *)str); + fflush(dstderr); + } } static const char *depth_dots_string = ".........."; private const char * -depth_dots_proc(const ms_entry *sp, const gc_mark_stack *pms) -{ int depth = sp - pms->entries - 1; - const gc_mark_stack *pss = pms; - - while ( (pss = pss->prev) != 0 ) - depth += pss->count - 1; - return depth_dots_string + (depth >= 10 ? 0 : 10 - depth); +depth_dots_proc(const ms_entry * sp, const gc_mark_stack * pms) +{ + int depth = sp - pms->entries - 1; + const gc_mark_stack *pss = pms; + + while ((pss = pss->prev) != 0) + depth += pss->count - 1; + return depth_dots_string + (depth >= 10 ? 0 : 10 - depth); } #else # define end_phase(str) DO_NOTHING #endif void -gs_reclaim(vm_spaces *pspaces, bool global) -{ vm_spaces spaces; +gs_reclaim(vm_spaces * pspaces, bool global) +{ + vm_spaces spaces; + #define nspaces (i_vm_max + 1) - gs_gc_root_t space_roots[nspaces]; - int max_trace; /* max space to trace */ - int min_collect; /* min space to collect */ - int ispace; - gs_ref_memory_t *mem; - chunk_t *cp; - gs_gc_root_t *rp; - gc_state_t state; - struct _msd { - gc_mark_stack stack; - ms_entry body[ms_size_default]; - } ms_default; - gc_mark_stack *mark_stack = &ms_default.stack; - - /* Optionally force global GC for debugging. */ - if ( force_global_gc ) - global = true; - - /* Determine which spaces we are collecting. */ - spaces = *pspaces; - if ( space_global != space_local ) - max_trace = i_vm_local; - else - max_trace = i_vm_global; - min_collect = (global ? 1 : max_trace); + gs_gc_root_t space_roots[nspaces]; + int max_trace; /* max space to trace */ + int min_collect; /* min space to collect */ + int ispace; + gs_ref_memory_t *mem; + chunk_t *cp; + gs_gc_root_t *rp; + gc_state_t state; + struct _msd { + gc_mark_stack stack; + ms_entry body[ms_size_default]; + } ms_default; + gc_mark_stack *mark_stack = &ms_default.stack; + + /* Optionally force global GC for debugging. */ + if (force_global_gc) + global = true; + + /* Determine which spaces we are collecting. */ + spaces = *pspaces; + if (space_global != space_local) + max_trace = i_vm_local; + else + max_trace = i_vm_global; + min_collect = (global ? 1 : max_trace); #define for_spaces(i, n)\ for ( i = 1; i <= n; ++i ) @@ -175,313 +185,320 @@ gs_reclaim(vm_spaces *pspaces, bool global) for_spaces(ispace, n)\ for ( mem = spaces.indexed[ispace], rp = mem->roots; rp != 0; rp = rp->next ) - /* Initialize the state. */ - state.loc.memory = spaces.named.global; /* any one will do */ - state.loc.cp = 0; - state.spaces = spaces; - state.min_collect = min_collect << r_space_shift; - state.relocating_untraced = false; + /* Initialize the state. */ + state.loc.memory = spaces.named.global; /* any one will do */ + + state.loc.cp = 0; + state.spaces = spaces; + state.min_collect = min_collect << r_space_shift; + state.relocating_untraced = false; - /* Register the allocators themselves as roots, */ - /* so we mark and relocate the change and save lists properly. */ + /* Register the allocators themselves as roots, */ + /* so we mark and relocate the change and save lists properly. */ - for_spaces(ispace, max_trace) - gs_register_struct_root((gs_memory_t *)spaces.indexed[ispace], - &space_roots[ispace], - (void **)&spaces.indexed[ispace], - "gc_top_level"); + for_spaces(ispace, max_trace) + gs_register_struct_root((gs_memory_t *) spaces.indexed[ispace], + &space_roots[ispace], + (void **)&spaces.indexed[ispace], + "gc_top_level"); - end_phase("register space roots"); + end_phase("register space roots"); #ifdef DEBUG - /* Pre-validate the state. This shouldn't be necessary.... */ + /* Pre-validate the state. This shouldn't be necessary.... */ - for_spaces(ispace, max_trace) - ialloc_validate_memory(spaces.indexed[ispace], &state); + for_spaces(ispace, max_trace) + ialloc_validate_memory(spaces.indexed[ispace], &state); - end_phase("pre-validate pointers"); + end_phase("pre-validate pointers"); #endif - if ( bypass_gc ) - { /* Don't collect at all. */ - goto no_collect; - } - - /* Clear marks in spaces to be collected. */ - - for_collected_spaces(ispace) - for_space_chunks(ispace, mem, cp) - { gc_objects_clear_marks(cp); - gc_strings_set_marks(cp, false); - } - - end_phase("clear chunk marks"); - - /* Clear the marks of roots. We must do this explicitly, */ - /* since some roots are not in any chunk. */ - - for_roots(max_trace, mem, rp) - { void *vptr = *rp->p; - if_debug_root('6', "[6]unmarking root", rp); - (*rp->ptype->unmark)(vptr, &state); - } - - end_phase("clear root marks"); - - if ( global ) - gc_unmark_names(); - - /* Initialize the (default) mark stack. */ - - gc_init_mark_stack(&ms_default.stack, ms_size_default); - ms_default.stack.prev = 0; - ms_default.stack.on_heap = false; - - /* Add all large-enough free blocks to the mark stack. */ - /* Also initialize the rescan pointers. */ - - { gc_mark_stack *end = mark_stack; - for_chunks(max_trace, mem, cp) - { uint avail = cp->ctop - cp->cbot; - if ( avail >= sizeof(gc_mark_stack) + sizeof(ms_entry) * - ms_size_min && - !cp->inner_count - ) - { gc_mark_stack *pms = (gc_mark_stack *)cp->cbot; - gc_init_mark_stack(pms, (avail - sizeof(gc_mark_stack)) / - sizeof(ms_entry)); - end->next = pms; - pms->prev = end; - pms->on_heap = false; - if_debug2('6', "[6]adding free 0x%lx(%u) to mark stack\n", - (ulong)pms, pms->count); - } - cp->rescan_bot = cp->cend; - cp->rescan_top = cp->cbase; + if (bypass_gc) { /* Don't collect at all. */ + goto no_collect; + } + /* Clear marks in spaces to be collected. */ + + for_collected_spaces(ispace) + for_space_chunks(ispace, mem, cp) { + gc_objects_clear_marks(cp); + gc_strings_set_marks(cp, false); + } + + end_phase("clear chunk marks"); + + /* Clear the marks of roots. We must do this explicitly, */ + /* since some roots are not in any chunk. */ + + for_roots(max_trace, mem, rp) { + void *vptr = *rp->p; + + if_debug_root('6', "[6]unmarking root", rp); + (*rp->ptype->unmark) (vptr, &state); + } + + end_phase("clear root marks"); + + if (global) + gc_unmark_names(); + + /* Initialize the (default) mark stack. */ + + gc_init_mark_stack(&ms_default.stack, ms_size_default); + ms_default.stack.prev = 0; + ms_default.stack.on_heap = false; + + /* Add all large-enough free blocks to the mark stack. */ + /* Also initialize the rescan pointers. */ + + { + gc_mark_stack *end = mark_stack; + + for_chunks(max_trace, mem, cp) { + uint avail = cp->ctop - cp->cbot; + + if (avail >= sizeof(gc_mark_stack) + sizeof(ms_entry) * + ms_size_min && + !cp->inner_count + ) { + gc_mark_stack *pms = (gc_mark_stack *) cp->cbot; + + gc_init_mark_stack(pms, (avail - sizeof(gc_mark_stack)) / + sizeof(ms_entry)); + end->next = pms; + pms->prev = end; + pms->on_heap = false; + if_debug2('6', "[6]adding free 0x%lx(%u) to mark stack\n", + (ulong) pms, pms->count); } + cp->rescan_bot = cp->cend; + cp->rescan_top = cp->cbase; } + } - /* Mark reachable objects. */ - - { int more = 0; + /* Mark reachable objects. */ - /* Mark from roots. */ + { + int more = 0; - for_roots(max_trace, mem, rp) - { if_debug_root('6', "[6]marking root", rp); - more |= gc_trace(rp, &state, mark_stack); - } + /* Mark from roots. */ - end_phase("mark"); + for_roots(max_trace, mem, rp) { + if_debug_root('6', "[6]marking root", rp); + more |= gc_trace(rp, &state, mark_stack); + } - /* If this is a local GC, mark from non-local chunks. */ + end_phase("mark"); - if ( !global ) - for_chunks(min_collect - 1, mem, cp) - more |= gc_trace_chunk(cp, &state, mark_stack); + /* If this is a local GC, mark from non-local chunks. */ - /* Handle mark stack overflow. */ + if (!global) + for_chunks(min_collect - 1, mem, cp) + more |= gc_trace_chunk(cp, &state, mark_stack); - while ( more < 0 ) /* stack overflowed */ - { more = 0; - for_chunks(max_trace, mem, cp) - more |= gc_rescan_chunk(cp, &state, mark_stack); - } + /* Handle mark stack overflow. */ - end_phase("mark overflow"); + while (more < 0) { /* stack overflowed */ + more = 0; + for_chunks(max_trace, mem, cp) + more |= gc_rescan_chunk(cp, &state, mark_stack); } - /* Free the mark stack. */ + end_phase("mark overflow"); + } + + /* Free the mark stack. */ - { gc_mark_stack *pms = mark_stack; + { + gc_mark_stack *pms = mark_stack; - while ( pms->next ) + while (pms->next) pms = pms->next; - while ( pms ) - { gc_mark_stack *prev = pms->prev; - uint size = sizeof(*pms) + sizeof(ms_entry) * pms->count; + while (pms) { + gc_mark_stack *prev = pms->prev; + uint size = sizeof(*pms) + sizeof(ms_entry) * pms->count; - if ( pms->on_heap ) + if (pms->on_heap) gs_free(pms, 1, size, "gc mark stack"); - else + else gs_alloc_fill(pms, gs_alloc_fill_free, size); - pms = prev; - } + pms = prev; } + } - end_phase("free mark stack"); + end_phase("free mark stack"); - if ( global ) - { - gc_trace_finish(&state); - name_trace_finish(&state); + if (global) { + gc_trace_finish(&state); + name_trace_finish(&state); - end_phase("finish trace"); - } + end_phase("finish trace"); + } + /* Clear marks and relocation in spaces that are only being traced. */ + /* We have to clear the marks first, because we want the */ + /* relocation to wind up as o_untraced, not o_unmarked. */ - /* Clear marks and relocation in spaces that are only being traced. */ - /* We have to clear the marks first, because we want the */ - /* relocation to wind up as o_untraced, not o_unmarked. */ + for_chunks(min_collect - 1, mem, cp) + gc_objects_clear_marks(cp); - for_chunks(min_collect - 1, mem, cp) - gc_objects_clear_marks(cp); + end_phase("post-clear marks"); - end_phase("post-clear marks"); + for_chunks(min_collect - 1, mem, cp) + gc_clear_reloc(cp); - for_chunks(min_collect - 1, mem, cp) - gc_clear_reloc(cp); + end_phase("clear reloc"); - end_phase("clear reloc"); + /* Set the relocation of roots outside any chunk to o_untraced, */ + /* so we won't try to relocate pointers to them. */ + /* (Currently, there aren't any.) */ - /* Set the relocation of roots outside any chunk to o_untraced, */ - /* so we won't try to relocate pointers to them. */ - /* (Currently, there aren't any.) */ + /* Disable freeing in the allocators of the spaces we are */ + /* collecting, so finalization procedures won't cause problems. */ + { + int i; - /* Disable freeing in the allocators of the spaces we are */ - /* collecting, so finalization procedures won't cause problems. */ - { int i; - for_collected_spaces(i) - gs_enable_free((gs_memory_t *)spaces.indexed[i], false); - } + for_collected_spaces(i) + gs_enable_free((gs_memory_t *) spaces.indexed[i], false); + } - /* Compute relocation based on marks, in the spaces */ - /* we are going to compact. Also finalize freed objects. */ + /* Compute relocation based on marks, in the spaces */ + /* we are going to compact. Also finalize freed objects. */ - for_collected_chunks(mem, cp) - { gc_objects_set_reloc(cp); - gc_strings_set_reloc(cp); - } + for_collected_chunks(mem, cp) { + gc_objects_set_reloc(cp); + gc_strings_set_reloc(cp); + } - /* Re-enable freeing. */ - { int i; - for_collected_spaces(i) - gs_enable_free((gs_memory_t *)spaces.indexed[i], true); - } + /* Re-enable freeing. */ + { + int i; - end_phase("set reloc"); + for_collected_spaces(i) + gs_enable_free((gs_memory_t *) spaces.indexed[i], true); + } - /* Relocate pointers. */ + end_phase("set reloc"); - state.relocating_untraced = true; - for_chunks(min_collect - 1, mem, cp) - gc_do_reloc(cp, mem, &state); - state.relocating_untraced = false; - for_collected_chunks(mem, cp) - gc_do_reloc(cp, mem, &state); + /* Relocate pointers. */ - end_phase("relocate chunks"); + state.relocating_untraced = true; + for_chunks(min_collect - 1, mem, cp) + gc_do_reloc(cp, mem, &state); + state.relocating_untraced = false; + for_collected_chunks(mem, cp) + gc_do_reloc(cp, mem, &state); - for_roots(max_trace, mem, rp) - { if_debug3('6', "[6]relocating root 0x%lx: 0x%lx -> 0x%lx\n", - (ulong)rp, (ulong)rp->p, (ulong)*rp->p); - if ( rp->ptype == ptr_ref_type ) - { ref *pref = (ref *)*rp->p; - gs_reloc_refs((ref_packed *)pref, - (ref_packed *)(pref + 1), - &state); - } - else - *rp->p = (*rp->ptype->reloc)(*rp->p, &state); - if_debug3('6', "[6]relocated root 0x%lx: 0x%lx -> 0x%lx\n", - (ulong)rp, (ulong)rp->p, (ulong)*rp->p); - } + end_phase("relocate chunks"); - end_phase("relocate roots"); + for_roots(max_trace, mem, rp) { + if_debug3('6', "[6]relocating root 0x%lx: 0x%lx -> 0x%lx\n", + (ulong) rp, (ulong) rp->p, (ulong) * rp->p); + if (rp->ptype == ptr_ref_type) { + ref *pref = (ref *) * rp->p; - /* Compact data. We only do this for spaces we are collecting. */ + gs_reloc_refs((ref_packed *) pref, + (ref_packed *) (pref + 1), + &state); + } else + *rp->p = (*rp->ptype->reloc) (*rp->p, &state); + if_debug3('6', "[6]relocated root 0x%lx: 0x%lx -> 0x%lx\n", + (ulong) rp, (ulong) rp->p, (ulong) * rp->p); + } - for_collected_spaces(ispace) - { for_space_mems(ispace, mem) - { for_mem_chunks(mem, cp) - { if_debug_chunk('6', "[6]compacting chunk", cp); - gc_objects_compact(cp, &state); - gc_strings_compact(cp); - if_debug_chunk('6', "[6]after compaction:", cp); - if ( mem->pcc == cp ) - mem->cc = *cp; - } - mem->saved = mem->reloc_saved; - ialloc_reset_free(mem); - } - } + end_phase("relocate roots"); - end_phase("compact"); + /* Compact data. We only do this for spaces we are collecting. */ - /* Free empty chunks. */ + for_collected_spaces(ispace) { + for_space_mems(ispace, mem) { + for_mem_chunks(mem, cp) { + if_debug_chunk('6', "[6]compacting chunk", cp); + gc_objects_compact(cp, &state); + gc_strings_compact(cp); + if_debug_chunk('6', "[6]after compaction:", cp); + if (mem->pcc == cp) + mem->cc = *cp; + } + mem->saved = mem->reloc_saved; + ialloc_reset_free(mem); + } + } + + end_phase("compact"); + + /* Free empty chunks. */ + + for_collected_spaces(ispace) + for_space_mems(ispace, mem) + gc_free_empty_chunks(mem); + + end_phase("free empty chunks"); + + /* + * Update previous_status to reflect any freed chunks, + * and set inherited to the negative of allocated, + * so it has no effect. We must update previous_status by + * working back-to-front along the save chain, using pointer reversal. + * (We could update inherited in any order, since it only uses + * information local to the individual save level.) + */ + + for_collected_spaces(ispace) { /* Reverse the pointers. */ + alloc_save_t *curr; + alloc_save_t *prev = 0; + alloc_save_t *next; + gs_memory_status_t total; + + for (curr = spaces.indexed[ispace]->saved; curr != 0; + prev = curr, curr = next + ) { + next = curr->state.saved; + curr->state.saved = prev; + } + /* Now work the other way, accumulating the values. */ + total.allocated = 0, total.used = 0; + for (curr = prev, prev = 0; curr != 0; + prev = curr, curr = next + ) { + mem = &curr->state; + next = mem->saved; + mem->saved = prev; + mem->previous_status = total; + if_debug3('6', + "[6]0x%lx previous allocated=%lu, used=%lu\n", + (ulong) mem, total.allocated, total.used); + gs_memory_status((gs_memory_t *) mem, &total); + mem->gc_allocated = mem->allocated + total.allocated; + mem->inherited = -mem->allocated; + } + mem = spaces.indexed[ispace]; + mem->previous_status = total; + mem->gc_allocated = mem->allocated + total.allocated; + if_debug3('6', "[6]0x%lx previous allocated=%lu, used=%lu\n", + (ulong) mem, total.allocated, total.used); + } - for_collected_spaces(ispace) - for_space_mems(ispace, mem) - gc_free_empty_chunks(mem); + end_phase("update stats"); - end_phase("free empty chunks"); + no_collect: - /* - * Update previous_status to reflect any freed chunks, - * and set inherited to the negative of allocated, - * so it has no effect. We must update previous_status by - * working back-to-front along the save chain, using pointer reversal. - * (We could update inherited in any order, since it only uses - * information local to the individual save level.) - */ + /* Unregister the allocator roots. */ - for_collected_spaces(ispace) - { /* Reverse the pointers. */ - alloc_save_t *curr; - alloc_save_t *prev = 0; - alloc_save_t *next; - gs_memory_status_t total; - - for ( curr = spaces.indexed[ispace]->saved; curr != 0; - prev = curr, curr = next - ) - { next = curr->state.saved; - curr->state.saved = prev; - } - /* Now work the other way, accumulating the values. */ - total.allocated = 0, total.used = 0; - for ( curr = prev, prev = 0; curr != 0; - prev = curr, curr = next - ) - { mem = &curr->state; - next = mem->saved; - mem->saved = prev; - mem->previous_status = total; - if_debug3('6', - "[6]0x%lx previous allocated=%lu, used=%lu\n", - (ulong)mem, total.allocated, total.used); - gs_memory_status((gs_memory_t *)mem, &total); - mem->gc_allocated = mem->allocated + total.allocated; - mem->inherited = -mem->allocated; - } - mem = spaces.indexed[ispace]; - mem->previous_status = total; - mem->gc_allocated = mem->allocated + total.allocated; - if_debug3('6', "[6]0x%lx previous allocated=%lu, used=%lu\n", - (ulong)mem, total.allocated, total.used); - } - - end_phase("update stats"); - -no_collect: - - /* Unregister the allocator roots. */ - - for_spaces(ispace, max_trace) - gs_unregister_root((gs_memory_t *)spaces.indexed[ispace], - &space_roots[ispace], "gc_top_level"); - - end_phase("unregister space roots"); + for_spaces(ispace, max_trace) + gs_unregister_root((gs_memory_t *) spaces.indexed[ispace], + &space_roots[ispace], "gc_top_level"); + + end_phase("unregister space roots"); #ifdef DEBUG - /* Validate the state. This shouldn't be necessary.... */ + /* Validate the state. This shouldn't be necessary.... */ - for_spaces(ispace, max_trace) - ialloc_validate_memory(spaces.indexed[ispace], &state); + for_spaces(ispace, max_trace) + ialloc_validate_memory(spaces.indexed[ispace], &state); - end_phase("validate pointers"); + end_phase("validate pointers"); #endif } @@ -500,130 +517,137 @@ no_collect: /* Unmark a single struct. */ private void -ptr_struct_unmark(void *vptr, gc_state_t *ignored) -{ if ( vptr != 0 ) - o_set_unmarked(((obj_header_t *)vptr - 1)); +ptr_struct_unmark(void *vptr, gc_state_t * ignored) +{ + if (vptr != 0) + o_set_unmarked(((obj_header_t *) vptr - 1)); } /* Unmark a single string. */ private void -ptr_string_unmark(void *vptr, gc_state_t *gcst) -{ discard(gc_string_mark(((gs_string *)vptr)->data, - ((gs_string *)vptr)->size, - false, gcst)); +ptr_string_unmark(void *vptr, gc_state_t * gcst) +{ + discard(gc_string_mark(((gs_string *) vptr)->data, + ((gs_string *) vptr)->size, + false, gcst)); } /* Unmark the objects in a chunk. */ private void -gc_objects_clear_marks(chunk_t *cp) -{ if_debug_chunk('6', "[6]unmarking chunk", cp); - SCAN_CHUNK_OBJECTS(cp) - DO_ALL - struct_proc_clear_marks((*proc)) = - pre->o_type->clear_marks; +gc_objects_clear_marks(chunk_t * cp) +{ + if_debug_chunk('6', "[6]unmarking chunk", cp); + SCAN_CHUNK_OBJECTS(cp) + DO_ALL + struct_proc_clear_marks((*proc)) = + pre->o_type->clear_marks; #ifdef DEBUG - if ( pre->o_type != &st_free ) - debug_check_object(pre, cp, NULL); + if (pre->o_type != &st_free) + debug_check_object(pre, cp, NULL); #endif - if_debug3('7', " [7](un)marking %s(%lu) 0x%lx\n", - struct_type_name_string(pre->o_type), - (ulong)size, (ulong)pre); - o_set_unmarked(pre); - if ( proc != 0 ) - (*proc)(pre + 1, size); - END_OBJECTS_SCAN + if_debug3('7', " [7](un)marking %s(%lu) 0x%lx\n", + struct_type_name_string(pre->o_type), + (ulong) size, (ulong) pre); + o_set_unmarked(pre); + if (proc != 0) + (*proc) (pre + 1, size); + END_OBJECTS_SCAN } /* Mark 0- and 1-character names, and those referenced from the */ /* op_array_nx_table, and unmark all the rest. */ private void gc_unmark_names(void) -{ register uint i; - name_unmark_all(); - for ( i = 0; i < op_array_table_global.count; i++ ) - { uint nidx = op_array_table_global.nx_table[i]; - name_index_ptr(nidx)->mark = 1; - } - for ( i = 0; i < op_array_table_local.count; i++ ) - { uint nidx = op_array_table_local.nx_table[i]; - name_index_ptr(nidx)->mark = 1; - } +{ + register uint i; + + name_unmark_all(); + for (i = 0; i < op_array_table_global.count; i++) { + uint nidx = op_array_table_global.nx_table[i]; + + name_index_ptr(nidx)->mark = 1; + } + for (i = 0; i < op_array_table_local.count; i++) { + uint nidx = op_array_table_local.nx_table[i]; + + name_index_ptr(nidx)->mark = 1; + } } /* ------ Marking phase ------ */ /* Initialize (a segment of) the mark stack. */ private void -gc_init_mark_stack(gc_mark_stack *pms, uint count) -{ pms->next = 0; - pms->count = count; - pms->entries[0].ptr = 0; - pms->entries[0].index = 0; - pms->entries[0].is_refs = false; +gc_init_mark_stack(gc_mark_stack * pms, uint count) +{ + pms->next = 0; + pms->count = count; + pms->entries[0].ptr = 0; + pms->entries[0].index = 0; + pms->entries[0].is_refs = false; } /* Mark starting from all marked objects in the interval of a chunk */ /* needing rescanning. */ private int -gc_rescan_chunk(chunk_t *cp, gc_state_t *pstate, gc_mark_stack *pmstack) -{ byte *sbot = cp->rescan_bot; - byte *stop = cp->rescan_top; - gs_gc_root_t root; - void *comp; - int more = 0; - - if ( sbot > stop ) - return 0; - root.p = ∁ - if_debug_chunk('6', "[6]rescanning chunk", cp); - cp->rescan_bot = cp->cend; - cp->rescan_top = cp->cbase; - SCAN_CHUNK_OBJECTS(cp) - DO_ALL - if ( (byte *)(pre + 1) + size < sbot ) - ; - else if ( (byte *)(pre + 1) > stop ) - return more; /* 'break' won't work here */ - else - { if_debug2('7', " [7]scanning/marking 0x%lx(%lu)\n", - (ulong)pre, (ulong)size); - if ( pre->o_type == &st_refs ) - { ref_packed *rp = (ref_packed *)(pre + 1); - char *end = (char *)rp + size; - root.ptype = ptr_ref_type; - while ( (char *)rp < end ) - { comp = rp; - if ( r_is_packed(rp) ) - { if ( r_has_pmark(rp) ) - { r_clear_pmark(rp); - more |= gc_trace(&root, pstate, - pmstack); - } - rp++; - } - else - { if ( r_has_attr((ref *)rp, l_mark) ) - { r_clear_attrs((ref *)rp, l_mark); - more |= gc_trace(&root, pstate, - pmstack); - } - rp += packed_per_ref; - } - } - } - else if ( !o_is_unmarked(pre) ) - { struct_proc_clear_marks((*proc)) = - pre->o_type->clear_marks; - root.ptype = ptr_struct_type; - comp = pre + 1; - if ( !o_is_untraced(pre) ) - o_set_unmarked(pre); - if ( proc != 0 ) - (*proc)(comp, size); - more |= gc_trace(&root, pstate, pmstack); - } - } - END_OBJECTS_SCAN +gc_rescan_chunk(chunk_t * cp, gc_state_t * pstate, gc_mark_stack * pmstack) +{ + byte *sbot = cp->rescan_bot; + byte *stop = cp->rescan_top; + gs_gc_root_t root; + void *comp; + int more = 0; + + if (sbot > stop) + return 0; + root.p = ∁ + if_debug_chunk('6', "[6]rescanning chunk", cp); + cp->rescan_bot = cp->cend; + cp->rescan_top = cp->cbase; + SCAN_CHUNK_OBJECTS(cp) + DO_ALL + if ((byte *) (pre + 1) + size < sbot); + else if ((byte *) (pre + 1) > stop) + return more; /* 'break' won't work here */ + else { + if_debug2('7', " [7]scanning/marking 0x%lx(%lu)\n", + (ulong) pre, (ulong) size); + if (pre->o_type == &st_refs) { + ref_packed *rp = (ref_packed *) (pre + 1); + char *end = (char *)rp + size; + + root.ptype = ptr_ref_type; + while ((char *)rp < end) { + comp = rp; + if (r_is_packed(rp)) { + if (r_has_pmark(rp)) { + r_clear_pmark(rp); + more |= gc_trace(&root, pstate, + pmstack); + } + rp++; + } else { + if (r_has_attr((ref *) rp, l_mark)) { + r_clear_attrs((ref *) rp, l_mark); + more |= gc_trace(&root, pstate, + pmstack); + } + rp += packed_per_ref; + } + } + } else if (!o_is_unmarked(pre)) { + struct_proc_clear_marks((*proc)) = + pre->o_type->clear_marks; + root.ptype = ptr_struct_type; + comp = pre + 1; + if (!o_is_untraced(pre)) + o_set_unmarked(pre); + if (proc != 0) + (*proc) (comp, size); + more |= gc_trace(&root, pstate, pmstack); + } + } + END_OBJECTS_SCAN return more; } @@ -631,55 +655,54 @@ gc_rescan_chunk(chunk_t *cp, gc_state_t *pstate, gc_mark_stack *pmstack) /* We assume that pstate->min_collect > avm_system, */ /* so we don't have to trace names. */ private int -gc_trace_chunk(chunk_t *cp, gc_state_t *pstate, gc_mark_stack *pmstack) -{ gs_gc_root_t root; - void *comp; - int more = 0; - int min_trace = pstate->min_collect; - - root.p = ∁ - if_debug_chunk('6', "[6]marking from chunk", cp); - SCAN_CHUNK_OBJECTS(cp) - DO_ALL - { if_debug2('7', " [7]scanning/marking 0x%lx(%lu)\n", - (ulong)pre, (ulong)size); - if ( pre->o_type == &st_refs ) - { ref_packed *rp = (ref_packed *)(pre + 1); - char *end = (char *)rp + size; - - root.ptype = ptr_ref_type; - while ( (char *)rp < end ) - { comp = rp; - if ( r_is_packed(rp) ) - { /* No packed refs need tracing. */ - rp++; - } - else - { if ( r_space((ref *)rp) >= min_trace ) - { r_clear_attrs((ref *)rp, l_mark); - more |= gc_trace(&root, pstate, - pmstack); - } - rp += packed_per_ref; - } - } - } - else if ( !o_is_unmarked(pre) ) - { if ( !o_is_untraced(pre) ) - o_set_unmarked(pre); - if ( pre->o_type != &st_free ) - { struct_proc_clear_marks((*proc)) = - pre->o_type->clear_marks; - - root.ptype = ptr_struct_type; - comp = pre + 1; - if ( proc != 0 ) - (*proc)(comp, size); - more |= gc_trace(&root, pstate, pmstack); - } - } - } - END_OBJECTS_SCAN +gc_trace_chunk(chunk_t * cp, gc_state_t * pstate, gc_mark_stack * pmstack) +{ + gs_gc_root_t root; + void *comp; + int more = 0; + int min_trace = pstate->min_collect; + + root.p = ∁ + if_debug_chunk('6', "[6]marking from chunk", cp); + SCAN_CHUNK_OBJECTS(cp) + DO_ALL + { + if_debug2('7', " [7]scanning/marking 0x%lx(%lu)\n", + (ulong) pre, (ulong) size); + if (pre->o_type == &st_refs) { + ref_packed *rp = (ref_packed *) (pre + 1); + char *end = (char *)rp + size; + + root.ptype = ptr_ref_type; + while ((char *)rp < end) { + comp = rp; + if (r_is_packed(rp)) { /* No packed refs need tracing. */ + rp++; + } else { + if (r_space((ref *) rp) >= min_trace) { + r_clear_attrs((ref *) rp, l_mark); + more |= gc_trace(&root, pstate, + pmstack); + } + rp += packed_per_ref; + } + } + } else if (!o_is_unmarked(pre)) { + if (!o_is_untraced(pre)) + o_set_unmarked(pre); + if (pre->o_type != &st_free) { + struct_proc_clear_marks((*proc)) = + pre->o_type->clear_marks; + + root.ptype = ptr_struct_type; + comp = pre + 1; + if (proc != 0) + (*proc) (comp, size); + more |= gc_trace(&root, pstate, pmstack); + } + } + } + END_OBJECTS_SCAN return more; } @@ -689,18 +712,22 @@ gc_trace_chunk(chunk_t *cp, gc_state_t *pstate, gc_mark_stack *pmstack) /* 1 if we completed and marked some new objects. */ private int gc_extend_stack(P2(gc_mark_stack *, gc_state_t *)); private int -gc_trace(gs_gc_root_t *rp, gc_state_t *pstate, gc_mark_stack *pmstack) -{ int min_trace = pstate->min_collect; - gc_mark_stack *pms = pmstack; - ms_entry *sp = pms->entries + 1; - /* We stop the mark stack 1 entry early, because we store into */ - /* the entry beyond the top. */ - ms_entry *stop = sp + pms->count - 2; +gc_trace(gs_gc_root_t * rp, gc_state_t * pstate, gc_mark_stack * pmstack) +{ + int min_trace = pstate->min_collect; + gc_mark_stack *pms = pmstack; + ms_entry *sp = pms->entries + 1; + + /* We stop the mark stack 1 entry early, because we store into */ + /* the entry beyond the top. */ + ms_entry *stop = sp + pms->count - 2; + #ifdef DEBUG # define depth_dots depth_dots_proc(sp, pms) #endif - int new = 0; - void *nptr = *rp->p; + int new = 0; + void *nptr = *rp->p; + #define mark_name(nidx, pname)\ { if ( !pname->mark )\ { pname->mark = 1;\ @@ -709,391 +736,394 @@ gc_trace(gs_gc_root_t *rp, gc_state_t *pstate, gc_mark_stack *pmstack) }\ } - if ( nptr == 0 ) - return 0; - - /* Initialize the stack */ - sp->ptr = nptr; - if ( rp->ptype == ptr_ref_type ) - sp->index = 1, sp->is_refs = true; - else - { sp->index = 0, sp->is_refs = false; - if ( (*rp->ptype->mark)(nptr, pstate) ) - new |= 1; - } - for ( ; ; ) - { gs_ptr_type_t ptp; - /* - * The following should really be an if..else, but that - * would force unnecessary is_refs tests. - */ - if ( sp->is_refs ) - goto do_refs; + if (nptr == 0) + return 0; + + /* Initialize the stack */ + sp->ptr = nptr; + if (rp->ptype == ptr_ref_type) + sp->index = 1, sp->is_refs = true; + else { + sp->index = 0, sp->is_refs = false; + if ((*rp->ptype->mark) (nptr, pstate)) + new |= 1; + } + for (;;) { + gs_ptr_type_t ptp; + + /* + * The following should really be an if..else, but that + * would force unnecessary is_refs tests. + */ + if (sp->is_refs) + goto do_refs; /* ---------------- Structure ---------------- */ -do_struct: - { obj_header_t *ptr = sp->ptr; - struct_proc_enum_ptrs((*mproc)); - - if ( ptr == 0 ) - { /* We've reached the bottom of a stack segment. */ - pms = pms->prev; - if ( pms == 0 ) - break; /* all done */ - stop = pms->entries + pms->count - 1; - sp = stop; - continue; - } - debug_check_object(ptr - 1, NULL, NULL); -ts: if_debug4('7', " [7]%smarking %s 0x%lx[%u]", - depth_dots, - struct_type_name_string(ptr[-1].o_type), - (ulong)ptr, sp->index); - mproc = ptr[-1].o_type->enum_ptrs; - /* The cast in the following statement is the one */ - /* place we need to break 'const' to make the */ - /* template for pointer enumeration work. */ - if ( mproc == 0 || - (ptp = (*mproc) - (ptr, pre_obj_contents_size(ptr - 1), - sp->index, (const void **)&nptr)) == 0 - ) - { if_debug0('7', " - done\n"); - sp--; - continue; - } - sp->index++; - if_debug1('7', " = 0x%lx\n", (ulong)nptr); - /* Descend into nptr, whose pointer type is ptp. */ - if ( ptp == ptr_struct_type ) - { sp[1].index = 0; - sp[1].is_refs = false; - if ( sp == stop ) - goto push; - if ( !ptr_struct_mark(nptr, pstate) ) - goto ts; - new |= 1; - (++sp)->ptr = nptr; - goto do_struct; - } - else if ( ptp == ptr_ref_type ) - { sp[1].index = 1; - sp[1].is_refs = true; - if ( sp == stop ) - goto push; - new |= 1; - (++sp)->ptr = nptr; - goto do_refs; - } - else - { /* We assume this is some non-pointer- */ - /* containing type. */ - if ( (*ptp->mark)(nptr, pstate) ) - new |= 1; - goto ts; - } - } + do_struct: + { + obj_header_t *ptr = sp->ptr; + + struct_proc_enum_ptrs((*mproc)); + + if (ptr == 0) { /* We've reached the bottom of a stack segment. */ + pms = pms->prev; + if (pms == 0) + break; /* all done */ + stop = pms->entries + pms->count - 1; + sp = stop; + continue; + } + debug_check_object(ptr - 1, NULL, NULL); + ts:if_debug4('7', " [7]%smarking %s 0x%lx[%u]", + depth_dots, + struct_type_name_string(ptr[-1].o_type), + (ulong) ptr, sp->index); + mproc = ptr[-1].o_type->enum_ptrs; + /* The cast in the following statement is the one */ + /* place we need to break 'const' to make the */ + /* template for pointer enumeration work. */ + if (mproc == 0 || + (ptp = (*mproc) + (ptr, pre_obj_contents_size(ptr - 1), + sp->index, (const void **)&nptr)) == 0 + ) { + if_debug0('7', " - done\n"); + sp--; + continue; + } + sp->index++; + if_debug1('7', " = 0x%lx\n", (ulong) nptr); + /* Descend into nptr, whose pointer type is ptp. */ + if (ptp == ptr_struct_type) { + sp[1].index = 0; + sp[1].is_refs = false; + if (sp == stop) + goto push; + if (!ptr_struct_mark(nptr, pstate)) + goto ts; + new |= 1; + (++sp)->ptr = nptr; + goto do_struct; + } else if (ptp == ptr_ref_type) { + sp[1].index = 1; + sp[1].is_refs = true; + if (sp == stop) + goto push; + new |= 1; + (++sp)->ptr = nptr; + goto do_refs; + } else { /* We assume this is some non-pointer- */ + /* containing type. */ + if ((*ptp->mark) (nptr, pstate)) + new |= 1; + goto ts; + } + } /* ---------------- Refs ---------------- */ -do_refs: - { ref_packed *pptr = sp->ptr; + do_refs: + { + ref_packed *pptr = sp->ptr; -tr: if ( !sp->index ) - { --sp; - continue; - } - --(sp->index); - if_debug3('8', " [8]%smarking refs 0x%lx[%u]\n", - depth_dots, (ulong)pptr, sp->index); + tr:if (!sp->index) { + --sp; + continue; + } + --(sp->index); + if_debug3('8', " [8]%smarking refs 0x%lx[%u]\n", + depth_dots, (ulong) pptr, sp->index); #define rptr ((ref *)pptr) - if ( r_is_packed(rptr) ) - { if ( !r_has_pmark(pptr) ) - { r_set_pmark(pptr); - new |= 1; - if ( r_packed_is_name(pptr) ) - { uint nidx = packed_name_index(pptr); - name *pname = name_index_ptr(nidx); - mark_name(nidx, pname); - } - } - ++pptr; - goto tr; - } - if ( r_has_attr(rptr, l_mark) ) - { pptr = (ref_packed *)(rptr + 1); - goto tr; - } - r_set_attrs(rptr, l_mark); + if (r_is_packed(rptr)) { + if (!r_has_pmark(pptr)) { + r_set_pmark(pptr); + new |= 1; + if (r_packed_is_name(pptr)) { + uint nidx = packed_name_index(pptr); + name *pname = name_index_ptr(nidx); + + mark_name(nidx, pname); + } + } + ++pptr; + goto tr; + } + if (r_has_attr(rptr, l_mark)) { + pptr = (ref_packed *) (rptr + 1); + goto tr; + } + r_set_attrs(rptr, l_mark); + new |= 1; + if (r_space(rptr) < min_trace) { /* Note that this always picks up all scalars. */ + pptr = (ref_packed *) (rptr + 1); + goto tr; + } + sp->ptr = rptr + 1; + switch (r_type(rptr)) { + /* Struct cases */ + case t_file: + nptr = rptr->value.pfile; + rs:sp[1].is_refs = false; + sp[1].index = 0; + if (sp == stop) { + ptp = ptr_struct_type; + break; + } + if (!ptr_struct_mark(nptr, pstate)) + goto nr; + new |= 1; + (++sp)->ptr = nptr; + goto do_struct; + case t_device: + nptr = rptr->value.pdevice; + goto rs; + case t_fontID: + case t_struct: + case t_astruct: + nptr = rptr->value.pstruct; + goto rs; + /* Non-trivial non-struct cases */ + case t_dictionary: + nptr = rptr->value.pdict; + sp[1].index = sizeof(dict) / sizeof(ref); + goto rrp; + case t_array: + nptr = rptr->value.refs; + rr:if ((sp[1].index = r_size(rptr)) == 0) { /* Set the base pointer to 0, */ + /* so we never try to relocate it. */ + rptr->value.refs = 0; + goto nr; + } + rrp: + rrc:sp[1].is_refs = true; + if (sp == stop) + break; + new |= 1; + (++sp)->ptr = nptr; + goto do_refs; + case t_mixedarray: + case t_shortarray: + nptr = (void *)rptr->value.packed; /* discard const */ + goto rr; + case t_name: + mark_name(name_index(rptr), rptr->value.pname); + nr:pptr = (ref_packed *) (rptr + 1); + goto tr; + case t_string: + if (gc_string_mark(rptr->value.bytes, r_size(rptr), true, pstate)) new |= 1; - if ( r_space(rptr) < min_trace ) - { /* Note that this always picks up all scalars. */ - pptr = (ref_packed *)(rptr + 1); - goto tr; - } - sp->ptr = rptr + 1; - switch ( r_type(rptr) ) - { - /* Struct cases */ - case t_file: - nptr = rptr->value.pfile; -rs: sp[1].is_refs = false; - sp[1].index = 0; - if ( sp == stop ) - { ptp = ptr_struct_type; - break; - } - if ( !ptr_struct_mark(nptr, pstate) ) - goto nr; - new |= 1; - (++sp)->ptr = nptr; - goto do_struct; - case t_device: - nptr = rptr->value.pdevice; - goto rs; - case t_fontID: - case t_struct: - case t_astruct: - nptr = rptr->value.pstruct; - goto rs; - /* Non-trivial non-struct cases */ - case t_dictionary: - nptr = rptr->value.pdict; - sp[1].index = sizeof(dict) / sizeof(ref); - goto rrp; - case t_array: - nptr = rptr->value.refs; -rr: if ( (sp[1].index = r_size(rptr)) == 0 ) - { /* Set the base pointer to 0, */ - /* so we never try to relocate it. */ - rptr->value.refs = 0; - goto nr; - } -rrp: -rrc: sp[1].is_refs = true; - if ( sp == stop ) - break; - new |= 1; - (++sp)->ptr = nptr; - goto do_refs; - case t_mixedarray: case t_shortarray: - nptr = (void *)rptr->value.packed; /* discard const */ - goto rr; - case t_name: - mark_name(name_index(rptr), rptr->value.pname); -nr: pptr = (ref_packed *)(rptr + 1); - goto tr; - case t_string: - if ( gc_string_mark(rptr->value.bytes, r_size(rptr), true, pstate) ) - new |= 1; - goto nr; - case t_oparray: - nptr = (void *)rptr->value.const_refs; /* discard const */ - sp[1].index = 1; - goto rrc; - default: - goto nr; - } + goto nr; + case t_oparray: + nptr = (void *)rptr->value.const_refs; /* discard const */ + sp[1].index = 1; + goto rrc; + default: + goto nr; + } #undef rptr - } + } /* ---------------- Recursion ---------------- */ -push: - if ( sp == stop ) - { /* The current segment is full. */ - int new_added = gc_extend_stack(pms, pstate); - if ( new_added ) - { new |= new_added; - continue; - } - pms = pms->next; - stop = pms->entries + pms->count - 1; - pms->entries[1] = sp[1]; - sp = pms->entries; - } - /* index and is_refs are already set */ - if ( !sp[1].is_refs ) - { if ( !(*ptp->mark)(nptr, pstate) ) - continue; - new |= 1; - } - (++sp)->ptr = nptr; + push: + if (sp == stop) { /* The current segment is full. */ + int new_added = gc_extend_stack(pms, pstate); + + if (new_added) { + new |= new_added; + continue; + } + pms = pms->next; + stop = pms->entries + pms->count - 1; + pms->entries[1] = sp[1]; + sp = pms->entries; + } + /* index and is_refs are already set */ + if (!sp[1].is_refs) { + if (!(*ptp->mark) (nptr, pstate)) + continue; + new |= 1; } - return new; + (++sp)->ptr = nptr; + } + return new; } /* Link to, attempting to allocate if necessary, */ /* another chunk of mark stack. */ private int -gc_extend_stack(gc_mark_stack *pms, gc_state_t *pstate) -{ if ( pms->next == 0 ) - { /* Try to allocate another segment. */ - uint count; - - for ( count = ms_size_desired; count >= ms_size_min; count >>= 1 ) - { pms->next = - gs_malloc(1, sizeof(gc_mark_stack) + - sizeof(ms_entry) * count, - "gc mark stack"); - if ( pms->next != 0 ) - break; - } - if ( pms->next == 0 ) - { /* The mark stack overflowed. */ - ms_entry *sp = pms->entries + pms->count - 1; - byte *cptr = sp->ptr; /* container */ - chunk_t *cp = gc_locate(cptr, pstate); - int new = 1; - - if ( cp == 0 ) - { /* We were tracing outside collectible */ - /* storage. This can't happen. */ - lprintf1("mark stack overflowed while outside collectible space at 0x%lx!\n", - (ulong)cptr); - gs_abort(); - } - if ( cptr < cp->rescan_bot ) - cp->rescan_bot = cptr, new = -1; - if ( cptr > cp->rescan_top ) - cp->rescan_top = cptr, new = -1; - return new; - } - gc_init_mark_stack(pms->next, count); - pms->next->prev = pms; - pms->next->on_heap = true; - } - return 0; +gc_extend_stack(gc_mark_stack * pms, gc_state_t * pstate) +{ + if (pms->next == 0) { /* Try to allocate another segment. */ + uint count; + + for (count = ms_size_desired; count >= ms_size_min; count >>= 1) { + pms->next = + gs_malloc(1, sizeof(gc_mark_stack) + + sizeof(ms_entry) * count, + "gc mark stack"); + if (pms->next != 0) + break; + } + if (pms->next == 0) { /* The mark stack overflowed. */ + ms_entry *sp = pms->entries + pms->count - 1; + byte *cptr = sp->ptr; /* container */ + chunk_t *cp = gc_locate(cptr, pstate); + int new = 1; + + if (cp == 0) { /* We were tracing outside collectible */ + /* storage. This can't happen. */ + lprintf1("mark stack overflowed while outside collectible space at 0x%lx!\n", + (ulong) cptr); + gs_abort(); + } + if (cptr < cp->rescan_bot) + cp->rescan_bot = cptr, new = -1; + if (cptr > cp->rescan_top) + cp->rescan_top = cptr, new = -1; + return new; + } + gc_init_mark_stack(pms->next, count); + pms->next->prev = pms; + pms->next->on_heap = true; + } + return 0; } /* Mark a struct. Return true if new mark. */ private bool -ptr_struct_mark(void *vptr, gc_state_t *ignored) -{ obj_header_t *ptr = vptr; - if ( vptr == 0 ) - return false; - ptr--; /* point to header */ - if ( !o_is_unmarked(ptr) ) - return false; - o_mark(ptr); - return true; +ptr_struct_mark(void *vptr, gc_state_t * ignored) +{ + obj_header_t *ptr = vptr; + + if (vptr == 0) + return false; + ptr--; /* point to header */ + if (!o_is_unmarked(ptr)) + return false; + o_mark(ptr); + return true; } /* Mark a string. Return true if new mark. */ private bool -ptr_string_mark(void *vptr, gc_state_t *gcst) -{ return gc_string_mark(((gs_string *)vptr)->data, - ((gs_string *)vptr)->size, - true, gcst); +ptr_string_mark(void *vptr, gc_state_t * gcst) +{ + return gc_string_mark(((gs_string *) vptr)->data, + ((gs_string *) vptr)->size, + true, gcst); } /* Finish tracing by marking names. */ private bool -gc_trace_finish(gc_state_t *pstate) -{ uint nidx = 0; - bool marked = false; - while ( (nidx = name_next_valid_index(nidx)) != 0 ) - { name *pname = name_index_ptr(nidx); - if ( pname->mark ) - { if ( !pname->foreign_string && gc_string_mark(pname->string_bytes, pname->string_size, true, pstate) ) - marked = true; - marked |= ptr_struct_mark(name_index_ptr_sub_table(nidx, pname), pstate); - } +gc_trace_finish(gc_state_t * pstate) +{ + uint nidx = 0; + bool marked = false; + + while ((nidx = name_next_valid_index(nidx)) != 0) { + name *pname = name_index_ptr(nidx); + + if (pname->mark) { + if (!pname->foreign_string && gc_string_mark(pname->string_bytes, pname->string_size, true, pstate)) + marked = true; + marked |= ptr_struct_mark(name_index_ptr_sub_table(nidx, pname), pstate); } - return marked; + } + return marked; } /* ------ Relocation planning phase ------ */ /* Initialize the relocation information in the chunk header. */ private void -gc_init_reloc(chunk_t *cp) -{ chunk_head_t *chead = cp->chead; - chead->dest = cp->cbase; - chead->free.o_back = - offset_of(chunk_head_t, free) >> obj_back_shift; - chead->free.o_size = sizeof(obj_header_t); - chead->free.o_nreloc = 0; +gc_init_reloc(chunk_t * cp) +{ + chunk_head_t *chead = cp->chead; + + chead->dest = cp->cbase; + chead->free.o_back = + offset_of(chunk_head_t, free) >> obj_back_shift; + chead->free.o_size = sizeof(obj_header_t); + chead->free.o_nreloc = 0; } /* Set marks and clear relocation for chunks that won't be compacted. */ private void -gc_clear_reloc(chunk_t *cp) -{ byte *pfree = (byte *)&cp->chead->free; - - gc_init_reloc(cp); - SCAN_CHUNK_OBJECTS(cp) - DO_ALL - const struct_shared_procs_t _ds *procs = - pre->o_type->shared; - - if ( procs != 0 ) - (*procs->clear_reloc)(pre, size); - o_set_untraced(pre); - if ( !pre->o_large ) - pre->o_back = ((byte *)pre - pfree) >> obj_back_shift; - END_OBJECTS_SCAN +gc_clear_reloc(chunk_t * cp) +{ + byte *pfree = (byte *) & cp->chead->free; + + gc_init_reloc(cp); + SCAN_CHUNK_OBJECTS(cp) + DO_ALL + const struct_shared_procs_t _ds *procs = + pre->o_type->shared; + + if (procs != 0) + (*procs->clear_reloc) (pre, size); + o_set_untraced(pre); + if (!pre->o_large) + pre->o_back = ((byte *) pre - pfree) >> obj_back_shift; + END_OBJECTS_SCAN gc_strings_set_marks(cp, true); - gc_strings_clear_reloc(cp); + gc_strings_clear_reloc(cp); } /* Set the relocation for the objects in a chunk. */ /* This will never be called for a chunk with any o_untraced objects. */ private void -gc_objects_set_reloc(chunk_t *cp) -{ uint reloc = 0; - chunk_head_t *chead = cp->chead; - byte *pfree = (byte *)&chead->free; /* most recent free object */ - if_debug_chunk('6', "[6]setting reloc for chunk", cp); - gc_init_reloc(cp); - SCAN_CHUNK_OBJECTS(cp) - DO_ALL - struct_proc_finalize((*finalize)); - const struct_shared_procs_t _ds *procs = - pre->o_type->shared; - if ( (procs == 0 ? o_is_unmarked(pre) : - !(*procs->set_reloc)(pre, reloc, size)) - ) - { /* Free object */ - reloc += sizeof(obj_header_t) + obj_align_round(size); - if ( (finalize = pre->o_type->finalize) != 0 ) - { if_debug2('u', "[u]GC finalizing %s 0x%lx\n", - struct_type_name_string(pre->o_type), - (ulong)(pre + 1)); - (*finalize)(pre + 1); - } - if ( pre->o_large ) - { /* We should chop this up into small */ - /* free blocks, but there's no value */ - /* in doing this right now. */ - o_set_unmarked_large(pre); - } - else - { pfree = (byte *)pre; - pre->o_back = - (pfree - (byte *)chead) >> obj_back_shift; - pre->o_nreloc = reloc; - } - if_debug3('7', " [7]at 0x%lx, unmarked %lu, new reloc = %u\n", - (ulong)pre, (ulong)size, reloc); - } - else - { /* Useful object */ - debug_check_object(pre, cp, NULL); - if ( pre->o_large ) - { if ( o_is_unmarked_large(pre) ) - o_mark_large(pre); - } - else - pre->o_back = - ((byte *)pre - pfree) >> obj_back_shift; - } - END_OBJECTS_SCAN -#ifdef DEBUG - if ( reloc != 0 ) - { if_debug1('6', "[6]freed %u", reloc); - if_debug_chunk('6', " in", cp); +gc_objects_set_reloc(chunk_t * cp) +{ + uint reloc = 0; + chunk_head_t *chead = cp->chead; + byte *pfree = (byte *) & chead->free; /* most recent free object */ + + if_debug_chunk('6', "[6]setting reloc for chunk", cp); + gc_init_reloc(cp); + SCAN_CHUNK_OBJECTS(cp) + DO_ALL + struct_proc_finalize((*finalize)); + const struct_shared_procs_t _ds *procs = + pre->o_type->shared; + + if ((procs == 0 ? o_is_unmarked(pre) : + !(*procs->set_reloc) (pre, reloc, size)) + ) { /* Free object */ + reloc += sizeof(obj_header_t) + obj_align_round(size); + if ((finalize = pre->o_type->finalize) != 0) { + if_debug2('u', "[u]GC finalizing %s 0x%lx\n", + struct_type_name_string(pre->o_type), + (ulong) (pre + 1)); + (*finalize) (pre + 1); + } + if (pre->o_large) { /* We should chop this up into small */ + /* free blocks, but there's no value */ + /* in doing this right now. */ + o_set_unmarked_large(pre); + } else { + pfree = (byte *) pre; + pre->o_back = + (pfree - (byte *) chead) >> obj_back_shift; + pre->o_nreloc = reloc; } + if_debug3('7', " [7]at 0x%lx, unmarked %lu, new reloc = %u\n", + (ulong) pre, (ulong) size, reloc); + } else { /* Useful object */ + debug_check_object(pre, cp, NULL); + if (pre->o_large) { + if (o_is_unmarked_large(pre)) + o_mark_large(pre); + } else + pre->o_back = + ((byte *) pre - pfree) >> obj_back_shift; + } + END_OBJECTS_SCAN +#ifdef DEBUG + if (reloc != 0) { + if_debug1('6', "[6]freed %u", reloc); + if_debug_chunk('6', " in", cp); + } #endif } @@ -1101,30 +1131,32 @@ gc_objects_set_reloc(chunk_t *cp) /* Relocate the pointers in all the objects in a chunk. */ private void -gc_do_reloc(chunk_t *cp, gs_ref_memory_t *mem, gc_state_t *pstate) -{ chunk_head_t *chead = cp->chead; - if_debug_chunk('6', "[6]relocating in chunk", cp); - SCAN_CHUNK_OBJECTS(cp) - DO_ALL - /* We need to relocate the pointers in an object iff */ - /* it is o_untraced, or it is a useful object. */ - /* An object is free iff its back pointer points to */ - /* the chunk_head structure. */ - if ( o_is_untraced(pre) || - (pre->o_large ? !o_is_unmarked(pre) : - pre->o_back << obj_back_shift != - (byte *)pre - (byte *)chead) - ) - { struct_proc_reloc_ptrs((*proc)) = - pre->o_type->reloc_ptrs; - if_debug3('7', - " [7]relocating ptrs in %s(%lu) 0x%lx\n", - struct_type_name_string(pre->o_type), - (ulong)size, (ulong)pre); - if ( proc != 0 ) - (*proc)(pre + 1, size, pstate); - } - END_OBJECTS_SCAN +gc_do_reloc(chunk_t * cp, gs_ref_memory_t * mem, gc_state_t * pstate) +{ + chunk_head_t *chead = cp->chead; + + if_debug_chunk('6', "[6]relocating in chunk", cp); + SCAN_CHUNK_OBJECTS(cp) + DO_ALL + /* We need to relocate the pointers in an object iff */ + /* it is o_untraced, or it is a useful object. */ + /* An object is free iff its back pointer points to */ + /* the chunk_head structure. */ + if (o_is_untraced(pre) || + (pre->o_large ? !o_is_unmarked(pre) : + pre->o_back << obj_back_shift != + (byte *) pre - (byte *) chead) + ) { + struct_proc_reloc_ptrs((*proc)) = + pre->o_type->reloc_ptrs; + if_debug3('7', + " [7]relocating ptrs in %s(%lu) 0x%lx\n", + struct_type_name_string(pre->o_type), + (ulong) size, (ulong) pre); + if (proc != 0) + (*proc) (pre + 1, size, pstate); + } + END_OBJECTS_SCAN } /* Print pointer relocation if debugging. */ @@ -1132,54 +1164,58 @@ gc_do_reloc(chunk_t *cp, gs_ref_memory_t *mem, gc_state_t *pstate) /* in case one of the other GC modules was compiled with DEBUG. */ void * print_reloc_proc(const void *obj, const char *cname, void *robj) -{ if_debug3('9', " [9]relocate %s * 0x%lx to 0x%lx\n", - cname, (ulong)obj, (ulong)robj); - return robj; +{ + if_debug3('9', " [9]relocate %s * 0x%lx to 0x%lx\n", + cname, (ulong) obj, (ulong) robj); + return robj; } /* Relocate a pointer to an (aligned) object. */ /* See gsmemory.h for why the argument is const and the result is not. */ -void /*obj_header_t*/ * -gs_reloc_struct_ptr(const void /*obj_header_t*/ *obj, gc_state_t *gcst) -{ const void *robj; +void /*obj_header_t */ * +gs_reloc_struct_ptr(const void /*obj_header_t */ *obj, gc_state_t * gcst) +{ + const void *robj; - if ( obj == 0 ) - return print_reloc(obj, "NULL", 0); + if (obj == 0) + return print_reloc(obj, "NULL", 0); #define optr ((const obj_header_t *)obj) - debug_check_object(optr - 1, NULL, gcst); - /* The following should be a conditional expression, */ - /* but Sun's cc compiler can't handle it. */ - if ( optr[-1].o_large ) - robj = obj; - else - { uint back = optr[-1].o_back; - if ( back == o_untraced ) - robj = obj; - else - { + debug_check_object(optr - 1, NULL, gcst); + /* The following should be a conditional expression, */ + /* but Sun's cc compiler can't handle it. */ + if (optr[-1].o_large) + robj = obj; + else { + uint back = optr[-1].o_back; + + if (back == o_untraced) + robj = obj; + else { #ifdef DEBUG - /* Do some sanity checking. */ - if ( back > gcst->space_local->chunk_size >> obj_back_shift ) - { lprintf2("Invalid back pointer %u at 0x%lx!\n", - back, (ulong)obj); - gs_abort(); - } + /* Do some sanity checking. */ + if (back > gcst->space_local->chunk_size >> obj_back_shift) { + lprintf2("Invalid back pointer %u at 0x%lx!\n", + back, (ulong) obj); + gs_abort(); + } #endif - { const obj_header_t *pfree = (const obj_header_t *) - ((const char *)(optr - 1) - - (back << obj_back_shift)); - const chunk_head_t *chead = (const chunk_head_t *) - ((const char *)pfree - - (pfree->o_back << obj_back_shift)); - robj = chead->dest + - ((const char *)obj - (const char *)(chead + 1) - - pfree->o_nreloc); - } - } - } - return print_reloc(obj, - struct_type_name_string(optr[-1].o_type), - (void *)robj); /* discard const */ + { + const obj_header_t *pfree = (const obj_header_t *) + ((const char *)(optr - 1) - + (back << obj_back_shift)); + const chunk_head_t *chead = (const chunk_head_t *) + ((const char *)pfree - + (pfree->o_back << obj_back_shift)); + + robj = chead->dest + + ((const char *)obj - (const char *)(chead + 1) - + pfree->o_nreloc); + } + } + } + return print_reloc(obj, + struct_type_name_string(optr[-1].o_type), + (void *)robj); /* discard const */ #undef optr } @@ -1188,62 +1224,65 @@ gs_reloc_struct_ptr(const void /*obj_header_t*/ *obj, gc_state_t *gcst) /* Compact the objects in a chunk. */ /* This will never be called for a chunk with any o_untraced objects. */ private void -gc_objects_compact(chunk_t *cp, gc_state_t *gcst) -{ chunk_head_t *chead = cp->chead; - obj_header_t *dpre = (obj_header_t *)chead->dest; - SCAN_CHUNK_OBJECTS(cp) - DO_ALL - /* An object is free iff its back pointer points to */ - /* the chunk_head structure. */ - if ( (pre->o_large ? !o_is_unmarked(pre) : - pre->o_back << obj_back_shift != - (byte *)pre - (byte *)chead) - ) - { const struct_shared_procs_t _ds *procs = - pre->o_type->shared; - debug_check_object(pre, cp, gcst); - if_debug4('7', - " [7]compacting %s 0x%lx(%lu) to 0x%lx\n", - struct_type_name_string(pre->o_type), - (ulong)pre, (ulong)size, (ulong)dpre); - if ( procs == 0 ) - { if ( dpre != pre ) - memmove(dpre, pre, - sizeof(obj_header_t) + size); - } - else - (*procs->compact)(pre, dpre, size); - dpre = (obj_header_t *) - ((byte *)dpre + obj_size_round(size)); - } - END_OBJECTS_SCAN - if ( cp->outer == 0 && chead->dest != cp->cbase ) - dpre = (obj_header_t *)cp->cbase; /* compacted this chunk into another */ - gs_alloc_fill(dpre, gs_alloc_fill_collected, cp->cbot - (byte *)dpre); - cp->cbot = (byte *)dpre; - cp->rcur = 0; - cp->rtop = 0; /* just to be sure */ +gc_objects_compact(chunk_t * cp, gc_state_t * gcst) +{ + chunk_head_t *chead = cp->chead; + obj_header_t *dpre = (obj_header_t *) chead->dest; + + SCAN_CHUNK_OBJECTS(cp) + DO_ALL + /* An object is free iff its back pointer points to */ + /* the chunk_head structure. */ + if ((pre->o_large ? !o_is_unmarked(pre) : + pre->o_back << obj_back_shift != + (byte *) pre - (byte *) chead) + ) { + const struct_shared_procs_t _ds *procs = + pre->o_type->shared; + + debug_check_object(pre, cp, gcst); + if_debug4('7', + " [7]compacting %s 0x%lx(%lu) to 0x%lx\n", + struct_type_name_string(pre->o_type), + (ulong) pre, (ulong) size, (ulong) dpre); + if (procs == 0) { + if (dpre != pre) + memmove(dpre, pre, + sizeof(obj_header_t) + size); + } else + (*procs->compact) (pre, dpre, size); + dpre = (obj_header_t *) + ((byte *) dpre + obj_size_round(size)); + } + END_OBJECTS_SCAN + if (cp->outer == 0 && chead->dest != cp->cbase) + dpre = (obj_header_t *) cp->cbase; /* compacted this chunk into another */ + gs_alloc_fill(dpre, gs_alloc_fill_collected, cp->cbot - (byte *) dpre); + cp->cbot = (byte *) dpre; + cp->rcur = 0; + cp->rtop = 0; /* just to be sure */ } /* ------ Cleanup ------ */ /* Free empty chunks. */ private void -gc_free_empty_chunks(gs_ref_memory_t *mem) -{ chunk_t *cp; - chunk_t *csucc; - /* Free the chunks in reverse order, */ - /* to encourage LIFO behavior. */ - for ( cp = mem->clast; cp != 0; cp = csucc ) - { /* Make sure this isn't an inner chunk, */ - /* or a chunk that has inner chunks. */ - csucc = cp->cprev; /* save before freeing */ - if ( cp->cbot == cp->cbase && cp->ctop == cp->climit && - cp->outer == 0 && cp->inner_count == 0 - ) - { alloc_free_chunk(cp, mem); - if ( mem->pcc == cp ) - mem->pcc = 0; - } +gc_free_empty_chunks(gs_ref_memory_t * mem) +{ + chunk_t *cp; + chunk_t *csucc; + + /* Free the chunks in reverse order, */ + /* to encourage LIFO behavior. */ + for (cp = mem->clast; cp != 0; cp = csucc) { /* Make sure this isn't an inner chunk, */ + /* or a chunk that has inner chunks. */ + csucc = cp->cprev; /* save before freeing */ + if (cp->cbot == cp->cbase && cp->ctop == cp->climit && + cp->outer == 0 && cp->inner_count == 0 + ) { + alloc_free_chunk(cp, mem); + if (mem->pcc == cp) + mem->pcc = 0; } + } } |