mirror of
https://github.com/encounter/bdwgc.git
synced 2026-03-30 10:57:55 -07:00
Fix missing GC_dirty calls for GC-allocated objects used internally
This change matters only in case of MANUAL_VDB mode. * finalize.c (GC_grow_table, GC_register_disappearing_link, GC_unregister_disappearing_link_inner, GC_process_togglerefs, GC_toggleref_add, GC_move_disappearing_link_inner, GC_register_finalizer_inner, ITERATE_DL_HASHTBL_END, DELETE_DL_HASHTBL_ENTRY, GC_finalize, GC_enqueue_all_finalizers): Call GC_dirty where needed. * gcj_mlc.c [GC_GCJ_SUPPORT] (GC_gcj_malloc, GC_debug_gcj_malloc, GC_gcj_malloc_ignore_off_page): Likewise. * pthread_start.c [GC_PTHREADS && !GC_WIN32_THREADS] (GC_inner_start_routine): Likewise. * pthread_support.c [GC_PTHREADS && !GC_WIN32_THREADS] (GC_new_thread, GC_delete_thread, GC_delete_gc_thread): Likewise. * specific.c [USE_CUSTOM_SPECIFIC] (GC_setspecific, GC_remove_specific_after_fork): Likewise. * typd_mlc.c (GC_make_sequence_descriptor, GC_malloc_explicitly_typed, GC_malloc_explicitly_typed_ignore_off_page, GC_calloc_explicitly_typed): Likewise. * win32_threads.c (GC_new_thread, GC_delete_gc_thread_no_free, GC_delete_thread, GC_CreateThread): Likewise. * win32_threads.c [!CYGWIN32 && !MSWINCE && !MSWIN_XBOX1] (GC_beginthreadex): Likewise. * win32_threads.c [GC_PTHREADS] (GC_pthread_create, GC_pthread_start_inner): Likewise. * include/gc_inline.h (GC_FAST_MALLOC_GRANS): Call GC_end_stubborn_change(my_fl) after GC_FAST_M_AO_STORE() call unless kind is GC_I_PTRFREE. * include/gc_inline.h (GC_CONS): Call GC_end_stubborn_change(result).
This commit is contained in:
+39
-1
@@ -154,12 +154,14 @@ STATIC void GC_grow_table(struct hash_chain_entry ***table,
|
||||
size_t new_hash = HASH3(real_key, new_size, log_new_size);
|
||||
|
||||
p -> next = new_table[new_hash];
|
||||
GC_dirty(p);
|
||||
new_table[new_hash] = p;
|
||||
p = next;
|
||||
}
|
||||
}
|
||||
*log_size_ptr = log_new_size;
|
||||
*table = new_table;
|
||||
GC_dirty(new_table); /* entire object */
|
||||
}
|
||||
|
||||
GC_API int GC_CALL GC_register_disappearing_link(void * * link)
|
||||
@@ -236,7 +238,9 @@ STATIC int GC_register_disappearing_link_inner(
|
||||
dl_set_next(new_dl, dl_hashtbl -> head[index]);
|
||||
dl_hashtbl -> head[index] = new_dl;
|
||||
dl_hashtbl -> entries++;
|
||||
GC_dirty(dl_hashtbl->head + index);
|
||||
UNLOCK();
|
||||
GC_dirty(new_dl);
|
||||
return GC_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -274,8 +278,10 @@ GC_INLINE struct disappearing_link *GC_unregister_disappearing_link_inner(
|
||||
/* Remove found entry from the table. */
|
||||
if (NULL == prev_dl) {
|
||||
dl_hashtbl -> head[index] = dl_next(curr_dl);
|
||||
GC_dirty(dl_hashtbl->head + index);
|
||||
} else {
|
||||
dl_set_next(prev_dl, dl_next(curr_dl));
|
||||
GC_dirty(prev_dl);
|
||||
}
|
||||
dl_hashtbl -> entries--;
|
||||
break;
|
||||
@@ -317,6 +323,7 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
|
||||
{
|
||||
int i;
|
||||
int new_size = 0;
|
||||
GC_bool needs_barrier = FALSE;
|
||||
|
||||
GC_ASSERT(I_HOLD_LOCK());
|
||||
for (i = 0; i < GC_toggleref_array_size; ++i) {
|
||||
@@ -334,6 +341,7 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
|
||||
break;
|
||||
case GC_TOGGLE_REF_STRONG:
|
||||
GC_toggleref_arr[new_size++].strong_ref = obj;
|
||||
needs_barrier = TRUE;
|
||||
break;
|
||||
case GC_TOGGLE_REF_WEAK:
|
||||
GC_toggleref_arr[new_size++].weak_ref = GC_HIDE_POINTER(obj);
|
||||
@@ -348,6 +356,8 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
|
||||
(GC_toggleref_array_size - new_size) * sizeof(GCToggleRef));
|
||||
GC_toggleref_array_size = new_size;
|
||||
}
|
||||
if (needs_barrier)
|
||||
GC_dirty(GC_toggleref_arr); /* entire object */
|
||||
}
|
||||
|
||||
STATIC void GC_normal_finalize_mark_proc(ptr_t);
|
||||
@@ -463,8 +473,11 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
|
||||
if (!ensure_toggleref_capacity(1)) {
|
||||
res = GC_NO_MEMORY;
|
||||
} else {
|
||||
GC_toggleref_arr[GC_toggleref_array_size++].strong_ref =
|
||||
GC_toggleref_arr[GC_toggleref_array_size].strong_ref =
|
||||
is_strong_ref ? obj : (void *)GC_HIDE_POINTER(obj);
|
||||
if (is_strong_ref)
|
||||
GC_dirty(GC_toggleref_arr + GC_toggleref_array_size);
|
||||
GC_toggleref_array_size++;
|
||||
}
|
||||
}
|
||||
UNLOCK();
|
||||
@@ -570,10 +583,13 @@ GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void)
|
||||
dl_hashtbl -> head[curr_index] = dl_next(curr_dl);
|
||||
} else {
|
||||
dl_set_next(prev_dl, dl_next(curr_dl));
|
||||
GC_dirty(prev_dl);
|
||||
}
|
||||
curr_dl -> dl_hidden_link = new_hidden_link;
|
||||
dl_set_next(curr_dl, dl_hashtbl -> head[new_index]);
|
||||
dl_hashtbl -> head[new_index] = curr_dl;
|
||||
GC_dirty(curr_dl);
|
||||
GC_dirty(dl_hashtbl->head); /* entire object */
|
||||
return GC_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -712,6 +728,7 @@ STATIC void GC_register_finalizer_inner(void * obj,
|
||||
GC_fnlz_roots.fo_head[index] = fo_next(curr_fo);
|
||||
} else {
|
||||
fo_set_next(prev_fo, fo_next(curr_fo));
|
||||
GC_dirty(prev_fo);
|
||||
}
|
||||
if (fn == 0) {
|
||||
GC_fo_entries--;
|
||||
@@ -725,14 +742,18 @@ STATIC void GC_register_finalizer_inner(void * obj,
|
||||
curr_fo -> fo_fn = fn;
|
||||
curr_fo -> fo_client_data = (ptr_t)cd;
|
||||
curr_fo -> fo_mark_proc = mp;
|
||||
GC_dirty(curr_fo);
|
||||
/* Reinsert it. We deleted it first to maintain */
|
||||
/* consistency in the event of a signal. */
|
||||
if (prev_fo == 0) {
|
||||
GC_fnlz_roots.fo_head[index] = curr_fo;
|
||||
} else {
|
||||
fo_set_next(prev_fo, curr_fo);
|
||||
GC_dirty(prev_fo);
|
||||
}
|
||||
}
|
||||
if (NULL == prev_fo)
|
||||
GC_dirty(GC_fnlz_roots.fo_head + index);
|
||||
UNLOCK();
|
||||
# ifndef DBG_HDRS_ALL
|
||||
if (EXPECT(new_fo != 0, FALSE)) {
|
||||
@@ -795,7 +816,9 @@ STATIC void GC_register_finalizer_inner(void * obj,
|
||||
fo_set_next(new_fo, GC_fnlz_roots.fo_head[index]);
|
||||
GC_fo_entries++;
|
||||
GC_fnlz_roots.fo_head[index] = new_fo;
|
||||
GC_dirty(GC_fnlz_roots.fo_head + index);
|
||||
UNLOCK();
|
||||
GC_dirty(new_fo);
|
||||
}
|
||||
|
||||
GC_API void GC_CALL GC_register_finalizer(void * obj,
|
||||
@@ -922,6 +945,7 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
|
||||
size_t i; \
|
||||
size_t dl_size = dl_hashtbl->log_size == -1 ? 0 : \
|
||||
(size_t)1 << dl_hashtbl->log_size; \
|
||||
GC_bool needs_barrier = FALSE; \
|
||||
GC_ASSERT(I_HOLD_LOCK()); \
|
||||
for (i = 0; i < dl_size; i++) { \
|
||||
struct disappearing_link *prev_dl = NULL; \
|
||||
@@ -933,6 +957,8 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
|
||||
curr_dl = dl_next(curr_dl); \
|
||||
} \
|
||||
} \
|
||||
if (needs_barrier) \
|
||||
GC_dirty(dl_hashtbl -> head); /* entire object */ \
|
||||
}
|
||||
|
||||
#define DELETE_DL_HASHTBL_ENTRY(dl_hashtbl, curr_dl, prev_dl, next_dl) \
|
||||
@@ -940,8 +966,10 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
|
||||
next_dl = dl_next(curr_dl); \
|
||||
if (NULL == prev_dl) { \
|
||||
dl_hashtbl -> head[i] = next_dl; \
|
||||
needs_barrier = TRUE; \
|
||||
} else { \
|
||||
dl_set_next(prev_dl, next_dl); \
|
||||
GC_dirty(prev_dl); \
|
||||
} \
|
||||
GC_clear_mark_bit(curr_dl); \
|
||||
dl_hashtbl -> entries--; \
|
||||
@@ -992,6 +1020,7 @@ GC_INNER void GC_finalize(void)
|
||||
size_t i;
|
||||
size_t fo_size = log_fo_table_size == -1 ? 0 :
|
||||
(size_t)1 << log_fo_table_size;
|
||||
GC_bool needs_barrier = FALSE;
|
||||
|
||||
GC_ASSERT(I_HOLD_LOCK());
|
||||
# ifndef SMALL_CONFIG
|
||||
@@ -1040,8 +1069,10 @@ GC_INNER void GC_finalize(void)
|
||||
next_fo = fo_next(curr_fo);
|
||||
if (NULL == prev_fo) {
|
||||
GC_fnlz_roots.fo_head[i] = next_fo;
|
||||
needs_barrier = TRUE;
|
||||
} else {
|
||||
fo_set_next(prev_fo, next_fo);
|
||||
GC_dirty(prev_fo);
|
||||
}
|
||||
GC_fo_entries--;
|
||||
if (GC_object_finalized_proc)
|
||||
@@ -1049,6 +1080,7 @@ GC_INNER void GC_finalize(void)
|
||||
|
||||
/* Add to list of objects awaiting finalization. */
|
||||
fo_set_next(curr_fo, GC_fnlz_roots.finalize_now);
|
||||
GC_dirty(curr_fo);
|
||||
SET_FINALIZE_NOW(curr_fo);
|
||||
/* unhide object pointer so any future collections will */
|
||||
/* see it. */
|
||||
@@ -1102,6 +1134,7 @@ GC_INNER void GC_finalize(void)
|
||||
SET_FINALIZE_NOW(next_fo);
|
||||
} else {
|
||||
fo_set_next(prev_fo, next_fo);
|
||||
GC_dirty(prev_fo);
|
||||
}
|
||||
curr_fo -> fo_hidden_base =
|
||||
GC_HIDE_POINTER(curr_fo -> fo_hidden_base);
|
||||
@@ -1110,9 +1143,11 @@ GC_INNER void GC_finalize(void)
|
||||
|
||||
i = HASH2(real_ptr, log_fo_table_size);
|
||||
fo_set_next(curr_fo, GC_fnlz_roots.fo_head[i]);
|
||||
GC_dirty(curr_fo);
|
||||
GC_fo_entries++;
|
||||
GC_fnlz_roots.fo_head[i] = curr_fo;
|
||||
curr_fo = prev_fo;
|
||||
needs_barrier = TRUE;
|
||||
}
|
||||
}
|
||||
prev_fo = curr_fo;
|
||||
@@ -1120,6 +1155,8 @@ GC_INNER void GC_finalize(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needs_barrier)
|
||||
GC_dirty(GC_fnlz_roots.fo_head); /* entire object */
|
||||
|
||||
GC_remove_dangling_disappearing_links(&GC_dl_hashtbl);
|
||||
# ifndef GC_TOGGLE_REFS_NOT_NEEDED
|
||||
@@ -1167,6 +1204,7 @@ GC_INNER void GC_finalize(void)
|
||||
|
||||
/* Add to list of objects awaiting finalization. */
|
||||
fo_set_next(curr_fo, GC_fnlz_roots.finalize_now);
|
||||
GC_dirty(curr_fo);
|
||||
SET_FINALIZE_NOW(curr_fo);
|
||||
|
||||
/* unhide object pointer so any future collections will */
|
||||
|
||||
@@ -193,6 +193,7 @@ static void maybe_finalize(void)
|
||||
}
|
||||
*(void **)op = ptr_to_struct_containing_descr;
|
||||
UNLOCK();
|
||||
GC_dirty(op);
|
||||
return((void *) op);
|
||||
}
|
||||
|
||||
@@ -224,6 +225,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_gcj_malloc(size_t lb,
|
||||
ADD_CALL_CHAIN(result, ra);
|
||||
result = GC_store_debug_info_inner(result, (word)lb, s, i);
|
||||
UNLOCK();
|
||||
GC_dirty(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -265,6 +267,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_gcj_malloc_ignore_off_page(size_t lb,
|
||||
}
|
||||
*(void **)op = ptr_to_struct_containing_descr;
|
||||
UNLOCK();
|
||||
GC_dirty(op);
|
||||
return((void *) op);
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +128,7 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||
GC_FAST_M_AO_STORE(my_fl, next); \
|
||||
init; \
|
||||
GC_PREFETCH_FOR_WRITE(next); \
|
||||
if ((kind) != GC_I_PTRFREE) GC_end_stubborn_change(my_fl); \
|
||||
GC_ASSERT(GC_size(result) >= (granules)*GC_GRANULE_BYTES); \
|
||||
GC_ASSERT((kind) == GC_I_PTRFREE \
|
||||
|| ((GC_word *)result)[1] == 0); \
|
||||
@@ -140,6 +141,7 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||
/* Small counter value, not NULL */ \
|
||||
GC_FAST_M_AO_STORE(my_fl, (char *)my_entry \
|
||||
+ (granules) + 1); \
|
||||
if ((kind) != GC_I_PTRFREE) GC_end_stubborn_change(my_fl); \
|
||||
result = (default_expr); \
|
||||
break; \
|
||||
} else { \
|
||||
@@ -189,6 +191,7 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||
if ((result) != NULL) { \
|
||||
*(void **)(result) = (void *)(first); \
|
||||
((void **)(result))[1] = (void *)(second); \
|
||||
GC_end_stubborn_change(result); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ GC_INNER_PTHRSTART void * GC_CALLBACK GC_inner_start_routine(
|
||||
GC_log_printf("Finishing thread %p\n", (void *)pthread_self());
|
||||
# endif
|
||||
me -> status = result;
|
||||
GC_dirty(me);
|
||||
# ifndef NACL
|
||||
pthread_cleanup_pop(1);
|
||||
/* Cleanup acquires lock, ensuring that we can't exit while */
|
||||
|
||||
@@ -565,6 +565,8 @@ STATIC GC_thread GC_new_thread(pthread_t id)
|
||||
GC_nacl_initialize_gc_thread();
|
||||
# endif
|
||||
GC_ASSERT(result -> flags == 0 && result -> thread_blocked == 0);
|
||||
if (EXPECT(result != &first_thread, TRUE))
|
||||
GC_dirty(result);
|
||||
return(result);
|
||||
}
|
||||
|
||||
@@ -597,6 +599,7 @@ STATIC void GC_delete_thread(pthread_t id)
|
||||
} else {
|
||||
GC_ASSERT(prev != &first_thread);
|
||||
prev -> next = p -> next;
|
||||
GC_dirty(prev);
|
||||
}
|
||||
if (p != &first_thread) {
|
||||
# ifdef GC_DARWIN_THREADS
|
||||
@@ -627,6 +630,7 @@ STATIC void GC_delete_gc_thread(GC_thread t)
|
||||
} else {
|
||||
GC_ASSERT(prev != &first_thread);
|
||||
prev -> next = p -> next;
|
||||
GC_dirty(prev);
|
||||
}
|
||||
# ifdef GC_DARWIN_THREADS
|
||||
mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
|
||||
|
||||
@@ -70,6 +70,8 @@ GC_INNER int GC_setspecific(tsd * key, void * value)
|
||||
/* There can only be one writer at a time, but this needs to be */
|
||||
/* atomic with respect to concurrent readers. */
|
||||
AO_store_release(&key->hash[hash_val].ao, (AO_t)entry);
|
||||
GC_dirty((/* no volatile */ void *)entry);
|
||||
GC_dirty(key->hash + hash_val);
|
||||
pthread_mutex_unlock(&(key -> lock));
|
||||
return 0;
|
||||
}
|
||||
@@ -101,8 +103,10 @@ GC_INNER void GC_remove_specific_after_fork(tsd * key, pthread_t t)
|
||||
entry -> qtid = INVALID_QTID;
|
||||
if (NULL == prev) {
|
||||
key->hash[hash_val].p = entry->next;
|
||||
GC_dirty(key->hash + hash_val);
|
||||
} else {
|
||||
prev->next = entry->next;
|
||||
GC_dirty(prev);
|
||||
}
|
||||
/* Atomic! concurrent accesses still work. */
|
||||
/* They must, since readers don't lock. */
|
||||
|
||||
@@ -325,6 +325,7 @@ GC_make_sequence_descriptor(complex_descriptor *first,
|
||||
result -> sd_tag = SEQUENCE_TAG;
|
||||
result -> sd_first = first;
|
||||
result -> sd_second = second;
|
||||
GC_dirty(result);
|
||||
}
|
||||
return((complex_descriptor *)result);
|
||||
}
|
||||
@@ -602,6 +603,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_explicitly_typed(size_t lb,
|
||||
/* the former might be updated asynchronously. */
|
||||
lg = BYTES_TO_GRANULES(GC_size(op));
|
||||
op[GRANULES_TO_WORDS(lg) - 1] = d;
|
||||
GC_dirty(op + GRANULES_TO_WORDS(lg) - 1);
|
||||
return op;
|
||||
}
|
||||
|
||||
@@ -642,6 +644,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL
|
||||
lg = BYTES_TO_GRANULES(GC_size(op));
|
||||
}
|
||||
((word *)op)[GRANULES_TO_WORDS(lg) - 1] = d;
|
||||
GC_dirty(op + GRANULES_TO_WORDS(lg) - 1);
|
||||
return op;
|
||||
}
|
||||
|
||||
@@ -695,6 +698,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_calloc_explicitly_typed(size_t n,
|
||||
size_t lw = GRANULES_TO_WORDS(lg);
|
||||
|
||||
op[lw - 1] = (word)complex_descr;
|
||||
GC_dirty(op + lw - 1);
|
||||
/* Make sure the descriptor is cleared once there is any danger */
|
||||
/* it may have been collected. */
|
||||
if (EXPECT(GC_general_register_disappearing_link(
|
||||
|
||||
@@ -360,6 +360,8 @@ STATIC GC_thread GC_new_thread(DWORD id)
|
||||
GC_ASSERT(result -> flags == 0);
|
||||
# endif
|
||||
GC_ASSERT(result -> thread_blocked_sp == NULL);
|
||||
if (EXPECT(result != &first_thread, TRUE))
|
||||
GC_dirty(result);
|
||||
return(result);
|
||||
}
|
||||
|
||||
@@ -683,6 +685,7 @@ STATIC void GC_delete_gc_thread_no_free(GC_vthread t)
|
||||
} else {
|
||||
GC_ASSERT(prev != &first_thread);
|
||||
prev -> tm.next = p -> tm.next;
|
||||
GC_dirty(prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -721,6 +724,7 @@ STATIC void GC_delete_thread(DWORD id)
|
||||
} else {
|
||||
GC_ASSERT(prev != &first_thread);
|
||||
prev -> tm.next = p -> tm.next;
|
||||
GC_dirty(prev);
|
||||
}
|
||||
if (EXPECT(p != &first_thread, TRUE)) {
|
||||
GC_INTERNAL_FREE(p);
|
||||
@@ -2261,6 +2265,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
|
||||
/* set up thread arguments */
|
||||
args -> start = lpStartAddress;
|
||||
args -> param = lpParameter;
|
||||
GC_dirty(args);
|
||||
|
||||
set_need_to_lock();
|
||||
thread_h = CreateThread(lpThreadAttributes, dwStackSize, GC_win32_start,
|
||||
@@ -2313,6 +2318,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
|
||||
/* set up thread arguments */
|
||||
args -> start = (LPTHREAD_START_ROUTINE)start_address;
|
||||
args -> param = arglist;
|
||||
GC_dirty(args);
|
||||
|
||||
set_need_to_lock();
|
||||
thread_h = _beginthreadex(security, stack_size,
|
||||
@@ -2605,6 +2611,7 @@ GC_INNER void GC_thr_init(void)
|
||||
|
||||
si -> start_routine = start_routine;
|
||||
si -> arg = arg;
|
||||
GC_dirty(si);
|
||||
if (attr != 0 &&
|
||||
pthread_attr_getdetachstate(attr, &si->detached)
|
||||
== PTHREAD_CREATE_DETACHED) {
|
||||
@@ -2665,6 +2672,7 @@ GC_INNER void GC_thr_init(void)
|
||||
pthread_cleanup_push(GC_thread_exit_proc, (void *)me);
|
||||
result = (*start)(start_arg);
|
||||
me -> status = result;
|
||||
GC_dirty(me);
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
# ifdef DEBUG_THREADS
|
||||
|
||||
Reference in New Issue
Block a user