|
@@ -55,7 +55,7 @@ STATIC struct dl_hashtbl_s GC_dl_hashtbl = {
|
|
|
STATIC struct dl_hashtbl_s GC_ll_hashtbl = { NULL, -1, 0 };
|
|
|
#endif
|
|
|
|
|
|
-STATIC struct finalizable_object {
|
|
|
+struct finalizable_object {
|
|
|
struct hash_chain_entry prolog;
|
|
|
# define fo_hidden_base prolog.hidden_key
|
|
|
/* Pointer to object base. */
|
|
@@ -67,30 +67,26 @@ STATIC struct finalizable_object {
|
|
|
ptr_t fo_client_data;
|
|
|
word fo_object_size; /* In bytes. */
|
|
|
finalization_mark_proc fo_mark_proc; /* Mark-through procedure */
|
|
|
-} **GC_fo_head = 0;
|
|
|
-
|
|
|
-STATIC struct finalizable_object * GC_finalize_now = 0;
|
|
|
- /* List of objects that should be finalized now. */
|
|
|
+};
|
|
|
|
|
|
static signed_word log_fo_table_size = -1;
|
|
|
|
|
|
+STATIC struct {
|
|
|
+ struct finalizable_object **fo_head;
|
|
|
+ /* List of objects that should be finalized now: */
|
|
|
+ struct finalizable_object *finalize_now;
|
|
|
+} GC_fnlz_roots = { NULL, NULL };
|
|
|
+
|
|
|
GC_API void GC_CALL GC_push_finalizer_structures(void)
|
|
|
{
|
|
|
- GC_ASSERT((word)&GC_dl_hashtbl.head % sizeof(word) == 0);
|
|
|
- GC_ASSERT((word)&GC_fo_head % sizeof(word) == 0);
|
|
|
- GC_ASSERT((word)&GC_finalize_now % sizeof(word) == 0);
|
|
|
-
|
|
|
+ GC_ASSERT((word)&GC_dl_hashtbl.head % sizeof(word) == 0);
|
|
|
+ GC_ASSERT((word)&GC_fnlz_roots % sizeof(word) == 0);
|
|
|
# ifndef GC_LONG_REFS_NOT_NEEDED
|
|
|
GC_ASSERT((word)&GC_ll_hashtbl.head % sizeof(word) == 0);
|
|
|
- GC_push_all((ptr_t)(&GC_ll_hashtbl.head),
|
|
|
- (ptr_t)(&GC_ll_hashtbl.head) + sizeof(word));
|
|
|
+ GC_PUSH_ALL_SYM(GC_ll_hashtbl.head);
|
|
|
# endif
|
|
|
-
|
|
|
- GC_push_all((ptr_t)(&GC_dl_hashtbl.head),
|
|
|
- (ptr_t)(&GC_dl_hashtbl.head) + sizeof(word));
|
|
|
- GC_push_all((ptr_t)(&GC_fo_head), (ptr_t)(&GC_fo_head) + sizeof(word));
|
|
|
- GC_push_all((ptr_t)(&GC_finalize_now),
|
|
|
- (ptr_t)(&GC_finalize_now) + sizeof(word));
|
|
|
+ GC_PUSH_ALL_SYM(GC_dl_hashtbl.head);
|
|
|
+ GC_PUSH_ALL_SYM(GC_fnlz_roots);
|
|
|
}
|
|
|
|
|
|
/* Double the size of a hash table. *size_ptr is the log of its current */
|
|
@@ -211,7 +207,7 @@ STATIC int GC_register_disappearing_link_inner(
|
|
|
GC_API int GC_CALL GC_general_register_disappearing_link(void * * link,
|
|
|
const void * obj)
|
|
|
{
|
|
|
- if (((word)link & (ALIGNMENT-1)) != 0 || NULL == link)
|
|
|
+ if (((word)link & (ALIGNMENT-1)) != 0 || !NONNULL_ARG_NOT_NULL(link))
|
|
|
ABORT("Bad arg to GC_general_register_disappearing_link");
|
|
|
return GC_register_disappearing_link_inner(&GC_dl_hashtbl, link, obj,
|
|
|
"dl");
|
|
@@ -264,6 +260,176 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
+/* Toggle-ref support. */
|
|
|
+#ifndef GC_TOGGLE_REFS_NOT_NEEDED
|
|
|
+ typedef union {
|
|
|
+ /* Lowest bit is used to distinguish between choices. */
|
|
|
+ void *strong_ref;
|
|
|
+ GC_hidden_pointer weak_ref;
|
|
|
+ } GCToggleRef;
|
|
|
+
|
|
|
+ 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;
|
|
|
+
|
|
|
+ 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 (((word)obj & 1) != 0) {
|
|
|
+ obj = GC_REVEAL_POINTER(r.weak_ref);
|
|
|
+ }
|
|
|
+ if (NULL == obj) {
|
|
|
+ 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;
|
|
|
+ break;
|
|
|
+ case GC_TOGGLE_REF_WEAK:
|
|
|
+ GC_toggleref_arr[new_size++].weak_ref = GC_HIDE_POINTER(obj);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ ABORT("Bad toggle-ref status returned by callback");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ STATIC void GC_normal_finalize_mark_proc(ptr_t);
|
|
|
+
|
|
|
+ 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(void)
|
|
|
+ {
|
|
|
+ int i;
|
|
|
+ if (NULL == GC_toggleref_arr)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* 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) {
|
|
|
+ void *obj = GC_toggleref_arr[i].strong_ref;
|
|
|
+ if (obj != NULL && ((word)obj & 1) == 0) {
|
|
|
+ push_and_mark_object(obj);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ STATIC void GC_clear_togglerefs(void)
|
|
|
+ {
|
|
|
+ int i;
|
|
|
+ for (i = 0; i < GC_toggleref_array_size; ++i) {
|
|
|
+ if ((GC_toggleref_arr[i].weak_ref & 1) != 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();
|
|
|
+ }
|
|
|
+
|
|
|
+ GC_API GC_toggleref_func GC_CALL GC_get_toggleref_func(void)
|
|
|
+ {
|
|
|
+ GC_toggleref_func fn;
|
|
|
+ DCL_LOCK_STATE;
|
|
|
+
|
|
|
+ LOCK();
|
|
|
+ fn = GC_toggleref_callback;
|
|
|
+ UNLOCK();
|
|
|
+ return fn;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ GC_API int GC_CALL GC_toggleref_add(void *obj, int is_strong_ref)
|
|
|
+ {
|
|
|
+ int res = GC_SUCCESS;
|
|
|
+ DCL_LOCK_STATE;
|
|
|
+
|
|
|
+ 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 : (void *)GC_HIDE_POINTER(obj);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ UNLOCK();
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+#endif /* !GC_TOGGLE_REFS_NOT_NEEDED */
|
|
|
+
|
|
|
/* Finalizer callback support. */
|
|
|
STATIC GC_await_finalize_proc GC_object_finalized_proc = 0;
|
|
|
|
|
@@ -290,7 +456,7 @@ GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void)
|
|
|
#ifndef GC_LONG_REFS_NOT_NEEDED
|
|
|
GC_API int GC_CALL GC_register_long_link(void * * link, const void * obj)
|
|
|
{
|
|
|
- if (((word)link & (ALIGNMENT-1)) != 0 || NULL == link)
|
|
|
+ if (((word)link & (ALIGNMENT-1)) != 0 || !NONNULL_ARG_NOT_NULL(link))
|
|
|
ABORT("Bad arg to GC_register_long_link");
|
|
|
return GC_register_disappearing_link_inner(&GC_ll_hashtbl, link, obj,
|
|
|
"long dl");
|
|
@@ -370,7 +536,8 @@ GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void)
|
|
|
int result;
|
|
|
DCL_LOCK_STATE;
|
|
|
|
|
|
- if (((word)new_link & (ALIGNMENT-1)) != 0 || new_link == NULL)
|
|
|
+ if (((word)new_link & (ALIGNMENT-1)) != 0
|
|
|
+ || !NONNULL_ARG_NOT_NULL(new_link))
|
|
|
ABORT("Bad new_link arg to GC_move_disappearing_link");
|
|
|
if (((word)link & (ALIGNMENT-1)) != 0)
|
|
|
return GC_NOT_FOUND; /* Nothing to do. */
|
|
@@ -387,8 +554,9 @@ GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void)
|
|
|
int result;
|
|
|
DCL_LOCK_STATE;
|
|
|
|
|
|
- if (((word)new_link & (ALIGNMENT-1)) != 0 || new_link == NULL)
|
|
|
- ABORT("Bad new_link arg to GC_move_disappearing_link");
|
|
|
+ if (((word)new_link & (ALIGNMENT-1)) != 0
|
|
|
+ || !NONNULL_ARG_NOT_NULL(new_link))
|
|
|
+ ABORT("Bad new_link arg to GC_move_long_link");
|
|
|
if (((word)link & (ALIGNMENT-1)) != 0)
|
|
|
return GC_NOT_FOUND; /* Nothing to do. */
|
|
|
|
|
@@ -471,7 +639,7 @@ STATIC void GC_register_finalizer_inner(void * obj,
|
|
|
LOCK();
|
|
|
if (log_fo_table_size == -1
|
|
|
|| GC_fo_entries > ((word)1 << log_fo_table_size)) {
|
|
|
- GC_grow_table((struct hash_chain_entry ***)&GC_fo_head,
|
|
|
+ GC_grow_table((struct hash_chain_entry ***)&GC_fnlz_roots.fo_head,
|
|
|
&log_fo_table_size);
|
|
|
GC_COND_LOG_PRINTF("Grew fo table to %u entries\n",
|
|
|
1 << (unsigned)log_fo_table_size);
|
|
@@ -481,7 +649,7 @@ STATIC void GC_register_finalizer_inner(void * obj,
|
|
|
for (;;) {
|
|
|
index = HASH2(base, log_fo_table_size);
|
|
|
prev_fo = 0;
|
|
|
- curr_fo = GC_fo_head[index];
|
|
|
+ curr_fo = GC_fnlz_roots.fo_head[index];
|
|
|
while (curr_fo != 0) {
|
|
|
GC_ASSERT(GC_size(curr_fo) >= sizeof(struct finalizable_object));
|
|
|
if (curr_fo -> fo_hidden_base == GC_HIDE_POINTER(base)) {
|
|
@@ -492,7 +660,7 @@ STATIC void GC_register_finalizer_inner(void * obj,
|
|
|
if (ofn) *ofn = curr_fo -> fo_fn;
|
|
|
/* Delete the structure for base. */
|
|
|
if (prev_fo == 0) {
|
|
|
- GC_fo_head[index] = fo_next(curr_fo);
|
|
|
+ GC_fnlz_roots.fo_head[index] = fo_next(curr_fo);
|
|
|
} else {
|
|
|
fo_set_next(prev_fo, fo_next(curr_fo));
|
|
|
}
|
|
@@ -511,7 +679,7 @@ STATIC void GC_register_finalizer_inner(void * obj,
|
|
|
/* Reinsert it. We deleted it first to maintain */
|
|
|
/* consistency in the event of a signal. */
|
|
|
if (prev_fo == 0) {
|
|
|
- GC_fo_head[index] = curr_fo;
|
|
|
+ GC_fnlz_roots.fo_head[index] = curr_fo;
|
|
|
} else {
|
|
|
fo_set_next(prev_fo, curr_fo);
|
|
|
}
|
|
@@ -571,9 +739,9 @@ STATIC void GC_register_finalizer_inner(void * obj,
|
|
|
new_fo -> fo_client_data = (ptr_t)cd;
|
|
|
new_fo -> fo_object_size = hhdr -> hb_sz;
|
|
|
new_fo -> fo_mark_proc = mp;
|
|
|
- fo_set_next(new_fo, GC_fo_head[index]);
|
|
|
+ fo_set_next(new_fo, GC_fnlz_roots.fo_head[index]);
|
|
|
GC_fo_entries++;
|
|
|
- GC_fo_head[index] = new_fo;
|
|
|
+ GC_fnlz_roots.fo_head[index] = new_fo;
|
|
|
UNLOCK();
|
|
|
}
|
|
|
|
|
@@ -649,8 +817,8 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
|
|
|
# endif
|
|
|
GC_printf("Finalizers:\n");
|
|
|
for (i = 0; i < fo_size; i++) {
|
|
|
- for (curr_fo = GC_fo_head[i]; curr_fo != 0;
|
|
|
- curr_fo = fo_next(curr_fo)) {
|
|
|
+ for (curr_fo = GC_fnlz_roots.fo_head[i];
|
|
|
+ curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
|
|
|
real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
|
|
|
GC_printf("Finalizable object: %p\n", real_ptr);
|
|
|
}
|
|
@@ -774,14 +942,17 @@ GC_INNER void GC_finalize(void)
|
|
|
# endif
|
|
|
# endif
|
|
|
|
|
|
+# 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 */
|
|
|
/* from finalizable objects. */
|
|
|
GC_ASSERT(GC_mark_state == MS_NONE);
|
|
|
for (i = 0; i < fo_size; i++) {
|
|
|
- for (curr_fo = GC_fo_head[i]; curr_fo != 0;
|
|
|
- curr_fo = fo_next(curr_fo)) {
|
|
|
+ for (curr_fo = GC_fnlz_roots.fo_head[i];
|
|
|
+ curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
|
|
|
GC_ASSERT(GC_size(curr_fo) >= sizeof(struct finalizable_object));
|
|
|
real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
|
|
|
if (!GC_is_marked(real_ptr)) {
|
|
@@ -797,7 +968,7 @@ GC_INNER void GC_finalize(void)
|
|
|
/* unreachable. */
|
|
|
GC_bytes_finalized = 0;
|
|
|
for (i = 0; i < fo_size; i++) {
|
|
|
- curr_fo = GC_fo_head[i];
|
|
|
+ curr_fo = GC_fnlz_roots.fo_head[i];
|
|
|
prev_fo = 0;
|
|
|
while (curr_fo != 0) {
|
|
|
real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
|
|
@@ -807,8 +978,8 @@ GC_INNER void GC_finalize(void)
|
|
|
}
|
|
|
/* Delete from hash table */
|
|
|
next_fo = fo_next(curr_fo);
|
|
|
- if (prev_fo == 0) {
|
|
|
- GC_fo_head[i] = next_fo;
|
|
|
+ if (NULL == prev_fo) {
|
|
|
+ GC_fnlz_roots.fo_head[i] = next_fo;
|
|
|
} else {
|
|
|
fo_set_next(prev_fo, next_fo);
|
|
|
}
|
|
@@ -817,8 +988,8 @@ GC_INNER void GC_finalize(void)
|
|
|
GC_object_finalized_proc(real_ptr);
|
|
|
|
|
|
/* Add to list of objects awaiting finalization. */
|
|
|
- fo_set_next(curr_fo, GC_finalize_now);
|
|
|
- GC_finalize_now = curr_fo;
|
|
|
+ fo_set_next(curr_fo, GC_fnlz_roots.finalize_now);
|
|
|
+ GC_fnlz_roots.finalize_now = curr_fo;
|
|
|
/* unhide object pointer so any future collections will */
|
|
|
/* see it. */
|
|
|
curr_fo -> fo_hidden_base =
|
|
@@ -838,8 +1009,8 @@ GC_INNER void GC_finalize(void)
|
|
|
if (GC_java_finalization) {
|
|
|
/* make sure we mark everything reachable from objects finalized
|
|
|
using the no_order mark_proc */
|
|
|
- for (curr_fo = GC_finalize_now;
|
|
|
- curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
|
|
|
+ for (curr_fo = GC_fnlz_roots.finalize_now;
|
|
|
+ curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
|
|
|
real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
|
|
|
if (!GC_is_marked(real_ptr)) {
|
|
|
if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
|
|
@@ -854,29 +1025,29 @@ GC_INNER void GC_finalize(void)
|
|
|
/* now revive finalize-when-unreachable objects reachable from
|
|
|
other finalizable objects */
|
|
|
if (need_unreachable_finalization) {
|
|
|
- curr_fo = GC_finalize_now;
|
|
|
- prev_fo = 0;
|
|
|
- while (curr_fo != 0) {
|
|
|
+ curr_fo = GC_fnlz_roots.finalize_now;
|
|
|
+ prev_fo = NULL;
|
|
|
+ while (curr_fo != NULL) {
|
|
|
next_fo = fo_next(curr_fo);
|
|
|
if (curr_fo -> fo_mark_proc == GC_unreachable_finalize_mark_proc) {
|
|
|
real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
|
|
|
if (!GC_is_marked(real_ptr)) {
|
|
|
GC_set_mark_bit(real_ptr);
|
|
|
} else {
|
|
|
- if (prev_fo == 0)
|
|
|
- GC_finalize_now = next_fo;
|
|
|
- else
|
|
|
+ if (NULL == prev_fo) {
|
|
|
+ GC_fnlz_roots.finalize_now = next_fo;
|
|
|
+ } else {
|
|
|
fo_set_next(prev_fo, next_fo);
|
|
|
-
|
|
|
+ }
|
|
|
curr_fo -> fo_hidden_base =
|
|
|
GC_HIDE_POINTER(curr_fo -> fo_hidden_base);
|
|
|
GC_bytes_finalized -=
|
|
|
curr_fo->fo_object_size + sizeof(struct finalizable_object);
|
|
|
|
|
|
i = HASH2(real_ptr, log_fo_table_size);
|
|
|
- fo_set_next (curr_fo, GC_fo_head[i]);
|
|
|
+ fo_set_next(curr_fo, GC_fnlz_roots.fo_head[i]);
|
|
|
GC_fo_entries++;
|
|
|
- GC_fo_head[i] = curr_fo;
|
|
|
+ GC_fnlz_roots.fo_head[i] = curr_fo;
|
|
|
curr_fo = prev_fo;
|
|
|
}
|
|
|
}
|
|
@@ -887,6 +1058,9 @@ GC_INNER void GC_finalize(void)
|
|
|
}
|
|
|
|
|
|
GC_remove_dangling_disappearing_links(&GC_dl_hashtbl);
|
|
|
+# 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);
|
|
@@ -916,9 +1090,9 @@ GC_INNER void GC_finalize(void)
|
|
|
fo_size = log_fo_table_size == -1 ? 0 : 1 << log_fo_table_size;
|
|
|
GC_bytes_finalized = 0;
|
|
|
for (i = 0; i < fo_size; i++) {
|
|
|
- curr_fo = GC_fo_head[i];
|
|
|
- prev_fo = 0;
|
|
|
- while (curr_fo != 0) {
|
|
|
+ curr_fo = GC_fnlz_roots.fo_head[i];
|
|
|
+ prev_fo = NULL;
|
|
|
+ while (curr_fo != NULL) {
|
|
|
real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
|
|
|
GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
|
|
|
GC_set_mark_bit(real_ptr);
|
|
@@ -926,15 +1100,15 @@ GC_INNER void GC_finalize(void)
|
|
|
/* Delete from hash table */
|
|
|
next_fo = fo_next(curr_fo);
|
|
|
if (prev_fo == 0) {
|
|
|
- GC_fo_head[i] = next_fo;
|
|
|
+ GC_fnlz_roots.fo_head[i] = next_fo;
|
|
|
} else {
|
|
|
- fo_set_next(prev_fo, next_fo);
|
|
|
+ fo_set_next(prev_fo, next_fo);
|
|
|
}
|
|
|
GC_fo_entries--;
|
|
|
|
|
|
/* Add to list of objects awaiting finalization. */
|
|
|
- fo_set_next(curr_fo, GC_finalize_now);
|
|
|
- GC_finalize_now = curr_fo;
|
|
|
+ fo_set_next(curr_fo, GC_fnlz_roots.finalize_now);
|
|
|
+ GC_fnlz_roots.finalize_now = curr_fo;
|
|
|
|
|
|
/* unhide object pointer so any future collections will */
|
|
|
/* see it. */
|
|
@@ -986,7 +1160,7 @@ GC_INNER void GC_finalize(void)
|
|
|
/* getting into that safe state is expensive.) */
|
|
|
GC_API int GC_CALL GC_should_invoke_finalizers(void)
|
|
|
{
|
|
|
- return GC_finalize_now != 0;
|
|
|
+ return GC_fnlz_roots.finalize_now != NULL;
|
|
|
}
|
|
|
|
|
|
/* Invoke finalizers for all objects that are ready to be finalized. */
|
|
@@ -998,7 +1172,7 @@ GC_API int GC_CALL GC_invoke_finalizers(void)
|
|
|
word bytes_freed_before = 0; /* initialized to prevent warning. */
|
|
|
DCL_LOCK_STATE;
|
|
|
|
|
|
- while (GC_finalize_now != 0) {
|
|
|
+ while (GC_fnlz_roots.finalize_now != NULL) {
|
|
|
# ifdef THREADS
|
|
|
LOCK();
|
|
|
# endif
|
|
@@ -1006,13 +1180,13 @@ GC_API int GC_CALL GC_invoke_finalizers(void)
|
|
|
bytes_freed_before = GC_bytes_freed;
|
|
|
/* Don't do this outside, since we need the lock. */
|
|
|
}
|
|
|
- curr_fo = GC_finalize_now;
|
|
|
+ curr_fo = GC_fnlz_roots.finalize_now;
|
|
|
# ifdef THREADS
|
|
|
- if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
|
|
|
+ if (curr_fo != 0) GC_fnlz_roots.finalize_now = fo_next(curr_fo);
|
|
|
UNLOCK();
|
|
|
if (curr_fo == 0) break;
|
|
|
# else
|
|
|
- GC_finalize_now = fo_next(curr_fo);
|
|
|
+ GC_fnlz_roots.finalize_now = fo_next(curr_fo);
|
|
|
# endif
|
|
|
fo_set_next(curr_fo, 0);
|
|
|
(*(curr_fo -> fo_fn))((ptr_t)(curr_fo -> fo_hidden_base),
|
|
@@ -1048,7 +1222,7 @@ GC_INNER void GC_notify_or_invoke_finalizers(void)
|
|
|
# if defined(THREADS) && !defined(KEEP_BACK_PTRS) \
|
|
|
&& !defined(MAKE_BACK_GRAPH)
|
|
|
/* Quick check (while unlocked) for an empty finalization queue. */
|
|
|
- if (GC_finalize_now == 0) return;
|
|
|
+ if (NULL == GC_fnlz_roots.finalize_now) return;
|
|
|
# endif
|
|
|
LOCK();
|
|
|
|
|
@@ -1080,7 +1254,7 @@ GC_INNER void GC_notify_or_invoke_finalizers(void)
|
|
|
# endif
|
|
|
}
|
|
|
# endif
|
|
|
- if (GC_finalize_now == 0) {
|
|
|
+ if (NULL == GC_fnlz_roots.finalize_now) {
|
|
|
UNLOCK();
|
|
|
return;
|
|
|
}
|
|
@@ -1093,7 +1267,7 @@ GC_INNER void GC_notify_or_invoke_finalizers(void)
|
|
|
(void) GC_invoke_finalizers();
|
|
|
*pnested = 0; /* Reset since no more finalizers. */
|
|
|
# ifndef THREADS
|
|
|
- GC_ASSERT(GC_finalize_now == 0);
|
|
|
+ GC_ASSERT(NULL == GC_fnlz_roots.finalize_now);
|
|
|
# endif /* Otherwise GC can run concurrently and add more */
|
|
|
}
|
|
|
return;
|
|
@@ -1128,7 +1302,7 @@ GC_INNER void GC_notify_or_invoke_finalizers(void)
|
|
|
(unsigned long)IF_LONG_REFS_PRESENT_ELSE(
|
|
|
GC_ll_hashtbl.entries, 0));
|
|
|
|
|
|
- for (fo = GC_finalize_now; 0 != fo; fo = fo_next(fo))
|
|
|
+ for (fo = GC_fnlz_roots.finalize_now; fo != NULL; fo = fo_next(fo))
|
|
|
++ready;
|
|
|
GC_log_printf("%lu finalization-ready objects;"
|
|
|
" %ld/%ld short/long links cleared\n",
|