浏览代码

Updated to latest Boehm GC.

woollybah 10 年之前
父节点
当前提交
d34cdd72b0

+ 5 - 4
blitz.mod/bdwgc/alloc.c

@@ -152,7 +152,7 @@ STATIC GC_stop_func GC_default_stop_func = GC_never_stop_func;
 GC_API void GC_CALL GC_set_stop_func(GC_stop_func stop_func)
 {
   DCL_LOCK_STATE;
-  GC_ASSERT(stop_func != 0);
+  GC_ASSERT(NONNULL_ARG_NOT_NULL(stop_func));
   LOCK();
   GC_default_stop_func = stop_func;
   UNLOCK();
@@ -637,13 +637,14 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
         GET_TIME(start_time);
 #   endif
 
+#   if !defined(GC_NO_FINALIZATION) && !defined(GC_TOGGLE_REFS_NOT_NEEDED)
+      GC_process_togglerefs();
+#   endif
 #   ifdef THREADS
       if (GC_on_collection_event)
         GC_on_collection_event(GC_EVENT_PRE_STOP_WORLD);
 #   endif
-
     STOP_WORLD();
-
 #   ifdef THREADS
       if (GC_on_collection_event)
         GC_on_collection_event(GC_EVENT_POST_STOP_WORLD);
@@ -1078,7 +1079,7 @@ STATIC GC_bool GC_try_to_collect_general(GC_stop_func stop_func,
 /* Externally callable routines to invoke full, stop-the-world collection. */
 GC_API int GC_CALL GC_try_to_collect(GC_stop_func stop_func)
 {
-    GC_ASSERT(stop_func != 0);
+    GC_ASSERT(NONNULL_ARG_NOT_NULL(stop_func));
     return (int)GC_try_to_collect_general(stop_func, FALSE);
 }
 

+ 1 - 1
blitz.mod/bdwgc/darwin_stop_world.c

@@ -178,7 +178,7 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
 #       if defined(ARM_UNIFIED_THREAD_STATE)
           state = unified_state;
 #       else
-          state = unified_state.ts_32;
+        state = unified_state.ts_32;
 #       endif
       } else
 #   endif

+ 3 - 3
blitz.mod/bdwgc/dyn_load.c

@@ -109,9 +109,9 @@ STATIC GC_has_static_roots_func GC_has_static_roots = 0;
 #     undef EM_ALPHA
 #   endif
 #   include <link.h>
-#   if !defined(GC_DONT_DEFINE_LINK_MAP)
-      /* link_map and r_debug should be defined explicitly,             */
-      /* as only bionic/linker/linker.h defines them but the header     */
+#   if !defined(GC_DONT_DEFINE_LINK_MAP) && !(__ANDROID_API__ >= 21)
+      /* link_map and r_debug are defined in link.h of NDK r10+.        */
+      /* bionic/linker/linker.h defines them too but the header         */
       /* itself is a C++ one starting from Android 4.3.                 */
       struct link_map {
         uintptr_t l_addr;

+ 238 - 64
blitz.mod/bdwgc/finalize.c

@@ -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",

+ 2 - 2
blitz.mod/bdwgc/include/cord.h

@@ -66,8 +66,8 @@
 #   elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \
          || defined(__CYGWIN__) || defined(__WATCOMC__)
 #     define CORD_API extern __declspec(dllexport)
-#   elif defined(__GNUC__) && (__GNUC__ >= 4 \
-                               || defined(GC_VISIBILITY_HIDDEN_SET))
+#   elif defined(__GNUC__) && !defined(GC_NO_VISIBILITY) \
+         && (__GNUC__ >= 4 || defined(GC_VISIBILITY_HIDDEN_SET))
     /* Only matters if used in conjunction with -fvisibility=hidden option. */
 #     define CORD_API extern __attribute__((__visibility__("default")))
 #   endif

+ 37 - 0
blitz.mod/bdwgc/include/gc.h

@@ -1172,6 +1172,43 @@ GC_API int GC_CALL GC_unregister_long_link(void ** /* link */);
         /* Similar to GC_unregister_disappearing_link but for a */
         /* registration by either of the above two routines.    */
 
+/* Support of toggle-ref style of external memory management    */
+/* without hooking up to the host retain/release machinery.     */
+/* The idea of toggle-ref is that an external reference to      */
+/* an object is kept and it can be either a strong or weak      */
+/* reference; a weak reference is used when the external peer   */
+/* has no interest in the object, and a strong otherwise.       */
+typedef enum {
+   GC_TOGGLE_REF_DROP,
+   GC_TOGGLE_REF_STRONG,
+   GC_TOGGLE_REF_WEAK
+} GC_ToggleRefStatus;
+
+/* The callback is to decide (return) the new state of a given  */
+/* object.  Invoked by the collector for all objects registered */
+/* for toggle-ref processing.  Invoked with the allocation lock */
+/* held (but the "world" is running).                           */
+typedef GC_ToggleRefStatus (GC_CALLBACK *GC_toggleref_func)(void * /* obj */);
+
+/* Set (register) a callback that decides the state of a given  */
+/* object (by, probably, inspecting its native state).          */
+/* The argument may be 0 (means no callback).  Both the setter  */
+/* and the getter acquire the allocation lock (to avoid data    */
+/* races).                                                      */
+GC_API void GC_CALL GC_set_toggleref_func(GC_toggleref_func);
+GC_API GC_toggleref_func GC_CALL GC_get_toggleref_func(void);
+
+/* Register a given object for toggle-ref processing.  It will  */
+/* be stored internally and the toggle-ref callback will be     */
+/* invoked on the object until the callback returns             */
+/* GC_TOGGLE_REF_DROP or the object is collected.  If is_strong */
+/* is true then the object is registered with a strong ref,     */
+/* a weak one otherwise.  Returns GC_SUCCESS if registration    */
+/* succeeded (or no callback registered yet), GC_NO_MEMORY if   */
+/* it failed for lack of memory.                                */
+GC_API int GC_CALL GC_toggleref_add(void * /* obj */, int /* is_strong */)
+                                                GC_ATTR_NONNULL(1);
+
 /* Finalizer callback support.  Invoked by the collector (with  */
 /* the allocation lock held) for each unreachable object        */
 /* enqueued for finalization.                                   */

+ 2 - 2
blitz.mod/bdwgc/include/gc_config_macros.h

@@ -202,8 +202,8 @@
 
 # elif defined(__GNUC__)
     /* Only matters if used in conjunction with -fvisibility=hidden option. */
-#   if defined(GC_BUILD) && (__GNUC__ >= 4 \
-                             || defined(GC_VISIBILITY_HIDDEN_SET))
+#   if defined(GC_BUILD) && !defined(GC_NO_VISIBILITY) \
+            && (__GNUC__ >= 4 || defined(GC_VISIBILITY_HIDDEN_SET))
 #     define GC_API extern __attribute__((__visibility__("default")))
 #   endif
 # endif

+ 25 - 9
blitz.mod/bdwgc/include/private/gc_priv.h

@@ -109,7 +109,7 @@ typedef char * ptr_t;   /* A generic pointer to which we can add        */
   /* located in the "extra" folder).                                    */
 # if defined(GC_DLL) && defined(__GNUC__) && !defined(MSWIN32) \
         && !defined(MSWINCE) && !defined(CYGWIN32)
-#   if __GNUC__ >= 4
+#   if (__GNUC__ >= 4) && !defined(GC_NO_VISIBILITY)
       /* See the corresponding GC_API definition. */
 #     define GC_INNER __attribute__((__visibility__("hidden")))
 #   else
@@ -165,7 +165,7 @@ typedef char * ptr_t;   /* A generic pointer to which we can add        */
 #ifndef GC_API_OSCALL
   /* This is used to identify GC routines called by name from OS.       */
 # if defined(__GNUC__)
-#   if __GNUC__ >= 4
+#   if (__GNUC__ >= 4) && !defined(GC_NO_VISIBILITY)
       /* Same as GC_API if GC_DLL.      */
 #     define GC_API_OSCALL extern __attribute__((__visibility__("default")))
 #   else
@@ -255,26 +255,30 @@ typedef char * ptr_t;   /* A generic pointer to which we can add        */
 
 
 #ifndef GC_NO_FINALIZATION
-#  define GC_INVOKE_FINALIZERS() GC_notify_or_invoke_finalizers()
-   GC_INNER void GC_notify_or_invoke_finalizers(void);
+# define GC_INVOKE_FINALIZERS() GC_notify_or_invoke_finalizers()
+  GC_INNER void GC_notify_or_invoke_finalizers(void);
                         /* If GC_finalize_on_demand is not set, invoke  */
                         /* eligible finalizers. Otherwise:              */
                         /* Call *GC_finalizer_notifier if there are     */
                         /* finalizers to be run, and we haven't called  */
                         /* this procedure yet this GC cycle.            */
 
-   GC_INNER void GC_finalize(void);
+  GC_INNER void GC_finalize(void);
                         /* Perform all indicated finalization actions   */
                         /* on unmarked objects.                         */
                         /* Unreachable finalizable objects are enqueued */
                         /* for processing by GC_invoke_finalizers.      */
                         /* Invoked with lock.                           */
 
-#  ifndef SMALL_CONFIG
-     GC_INNER void GC_print_finalization_stats(void);
-#  endif
+# ifndef GC_TOGGLE_REFS_NOT_NEEDED
+    GC_INNER void GC_process_togglerefs(void);
+                        /* Process the toggle-refs before GC starts.    */
+# endif
+# ifndef SMALL_CONFIG
+    GC_INNER void GC_print_finalization_stats(void);
+# endif
 #else
-#  define GC_INVOKE_FINALIZERS() (void)0
+# define GC_INVOKE_FINALIZERS() (void)0
 #endif /* GC_NO_FINALIZATION */
 
 #if !defined(DONT_ADD_BYTE_AT_END)
@@ -1603,6 +1607,9 @@ GC_INNER GC_bool GC_collection_in_progress(void);
 # define GC_PUSH_CONDITIONAL(b, t, all) GC_push_all((ptr_t)(b), (ptr_t)(t))
 #endif
 
+#define GC_PUSH_ALL_SYM(sym) \
+                GC_push_all((ptr_t)&(sym), (ptr_t)&(sym) + sizeof(sym))
+
 GC_INNER void GC_push_all_stack(ptr_t b, ptr_t t);
                                     /* As GC_push_all but consider      */
                                     /* interior pointers as valid.      */
@@ -2350,6 +2357,14 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
 # define GC_STATIC_ASSERT(expr) (void)sizeof(char[(expr)? 1 : -1])
 #endif
 
+/* Runtime check for an argument declared as non-null is actually not null. */
+#if defined(__GNUC__) && __GNUC__ >= 4
+  /* Workaround tautological-pointer-compare Clang warning.     */
+# define NONNULL_ARG_NOT_NULL(arg) (*(volatile void **)&(arg) != NULL)
+#else
+# define NONNULL_ARG_NOT_NULL(arg) (NULL != (arg))
+#endif
+
 #define COND_DUMP_CHECKS \
           do { \
             GC_ASSERT(GC_compute_large_free_bytes() == GC_large_free_bytes); \
@@ -2386,6 +2401,7 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
   /* GC_notify_all_builder() is called when GC_fl_builder_count         */
   /* reaches 0.                                                         */
 
+  GC_INNER void GC_wait_for_markers_init(void);
   GC_INNER void GC_acquire_mark_lock(void);
   GC_INNER void GC_release_mark_lock(void);
   GC_INNER void GC_notify_all_builder(void);

+ 58 - 16
blitz.mod/bdwgc/include/private/gcconfig.h

@@ -429,6 +429,10 @@
 #   define AARCH64
 #   define mach_type_known
 # endif
+# if defined(FREEBSD) && (defined(mips) || defined(__mips) || defined(_mips))
+#   define MIPS
+#   define mach_type_known
+# endif
 # if defined(bsdi) && (defined(i386) || defined(__i386__))
 #    define I386
 #    define BSDI
@@ -946,7 +950,7 @@
 #     endif
       extern int __data_start[];
 #     define DATASTART ((ptr_t)__data_start)
-      extern char _end[];
+      extern int _end[];
 #     define DATAEND ((ptr_t)(&_end))
 #     define DYNAMIC_LOADING
 #   endif
@@ -986,7 +990,7 @@
 #     define NO_GETENV
 #     define CPP_WORDSZ 32
 #     define ALIGNMENT 4
-      extern int _end [];
+      extern int _end[];
       extern int __bss_start;
 #     define DATAEND (ptr_t)(_end)
 #     define DATASTART (ptr_t)(__bss_start)
@@ -1148,7 +1152,7 @@
 #     endif
       extern int __data_start[];
 #     define DATASTART ((ptr_t)__data_start)
-      extern char _end[];
+      extern int _end[];
 #     define DATAEND ((ptr_t)(&_end))
 #     define DYNAMIC_LOADING
 #   endif
@@ -1338,9 +1342,15 @@
 #            endif
              extern int _end[];
 #            define DATAEND (ptr_t)(_end)
-#            if defined(PLATFORM_ANDROID) && !defined(GC_NO_SIGSETJMP)
-               /* As of Android NDK r8b, _sigsetjmp is still missing    */
-               /* for x86 (setjmp is used instead to find data_start).  */
+#            if defined(PLATFORM_ANDROID) && !defined(GC_NO_SIGSETJMP) \
+                && !(__ANDROID_API__ >= 18 || __GNUC__ > 4 \
+                     || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) \
+                     || __clang_major__ > 3 \
+                     || (__clang_major__ == 3 && __clang_minor__ >= 2))
+               /* Older Android NDK releases lack sigsetjmp in x86 libc */
+               /* (setjmp is used instead to find data_start).  The bug */
+               /* is fixed in Android NDK r8e (so, ok to use sigsetjmp  */
+               /* if gcc4.8+, clang3.2+ or Android API level 18+).      */
 #              define GC_NO_SIGSETJMP
 #            endif
 #       else
@@ -1424,7 +1434,7 @@
 #       endif
         extern int __data_start[];
 #       define DATASTART ((ptr_t)__data_start)
-        extern char _end[];
+        extern int _end[];
 #       define DATAEND ((ptr_t)(&_end))
 #       define DYNAMIC_LOADING
 #   endif
@@ -1664,10 +1674,26 @@
 #    endif
      extern int _fdata[];
 #    define DATASTART ((ptr_t)_fdata)
-     extern char _end[];
+     extern int _end[];
 #    define DATAEND ((ptr_t)(&_end))
 #    define DYNAMIC_LOADING
 #  endif
+#  ifdef FREEBSD
+#    define OS_TYPE "FREEBSD"
+#    define ALIGNMENT 4
+#    ifndef GC_FREEBSD_THREADS
+#      define MPROTECT_VDB
+#    endif
+#    define SIG_SUSPEND SIGUSR1
+#    define SIG_THR_RESTART SIGUSR2
+#    define FREEBSD_STACKBOTTOM
+#    ifdef __ELF__
+#      define DYNAMIC_LOADING
+#    endif
+     extern char etext[];
+#    define DATASTART GC_FreeBSDGetDataStart(0x1000, (ptr_t)etext)
+#    define DATASTART_USES_BSDGETDATASTART
+#  endif /* FreeBSD */
 #  if defined(NONSTOP)
 #    define CPP_WORDSZ 32
 #    define OS_TYPE "NONSTOP"
@@ -1758,7 +1784,7 @@
 #     endif
       extern int __data_start[];
 #     define DATASTART ((ptr_t)__data_start)
-      extern char _end[];
+      extern int _end[];
 #     define DATAEND ((ptr_t)(&_end))
 #     define DYNAMIC_LOADING
 #  endif
@@ -1788,7 +1814,7 @@
 #       endif
         extern int __data_start[];
 #       define DATASTART ((ptr_t)__data_start)
-        extern char _end[];
+        extern int _end[];
 #       define DATAEND ((ptr_t)(&_end))
 #       define DYNAMIC_LOADING
 #   endif
@@ -2035,7 +2061,7 @@
 #     define DYNAMIC_LOADING
       extern int __data_start[];
 #     define DATASTART ((ptr_t)__data_start)
-      extern char _end[];
+      extern int _end[];
 #     define DATAEND ((ptr_t)(&_end))
 #   endif
 #   ifdef DARWIN
@@ -2184,7 +2210,7 @@
 #     endif
       extern int __data_start[];
 #     define DATASTART ((ptr_t)__data_start)
-      extern char _end[];
+      extern int _end[];
 #     define DATAEND ((ptr_t)(&_end))
 #     define DYNAMIC_LOADING
 #   endif
@@ -2241,7 +2267,7 @@
 #      endif
        extern int __data_start[];
 #      define DATASTART ((ptr_t)__data_start)
-       extern char _end[];
+       extern int _end[];
 #      define DATAEND ((ptr_t)(&_end))
 #      define DYNAMIC_LOADING
 #   endif
@@ -2305,7 +2331,7 @@
 #       endif
         extern int __data_start[];
 #       define DATASTART ((ptr_t)__data_start)
-        extern char _end[];
+        extern int _end[];
 #       define DATAEND ((ptr_t)(&_end))
 #       define DYNAMIC_LOADING
 #   endif
@@ -2577,6 +2603,12 @@
 # define GETPAGESIZE() getpagesize()
 #endif
 
+#if defined(PLATFORM_ANDROID) && ((defined(MIPS) && (CPP_WORDSZ == 32)) \
+                        || defined(ARM32) || defined(I386) /* but not x32 */)
+  /* tkill() exists only on arm32/mips(32)/x86. */
+# define USE_TKILL_ON_ANDROID
+#endif
+
 #if defined(SOLARIS) || defined(DRSNX) || defined(UTS4)
         /* OS has SVR4 generic features.        */
         /* Probably others also qualify.        */
@@ -2711,6 +2743,15 @@
 # undef MPROTECT_VDB
 #endif
 
+#ifndef SA_SIGINFO
+# define NO_SA_SIGACTION
+#endif
+
+#if defined(NO_SA_SIGACTION) && defined(MPROTECT_VDB) && !defined(DARWIN) \
+    && !defined(MSWIN32) && !defined(MSWINCE)
+# undef MPROTECT_VDB
+#endif
+
 #if !defined(PCR_VDB) && !defined(PROC_VDB) && !defined(MPROTECT_VDB) \
     && !defined(GWW_VDB) && !defined(MANUAL_VDB) \
     && !defined(GC_DISABLE_INCREMENTAL)
@@ -2722,7 +2763,7 @@
                              || defined(MIPS) || defined(AVR32) \
                              || defined(OR1K))) \
      || (defined(LINUX) && (defined(SPARC) || defined(M68K))) \
-     || ((defined(RTEMS) || defined(PLATFORM_ANDROID)) && defined(I386))) \
+     || (defined(RTEMS) && defined(I386)) || defined(PLATFORM_ANDROID)) \
     && !defined(NO_GETCONTEXT)
 # define NO_GETCONTEXT
 #endif
@@ -2857,7 +2898,8 @@
 #endif
 
 #if defined(CAN_HANDLE_FORK) && !defined(CAN_CALL_ATFORK) \
-    && !defined(HURD) && !defined(PLATFORM_ANDROID)
+    && !defined(HURD) \
+    && (!defined(PLATFORM_ANDROID) || __ANDROID_API__ >= 21)
   /* Have working pthread_atfork().     */
 # define CAN_CALL_ATFORK
 #endif

+ 16 - 5
blitz.mod/bdwgc/include/private/thread_local_alloc.h

@@ -38,7 +38,7 @@
 # if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
 #   if defined(CYGWIN32) && (__GNUC__ >= 4)
 #     if defined(__clang__)
-        /* As of Cygwin clang3.1, thread-local storage is unsupported.  */
+        /* As of Cygwin clang3.5.2, thread-local storage is unsupported.    */
 #       define USE_PTHREAD_SPECIFIC
 #     else
 #       define USE_COMPILER_TLS
@@ -51,9 +51,18 @@
 # elif (defined(LINUX) && !defined(ARM32) && !defined(AVR32) \
          && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) \
          && !(defined(__clang__) && defined(PLATFORM_ANDROID))) \
-       || (defined(PLATFORM_ANDROID) && defined(ARM32) \
-            && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
-          /* As of Android NDK r8e, Clang cannot find __tls_get_addr.   */
+       || (defined(PLATFORM_ANDROID) && !defined(__clang__) \
+            && defined(ARM32) \
+            && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) \
+       || (defined(PLATFORM_ANDROID) && !defined(ARM32) && !defined(MIPS) \
+            && (__clang_major__ > 3 \
+                || (__clang_major__ == 3 && __clang_minor__ >= 6)))
+          /* As of Android NDK r10e, Clang/arm with bfd linker and      */
+          /* Clang/mips cannot find __tls_get_addr.  Older NDK releases */
+          /* have same issue for arm (regardless of linker) and x86 if  */
+          /* gcc 4.6 toolchain is used for linking (checked condition   */
+          /* is based on the fact that Android NDK r10e added clang 3.6 */
+          /* dropping gcc 4.6).                                         */
 #   define USE_COMPILER_TLS
 # elif defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) \
        || defined(GC_AIX_THREADS) || defined(GC_DARWIN_THREADS) \
@@ -108,7 +117,9 @@ typedef struct thread_local_freelists {
 # define GC_getspecific pthread_getspecific
 # define GC_setspecific pthread_setspecific
 # define GC_key_create pthread_key_create
-# define GC_remove_specific(key)  /* No need for cleanup on exit. */
+# define GC_remove_specific(key) pthread_setspecific(key, NULL)
+                        /* Explicitly delete the value to stop the TLS  */
+                        /* destructor from being called repeatedly.     */
   typedef pthread_key_t GC_key_t;
 #elif defined(USE_COMPILER_TLS) || defined(USE_WIN32_COMPILER_TLS)
 # define GC_getspecific(x) (x)

+ 0 - 13
blitz.mod/bdwgc/libatomic_ops/TODO

@@ -1,13 +0,0 @@
-== TODO tasks ==
-
-Add C++0x ATM (atomic memory operations) layer.
-
-
-== FIXME tasks ==
-
-RHELinux6/POWER7 (gcc-4.4.7-3/ppc64), Fedora16/POWER7 (gcc-4.6.2-1/ppc64),
-Debian/powerpc (gcc 4.6.3-7):
-test_stack failed (Debian Bug #680100).
-
-Debian/m68k (Linux 3.2.0-2-atari):
-test_stack failed (Bus error), regression (Debian Bug #680066).

+ 18 - 0
blitz.mod/bdwgc/mark.c

@@ -888,6 +888,24 @@ GC_INNER word GC_mark_no = 0;
         /* we don't overflow half of it in a single call to             */
         /* GC_mark_from.                                                */
 
+/* Wait all markers to finish initialization (i.e. store        */
+/* marker_[b]sp, marker_mach_threads, GC_marker_Id).            */
+GC_INNER void GC_wait_for_markers_init(void)
+{
+  word count;
+
+  if (GC_markers_m1 == 0)
+    return;
+
+  /* Reuse marker lock and builders count to synchronize        */
+  /* marker threads startup.                                    */
+  GC_acquire_mark_lock();
+  GC_fl_builder_count += (word)GC_markers_m1;
+  count = GC_fl_builder_count;
+  GC_release_mark_lock();
+  if (count != 0)
+    GC_wait_for_reclaim();
+}
 
 /* Steal mark stack entries starting at mse low into mark stack local   */
 /* until we either steal mse high, or we have max entries.              */

+ 3 - 3
blitz.mod/bdwgc/misc.c

@@ -1675,7 +1675,7 @@ GC_API void GC_CALLBACK GC_ignore_warn_proc(char *msg, GC_word arg)
 GC_API void GC_CALL GC_set_warn_proc(GC_warn_proc p)
 {
     DCL_LOCK_STATE;
-    GC_ASSERT(p != 0);
+    GC_ASSERT(NONNULL_ARG_NOT_NULL(p));
 #   ifdef GC_WIN32_THREADS
 #     ifdef CYGWIN32
         /* Need explicit GC_INIT call */
@@ -1748,7 +1748,7 @@ GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void)
   GC_API void GC_CALL GC_set_abort_func(GC_abort_func fn)
   {
       DCL_LOCK_STATE;
-      GC_ASSERT(fn != 0);
+      GC_ASSERT(NONNULL_ARG_NOT_NULL(fn));
       LOCK();
       GC_on_abort = fn;
       UNLOCK();
@@ -2077,7 +2077,7 @@ GC_API GC_word GC_CALL GC_get_gc_no(void)
 
 GC_API void GC_CALL GC_set_oom_fn(GC_oom_func fn)
 {
-    GC_ASSERT(fn != 0);
+    GC_ASSERT(NONNULL_ARG_NOT_NULL(fn));
     DCL_LOCK_STATE;
     LOCK();
     GC_oom_fn = fn;

+ 1 - 1
blitz.mod/bdwgc/os_dep.c

@@ -3060,7 +3060,7 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void)
 #     ifndef SEGV_ACCERR
 #       define SEGV_ACCERR 2
 #     endif
-#     if defined(AARCH64) || defined(ARM32)
+#     if defined(AARCH64) || defined(ARM32) || defined(MIPS)
 #       define CODE_OK (si -> si_code == SEGV_ACCERR)
 #     elif defined(POWERPC)
 #       define AIM  /* Pretend that we're AIM. */

+ 14 - 13
blitz.mod/bdwgc/pthread_stop_world.c

@@ -202,7 +202,7 @@ STATIC sem_t GC_suspend_ack_sem;
 
 STATIC void GC_suspend_handler_inner(ptr_t sig_arg, void *context);
 
-#ifdef SA_SIGINFO
+#ifndef NO_SA_SIGACTION
   STATIC void GC_suspend_handler(int sig, siginfo_t * info GC_ATTR_UNUSED,
                                  void * context GC_ATTR_UNUSED)
 #else
@@ -216,7 +216,7 @@ STATIC void GC_suspend_handler_inner(ptr_t sig_arg, void *context);
 # else
     /* We believe that in all other cases the full context is already   */
     /* in the signal handler frame.                                     */
-#   ifndef SA_SIGINFO
+#   ifdef NO_SA_SIGACTION
       void *context = 0;
 #   endif
     GC_suspend_handler_inner((ptr_t)(word)sig, context);
@@ -447,7 +447,7 @@ GC_INNER void GC_push_all_stacks(void)
   int GC_stopping_pid = 0;
 #endif
 
-#ifdef PLATFORM_ANDROID
+#ifdef USE_TKILL_ON_ANDROID
   extern int tkill(pid_t tid, int sig); /* from sys/linux-unistd.h */
 
   static int android_thread_kill(pid_t tid, int sig)
@@ -463,7 +463,7 @@ GC_INNER void GC_push_all_stacks(void)
 
     return ret;
   }
-#endif /* PLATFORM_ANDROID */
+#endif /* USE_TKILL_ON_ANDROID */
 
 /* We hold the allocation lock.  Suspend all threads that might */
 /* still be running.  Return the number of suspend signals that */
@@ -473,7 +473,7 @@ STATIC int GC_suspend_all(void)
   int n_live_threads = 0;
   int i;
 # ifndef NACL
-#   ifndef PLATFORM_ANDROID
+#   ifndef USE_TKILL_ON_ANDROID
       pthread_t thread_id;
 #   else
       pid_t thread_id;
@@ -514,7 +514,7 @@ STATIC int GC_suspend_all(void)
                                      (void *)p->id);
               }
 #           else
-#             ifndef PLATFORM_ANDROID
+#             ifndef USE_TKILL_ON_ANDROID
                 thread_id = p -> id;
                 result = pthread_kill(thread_id, GC_sig_suspend);
 #             else
@@ -529,7 +529,8 @@ STATIC int GC_suspend_all(void)
                 case 0:
                     if (GC_on_thread_event)
                       GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED,
-                                         (void *)thread_id);
+                                         (void *)(word)thread_id);
+                                /* Note: thread_id might be truncated.  */
                     break;
                 default:
                     ABORT_ARG1("pthread_kill failed at suspend",
@@ -817,7 +818,7 @@ GC_INNER void GC_start_world(void)
       register int n_live_threads = 0;
       register int result;
 #   endif
-#   ifndef PLATFORM_ANDROID
+#   ifndef USE_TKILL_ON_ANDROID
       pthread_t thread_id;
 #   else
       pid_t thread_id;
@@ -851,7 +852,7 @@ GC_INNER void GC_start_world(void)
             if (GC_on_thread_event)
               GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, (void *)p->id);
 #         else
-#           ifndef PLATFORM_ANDROID
+#           ifndef USE_TKILL_ON_ANDROID
               thread_id = p -> id;
               result = pthread_kill(thread_id, GC_sig_thr_restart);
 #           else
@@ -866,7 +867,7 @@ GC_INNER void GC_start_world(void)
                 case 0:
                     if (GC_on_thread_event)
                       GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED,
-                                         (void *)thread_id);
+                                         (void *)(word)thread_id);
                     break;
                 default:
                     ABORT_ARG1("pthread_kill failed at resume",
@@ -924,7 +925,7 @@ GC_INNER void GC_stop_init(void)
 #   else
       act.sa_flags = 0
 #   endif
-#   ifdef SA_SIGINFO
+#   ifndef NO_SA_SIGACTION
                      | SA_SIGINFO
 #   endif
         ;
@@ -939,7 +940,7 @@ GC_INNER void GC_stop_init(void)
     GC_remove_allowed_signals(&act.sa_mask);
     /* GC_sig_thr_restart is set in the resulting mask. */
     /* It is unmasked by the handler when necessary.    */
-#   ifdef SA_SIGINFO
+#   ifndef NO_SA_SIGACTION
       act.sa_sigaction = GC_suspend_handler;
 #   else
       act.sa_handler = GC_suspend_handler;
@@ -949,7 +950,7 @@ GC_INNER void GC_stop_init(void)
         ABORT("Cannot set SIG_SUSPEND handler");
     }
 
-#   ifdef SA_SIGINFO
+#   ifndef NO_SA_SIGACTION
       act.sa_flags &= ~SA_SIGINFO;
 #   endif
     act.sa_handler = GC_restart_handler;

+ 10 - 3
blitz.mod/bdwgc/pthread_support.c

@@ -372,6 +372,12 @@ STATIC void * GC_mark_thread(void * id)
     marker_mach_threads[(word)id] = mach_thread_self();
 # endif
 
+  /* Inform start_mark_threads() about completion of marker data init.  */
+  GC_acquire_mark_lock();
+  if (0 == --GC_fl_builder_count)
+    GC_notify_all_builder();
+  GC_release_mark_lock();
+
   for (;; ++my_mark_no) {
     /* GC_mark_no is passed only to allow GC_help_marker to terminate   */
     /* promptly.  This is important if it were called from the signal   */
@@ -408,6 +414,7 @@ start_mark_threads(void)
     pthread_attr_t attr;
 
     GC_ASSERT(I_DONT_HOLD_LOCK());
+    GC_ASSERT(GC_fl_builder_count == 0);
 #   ifdef CAN_HANDLE_FORK
       if (available_markers_m1 <= 0 || GC_parallel) return;
                 /* Skip if parallel markers disabled or already started. */
@@ -446,6 +453,7 @@ start_mark_threads(void)
     }
     GC_markers_m1 = i;
     (void)pthread_attr_destroy(&attr);
+    GC_wait_for_markers_init();
     GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
 }
 
@@ -458,10 +466,9 @@ GC_INNER volatile GC_thread GC_threads[THREAD_TABLE_SZ] = {0};
 void GC_push_thread_structures(void)
 {
     GC_ASSERT(I_HOLD_LOCK());
-    GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
+    GC_PUSH_ALL_SYM(GC_threads);
 #   if defined(THREAD_LOCAL_ALLOC)
-      GC_push_all((ptr_t)(&GC_thread_key),
-                  (ptr_t)(&GC_thread_key) + sizeof(GC_thread_key));
+      GC_PUSH_ALL_SYM(GC_thread_key);
 #   endif
 }
 

+ 14 - 1
blitz.mod/bdwgc/thread_local_alloc.c

@@ -82,6 +82,19 @@ static void return_freelists(void **fl, void **gfl)
     }
 }
 
+#ifdef USE_PTHREAD_SPECIFIC
+  /* Re-set the TLS value on thread cleanup to allow thread-local       */
+  /* allocations to happen in the TLS destructors.                      */
+  /* GC_unregister_my_thread (and similar routines) will finally set    */
+  /* the GC_thread_key to NULL preventing this destructor from being    */
+  /* called repeatedly.                                                 */
+  static void reset_thread_key(void* v) {
+    pthread_setspecific(GC_thread_key, v);
+  }
+#else
+# define reset_thread_key 0
+#endif
+
 /* Each thread structure must be initialized.   */
 /* This call must be made from the new thread.  */
 GC_INNER void GC_init_thread_local(GC_tlfs p)
@@ -91,7 +104,7 @@ GC_INNER void GC_init_thread_local(GC_tlfs p)
     GC_ASSERT(I_HOLD_LOCK());
     if (!EXPECT(keys_initialized, TRUE)) {
         GC_ASSERT((word)&GC_thread_key % sizeof(word) == 0);
-        if (0 != GC_key_create(&GC_thread_key, 0)) {
+        if (0 != GC_key_create(&GC_thread_key, reset_thread_key)) {
             ABORT("Failed to create key for local allocator");
         }
         keys_initialized = TRUE;

+ 37 - 17
blitz.mod/bdwgc/typd_mlc.c

@@ -41,8 +41,6 @@
 
 #define TYPD_EXTRA_BYTES (sizeof(word) - EXTRA_BYTES)
 
-STATIC GC_bool GC_explicit_typing_initialized = FALSE;
-
 STATIC int GC_explicit_kind = 0;
                         /* Object kind for objects with indirect        */
                         /* (possibly extended) descriptors.             */
@@ -100,10 +98,21 @@ STATIC size_t GC_avail_descr = 0;       /* Next available slot.         */
 STATIC int GC_typed_mark_proc_index = 0; /* Indices of my mark          */
 STATIC int GC_array_mark_proc_index = 0; /* procedures.                 */
 
+#if !defined(AO_HAVE_load_acquire) && defined(GC_FORCE_INCLUDE_ATOMIC_OPS)
+# include "atomic_ops.h"
+#endif
+
+STATIC
+# ifdef AO_HAVE_load_acquire
+    AO_t
+# else
+    GC_bool
+# endif
+  GC_explicit_typing_initialized = FALSE;
+
 STATIC void GC_push_typed_structures_proc(void)
 {
-  GC_push_all((ptr_t)&GC_ext_descriptors,
-              (ptr_t)&GC_ext_descriptors + sizeof(word));
+  GC_PUSH_ALL_SYM(GC_ext_descriptors);
 }
 
 /* Add a multiword bitmap to GC_ext_descriptors arrays.  Return */
@@ -344,19 +353,11 @@ STATIC mse * GC_typed_mark_proc(word * addr, mse * mark_stack_ptr,
 STATIC mse * GC_array_mark_proc(word * addr, mse * mark_stack_ptr,
                                 mse * mark_stack_limit, word env);
 
-/* Caller does not hold allocation lock. */
 STATIC void GC_init_explicit_typing(void)
 {
-    register unsigned i;
-    DCL_LOCK_STATE;
+    unsigned i;
 
     GC_STATIC_ASSERT(sizeof(struct LeafDescriptor) % sizeof(word) == 0);
-    LOCK();
-    if (GC_explicit_typing_initialized) {
-      UNLOCK();
-      return;
-    }
-    GC_explicit_typing_initialized = TRUE;
     /* Set up object kind with simple indirect descriptor. */
       GC_eobjfreelist = (ptr_t *)GC_new_free_list_inner();
       GC_explicit_kind = GC_new_kind_inner(
@@ -375,7 +376,6 @@ STATIC void GC_init_explicit_typing(void)
       for (i = 0; i < WORDSZ/2; i++) {
           GC_bm_table[i] = (((word)-1) << (WORDSZ - i)) | GC_DS_BITMAP;
       }
-    UNLOCK();
 }
 
 STATIC mse * GC_typed_mark_proc(word * addr, mse * mark_stack_ptr,
@@ -537,9 +537,26 @@ GC_API GC_descr GC_CALL GC_make_descriptor(const GC_word * bm, size_t len)
     GC_descr result;
     signed_word i;
 #   define HIGH_BIT (((word)1) << (WORDSZ - 1))
+    DCL_LOCK_STATE;
 
-    if (!EXPECT(GC_explicit_typing_initialized, TRUE))
-      GC_init_explicit_typing();
+#   if defined(THREADS) && defined(AO_HAVE_load_acquire)
+      if (!EXPECT(AO_load_acquire(
+                        (volatile AO_t *)&GC_explicit_typing_initialized),
+                  TRUE))
+#   endif
+    {
+      LOCK();
+#     if defined(THREADS) && defined(AO_HAVE_load_acquire)
+        if (!GC_explicit_typing_initialized)
+#     else
+        if (!EXPECT(GC_explicit_typing_initialized, TRUE))
+#     endif
+      {
+        GC_init_explicit_typing();
+        GC_explicit_typing_initialized = TRUE;
+      }
+      UNLOCK();
+    }
 
     while (last_set_bit >= 0 && !GC_get_bit(bm, last_set_bit))
       last_set_bit--;
@@ -583,8 +600,9 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_explicitly_typed(size_t lb,
     size_t lg;
     DCL_LOCK_STATE;
 
+    GC_ASSERT(GC_explicit_typing_initialized);
     lb += TYPD_EXTRA_BYTES;
-    if(SMALL_OBJ(lb)) {
+    if (SMALL_OBJ(lb)) {
         GC_DBG_COLLECT_AT_MALLOC(lb);
         lg = GC_size_map[lb];
         LOCK();
@@ -618,6 +636,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL
     size_t lg;
     DCL_LOCK_STATE;
 
+    GC_ASSERT(GC_explicit_typing_initialized);
     lb += TYPD_EXTRA_BYTES;
     if (SMALL_OBJ(lb)) {
         GC_DBG_COLLECT_AT_MALLOC(lb);
@@ -657,6 +676,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_calloc_explicitly_typed(size_t n,
     struct LeafDescriptor leaf;
     DCL_LOCK_STATE;
 
+    GC_ASSERT(GC_explicit_typing_initialized);
     descr_type = GC_make_array_descriptor((word)n, (word)lb, d,
                                           &simple_descr, &complex_descr, &leaf);
     switch(descr_type) {

+ 15 - 8
blitz.mod/bdwgc/win32_threads.c

@@ -1134,11 +1134,10 @@ void GC_push_thread_structures(void)
     } else
 # endif
   /* else */ {
-    GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
+    GC_PUSH_ALL_SYM(GC_threads);
   }
 # if defined(THREAD_LOCAL_ALLOC)
-    GC_push_all((ptr_t)(&GC_thread_key),
-                (ptr_t)(&GC_thread_key) + sizeof(GC_thread_key));
+    GC_PUSH_ALL_SYM(GC_thread_key);
     /* Just in case we ever use our own TLS implementation.     */
 # endif
 }
@@ -1705,12 +1704,10 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
   /* GC_mark_thread() is the same as in pthread_support.c */
 # ifdef GC_PTHREADS_PARAMARK
     STATIC void * GC_mark_thread(void * id)
+# elif defined(MSWINCE)
+    STATIC DWORD WINAPI GC_mark_thread(LPVOID id)
 # else
-#   ifdef MSWINCE
-      STATIC DWORD WINAPI GC_mark_thread(LPVOID id)
-#   else
-      STATIC unsigned __stdcall GC_mark_thread(void * id)
-#   endif
+    STATIC unsigned __stdcall GC_mark_thread(void * id)
 # endif
   {
     word my_mark_no = 0;
@@ -1724,6 +1721,12 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
       GC_marker_Id[(word)id] = GetCurrentThreadId();
 #   endif
 
+    /* Inform start_mark_threads() about completion of marker data init. */
+    GC_acquire_mark_lock();
+    if (0 == --GC_fl_builder_count)
+      GC_notify_all_builder();
+    GC_release_mark_lock();
+
     for (;; ++my_mark_no) {
       if (my_mark_no - GC_mark_no > (word)2) {
         /* resynchronize if we get far off, e.g. because GC_mark_no     */
@@ -1773,6 +1776,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
       pthread_t new_thread;
 
       GC_ASSERT(I_DONT_HOLD_LOCK());
+      GC_ASSERT(GC_fl_builder_count == 0);
 #     ifdef CAN_HANDLE_FORK
         if (available_markers_m1 <= 0 || GC_parallel) return;
                 /* Skip if parallel markers disabled or already started. */
@@ -1793,6 +1797,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
       }
       GC_markers_m1 = i;
       (void)pthread_attr_destroy(&attr);
+      GC_wait_for_markers_init();
       GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
     }
 
@@ -1916,6 +1921,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
         unsigned thread_id;
 #     endif
 
+      GC_ASSERT(GC_fl_builder_count == 0);
       /* Initialize GC_marker_cv[] fully before starting the    */
       /* first helper thread.                                   */
       for (i = 0; i < GC_markers_m1; ++i) {
@@ -1962,6 +1968,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
         GC_markers_m1--;
         CloseHandle(GC_marker_cv[GC_markers_m1]);
       }
+      GC_wait_for_markers_init();
       GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
       if (i == 0) {
         CloseHandle(mark_cv);