diff options
Diffstat (limited to 'finalize.c')
-rw-r--r-- | finalize.c | 200 |
1 files changed, 161 insertions, 39 deletions
@@ -11,12 +11,16 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, May 19, 1994 2:08 pm PDT */ +/* Boehm, September 22, 1995 5:49 pm PDT */ # define I_HIDE_POINTERS -# include "gc.h" # include "gc_priv.h" # include "gc_mark.h" +/* Type of mark procedure used for marking from finalizable object. */ +/* This procedure normally does not mark the object, only its */ +/* descendents. */ +typedef void finalization_mark_proc(/* ptr_t finalizable_obj_ptr */); + # define HASH3(addr,size,log_size) \ ((((word)(addr) >> 3) ^ ((word)(addr) >> (3+(log_size)))) \ & ((size) - 1)) @@ -57,6 +61,7 @@ static struct finalizable_object { GC_finalization_proc fo_fn; /* Finalizer. */ ptr_t fo_client_data; word fo_object_size; /* In bytes. */ + finalization_mark_proc * fo_mark_proc; /* Mark-through procedure */ } **fo_head = 0; struct finalizable_object * GC_finalize_now = 0; @@ -74,8 +79,6 @@ void GC_push_finalizer_structures() } # endif -# define ALLOC(x, t) t *x = GC_NEW(t) - /* Double the size of a hash table. *size_ptr is the log of its current */ /* size. May be a noop. */ /* *table is a pointer to an array of hash headers. If we succeed, we */ @@ -92,8 +95,8 @@ signed_word * log_size_ptr; word old_size = ((log_old_size == -1)? 0: (1 << log_old_size)); register word new_size = 1 << log_new_size; struct hash_chain_entry **new_table = (struct hash_chain_entry **) - GC_malloc_ignore_off_page_inner( - (size_t)new_size * sizeof(struct hash_chain_entry *)); + GC_generic_malloc_inner_ignore_off_page( + (size_t)new_size * sizeof(struct hash_chain_entry *), NORMAL); if (new_table == 0) { if (table == 0) { @@ -118,21 +121,30 @@ signed_word * log_size_ptr; *table = new_table; } - -int GC_register_disappearing_link(link) -extern_ptr_t * link; +# if defined(__STDC__) || defined(__cplusplus) + int GC_register_disappearing_link(GC_PTR * link) +# else + int GC_register_disappearing_link(link) + GC_PTR * link; +# endif { ptr_t base; - base = (ptr_t)GC_base((extern_ptr_t)link); + base = (ptr_t)GC_base((GC_PTR)link); if (base == 0) ABORT("Bad arg to GC_register_disappearing_link"); return(GC_general_register_disappearing_link(link, base)); } -int GC_general_register_disappearing_link(link, obj) -extern_ptr_t * link; -extern_ptr_t obj; +# if defined(__STDC__) || defined(__cplusplus) + int GC_general_register_disappearing_link(GC_PTR * link, + GC_PTR obj) +# else + int GC_general_register_disappearing_link(link, obj) + GC_PTR * link; + GC_PTR obj; +# endif + { struct disappearing_link *curr_dl; int index; @@ -176,7 +188,8 @@ extern_ptr_t obj; new_dl = (struct disappearing_link *) GC_generic_malloc_inner(sizeof(struct disappearing_link),NORMAL); # else - new_dl = GC_NEW(struct disappearing_link); + new_dl = (struct disappearing_link *) + GC_malloc(sizeof(struct disappearing_link)); # endif if (new_dl != 0) { new_dl -> dl_hidden_obj = HIDE_POINTER(obj); @@ -194,8 +207,12 @@ extern_ptr_t obj; return(0); } -int GC_unregister_disappearing_link(link) -extern_ptr_t * link; +# if defined(__STDC__) || defined(__cplusplus) + int GC_unregister_disappearing_link(GC_PTR * link) +# else + int GC_unregister_disappearing_link(link) + GC_PTR * link; +# endif { struct disappearing_link *curr_dl, *prev_dl; int index; @@ -216,7 +233,7 @@ extern_ptr_t * link; GC_dl_entries--; UNLOCK(); ENABLE_SIGNALS(); - GC_free((extern_ptr_t)curr_dl); + GC_free((GC_PTR)curr_dl); return(1); } prev_dl = curr_dl; @@ -228,16 +245,61 @@ out: return(0); } +/* Possible finalization_marker procedures. Note that mark stack */ +/* overflow is handled by the caller, and is not a disaster. */ +void GC_normal_finalize_mark_proc(p) +ptr_t p; +{ + hdr * hhdr = HDR(p); + + PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top, + &(GC_mark_stack[GC_mark_stack_size])); +} + +/* This only pays very partial attention to the mark descriptor. */ +/* It does the right thing for normal and atomic objects, and treats */ +/* most others as normal. */ +void GC_ignore_self_finalize_mark_proc(p) +ptr_t p; +{ + hdr * hhdr = HDR(p); + word descr = hhdr -> hb_descr; + ptr_t q, r; + ptr_t scan_limit; + ptr_t target_limit = p + WORDS_TO_BYTES(hhdr -> hb_sz) - 1; + + if ((descr & DS_TAGS) == DS_LENGTH) { + scan_limit = p + descr - sizeof(word); + } else { + scan_limit = target_limit + 1 - sizeof(word); + } + for (q = p; q <= scan_limit; q += ALIGNMENT) { + r = *(ptr_t *)q; + if (r < p || r > target_limit) { + GC_PUSH_ONE_HEAP((word)r); + } + } +} + +/*ARGSUSED*/ +void GC_null_finalize_mark_proc(p) +ptr_t p; +{ +} + + + /* Register a finalization function. See gc.h for details. */ /* in the nonthreads case, we try to avoid disabling signals, */ /* since it can be expensive. Threads packages typically */ /* make it cheaper. */ -void GC_register_finalizer(obj, fn, cd, ofn, ocd) -extern_ptr_t obj; +void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp) +GC_PTR obj; GC_finalization_proc fn; -extern_ptr_t cd; +GC_PTR cd; GC_finalization_proc * ofn; -extern_ptr_t * ocd; +GC_PTR * ocd; +finalization_mark_proc * mp; { ptr_t base; struct finalizable_object * curr_fo, * prev_fo; @@ -275,7 +337,7 @@ extern_ptr_t * ocd; /* should be safe. The client may see only *ocd */ /* updated, but we'll declare that to be his */ /* problem. */ - if (ocd) *ocd = (extern_ptr_t) curr_fo -> fo_client_data; + if (ocd) *ocd = (GC_PTR) curr_fo -> fo_client_data; if (ofn) *ofn = curr_fo -> fo_fn; /* Delete the structure for base. */ if (prev_fo == 0) { @@ -289,11 +351,12 @@ extern_ptr_t * ocd; /* estimate will only make the table larger than */ /* necessary. */ # ifndef THREADS - GC_free((extern_ptr_t)curr_fo); + GC_free((GC_PTR)curr_fo); # endif } else { curr_fo -> fo_fn = fn; curr_fo -> fo_client_data = (ptr_t)cd; + curr_fo -> fo_mark_proc = mp; /* Reinsert it. We deleted it first to maintain */ /* consistency in the event of a signal. */ if (prev_fo == 0) { @@ -324,13 +387,15 @@ extern_ptr_t * ocd; new_fo = (struct finalizable_object *) GC_generic_malloc_inner(sizeof(struct finalizable_object),NORMAL); # else - new_fo = GC_NEW(struct finalizable_object); + new_fo = (struct finalizable_object *) + GC_malloc(sizeof(struct finalizable_object)); # endif if (new_fo != 0) { new_fo -> fo_hidden_base = (word)HIDE_POINTER(base); new_fo -> fo_fn = fn; new_fo -> fo_client_data = (ptr_t)cd; new_fo -> fo_object_size = GC_size(base); + new_fo -> fo_mark_proc = mp; fo_set_next(new_fo, fo_head[index]); GC_fo_entries++; fo_head[index] = new_fo; @@ -343,6 +408,58 @@ extern_ptr_t * ocd; # endif } +# if defined(__STDC__) + void GC_register_finalizer(void * obj, + GC_finalization_proc fn, void * cd, + GC_finalization_proc *ofn, void ** ocd) +# else + void GC_register_finalizer(obj, fn, cd, ofn, ocd) + GC_PTR obj; + GC_finalization_proc fn; + GC_PTR cd; + GC_finalization_proc * ofn; + GC_PTR * ocd; +# endif +{ + GC_register_finalizer_inner(obj, fn, cd, ofn, + ocd, GC_normal_finalize_mark_proc); +} + +# if defined(__STDC__) + void GC_register_finalizer_ignore_self(void * obj, + GC_finalization_proc fn, void * cd, + GC_finalization_proc *ofn, void ** ocd) +# else + void GC_register_finalizer_ignore_self(obj, fn, cd, ofn, ocd) + GC_PTR obj; + GC_finalization_proc fn; + GC_PTR cd; + GC_finalization_proc * ofn; + GC_PTR * ocd; +# endif +{ + GC_register_finalizer_inner(obj, fn, cd, ofn, + ocd, GC_ignore_self_finalize_mark_proc); +} + +# if defined(__STDC__) + void GC_register_finalizer_no_order(void * obj, + GC_finalization_proc fn, void * cd, + GC_finalization_proc *ofn, void ** ocd) +# else + void GC_register_finalizer_no_order(obj, fn, cd, ofn, ocd) + GC_PTR obj; + GC_finalization_proc fn; + GC_PTR cd; + GC_finalization_proc * ofn; + GC_PTR * ocd; +# endif +{ + GC_register_finalizer_inner(obj, fn, cd, ofn, + ocd, GC_null_finalize_mark_proc); +} + + /* Called with world stopped. Cause disappearing links to disappear, */ /* and invoke finalizers. */ void GC_finalize() @@ -351,8 +468,8 @@ void GC_finalize() struct finalizable_object * curr_fo, * prev_fo, * next_fo; ptr_t real_ptr, real_link; register int i; - int dl_size = 1 << log_dl_table_size; - int fo_size = 1 << log_fo_table_size; + int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size); + int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size); /* Make disappearing links disappear */ for (i = 0; i < dl_size; i++) { @@ -387,10 +504,7 @@ void GC_finalize() for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) { real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base); if (!GC_is_marked(real_ptr)) { - hdr * hhdr = HDR(real_ptr); - - PUSH_OBJ((word *)real_ptr, hhdr, GC_mark_stack_top, - &(GC_mark_stack[GC_mark_stack_size])); + (*(curr_fo -> fo_mark_proc))(real_ptr); while (!GC_mark_stack_empty()) GC_mark_from_mark_stack(); if (GC_mark_state != MS_NONE) { /* Mark stack overflowed. Very unlikely. */ @@ -403,17 +517,16 @@ void GC_finalize() GC_set_mark_bit(real_ptr); while (!GC_mark_some()); } - /* if (GC_is_marked(real_ptr)) { - --> Report finalization cycle here, if desired + WARN("Finalization cycle involving %lx\n", real_ptr); } - */ } } } /* Enqueue for finalization all objects that are still */ /* unreachable. */ + GC_words_finalized = 0; for (i = 0; i < fo_size; i++) { curr_fo = fo_head[i]; prev_fo = 0; @@ -432,6 +545,9 @@ void GC_finalize() /* Add to list of objects awaiting finalization. */ fo_set_next(curr_fo, GC_finalize_now); GC_finalize_now = curr_fo; + GC_words_finalized += + ALIGNED_WORDS(curr_fo -> fo_object_size) + + ALIGNED_WORDS(sizeof(struct finalizable_object)); # ifdef PRINTSTATS if (!GC_is_marked((ptr_t)curr_fo)) { ABORT("GC_finalize: found accessible unmarked object\n"); @@ -490,23 +606,29 @@ void GC_invoke_finalizers() # else GC_finalize_now = fo_next(curr_fo); # endif + fo_set_next(curr_fo, 0); real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base); (*(curr_fo -> fo_fn))(real_ptr, curr_fo -> fo_client_data); -# ifndef THREADS - GC_free((extern_ptr_t)curr_fo); + curr_fo -> fo_client_data = 0; +# ifdef UNDEFINED + /* This is probably a bad idea. It throws off accounting if */ + /* nearly all objects are finalizable. O.w. it shouldn't */ + /* matter. */ + GC_free((GC_PTR)curr_fo); # endif } } # ifdef __STDC__ - extern_ptr_t GC_call_with_alloc_lock(GC_fn_type fn, extern_ptr_t client_data) + GC_PTR GC_call_with_alloc_lock(GC_fn_type fn, + GC_PTR client_data) # else - extern_ptr_t GC_call_with_alloc_lock(fn, client_data) + GC_PTR GC_call_with_alloc_lock(fn, client_data) GC_fn_type fn; - extern_ptr_t client_data; + GC_PTR client_data; # endif { - extern_ptr_t result; + GC_PTR result; DCL_LOCK_STATE; # ifdef THREADS |