diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2015-08-28 01:37:33 +0300 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2015-08-28 11:20:47 +0300 |
commit | 86991cba3cbce83bfd3a0619f11f86cc1ee56917 (patch) | |
tree | 5523311ce472f5d7141b769876c3ea9c402e09e6 /finalize.c | |
parent | 467b279de834a48f9d5ba731727f75949afa4000 (diff) | |
download | bdwgc-86991cba3cbce83bfd3a0619f11f86cc1ee56917.tar.gz |
Code refactoring of toggle-ref support
* alloc.c (GC_stopped_mark): Move GC_process_togglerefs() call from
GC_stop_world; do not call it if GC_NO_FINALIZATION or
GC_TOGGLE_REFS_NOT_NEEDED.
* darwin_stop_world.c (GC_stop_world): Remove GC_process_togglerefs()
call.
* pthread_stop_world.c (GC_stop_world): Likewise.
* doc/README.macros (GC_TOGGLE_REFS_NOT_NEEDED): Document.
* finalize.c (GCToggleRef, GC_process_togglerefs, push_and_mark_object,
GC_clear_togglerefs, GC_toggleref_add): Replace GC_PTR with void*.
* include/gc.h (GC_toggleref_add): Likewise.
* finalize.c (GCToggleRef, GC_toggleref_callback, GC_toggleref_arr,
GC_toggleref_array_size, GC_toggleref_array_capacity,
GC_process_togglerefs, push_and_mark_object, GC_mark_togglerefs,
GC_clear_togglerefs, GC_set_toggleref_func, ensure_toggleref_capacity,
GC_toggleref_add): Do not defined if GC_TOGGLE_REFS_NOT_NEEDED.
* finalize.c (GCToggleRef): Add comment.
* finalize.c (GC_toggleref_array): Rename to GC_toggleref_arr.
* finalize.c (GC_toggleref_callback, GC_toggleref_array,
GC_toggleref_array_size, GC_toggleref_array_capacity): Make it STATIC
(instead "static").
* finalize.c (GC_process_togglerefs): Decorate with GC_INNER; remove
"toggle_ref_counts", "res" local variables; rename "w" local variable
to "new_size"; add assertion on lock state; use GC_TOGGLE_REF_* enum
element in switch statement; use BZERO to clear moved elements of
GC_toggleref_arr.
* finalize.c (GC_normal_finalize_mark_proc): Declare (before use).
* finalize.c (push_and_mark_object): Replace PUSH_OBJ with
GC_normal_finalize_mark_proc call.
* finalize.c (GC_mark_togglerefs, GC_clear_togglerefs): Remove
"object" local variable.
* finalize.c (GC_toggleref_register_callback): Rename to
GC_set_toggleref_func; change argument to GC_toggleref_func (which
returns GC_ToggleRefStatus instead of int).
* finalize.c (GC_toggleref_register_callback, GC_toggleref_add):
Decorate with GC_API and GC_CALL.
* include/gc.h (GC_toggleref_register_callback): Likewise.
* finalize.c (GC_set_toggleref_func): Acquire allocation lock.
* finalize.c (GC_get_toggleref_func): New API function.
* finalize.c (ensure_toggleref_capacity): Rename "capacity" argument
to "capacity_inc"; add assertion on argument value; rename "tmp" local
variable to "new_array"; remove unused "old_capacity" variable; replace
memcpy() with BCOPY() call.
* finalize.c (GC_toggleref_add): Rename "strong_ref" argument to
"is_strong_ref".
* finalize.c (GC_finalize): Do not call GC_clear_togglerefs and
GC_mark_togglerefs if GC_TOGGLE_REFS_NOT_NEEDED.
* include/gc.h (GC_ToggleRefStatus, GC_toggleref_func): New type.
* include/gc.h (GC_toggleref_register_callback): Add comment
(including about locking).
* include/gc.h (GC_get_toggleref_func): New API function declaration.
* include/gc.h (GC_toggleref_add): Decorate with GC_CALL; add comment;
add GC_ATTR_NONNULL attribute.
* include/private/gc_priv.h (GC_process_togglerefs): Do not declare if
GC_TOGGLE_REFS_NOT_NEEDED; decorate with GC_INNER.
Diffstat (limited to 'finalize.c')
-rw-r--r-- | finalize.c | 283 |
1 files changed, 149 insertions, 134 deletions
@@ -260,171 +260,182 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link) return 1; } -/* toggleref support */ -typedef struct { - GC_PTR strong_ref; +/* Toggle-ref support. */ +#ifndef GC_TOGGLE_REFS_NOT_NEEDED + typedef struct { + /* Only one of the two fields can be non-NULL at a time. */ + void *strong_ref; GC_hidden_pointer weak_ref; -} GCToggleRef; + } GCToggleRef; -static int (*GC_toggleref_callback) (GC_PTR obj); -static GCToggleRef *GC_toggleref_array; -static int GC_toggleref_array_size; -static int GC_toggleref_array_capacity; + STATIC GC_toggleref_func GC_toggleref_callback = 0; + STATIC GCToggleRef *GC_toggleref_arr = NULL; + STATIC int GC_toggleref_array_size = 0; + STATIC int GC_toggleref_array_capacity = 0; + GC_INNER void GC_process_togglerefs(void) + { + int i; + int new_size = 0; -void -GC_process_togglerefs (void) -{ - int i, w; - int toggle_ref_counts [3] = { 0, 0, 0 }; - - for (i = w = 0; i < GC_toggleref_array_size; ++i) { - int res; - GCToggleRef r = GC_toggleref_array [i]; - - GC_PTR obj; - - if (r.strong_ref) - obj = r.strong_ref; - else if (r.weak_ref) - obj = GC_REVEAL_POINTER (r.weak_ref); - else - continue; - - res = GC_toggleref_callback (obj); - ++toggle_ref_counts [res]; - switch (res) { - case 0: - break; - case 1: - GC_toggleref_array [w].strong_ref = obj; - GC_toggleref_array [w].weak_ref = (GC_hidden_pointer)NULL; - ++w; - break; - case 2: - GC_toggleref_array [w].strong_ref = NULL; - GC_toggleref_array [w].weak_ref = GC_HIDE_POINTER (obj); - ++w; - break; - default: - ABORT("Invalid callback result"); + GC_ASSERT(I_HOLD_LOCK()); + for (i = 0; i < GC_toggleref_array_size; ++i) { + GCToggleRef r = GC_toggleref_arr[i]; + void *obj = r.strong_ref; + + if (NULL == obj) { + if (r.weak_ref != 0) { + obj = GC_REVEAL_POINTER(r.weak_ref); + } else { + continue; } + } + switch (GC_toggleref_callback(obj)) { + case GC_TOGGLE_REF_DROP: + break; + case GC_TOGGLE_REF_STRONG: + GC_toggleref_arr[new_size].strong_ref = obj; + GC_toggleref_arr[new_size].weak_ref = 0; + ++new_size; + break; + case GC_TOGGLE_REF_WEAK: + GC_toggleref_arr[new_size].strong_ref = NULL; + GC_toggleref_arr[new_size].weak_ref = GC_HIDE_POINTER(obj); + ++new_size; + break; + default: + ABORT("Bad toggle-ref status returned by callback"); + } } - for (i = w; i < GC_toggleref_array_size; ++i) { - GC_toggleref_array [i].strong_ref = NULL; - GC_toggleref_array [i].weak_ref = (GC_hidden_pointer)NULL; + if (new_size < GC_toggleref_array_size) { + BZERO(&GC_toggleref_arr[new_size], + (GC_toggleref_array_size - new_size) * sizeof(GCToggleRef)); + GC_toggleref_array_size = new_size; } + } - GC_toggleref_array_size = w; -} - + STATIC void GC_normal_finalize_mark_proc(ptr_t); -static void push_and_mark_object (GC_PTR p) -{ - hdr * hhdr = HDR(p); - - PUSH_OBJ(p, hhdr, GC_mark_stack_top, - &(GC_mark_stack[GC_mark_stack_size])); - - while (!GC_mark_stack_empty()) MARK_FROM_MARK_STACK(); - GC_set_mark_bit (p); - if (GC_mark_state != MS_NONE) - while (!GC_mark_some((ptr_t)0)) {} -} + static void push_and_mark_object(void *p) + { + GC_normal_finalize_mark_proc(p); + while (!GC_mark_stack_empty()) { + MARK_FROM_MARK_STACK(); + } + GC_set_mark_bit(p); + if (GC_mark_state != MS_NONE) { + while (!GC_mark_some(0)) { + /* Empty. */ + } + } + } -static void GC_mark_togglerefs () -{ + STATIC void GC_mark_togglerefs(void) + { int i; - if (!GC_toggleref_array) - return; + if (NULL == GC_toggleref_arr) + return; - GC_set_mark_bit (GC_toggleref_array); + /* TODO: Hide GC_toggleref_arr to avoid its marking from roots. */ + GC_set_mark_bit(GC_toggleref_arr); for (i = 0; i < GC_toggleref_array_size; ++i) { - if (GC_toggleref_array [i].strong_ref) { - GC_PTR object = GC_toggleref_array [i].strong_ref; - - push_and_mark_object (object); - } + if (GC_toggleref_arr[i].strong_ref != NULL) { + push_and_mark_object(GC_toggleref_arr[i].strong_ref); + } } -} + } -static void GC_clear_togglerefs () -{ + STATIC void GC_clear_togglerefs(void) + { int i; for (i = 0; i < GC_toggleref_array_size; ++i) { - if (GC_toggleref_array [i].weak_ref) { - GC_PTR object = GC_REVEAL_POINTER (GC_toggleref_array [i].weak_ref); - - if (!GC_is_marked (object)) { - GC_toggleref_array [i].weak_ref = (GC_hidden_pointer)NULL; /* We defer compaction to only happen on the callback step. */ - } else { - /*No need to copy, boehm is non-moving */ - } + if (GC_toggleref_arr[i].weak_ref != 0) { + if (!GC_is_marked(GC_REVEAL_POINTER(GC_toggleref_arr[i].weak_ref))) { + GC_toggleref_arr[i].weak_ref = 0; + } else { + /* No need to copy, BDWGC is a non-moving collector. */ } + } } -} + } + GC_API void GC_CALL GC_set_toggleref_func(GC_toggleref_func fn) + { + DCL_LOCK_STATE; + LOCK(); + GC_toggleref_callback = fn; + UNLOCK(); + } -void GC_toggleref_register_callback(int (*proccess_toggleref) (GC_PTR obj)) -{ - GC_toggleref_callback = proccess_toggleref; -} + GC_API GC_toggleref_func GC_CALL GC_get_toggleref_func(void) + { + GC_toggleref_func fn; + DCL_LOCK_STATE; -static GC_bool -ensure_toggleref_capacity (int capacity) -{ - if (!GC_toggleref_array) { - GC_toggleref_array_capacity = 32; - GC_toggleref_array = (GCToggleRef *) GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE (GC_toggleref_array_capacity * sizeof (GCToggleRef), NORMAL); - if (NULL == GC_toggleref_array) - return FALSE; - } - if ((unsigned)GC_toggleref_array_size + (unsigned)capacity - >= (unsigned)GC_toggleref_array_capacity) { - GCToggleRef *tmp; - int old_capacity = GC_toggleref_array_capacity; - while ((unsigned)GC_toggleref_array_capacity - < (unsigned)GC_toggleref_array_size + (unsigned)capacity) { - GC_toggleref_array_capacity *= 2; - if (GC_toggleref_array_capacity < 0) /* overflow */ - return FALSE; - } + LOCK(); + fn = GC_toggleref_callback; + UNLOCK(); + return fn; + } - tmp = (GCToggleRef *) GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE (GC_toggleref_array_capacity * sizeof (GCToggleRef), NORMAL); - if (NULL == tmp) - return FALSE; - memcpy (tmp, GC_toggleref_array, GC_toggleref_array_size * sizeof (GCToggleRef)); + static GC_bool ensure_toggleref_capacity(int capacity_inc) + { + GC_ASSERT(capacity_inc >= 0); + if (NULL == GC_toggleref_arr) { + GC_toggleref_array_capacity = 32; /* initial capacity */ + GC_toggleref_arr = GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE( + GC_toggleref_array_capacity * sizeof(GCToggleRef), + NORMAL); + if (NULL == GC_toggleref_arr) + return FALSE; + } + if ((unsigned)GC_toggleref_array_size + (unsigned)capacity_inc + >= (unsigned)GC_toggleref_array_capacity) { + GCToggleRef *new_array; + while ((unsigned)GC_toggleref_array_capacity + < (unsigned)GC_toggleref_array_size + (unsigned)capacity_inc) { + GC_toggleref_array_capacity *= 2; + if (GC_toggleref_array_capacity < 0) /* overflow */ + return FALSE; + } - GC_INTERNAL_FREE(GC_toggleref_array); - GC_toggleref_array = tmp; + new_array = GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE( + GC_toggleref_array_capacity * sizeof(GCToggleRef), + NORMAL); + if (NULL == new_array) + return FALSE; + BCOPY(GC_toggleref_arr, new_array, + GC_toggleref_array_size * sizeof(GCToggleRef)); + GC_INTERNAL_FREE(GC_toggleref_arr); + GC_toggleref_arr = new_array; } return TRUE; -} + } -int -GC_toggleref_add (GC_PTR object, int strong_ref) -{ + GC_API int GC_CALL GC_toggleref_add(void *obj, int is_strong_ref) + { + int res = GC_SUCCESS; DCL_LOCK_STATE; - LOCK(); - if (!GC_toggleref_callback) - goto end; - - if (!ensure_toggleref_capacity(1)) { - UNLOCK(); - return GC_NO_MEMORY; + GC_ASSERT(obj != NULL); + LOCK(); + if (GC_toggleref_callback != 0) { + if (!ensure_toggleref_capacity(1)) { + res = GC_NO_MEMORY; + } else { + GC_toggleref_arr[GC_toggleref_array_size].strong_ref = + is_strong_ref ? obj : NULL; + GC_toggleref_arr[GC_toggleref_array_size].weak_ref = + is_strong_ref ? 0 : GC_HIDE_POINTER(obj); + ++GC_toggleref_array_size; + } } - GC_toggleref_array [GC_toggleref_array_size].strong_ref = strong_ref ? object : NULL; - GC_toggleref_array [GC_toggleref_array_size].weak_ref = strong_ref ? (GC_hidden_pointer)NULL : GC_HIDE_POINTER (object); - ++GC_toggleref_array_size; - -end: UNLOCK(); - return GC_SUCCESS; -} - + return res; + } +#endif /* !GC_TOGGLE_REFS_NOT_NEEDED */ /* Finalizer callback support. */ STATIC GC_await_finalize_proc GC_object_finalized_proc = 0; @@ -936,7 +947,9 @@ GC_INNER void GC_finalize(void) # endif # endif - GC_mark_togglerefs(); +# ifndef GC_TOGGLE_REFS_NOT_NEEDED + GC_mark_togglerefs(); +# endif GC_make_disappearing_links_disappear(&GC_dl_hashtbl); /* Mark all objects reachable via chains of 1 or more pointers */ @@ -1050,7 +1063,9 @@ GC_INNER void GC_finalize(void) } GC_remove_dangling_disappearing_links(&GC_dl_hashtbl); - GC_clear_togglerefs (); +# ifndef GC_TOGGLE_REFS_NOT_NEEDED + GC_clear_togglerefs(); +# endif # ifndef GC_LONG_REFS_NOT_NEEDED GC_make_disappearing_links_disappear(&GC_ll_hashtbl); GC_remove_dangling_disappearing_links(&GC_ll_hashtbl); |