]> granicus.if.org Git - gc/commitdiff
Fix missing GC_dirty calls for GC-allocated objects used internally
authorIvan Maidanski <ivmai@mail.ru>
Fri, 18 May 2018 07:58:54 +0000 (10:58 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Tue, 10 Jul 2018 07:17:21 +0000 (10:17 +0300)
(a cherry-pick of commits 73d30d2e5fb5748eb6f8d0553eb0 from 'master')

This change matters only in case of MANUAL_VDB mode.

Also, GC_reachable_here calls are inserted after GC_dirty.

Also, this commit actually disables multiple objects allocation in
GC_generic_malloc_many if MANUAL_VDB and the incremental mode are on.

* 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.
* gcj_mlc.c (GC_gcj_malloc, GC_debug_gcj_malloc,
GC_gcj_malloc_ignore_off_page): Call
REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr) after GC_dirty(op).
* mallocx.c [MANUAL_VDB] (GC_generic_malloc_many): Always fall back to
GC_generic_malloc (unless !GC_incremental).
* mallocx.c [MANUAL_VDB] (GC_generic_malloc_many): If
GC_is_heap_ptr(result) then call GC_dirty(result) and
REACHABLE_AFTER_DIRTY(op) after storing op pointer.
* 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.
* typd_mlc.c (GC_make_sequence_descriptor): Call REACHABLE_AFTER_DIRTY
for the stored pointers after GC_dirty(result).
* typd_mlc.c (GC_malloc_explicitly_typed,
GC_malloc_explicitly_typed_ignore_off_page, GC_calloc_explicitly_typed):
Call REACHABLE_AFTER_DIRTY(d) after GC_dirty(op).
* win32_threads.c (GC_CreateThread, GC_beginthreadex,
GC_pthread_create): Call REACHABLE_AFTER_DIRTY for the stored pointer
after GC_dirty.
* 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_FAST_MALLOC_GRANS): Call
GC_reachable_here(next) after GC_end_stubborn_change(my_fl).
* include/gc_inline.h (GC_CONS): Call GC_end_stubborn_change(result).
* include/gc_inline.h (GC_CONS): Call GC_reachable_here for the stored
pointers after GC_end_stubborn_change call.
* include/gc_inline.h (GC_CONS): Declare l and r local variables;
compute first and second expression even in case of
GC_MALLOC_WORDS_KIND failure; pass l and r to GC_reachable_here (instead
of first and second).
* include/private/gc_priv.h (REACHABLE_AFTER_DIRTY): New macro.

finalize.c
gcj_mlc.c
include/gc_inline.h
include/private/gc_priv.h
mallocx.c
pthread_start.c
pthread_support.c
specific.c
typd_mlc.c
win32_threads.c

index 305017154b1185a5afcfb431d5a5cc1f89c4007d..95bbda7bf2e1398d22f98e19c15885ba9542462a 100644 (file)
@@ -144,12 +144,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)
@@ -224,8 +226,10 @@ STATIC int GC_register_disappearing_link_inner(
     new_dl -> dl_hidden_obj = GC_HIDE_POINTER(obj);
     new_dl -> dl_hidden_link = GC_HIDE_POINTER(link);
     dl_set_next(new_dl, dl_hashtbl -> head[index]);
+    GC_dirty(new_dl);
     dl_hashtbl -> head[index] = new_dl;
     dl_hashtbl -> entries++;
+    GC_dirty(dl_hashtbl->head + index);
     UNLOCK();
     return GC_SUCCESS;
 }
@@ -264,8 +268,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;
@@ -307,6 +313,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) {
@@ -324,6 +331,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);
@@ -338,6 +346,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);
@@ -451,8 +461,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();
@@ -557,10 +570,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;
   }
 
@@ -699,6 +715,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--;
@@ -712,14 +729,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)) {
@@ -780,8 +801,10 @@ STATIC void GC_register_finalizer_inner(void * obj,
     new_fo -> fo_object_size = hhdr -> hb_sz;
     new_fo -> fo_mark_proc = mp;
     fo_set_next(new_fo, GC_fnlz_roots.fo_head[index]);
+    GC_dirty(new_fo);
     GC_fo_entries++;
     GC_fnlz_roots.fo_head[index] = new_fo;
+    GC_dirty(GC_fnlz_roots.fo_head + index);
     UNLOCK();
 }
 
@@ -909,6 +932,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; \
     for (i = 0; i < dl_size; i++) { \
       struct disappearing_link *prev_dl = NULL; \
       curr_dl = dl_hashtbl -> head[i]; \
@@ -919,6 +943,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) \
@@ -926,8 +952,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--; \
@@ -975,6 +1003,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;
 
 #   ifndef SMALL_CONFIG
       /* Save current GC_[dl/ll]_entries value for stats printing */
@@ -1022,8 +1051,14 @@ GC_INNER void GC_finalize(void)
               next_fo = fo_next(curr_fo);
               if (NULL == prev_fo) {
                 GC_fnlz_roots.fo_head[i] = next_fo;
+                if (GC_object_finalized_proc) {
+                  GC_dirty(GC_fnlz_roots.fo_head + i);
+                } else {
+                  needs_barrier = TRUE;
+                }
               } else {
                 fo_set_next(prev_fo, next_fo);
+                GC_dirty(prev_fo);
               }
               GC_fo_entries--;
               if (GC_object_finalized_proc)
@@ -1031,6 +1066,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);
               GC_fnlz_roots.finalize_now = curr_fo;
               /* unhide object pointer so any future collections will   */
               /* see it.                                                */
@@ -1084,6 +1120,7 @@ GC_INNER void GC_finalize(void)
                 GC_fnlz_roots.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);
@@ -1092,9 +1129,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;
@@ -1102,6 +1141,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
@@ -1148,6 +1189,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);
           GC_fnlz_roots.finalize_now = curr_fo;
 
           /* unhide object pointer so any future collections will       */
index 64f0d1462df222f8c3af43c7047da424d0f81319..8879a3bbc5c324b9dda1c6b5bf8fd90e8d6ef5c1 100644 (file)
--- a/gcj_mlc.c
+++ b/gcj_mlc.c
@@ -192,7 +192,9 @@ static void maybe_finalize(void)
     }
     *(void **)op = ptr_to_struct_containing_descr;
     UNLOCK();
-    return((void *) op);
+    GC_dirty(op);
+    REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr);
+    return (void *)op;
 }
 
 /* Similar to GC_gcj_malloc, but add debug info.  This is allocated     */
@@ -223,6 +225,8 @@ 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);
+    REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr);
     return result;
 }
 
@@ -263,7 +267,9 @@ 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();
-    return((void *) op);
+    GC_dirty(op);
+    REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr);
+    return (void *)op;
 }
 
 #endif  /* GC_GCJ_SUPPORT */
index dcbd808383bdfd7c1ead878f98e162a052bd252a..7372fadd5fe83efcff1b3c0e29e221e0fd2132c8 100644 (file)
@@ -106,6 +106,10 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
                 *my_fl = next; \
                 init; \
                 GC_PREFETCH_FOR_WRITE(next); \
+                if ((kind) != GC_I_PTRFREE) { \
+                    GC_end_stubborn_change(my_fl); \
+                    GC_reachable_here(next); \
+                } \
                 GC_ASSERT(GC_size(result) >= (granules)*GC_GRANULE_BYTES); \
                 GC_ASSERT((kind) == GC_I_PTRFREE \
                           || ((GC_word *)result)[1] == 0); \
@@ -162,10 +166,15 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
 /* And once more for two word initialized objects: */
 # define GC_CONS(result, first, second, tiny_fl) \
     do { \
+      void *l = (void *)(first); \
+      void *r = (void *)(second); \
       GC_MALLOC_WORDS_KIND(result, 2, tiny_fl, GC_I_NORMAL, (void)0); \
       if ((result) != NULL) { \
-        *(void **)(result) = (void *)(first); \
-        ((void **)(result))[1] = (void *)(second); \
+        *(void **)(result) = l; \
+        ((void **)(result))[1] = r; \
+        GC_end_stubborn_change(result); \
+        GC_reachable_here(l); \
+        GC_reachable_here(r); \
       } \
     } while (0)
 
index 19a15ee9b99cfa7f31a9076068f35576d9f3dbad..9080f05c0dd624dc52c5e955bdd953d42ab448e7 100644 (file)
@@ -2150,8 +2150,10 @@ GC_EXTERN GC_bool GC_print_back_height;
 #ifdef MANUAL_VDB
   GC_INNER void GC_dirty_inner(const void *p); /* does not require locking */
 # define GC_dirty(p) (GC_incremental ? GC_dirty_inner(p) : (void)0)
+# define REACHABLE_AFTER_DIRTY(p) GC_reachable_here(p)
 #else
 # define GC_dirty(p) (void)(p)
+# define REACHABLE_AFTER_DIRTY(p) (void)(p)
 #endif
 
 /* Same as GC_base but excepts and returns a pointer to const object.   */
index d6b7f965b1bc34f637a673d4aac29507c9300303..fc5c963cd200b6beba0235bc9c32c39e9f967dbb 100644 (file)
--- a/mallocx.c
+++ b/mallocx.c
@@ -286,11 +286,24 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t lb, int k, void **result)
     DCL_LOCK_STATE;
 
     GC_ASSERT(lb != 0 && (lb & (GRANULE_BYTES-1)) == 0);
-    if (!SMALL_OBJ(lb)) {
+    if (!SMALL_OBJ(lb)
+#     ifdef MANUAL_VDB
+        /* Currently a single object is allocated.                      */
+        /* TODO: GC_dirty should be called for each linked object (but  */
+        /* the last one) to support multiple objects allocation.        */
+        || GC_incremental
+#     endif
+       ) {
         op = GC_generic_malloc(lb, k);
         if (EXPECT(0 != op, TRUE))
             obj_link(op) = 0;
         *result = op;
+#       ifdef MANUAL_VDB
+          if (GC_is_heap_ptr(result)) {
+            GC_dirty(result);
+            REACHABLE_AFTER_DIRTY(op);
+          }
+#       endif
         return;
     }
     GC_ASSERT(k < MAXOBJKINDS);
index bd4fc4a048893f655903a8d5c56f40ed968f83e9..f83dc434ca49ee6ad899ce3373cf601f3613b23c 100644 (file)
@@ -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         */
index 969f477a1a9c09cc337db6902fa77d9679075ee4..3dc7b59e47f1022a583737a94278db54165274ca 100644 (file)
@@ -563,6 +563,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);
 }
 
@@ -594,6 +596,7 @@ STATIC void GC_delete_thread(pthread_t id)
         GC_threads[hv] = p -> next;
     } else {
         prev -> next = p -> next;
+        GC_dirty(prev);
     }
     if (p != &first_thread) {
 #     ifdef GC_DARWIN_THREADS
@@ -623,6 +626,7 @@ STATIC void GC_delete_gc_thread(GC_thread t)
         GC_threads[hv] = p -> next;
     } else {
         prev -> next = p -> next;
+        GC_dirty(prev);
     }
 #   ifdef GC_DARWIN_THREADS
         mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
index 75917294d27a7ad080793ccaaa3457b2fe745605..579be6f7b890bb150313b198ef88256bd8fc594b 100644 (file)
@@ -68,6 +68,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;
 }
@@ -99,8 +101,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.           */
index 42c20c9ad386b26fd7ae1a68e45ac906ef78caad..22b980c55cf80cca5ae34a2d2ce924191761b62e 100644 (file)
@@ -321,6 +321,9 @@ GC_make_sequence_descriptor(complex_descriptor *first,
         result -> sd_tag = SEQUENCE_TAG;
         result -> sd_first = first;
         result -> sd_second = second;
+        GC_dirty(result);
+        REACHABLE_AFTER_DIRTY(first);
+        REACHABLE_AFTER_DIRTY(second);
     }
     return((complex_descriptor *)result);
 }
@@ -599,6 +602,8 @@ 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);
+    REACHABLE_AFTER_DIRTY(d);
     return op;
 }
 
@@ -634,6 +639,8 @@ 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);
+    REACHABLE_AFTER_DIRTY(d);
     return op;
 }
 
@@ -687,6 +694,9 @@ 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);
+        REACHABLE_AFTER_DIRTY(complex_descr);
+
         /* Make sure the descriptor is cleared once there is any danger */
         /* it may have been collected.                                  */
         if (EXPECT(GC_general_register_disappearing_link(
index b2753f85a2f370505e946c17e021155b27e2d819..a9cff3fc91d03c30c5abda38c7dbf4bc9978d4ff 100644 (file)
@@ -356,6 +356,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);
 }
 
@@ -678,6 +680,7 @@ STATIC void GC_delete_gc_thread_no_free(GC_vthread t)
       GC_threads[hv] = p -> tm.next;
     } else {
       prev -> tm.next = p -> tm.next;
+      GC_dirty(prev);
     }
   }
 }
@@ -715,6 +718,7 @@ STATIC void GC_delete_thread(DWORD id)
       GC_threads[hv] = p -> tm.next;
     } else {
       prev -> tm.next = p -> tm.next;
+      GC_dirty(prev);
     }
     if (p != &first_thread) {
       GC_INTERNAL_FREE(p);
@@ -2251,6 +2255,8 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
       /* set up thread arguments */
       args -> start = lpStartAddress;
       args -> param = lpParameter;
+      GC_dirty(args);
+      REACHABLE_AFTER_DIRTY(lpParameter);
 
       set_need_to_lock();
       thread_h = CreateThread(lpThreadAttributes, dwStackSize, GC_win32_start,
@@ -2303,6 +2309,8 @@ 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);
+        REACHABLE_AFTER_DIRTY(arglist);
 
         set_need_to_lock();
         thread_h = _beginthreadex(security, stack_size,
@@ -2589,6 +2597,8 @@ GC_INNER void GC_thr_init(void)
 
       si -> start_routine = start_routine;
       si -> arg = arg;
+      GC_dirty(si);
+      REACHABLE_AFTER_DIRTY(arg);
       if (attr != 0 &&
           pthread_attr_getdetachstate(attr, &si->detached)
           == PTHREAD_CREATE_DETACHED) {
@@ -2648,6 +2658,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