Browse Source

Updated to bdwgc 8.1.0.fbcdf44.

Brucey 5 years ago
parent
commit
713d2d50e2
67 changed files with 3571 additions and 1590 deletions
  1. 12 26
      blitz.mod/bdwgc/allchblk.c
  2. 188 85
      blitz.mod/bdwgc/alloc.c
  3. 3 3
      blitz.mod/bdwgc/backgraph.c
  4. 6 0
      blitz.mod/bdwgc/darwin_stop_world.c
  5. 14 5
      blitz.mod/bdwgc/dbg_mlc.c
  6. 6 13
      blitz.mod/bdwgc/dyn_load.c
  7. 72 93
      blitz.mod/bdwgc/finalize.c
  8. 0 2
      blitz.mod/bdwgc/fnlz_mlc.c
  9. 39 0
      blitz.mod/bdwgc/gc_badalc.cc
  10. 2 0
      blitz.mod/bdwgc/gc_badalc.cpp
  11. 45 13
      blitz.mod/bdwgc/gc_cpp.cc
  12. 2 0
      blitz.mod/bdwgc/gc_dlopen.c
  13. 8 20
      blitz.mod/bdwgc/gcj_mlc.c
  14. 13 27
      blitz.mod/bdwgc/headers.c
  15. 18 5
      blitz.mod/bdwgc/include/ec.h
  16. 157 59
      blitz.mod/bdwgc/include/gc.h
  17. 0 24
      blitz.mod/bdwgc/include/gc_allocator.h
  18. 49 2
      blitz.mod/bdwgc/include/gc_config_macros.h
  19. 26 25
      blitz.mod/bdwgc/include/gc_cpp.h
  20. 3 4
      blitz.mod/bdwgc/include/gc_inline.h
  21. 18 7
      blitz.mod/bdwgc/include/gc_mark.h
  22. 5 0
      blitz.mod/bdwgc/include/gc_pthread_redirects.h
  23. 3 2
      blitz.mod/bdwgc/include/gc_typed.h
  24. 2 2
      blitz.mod/bdwgc/include/gc_version.h
  25. 2 8
      blitz.mod/bdwgc/include/private/gc_locks.h
  26. 9 19
      blitz.mod/bdwgc/include/private/gc_pmark.h
  27. 278 82
      blitz.mod/bdwgc/include/private/gc_priv.h
  28. 267 191
      blitz.mod/bdwgc/include/private/gcconfig.h
  29. 2 2
      blitz.mod/bdwgc/include/private/pthread_support.h
  30. 14 1
      blitz.mod/bdwgc/include/private/specific.h
  31. 3 9
      blitz.mod/bdwgc/include/private/thread_local_alloc.h
  32. 7 0
      blitz.mod/bdwgc/libatomic_ops/.gitattributes
  33. 83 0
      blitz.mod/bdwgc/libatomic_ops/.gitignore
  34. 701 0
      blitz.mod/bdwgc/libatomic_ops/.travis.yml
  35. 2 0
      blitz.mod/bdwgc/libatomic_ops/AUTHORS
  36. 24 0
      blitz.mod/bdwgc/libatomic_ops/ChangeLog
  37. 10 2
      blitz.mod/bdwgc/libatomic_ops/README.md
  38. 26 0
      blitz.mod/bdwgc/libatomic_ops/appveyor.yml
  39. 4 4
      blitz.mod/bdwgc/libatomic_ops/configure.ac
  40. 31 35
      blitz.mod/bdwgc/libatomic_ops/doc/README_details.txt
  41. 5 8
      blitz.mod/bdwgc/libatomic_ops/doc/README_win32.txt
  42. 3 0
      blitz.mod/bdwgc/libatomic_ops/m4/.gitignore
  43. 2 2
      blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/ao_version.h
  44. 64 0
      blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/sysdeps/gcc/generic-arithm.h
  45. 4 0
      blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/sysdeps/gcc/generic-arithm.template
  46. 1 1
      blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/sysdeps/gcc/powerpc.h
  47. 16 6
      blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/sysdeps/gcc/riscv.h
  48. 12 2
      blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/sysdeps/gcc/s390.h
  49. 112 60
      blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/sysdeps/gcc/x86.h
  50. 5 2
      blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/sysdeps/sunc/x86.h
  51. 3 0
      blitz.mod/bdwgc/mach_dep.c
  52. 14 8
      blitz.mod/bdwgc/malloc.c
  53. 13 18
      blitz.mod/bdwgc/mallocx.c
  54. 93 118
      blitz.mod/bdwgc/mark.c
  55. 97 115
      blitz.mod/bdwgc/mark_rts.c
  56. 138 68
      blitz.mod/bdwgc/misc.c
  57. 1 1
      blitz.mod/bdwgc/new_hblk.c
  58. 1 0
      blitz.mod/bdwgc/obj_map.c
  59. 200 150
      blitz.mod/bdwgc/os_dep.c
  60. 9 8
      blitz.mod/bdwgc/pthread_stop_world.c
  61. 150 44
      blitz.mod/bdwgc/pthread_support.c
  62. 12 7
      blitz.mod/bdwgc/reclaim.c
  63. 2 3
      blitz.mod/bdwgc/specific.c
  64. 1 1
      blitz.mod/bdwgc/thread_local_alloc.c
  65. 16 37
      blitz.mod/bdwgc/typd_mlc.c
  66. 440 160
      blitz.mod/bdwgc/win32_threads.c
  67. 3 1
      blitz.mod/blitz.bmx

+ 12 - 26
blitz.mod/bdwgc/allchblk.c

@@ -130,7 +130,7 @@ void GC_print_hblkfreelist(void)
 
       if (0 != h) GC_printf("Free list %u (total size %lu):\n",
                             i, (unsigned long)GC_free_bytes[i]);
-      while (h != 0) {
+      while (h /* != NULL */) { /* CPPCHECK */
         hdr * hhdr = HDR(h);
 
         GC_printf("\t%p size %lu %s black listed\n",
@@ -345,7 +345,7 @@ STATIC struct hblk * GC_free_block_ending_at(struct hblk *h)
         }
     }
     p = GC_prev_block(h - 1);
-    if (0 != p) {
+    if (p /* != NULL */) { /* CPPCHECK */
       phdr = HDR(p);
       if (HBLK_IS_FREE(phdr) && (ptr_t)p + phdr -> hb_sz == (ptr_t)h) {
         return p;
@@ -378,7 +378,7 @@ STATIC void GC_add_to_fl(struct hblk *h, hdr *hhdr)
     GC_ASSERT(GC_free_bytes[index] <= GC_large_free_bytes);
     hhdr -> hb_next = second;
     hhdr -> hb_prev = 0;
-    if (0 != second) {
+    if (second /* != NULL */) { /* CPPCHECK */
       hdr * second_hdr;
 
       GET_HDR(second, second_hdr);
@@ -423,24 +423,6 @@ GC_INNER void GC_unmap_old(void)
     }
 }
 
-# ifdef MPROTECT_VDB
-    GC_INNER GC_bool GC_has_unmapped_memory(void)
-    {
-      int i;
-
-      for (i = 0; i <= N_HBLK_FLS; ++i) {
-        struct hblk * h;
-        hdr * hhdr;
-
-        for (h = GC_hblkfreelist[i]; h != NULL; h = hhdr -> hb_next) {
-          hhdr = HDR(h);
-          if (!IS_MAPPED(hhdr)) return TRUE;
-        }
-      }
-      return FALSE;
-    }
-# endif /* MPROTECT_VDB */
-
 /* Merge all unmapped blocks that are adjacent to other free            */
 /* blocks.  This may involve remapping, since all blocks are either     */
 /* fully mapped or fully unmapped.                                      */
@@ -571,12 +553,12 @@ STATIC void GC_split_block(struct hblk *h, hdr *hhdr, struct hblk *n,
       nhdr -> hb_next = next;
       nhdr -> hb_sz = total_size - h_size;
       nhdr -> hb_flags = 0;
-      if (0 != prev) {
+      if (prev /* != NULL */) { /* CPPCHECK */
         HDR(prev) -> hb_next = n;
       } else {
         GC_hblkfreelist[index] = n;
       }
-      if (0 != next) {
+      if (next /* != NULL */) {
         HDR(next) -> hb_prev = n;
       }
       GC_ASSERT(GC_free_bytes[index] > h_size);
@@ -681,7 +663,11 @@ GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n, int may_split)
         for (hbp = GC_hblkfreelist[n];; hbp = hhdr -> hb_next) {
             signed_word size_avail; /* bytes available in this block */
 
-            if (NULL == hbp) return NULL;
+            if (hbp /* != NULL */) {
+              /* CPPCHECK */
+            } else {
+              return NULL;
+            }
             GET_HDR(hbp, hhdr); /* set hhdr value */
             size_avail = (signed_word)hhdr->hb_sz;
             if (size_avail < size_needed) continue;
@@ -691,7 +677,7 @@ GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n, int may_split)
               /* This prevents us from disassembling a single large     */
               /* block to get tiny blocks.                              */
               thishbp = hhdr -> hb_next;
-              if (thishbp != 0) {
+              if (thishbp /* != NULL */) { /* CPPCHECK */
                 signed_word next_size;
 
                 GET_HDR(thishbp, thishdr);
@@ -893,7 +879,7 @@ GC_INNER void GC_freehblk(struct hblk *hbp)
         GC_remove_header(next);
       }
     /* Coalesce with predecessor, if possible. */
-      if (0 != prev) {
+      if (prev /* != NULL */) { /* CPPCHECK */
         prevhdr = HDR(prev);
         if (IS_MAPPED(prevhdr)
             && (signed_word)(hhdr -> hb_sz + prevhdr -> hb_sz) > 0) {

+ 188 - 85
blitz.mod/bdwgc/alloc.c

@@ -3,7 +3,7 @@
  * Copyright (c) 1991-1996 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1998 by Silicon Graphics.  All rights reserved.
  * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
- * Copyright (c) 2008-2018 Ivan Maidanski
+ * Copyright (c) 2008-2020 Ivan Maidanski
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -69,7 +69,8 @@ word GC_non_gc_bytes = 0;  /* Number of bytes not intended to be collected */
 word GC_gc_no = 0;
 
 #ifndef NO_CLOCK
-  static unsigned long full_gc_total_time = 0; /* in msecs, may wrap */
+  static unsigned long full_gc_total_time = 0; /* in ms, may wrap */
+  static unsigned full_gc_total_ns_frac = 0; /* fraction of 1 ms */
   static GC_bool measure_performance = FALSE;
                 /* Do performance measurements if set to true (e.g.,    */
                 /* accumulation of the total time of full collections). */
@@ -124,7 +125,7 @@ const char * const GC_copyright[] =
 "Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved. ",
 "Copyright (c) 1996-1998 by Silicon Graphics.  All rights reserved. ",
 "Copyright (c) 1999-2009 by Hewlett-Packard Company.  All rights reserved. ",
-"Copyright (c) 2008-2018 Ivan Maidanski ",
+"Copyright (c) 2008-2020 Ivan Maidanski ",
 "THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY",
 " EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.",
 "See source code for details." };
@@ -168,15 +169,44 @@ GC_INNER int GC_CALLBACK GC_never_stop_func(void)
   unsigned long GC_time_limit = GC_TIME_LIMIT;
                            /* We try to keep pause times from exceeding  */
                            /* this by much. In milliseconds.             */
+#elif defined(PARALLEL_MARK)
+  unsigned long GC_time_limit = GC_TIME_UNLIMITED;
+                        /* The parallel marker cannot be interrupted for */
+                        /* now, so the time limit is absent by default.  */
 #else
   unsigned long GC_time_limit = 50;
 #endif
 
 #ifndef NO_CLOCK
+  STATIC unsigned long GC_time_lim_nsec = 0;
+                        /* The nanoseconds add-on to GC_time_limit      */
+                        /* value.  Not updated by GC_set_time_limit().  */
+                        /* Ignored if the value of GC_time_limit is     */
+                        /* GC_TIME_UNLIMITED.                           */
+
+# define TV_NSEC_LIMIT (1000UL * 1000) /* amount of nanoseconds in 1 ms */
+
+  GC_API void GC_CALL GC_set_time_limit_tv(struct GC_timeval_s tv)
+  {
+    GC_ASSERT(tv.tv_ms <= GC_TIME_UNLIMITED);
+    GC_ASSERT(tv.tv_nsec < TV_NSEC_LIMIT);
+    GC_time_limit = tv.tv_ms;
+    GC_time_lim_nsec = tv.tv_nsec;
+  }
+
+  GC_API struct GC_timeval_s GC_CALL GC_get_time_limit_tv(void)
+  {
+    struct GC_timeval_s tv;
+
+    tv.tv_ms = GC_time_limit;
+    tv.tv_nsec = GC_time_lim_nsec;
+    return tv;
+  }
+
   STATIC CLOCK_TYPE GC_start_time = CLOCK_TYPE_INITIALIZER;
                                 /* Time at which we stopped world.      */
                                 /* used only in GC_timeout_stop_func.   */
-#endif
+#endif /* !NO_CLOCK */
 
 STATIC int GC_n_attempts = 0;   /* Number of attempts at finishing      */
                                 /* collection within GC_time_limit.     */
@@ -210,7 +240,7 @@ GC_API GC_stop_func GC_CALL GC_get_stop_func(void)
   {
     CLOCK_TYPE current_time;
     static unsigned count = 0;
-    unsigned long time_diff;
+    unsigned long time_diff, nsec_diff;
 
     if ((*GC_default_stop_func)())
       return(1);
@@ -218,11 +248,16 @@ GC_API GC_stop_func GC_CALL GC_get_stop_func(void)
     if ((count++ & 3) != 0) return(0);
     GET_TIME(current_time);
     time_diff = MS_TIME_DIFF(current_time,GC_start_time);
-    if (time_diff >= GC_time_limit) {
-        GC_COND_LOG_PRINTF(
-                "Abandoning stopped marking after %lu msecs (attempt %d)\n",
-                time_diff, GC_n_attempts);
-        return(1);
+    nsec_diff = NS_FRAC_TIME_DIFF(current_time, GC_start_time);
+#   if defined(CPPCHECK)
+      GC_noop1((word)&nsec_diff);
+#   endif
+    if (time_diff >= GC_time_limit
+        && (time_diff > GC_time_limit || nsec_diff >= GC_time_lim_nsec)) {
+      GC_COND_LOG_PRINTF("Abandoning stopped marking after %lu ms %lu ns"
+                         " (attempt %d)\n",
+                         time_diff, nsec_diff, GC_n_attempts);
+      return 1;
     }
     return(0);
   }
@@ -357,8 +392,8 @@ GC_INNER GC_bool GC_should_collect(void)
     static word last_min_bytes_allocd;
     static word last_gc_no;
     if (last_gc_no != GC_gc_no) {
-      last_gc_no = GC_gc_no;
       last_min_bytes_allocd = min_bytes_allocd();
+      last_gc_no = GC_gc_no;
     }
     return(GC_adj_bytes_allocd() >= last_min_bytes_allocd
            || GC_heapsize >= GC_collect_at_heapsize);
@@ -503,7 +538,9 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func)
               /* TODO: Notify GC_EVENT_ABANDON */
               return(FALSE);
             }
+            ENTER_GC();
             GC_collect_a_little_inner(1);
+            EXIT_GC();
         }
     }
     GC_notify_full_gc();
@@ -554,14 +591,23 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func)
 #   ifndef NO_CLOCK
       if (start_time_valid) {
         CLOCK_TYPE current_time;
-        unsigned long time_diff;
+        unsigned long time_diff, ns_frac_diff;
 
         GET_TIME(current_time);
         time_diff = MS_TIME_DIFF(current_time, start_time);
-        if (measure_performance)
+        ns_frac_diff = NS_FRAC_TIME_DIFF(current_time, start_time);
+        if (measure_performance) {
           full_gc_total_time += time_diff; /* may wrap */
+          full_gc_total_ns_frac += (unsigned)ns_frac_diff;
+          if (full_gc_total_ns_frac >= 1000000U) {
+            /* Overflow of the nanoseconds part. */
+            full_gc_total_ns_frac -= 1000000U;
+            full_gc_total_time++;
+          }
+        }
         if (GC_print_stats)
-          GC_log_printf("Complete collection took %lu msecs\n", time_diff);
+          GC_log_printf("Complete collection took %lu ms %lu ns\n",
+                        time_diff, ns_frac_diff);
       }
 #   endif
     if (GC_on_collection_event)
@@ -629,32 +675,42 @@ GC_INNER void GC_collect_a_little_inner(int n)
         int i;
         int max_deficit = GC_rate * n;
 
+#       ifdef PARALLEL_MARK
+            if (GC_time_limit != GC_TIME_UNLIMITED)
+                GC_parallel_mark_disabled = TRUE;
+#       endif
         for (i = GC_deficit; i < max_deficit; i++) {
-            if (GC_mark_some((ptr_t)0)) {
-                /* Need to finish a collection */
-#               ifdef SAVE_CALL_CHAIN
-                    GC_save_callers(GC_last_stack);
-#               endif
-#               ifdef PARALLEL_MARK
-                    if (GC_parallel)
-                      GC_wait_for_reclaim();
-#               endif
-                if (GC_n_attempts < max_prior_attempts
-                    && GC_time_limit != GC_TIME_UNLIMITED) {
-#                 ifndef NO_CLOCK
+            if (GC_mark_some(NULL))
+                break;
+        }
+#       ifdef PARALLEL_MARK
+            GC_parallel_mark_disabled = FALSE;
+#       endif
+
+        if (i < max_deficit) {
+            /* Need to finish a collection.     */
+#           ifdef SAVE_CALL_CHAIN
+                GC_save_callers(GC_last_stack);
+#           endif
+#           ifdef PARALLEL_MARK
+                if (GC_parallel)
+                    GC_wait_for_reclaim();
+#           endif
+            if (GC_n_attempts < max_prior_attempts
+                && GC_time_limit != GC_TIME_UNLIMITED) {
+#               ifndef NO_CLOCK
                     GET_TIME(GC_start_time);
-#                 endif
-                  if (!GC_stopped_mark(GC_timeout_stop_func)) {
-                    GC_n_attempts++;
-                    break;
-                  }
+#               endif
+                if (GC_stopped_mark(GC_timeout_stop_func)) {
+                    GC_finish_collection();
                 } else {
-                  /* TODO: If possible, GC_default_stop_func should be  */
-                  /* used here.                                         */
-                  (void)GC_stopped_mark(GC_never_stop_func);
+                    GC_n_attempts++;
                 }
+            } else {
+                /* TODO: If possible, GC_default_stop_func should be    */
+                /* used here.                                           */
+                (void)GC_stopped_mark(GC_never_stop_func);
                 GC_finish_collection();
-                break;
             }
         }
         if (GC_deficit > 0) {
@@ -677,7 +733,9 @@ GC_API int GC_CALL GC_collect_a_little(void)
     DCL_LOCK_STATE;
 
     LOCK();
+    ENTER_GC();
     GC_collect_a_little_inner(1);
+    EXIT_GC();
     result = (int)GC_collection_in_progress();
     UNLOCK();
     if (!result && GC_debugging_started) GC_print_all_smashed();
@@ -713,7 +771,7 @@ GC_API int GC_CALL GC_collect_a_little(void)
  */
 STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
 {
-    unsigned i;
+    int i;
 #   ifndef NO_CLOCK
       CLOCK_TYPE start_time = CLOCK_TYPE_INITIALIZER;
 #   endif
@@ -766,31 +824,48 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
             GC_noop6(0,0,0,0,0,0);
 
         GC_initiate_gc();
-        for (i = 0;;i++) {
-          if ((*stop_func)()) {
-            GC_COND_LOG_PRINTF("Abandoned stopped marking after"
-                               " %u iterations\n", i);
-            GC_deficit = i;     /* Give the mutator a chance.   */
-#           ifdef THREAD_LOCAL_ALLOC
-              GC_world_stopped = FALSE;
+#       ifdef PARALLEL_MARK
+          if (stop_func != GC_never_stop_func)
+            GC_parallel_mark_disabled = TRUE;
+#       endif
+        for (i = 0; !(*stop_func)(); i++) {
+          if (GC_mark_some(GC_approx_sp())) {
+#           ifdef PARALLEL_MARK
+              if (GC_parallel && GC_parallel_mark_disabled) {
+                GC_COND_LOG_PRINTF("Stopped marking done after %d iterations"
+                                   " with disabled parallel marker\n", i);
+              }
 #           endif
+            i = -1;
+            break;
+          }
+        }
+#       ifdef PARALLEL_MARK
+          GC_parallel_mark_disabled = FALSE;
+#       endif
 
-#           ifdef THREADS
-              if (GC_on_collection_event)
-                GC_on_collection_event(GC_EVENT_PRE_START_WORLD);
-#           endif
+        if (i >= 0) {
+          GC_COND_LOG_PRINTF("Abandoned stopped marking after"
+                             " %d iterations\n", i);
+          GC_deficit = i;       /* Give the mutator a chance.   */
+#         ifdef THREAD_LOCAL_ALLOC
+            GC_world_stopped = FALSE;
+#         endif
+
+#         ifdef THREADS
+            if (GC_on_collection_event)
+              GC_on_collection_event(GC_EVENT_PRE_START_WORLD);
+#         endif
 
-            START_WORLD();
+          START_WORLD();
 
-#           ifdef THREADS
-              if (GC_on_collection_event)
-                GC_on_collection_event(GC_EVENT_POST_START_WORLD);
-#           endif
+#         ifdef THREADS
+            if (GC_on_collection_event)
+              GC_on_collection_event(GC_EVENT_POST_START_WORLD);
+#         endif
 
-            /* TODO: Notify GC_EVENT_MARK_ABANDON */
-            return(FALSE);
-          }
-          if (GC_mark_some(GC_approx_sp())) break;
+          /* TODO: Notify GC_EVENT_MARK_ABANDON */
+          return FALSE;
         }
 
     GC_gc_no++;
@@ -804,18 +879,16 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
     if (GC_debugging_started) {
       (*GC_check_heap)();
     }
-    if (GC_on_collection_event)
+    if (GC_on_collection_event) {
       GC_on_collection_event(GC_EVENT_MARK_END);
-
+#     ifdef THREADS
+        GC_on_collection_event(GC_EVENT_PRE_START_WORLD);
+#     endif
+    }
 #   ifdef THREAD_LOCAL_ALLOC
       GC_world_stopped = FALSE;
 #   endif
 
-#   ifdef THREADS
-      if (GC_on_collection_event)
-        GC_on_collection_event(GC_EVENT_PRE_START_WORLD);
-#   endif
-
     START_WORLD();
 
 #   ifdef THREADS
@@ -847,9 +920,10 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
         world_stopped_total_divisor = ++divisor;
 
         GC_ASSERT(divisor != 0);
-        GC_log_printf(
-                "World-stopped marking took %lu msecs (%u in average)\n",
-                time_diff, total_time / divisor);
+        GC_log_printf("World-stopped marking took %lu ms %lu ns"
+                      " (%u ms in average)\n",
+                      time_diff, NS_FRAC_TIME_DIFF(current_time, start_time),
+                      total_time / divisor);
       }
 #   endif
     return(TRUE);
@@ -858,7 +932,7 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
 /* Set all mark bits for the free list whose first entry is q   */
 GC_INNER void GC_set_fl_marks(ptr_t q)
 {
-    if (q != NULL) {
+    if (q /* != NULL */) { /* CPPCHECK */
       struct hblk *h = HBLKPTR(q);
       struct hblk *last_h = h;
       hdr *hhdr = HDR(h);
@@ -984,7 +1058,13 @@ GC_INLINE int GC_compute_heap_usage_percent(void)
 {
   word used = GC_composite_in_use + GC_atomic_in_use;
   word heap_sz = GC_heapsize - GC_unmapped_bytes;
-  return used >= heap_sz ? 0 : used < GC_WORD_MAX / 100 ?
+# if defined(CPPCHECK)
+    word limit = (GC_WORD_MAX >> 1) / 50; /* to avoid a false positive */
+# else
+    const word limit = GC_WORD_MAX / 100;
+# endif
+
+  return used >= heap_sz ? 0 : used < limit ?
                 (int)((used * 100) / heap_sz) : (int)(used / (heap_sz / 100));
 }
 
@@ -1125,9 +1205,12 @@ STATIC void GC_finish_collection(void)
           /* A convenient place to output finalization statistics.      */
           GC_print_finalization_stats();
 #       endif
-        GC_log_printf("Finalize plus initiate sweep took %lu + %lu msecs\n",
-                      MS_TIME_DIFF(finalize_time,start_time),
-                      MS_TIME_DIFF(done_time,finalize_time));
+        GC_log_printf("Finalize and initiate sweep took %lu ms %lu ns"
+                      " + %lu ms %lu ns\n",
+                      MS_TIME_DIFF(finalize_time, start_time),
+                      NS_FRAC_TIME_DIFF(finalize_time, start_time),
+                      MS_TIME_DIFF(done_time, finalize_time),
+                      NS_FRAC_TIME_DIFF(done_time, finalize_time));
       }
 #   elif !defined(SMALL_CONFIG) && !defined(GC_NO_FINALIZATION)
       if (GC_print_stats)
@@ -1197,14 +1280,6 @@ GC_API void GC_CALL GC_gcollect_and_unmap(void)
     (void)GC_try_to_collect_general(GC_never_stop_func, TRUE);
 }
 
-GC_INNER word GC_n_heap_sects = 0;
-                        /* Number of sections currently in heap. */
-
-#ifdef USE_PROC_FOR_LIBRARIES
-  GC_INNER word GC_n_memory = 0;
-                        /* Number of GET_MEM allocated memory sections. */
-#endif
-
 #ifdef USE_PROC_FOR_LIBRARIES
   /* Add HBLKSIZE aligned, GET_MEM-generated block to GC_our_memory. */
   /* Defined to do nothing if USE_PROC_FOR_LIBRARIES not set.       */
@@ -1340,6 +1415,7 @@ GC_INNER GC_bool GC_expand_hp_inner(word n)
     word expansion_slop;        /* Number of bytes by which we expect the */
                                 /* heap to expand soon.                   */
 
+    GC_ASSERT(I_HOLD_LOCK());
     if (n < MINHINCR) n = MINHINCR;
     bytes = ROUNDUP_PAGESIZE((size_t)n * HBLKSIZE);
     if (GC_max_heapsize != 0
@@ -1410,12 +1486,30 @@ GC_API int GC_CALL GC_expand_hp(size_t bytes)
     return(result);
 }
 
-word GC_fo_entries = 0; /* used also in extra/MacOS.c */
-
 GC_INNER unsigned GC_fail_count = 0;
                         /* How many consecutive GC/expansion failures?  */
                         /* Reset by GC_allochblk.                       */
 
+/* The minimum value of the ratio of allocated bytes since the latest   */
+/* GC to the amount of finalizers created since that GC which triggers  */
+/* the collection instead heap expansion.  Has no effect in the         */
+/* incremental mode.                                                    */
+#if defined(GC_ALLOCD_BYTES_PER_FINALIZER) && !defined(CPPCHECK)
+  STATIC word GC_allocd_bytes_per_finalizer = GC_ALLOCD_BYTES_PER_FINALIZER;
+#else
+  STATIC word GC_allocd_bytes_per_finalizer = 10000;
+#endif
+
+GC_API void GC_CALL GC_set_allocd_bytes_per_finalizer(GC_word value)
+{
+  GC_allocd_bytes_per_finalizer = value;
+}
+
+GC_API GC_word GC_CALL GC_get_allocd_bytes_per_finalizer(void)
+{
+  return GC_allocd_bytes_per_finalizer;
+}
+
 static word last_fo_entries = 0;
 static word last_bytes_finalized = 0;
 
@@ -1431,11 +1525,14 @@ GC_INNER GC_bool GC_collect_or_expand(word needed_blocks,
     word blocks_to_get;
     IF_CANCEL(int cancel_state;)
 
+    GC_ASSERT(I_HOLD_LOCK());
     DISABLE_CANCEL(cancel_state);
     if (!GC_incremental && !GC_dont_gc &&
         ((GC_dont_expand && GC_bytes_allocd > 0)
-         || (GC_fo_entries > (last_fo_entries + 500)
-             && (last_bytes_finalized | GC_bytes_finalized) != 0)
+         || (GC_fo_entries > last_fo_entries
+             && (last_bytes_finalized | GC_bytes_finalized) != 0
+             && (GC_fo_entries - last_fo_entries)
+                * GC_allocd_bytes_per_finalizer > GC_bytes_allocd)
          || GC_should_collect())) {
       /* Try to do a full collection using 'default' stop_func (unless  */
       /* nothing has been allocated since the latest collection or heap */
@@ -1531,9 +1628,15 @@ GC_INNER ptr_t GC_allocobj(size_t gran, int kind)
                   || NULL == GC_obj_kinds[kind].ok_reclaim_list[gran]);
         GC_continue_reclaim(gran, kind);
       EXIT_GC();
-      if (*flh == 0) {
+#     if defined(CPPCHECK)
+        GC_noop1((word)&flh);
+#     endif
+      if (NULL == *flh) {
         GC_new_hblk(gran, kind);
-        if (*flh == 0) {
+#       if defined(CPPCHECK)
+          GC_noop1((word)&flh);
+#       endif
+        if (NULL == *flh) {
           ENTER_GC();
           if (GC_incremental && GC_time_limit == GC_TIME_UNLIMITED
               && !tried_minor) {

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

@@ -63,9 +63,9 @@ typedef struct back_edges_struct {
   signed_word height;
                 /* Longest path through unreachable nodes to this node  */
                 /* that we found using depth first search.              */
+# define HEIGHT_UNKNOWN      (-2)
+# define HEIGHT_IN_PROGRESS  (-1)
 
-#   define HEIGHT_UNKNOWN ((signed_word)(-2))
-#   define HEIGHT_IN_PROGRESS ((signed_word)(-1))
   ptr_t edges[MAX_IN];
   struct back_edges_struct *cont;
                 /* Pointer to continuation structure; we use only the   */
@@ -240,7 +240,7 @@ static void add_edge(ptr_t p, ptr_t q)
 
       if (((word)pred & FLAG_MANY) != 0) {
         n_edges = e -> n_edges;
-      } else if (pred != NULL && ((word)pred & 1) == 0) {
+      } else if (((word)COVERT_DATAFLOW(pred) & 1) == 0) {
         /* A misinterpreted freelist link.      */
         n_edges = 1;
         local = -1;

+ 6 - 0
blitz.mod/bdwgc/darwin_stop_world.c

@@ -73,6 +73,9 @@ GC_INNER ptr_t GC_FindTopOfStack(unsigned long stack_start)
         __asm__ __volatile__ ("mov %0, x29\n" : "=r" (sp_reg));
         frame = (StackFrame *)sp_reg;
 #   else
+#     if defined(CPPCHECK)
+        GC_noop1((word)&frame);
+#     endif
       ABORT("GC_FindTopOfStack(0) is not implemented");
 #   endif
   }
@@ -658,6 +661,9 @@ GC_INLINE void GC_thread_resume(thread_act_t thread)
     struct thread_basic_info info;
     mach_msg_type_number_t outCount = THREAD_BASIC_INFO_COUNT;
 
+#   if defined(CPPCHECK) && defined(DEBUG_THREADS)
+      info.run_state = 0;
+#   endif
     kern_result = thread_info(thread, THREAD_BASIC_INFO,
                               (thread_info_t)&info, &outCount);
     if (kern_result != KERN_SUCCESS)

+ 14 - 5
blitz.mod/bdwgc/dbg_mlc.c

@@ -489,9 +489,16 @@ GC_INNER void GC_start_debugging_inner(void)
   GC_print_heap_obj = GC_debug_print_heap_obj_proc;
   GC_debugging_started = TRUE;
   GC_register_displacement_inner((word)sizeof(oh));
+# if defined(CPPCHECK)
+    GC_noop1(GC_debug_header_size);
+# endif
 }
 
-size_t GC_debug_header_size = sizeof(oh);
+const size_t GC_debug_header_size = sizeof(oh);
+
+GC_API size_t GC_CALL GC_get_debug_header_size(void) {
+  return sizeof(oh);
+}
 
 GC_API void GC_CALL GC_debug_register_displacement(size_t offset)
 {
@@ -612,13 +619,15 @@ STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
   }
 #endif /* DBG_HDRS_ALL */
 
-GC_API void * GC_CALL GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
-{
+#ifndef CPPCHECK
+  GC_API void * GC_CALL GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
+  {
     return GC_debug_malloc(lb, OPT_RA s, i);
-}
+  }
 
-GC_API void GC_CALL GC_debug_change_stubborn(
+  GC_API void GC_CALL GC_debug_change_stubborn(
                                 const void * p GC_ATTR_UNUSED) {}
+#endif /* !CPPCHECK */
 
 GC_API void GC_CALL GC_debug_end_stubborn_change(const void *p)
 {

+ 6 - 13
blitz.mod/bdwgc/dyn_load.c

@@ -58,10 +58,10 @@ STATIC GC_has_static_roots_func GC_has_static_roots = 0;
     && !defined(CYGWIN32) && !defined(MSWIN32) && !defined(MSWINCE) \
     && !(defined(ALPHA) && defined(OSF1)) \
     && !(defined(FREEBSD) && defined(__ELF__)) \
-    && !((defined(LINUX) || defined(NACL)) && defined(__ELF__)) \
+    && !(defined(LINUX) && defined(__ELF__)) \
     && !(defined(NETBSD) && defined(__ELF__)) \
-    && !defined(HAIKU) && !defined(HURD) \
     && !(defined(OPENBSD) && (defined(__ELF__) || defined(M68K))) \
+    && !defined(HAIKU) && !defined(HURD) && !defined(NACL) \
     && !defined(CPPCHECK)
 # error We only know how to find data segments of dynamic libraries for above.
 # error Additional SVR4 variants might not be too hard to add.
@@ -88,10 +88,9 @@ STATIC GC_has_static_roots_func GC_has_static_roots = 0;
 # endif
 #endif /* OPENBSD */
 
-#if defined(SCO_ELF) || defined(DGUX) || defined(HURD) \
+#if defined(SCO_ELF) || defined(DGUX) || defined(HURD) || defined(NACL) \
     || (defined(__ELF__) && (defined(LINUX) || defined(FREEBSD) \
-                             || defined(NACL) || defined(NETBSD) \
-                             || defined(OPENBSD)))
+                             || defined(NETBSD) || defined(OPENBSD)))
 # include <stddef.h>
 # if !defined(OPENBSD) && !defined(HOST_ANDROID)
     /* OpenBSD does not have elf.h file; link.h below is sufficient.    */
@@ -259,10 +258,9 @@ GC_INNER void GC_register_dynamic_libraries(void)
 # endif /* !USE_PROC ... */
 # endif /* SOLARISDL */
 
-#if defined(SCO_ELF) || defined(DGUX) || defined(HURD) \
+#if defined(SCO_ELF) || defined(DGUX) || defined(HURD) || defined(NACL) \
     || (defined(__ELF__) && (defined(LINUX) || defined(FREEBSD) \
-                             || defined(NACL) || defined(NETBSD) \
-                             || defined(OPENBSD)))
+                             || defined(NETBSD) || defined(OPENBSD)))
 
 #ifdef USE_PROC_FOR_LIBRARIES
 
@@ -923,11 +921,6 @@ GC_INNER void GC_register_dynamic_libraries(void)
 
 # if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
 
-# ifndef WIN32_LEAN_AND_MEAN
-#   define WIN32_LEAN_AND_MEAN 1
-# endif
-# define NOSERVICE
-# include <windows.h>
 # include <stdlib.h>
 
   /* We traverse the entire address space and register all segments     */

+ 72 - 93
blitz.mod/bdwgc/finalize.c

@@ -3,7 +3,8 @@
  * Copyright (c) 1991-1996 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
  * Copyright (C) 2007 Free Software Foundation, Inc
-
+ * Copyright (c) 2008-2020 Ivan Maidanski
+ *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
  *
@@ -44,18 +45,6 @@ struct disappearing_link {
     word dl_hidden_obj;         /* Pointer to object base       */
 };
 
-struct dl_hashtbl_s {
-    struct disappearing_link **head;
-    signed_word log_size;
-    word entries;
-};
-
-STATIC struct dl_hashtbl_s GC_dl_hashtbl = {
-    /* head */ NULL, /* log_size */ -1, /* entries */ 0 };
-#ifndef GC_LONG_REFS_NOT_NEEDED
-  STATIC struct dl_hashtbl_s GC_ll_hashtbl = { NULL, -1, 0 };
-#endif
-
 struct finalizable_object {
     struct hash_chain_entry prolog;
 #   define fo_hidden_base prolog.hidden_key
@@ -70,14 +59,6 @@ struct finalizable_object {
     finalization_mark_proc fo_mark_proc;        /* Mark-through procedure */
 };
 
-static signed_word log_fo_table_size = -1;
-
-STATIC struct fnlz_roots_s {
-  struct finalizable_object **fo_head;
-  /* List of objects that should be finalized now: */
-  struct finalizable_object *finalize_now;
-} GC_fnlz_roots = { NULL, NULL };
-
 #ifdef AO_HAVE_store
   /* Update finalize_now atomically as GC_should_invoke_finalizers does */
   /* not acquire the allocation lock.                                   */
@@ -97,6 +78,7 @@ GC_API void GC_CALL GC_push_finalizer_structures(void)
 # endif
   GC_PUSH_ALL_SYM(GC_dl_hashtbl.head);
   GC_PUSH_ALL_SYM(GC_fnlz_roots);
+  /* GC_toggleref_arr is pushed specially by GC_mark_togglerefs.        */
 }
 
 /* Threshold of log_size to initiate full collection before growing     */
@@ -110,13 +92,13 @@ GC_API void GC_CALL GC_push_finalizer_structures(void)
 /* *table is a pointer to an array of hash headers.  If we succeed, we  */
 /* update both *table and *log_size_ptr.  Lock is held.                 */
 STATIC void GC_grow_table(struct hash_chain_entry ***table,
-                          signed_word *log_size_ptr, word *entries_ptr)
+                          unsigned *log_size_ptr, word *entries_ptr)
 {
     word i;
     struct hash_chain_entry *p;
-    signed_word log_old_size = *log_size_ptr;
-    signed_word log_new_size = log_old_size + 1;
-    word old_size = log_old_size == -1 ? 0 : (word)1 << log_old_size;
+    unsigned log_old_size = *log_size_ptr;
+    unsigned log_new_size = log_old_size + 1;
+    word old_size = *table == NULL ? 0 : (word)1 << log_old_size;
     word new_size = (word)1 << log_new_size;
     /* FIXME: Power of 2 size often gets rounded up to one more page. */
     struct hash_chain_entry **new_table;
@@ -188,15 +170,13 @@ STATIC int GC_register_disappearing_link_inner(
     if (EXPECT(GC_find_leak, FALSE)) return GC_UNIMPLEMENTED;
     LOCK();
     GC_ASSERT(obj != NULL && GC_base_C(obj) == obj);
-    if (dl_hashtbl -> log_size == -1
-        || dl_hashtbl -> entries > ((word)1 << dl_hashtbl -> log_size)) {
+    if (EXPECT(NULL == dl_hashtbl -> head, FALSE)
+        || EXPECT(dl_hashtbl -> entries
+                  > ((word)1 << dl_hashtbl -> log_size), FALSE)) {
         GC_grow_table((struct hash_chain_entry ***)&dl_hashtbl -> head,
                       &dl_hashtbl -> log_size, &dl_hashtbl -> entries);
-#       ifdef LINT2
-          if (dl_hashtbl->log_size < 0) ABORT("log_size is negative");
-#       endif
         GC_COND_LOG_PRINTF("Grew %s table to %u entries\n", tbl_log_name,
-                           1 << (unsigned)dl_hashtbl -> log_size);
+                           1U << dl_hashtbl -> log_size);
     }
     index = HASH2(link, dl_hashtbl -> log_size);
     for (curr_dl = dl_hashtbl -> head[index]; curr_dl != 0;
@@ -270,10 +250,9 @@ GC_INLINE struct disappearing_link *GC_unregister_disappearing_link_inner(
     size_t index;
 
     GC_ASSERT(I_HOLD_LOCK());
-    if (dl_hashtbl->log_size == -1)
-        return NULL; /* prevent integer shift by a negative amount */
+    if (EXPECT(NULL == dl_hashtbl -> head, FALSE)) return NULL;
 
-    index = HASH2(link, dl_hashtbl->log_size);
+    index = HASH2(link, dl_hashtbl -> log_size);
     for (curr_dl = dl_hashtbl -> head[index]; curr_dl;
          curr_dl = dl_next(curr_dl)) {
         if (curr_dl -> dl_hidden_link == GC_HIDE_POINTER(link)) {
@@ -310,21 +289,14 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
 
 /* 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;
+  typedef union toggle_ref_u 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;
+    size_t i;
+    size_t new_size = 0;
     GC_bool needs_barrier = FALSE;
 
     GC_ASSERT(I_HOLD_LOCK());
@@ -380,11 +352,10 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
 
   STATIC void GC_mark_togglerefs(void)
   {
-    int i;
+    size_t 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;
@@ -396,7 +367,7 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
 
   STATIC void GC_clear_togglerefs(void)
   {
-    int i;
+    size_t 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))) {
@@ -428,9 +399,8 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
     return fn;
   }
 
-  static GC_bool ensure_toggleref_capacity(int capacity_inc)
+  static GC_bool ensure_toggleref_capacity(size_t capacity_inc)
   {
-    GC_ASSERT(capacity_inc >= 0);
     GC_ASSERT(I_HOLD_LOCK());
     if (NULL == GC_toggleref_arr) {
       GC_toggleref_array_capacity = 32; /* initial capacity */
@@ -440,14 +410,15 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
       if (NULL == GC_toggleref_arr)
         return FALSE;
     }
-    if ((unsigned)GC_toggleref_array_size + (unsigned)capacity_inc
-        >= (unsigned)GC_toggleref_array_capacity) {
+    if (GC_toggleref_array_size + capacity_inc
+        >= GC_toggleref_array_capacity) {
       GCToggleRef *new_array;
-      while ((unsigned)GC_toggleref_array_capacity
-              < (unsigned)GC_toggleref_array_size + (unsigned)capacity_inc) {
+      while (GC_toggleref_array_capacity
+              < GC_toggleref_array_size + capacity_inc) {
         GC_toggleref_array_capacity *= 2;
-        if (GC_toggleref_array_capacity < 0) /* overflow */
-          return FALSE;
+        if ((GC_toggleref_array_capacity
+             & ((size_t)1 << (sizeof(size_t) * 8 - 1))) != 0)
+          return FALSE; /* overflow */
       }
 
       new_array = (GCToggleRef *)GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
@@ -541,31 +512,26 @@ GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void)
                                 struct dl_hashtbl_s *dl_hashtbl,
                                 void **link, void **new_link)
   {
-    struct disappearing_link *curr_dl, *prev_dl, *new_dl;
+    struct disappearing_link *curr_dl, *new_dl;
+    struct disappearing_link *prev_dl = NULL;
     size_t curr_index, new_index;
-    word curr_hidden_link;
-    word new_hidden_link;
+    word curr_hidden_link, new_hidden_link;
 
     GC_ASSERT(I_HOLD_LOCK());
-    if (dl_hashtbl->log_size == -1)
-        return GC_NOT_FOUND; /* prevent integer shift by a negative amount */
+    if (EXPECT(NULL == dl_hashtbl -> head, FALSE)) return GC_NOT_FOUND;
 
     /* Find current link.       */
     curr_index = HASH2(link, dl_hashtbl -> log_size);
     curr_hidden_link = GC_HIDE_POINTER(link);
-    prev_dl = NULL;
     for (curr_dl = dl_hashtbl -> head[curr_index]; curr_dl;
          curr_dl = dl_next(curr_dl)) {
       if (curr_dl -> dl_hidden_link == curr_hidden_link)
         break;
       prev_dl = curr_dl;
     }
-
-    if (NULL == curr_dl) {
+    if (EXPECT(NULL == curr_dl, FALSE)) {
       return GC_NOT_FOUND;
-    }
-
-    if (link == new_link) {
+    } else if (link == new_link) {
       return GC_SUCCESS; /* Nothing to do.      */
     }
 
@@ -636,8 +602,27 @@ GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void)
 /* overflow is handled by the caller, and is not a disaster.            */
 STATIC void GC_normal_finalize_mark_proc(ptr_t p)
 {
+# if defined(_MSC_VER) && defined(I386)
+    hdr * hhdr = HDR(p);
+    /* This is a manually inlined variant of GC_push_obj().  Otherwise  */
+    /* some optimizer bug is tickled in VC for X86 (v19, at least).     */
+#   define mark_stack_top GC_mark_stack_top
+    mse * mark_stack_limit = GC_mark_stack + GC_mark_stack_size;
+    word descr = hhdr -> hb_descr;
+
+    if (descr != 0) {
+      mark_stack_top++;
+      if ((word)mark_stack_top >= (word)mark_stack_limit) {
+        mark_stack_top = GC_signal_mark_stack_overflow(mark_stack_top);
+      }
+      mark_stack_top -> mse_start = p;
+      mark_stack_top -> mse_descr.w = descr;
+    }
+#   undef mark_stack_top
+# else
     GC_mark_stack_top = GC_push_obj(p, HDR(p), GC_mark_stack_top,
                                     GC_mark_stack + GC_mark_stack_size);
+# endif
 }
 
 /* This only pays very partial attention to the mark descriptor.        */
@@ -698,22 +683,19 @@ STATIC void GC_register_finalizer_inner(void * obj,
 
     if (EXPECT(GC_find_leak, FALSE)) return;
     LOCK();
-    if (log_fo_table_size == -1
-        || GC_fo_entries > ((word)1 << log_fo_table_size)) {
+    if (EXPECT(NULL == GC_fnlz_roots.fo_head, FALSE)
+        || EXPECT(GC_fo_entries > ((word)1 << GC_log_fo_table_size), FALSE)) {
         GC_grow_table((struct hash_chain_entry ***)&GC_fnlz_roots.fo_head,
-                      &log_fo_table_size, &GC_fo_entries);
-#       ifdef LINT2
-          if (log_fo_table_size < 0) ABORT("log_size is negative");
-#       endif
+                      &GC_log_fo_table_size, &GC_fo_entries);
         GC_COND_LOG_PRINTF("Grew fo table to %u entries\n",
-                           1 << (unsigned)log_fo_table_size);
+                           1U << GC_log_fo_table_size);
     }
     /* in the THREADS case we hold allocation lock.             */
     for (;;) {
       struct finalizable_object *prev_fo = NULL;
       GC_oom_func oom_fn;
 
-      index = HASH2(obj, log_fo_table_size);
+      index = HASH2(obj, GC_log_fo_table_size);
       curr_fo = GC_fnlz_roots.fo_head[index];
       while (curr_fo != 0) {
         GC_ASSERT(GC_size(curr_fo) >= sizeof(struct finalizable_object));
@@ -756,10 +738,8 @@ STATIC void GC_register_finalizer_inner(void * obj,
             GC_dirty(GC_fnlz_roots.fo_head + index);
           UNLOCK();
 #         ifndef DBG_HDRS_ALL
-            if (EXPECT(new_fo != 0, FALSE)) {
               /* Free unused new_fo returned by GC_oom_fn() */
               GC_free((void *)new_fo);
-            }
 #         endif
           return;
         }
@@ -862,10 +842,11 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
   STATIC void GC_dump_finalization_links(
                                 const struct dl_hashtbl_s *dl_hashtbl)
   {
-    size_t dl_size = dl_hashtbl->log_size == -1 ? 0 :
-                                (size_t)1 << dl_hashtbl->log_size;
+    size_t dl_size = (size_t)1 << dl_hashtbl -> log_size;
     size_t i;
 
+    if (NULL == dl_hashtbl -> head) return; /* empty table  */
+
     for (i = 0; i < dl_size; i++) {
       struct disappearing_link *curr_dl;
 
@@ -883,9 +864,9 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
   GC_API void GC_CALL GC_dump_finalization(void)
   {
     struct finalizable_object * curr_fo;
-    size_t fo_size = log_fo_table_size == -1 ? 0 :
-                                (size_t)1 << log_fo_table_size;
     size_t i;
+    size_t fo_size = GC_fnlz_roots.fo_head == NULL ? 0 :
+                                (size_t)1 << GC_log_fo_table_size;
 
     GC_printf("Disappearing (short) links:\n");
     GC_dump_finalization_links(&GC_dl_hashtbl);
@@ -945,11 +926,12 @@ GC_INLINE void GC_make_disappearing_links_disappear(
                                         GC_bool is_remove_dangling)
 {
   size_t i;
-  size_t dl_size = dl_hashtbl->log_size == -1 ? 0
-                        : (size_t)1 << dl_hashtbl->log_size;
+  size_t dl_size = (size_t)1 << dl_hashtbl -> log_size;
   GC_bool needs_barrier = FALSE;
 
   GC_ASSERT(I_HOLD_LOCK());
+  if (NULL == dl_hashtbl -> head) return; /* empty table  */
+
   for (i = 0; i < dl_size; i++) {
     struct disappearing_link *curr_dl, *next_dl;
     struct disappearing_link *prev_dl = NULL;
@@ -997,8 +979,8 @@ GC_INNER void GC_finalize(void)
     struct finalizable_object * curr_fo, * prev_fo, * next_fo;
     ptr_t real_ptr;
     size_t i;
-    size_t fo_size = log_fo_table_size == -1 ? 0 :
-                                (size_t)1 << log_fo_table_size;
+    size_t fo_size = GC_fnlz_roots.fo_head == NULL ? 0 :
+                                (size_t)1 << GC_log_fo_table_size;
     GC_bool needs_barrier = FALSE;
 
     GC_ASSERT(I_HOLD_LOCK());
@@ -1101,10 +1083,7 @@ GC_INNER void GC_finalize(void)
        other finalizable objects */
       if (need_unreachable_finalization) {
         curr_fo = GC_fnlz_roots.finalize_now;
-#       if defined(GC_ASSERTIONS) || defined(LINT2)
-          if (curr_fo != NULL && log_fo_table_size < 0)
-            ABORT("log_size is negative");
-#       endif
+        GC_ASSERT(NULL == curr_fo || GC_fnlz_roots.fo_head != NULL);
         prev_fo = NULL;
         while (curr_fo != NULL) {
           next_fo = fo_next(curr_fo);
@@ -1124,7 +1103,7 @@ GC_INNER void GC_finalize(void)
               GC_bytes_finalized -=
                   curr_fo->fo_object_size + sizeof(struct finalizable_object);
 
-              i = HASH2(real_ptr, log_fo_table_size);
+              i = HASH2(real_ptr, GC_log_fo_table_size);
               fo_set_next(curr_fo, GC_fnlz_roots.fo_head[i]);
               GC_dirty(curr_fo);
               GC_fo_entries++;
@@ -1169,11 +1148,11 @@ GC_INNER void GC_finalize(void)
   STATIC void GC_enqueue_all_finalizers(void)
   {
     struct finalizable_object * next_fo;
-    int i;
-    int fo_size;
+    size_t i;
+    size_t fo_size = GC_fnlz_roots.fo_head == NULL ? 0 :
+                                (size_t)1 << GC_log_fo_table_size;
 
     GC_ASSERT(I_HOLD_LOCK());
-    fo_size = log_fo_table_size == -1 ? 0 : 1 << log_fo_table_size;
     GC_bytes_finalized = 0;
     for (i = 0; i < fo_size; i++) {
       struct finalizable_object * curr_fo = GC_fnlz_roots.fo_head[i];
@@ -1368,8 +1347,8 @@ GC_INNER void GC_notify_or_invoke_finalizers(void)
 
     /* These variables require synchronization to avoid data races.     */
     if (last_finalizer_notification != GC_gc_no) {
-        last_finalizer_notification = GC_gc_no;
         notifier_fn = GC_finalizer_notifier;
+        last_finalizer_notification = GC_gc_no;
     }
     UNLOCK();
     if (notifier_fn != 0)

+ 0 - 2
blitz.mod/bdwgc/fnlz_mlc.c

@@ -20,8 +20,6 @@
 #include "gc_inline.h" /* for GC_malloc_kind */
 #include "private/dbg_mlc.h" /* for oh type */
 
-STATIC int GC_finalized_kind = 0;
-
 #if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
   /* The first bit is already used for a debug purpose. */
 # define FINALIZER_CLOSURE_FLAG 0x2

+ 39 - 0
blitz.mod/bdwgc/gc_badalc.cc

@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018-2020 Ivan Maidanski
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+
+// This file provides the implementation of GC_throw_bad_alloc() which
+// is invoked by GC operator "new" in case of an out-of-memory event.
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef GC_BUILD
+# define GC_BUILD
+#endif
+
+#define GC_DONT_INCL_WINDOWS_H
+#include "gc.h"
+
+#include <new> // for bad_alloc, precedes include of gc_cpp.h
+
+#if defined(GC_NEW_ABORTS_ON_OOM) || defined(_LIBCPP_NO_EXCEPTIONS)
+# define GC_ALLOCATOR_THROW_OR_ABORT() GC_abort_on_oom()
+#else
+# define GC_ALLOCATOR_THROW_OR_ABORT() throw std::bad_alloc()
+#endif
+
+GC_API void GC_CALL GC_throw_bad_alloc() {
+  GC_ALLOCATOR_THROW_OR_ABORT();
+}

+ 2 - 0
blitz.mod/bdwgc/gc_badalc.cpp

@@ -0,0 +1,2 @@
+// Visual C++ seems to prefer a .cpp extension to .cc one.
+#include "gc_badalc.cc"

+ 45 - 13
blitz.mod/bdwgc/gc_cpp.cc

@@ -4,12 +4,15 @@
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
  *
- * Permission is hereby granted to copy this code for any purpose,
- * provided the above notices are retained on all copies.
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
  */
 
 /*************************************************************************
-This implementation module for gc_c++.h provides an implementation of
+This implementation module for gc_cpp.h provides an implementation of
 the global operators "new" and "delete" that calls the Boehm
 allocator.  All objects allocated by this implementation will be
 uncollectible but part of the root set of the collector.
@@ -32,20 +35,17 @@ built-in "new" and "delete".
 
 #include <new> // for bad_alloc, precedes include of gc_cpp.h
 
-#include "gc_cpp.h" // for GC_OPERATOR_NEW_ARRAY, GC_NOEXCEPT
+#include "gc_cpp.h" // for GC_OPERATOR_NEW_ARRAY
+
+#if !(defined(_MSC_VER) || defined(__DMC__)) || defined(GC_NO_INLINE_STD_NEW)
 
 #if defined(GC_NEW_ABORTS_ON_OOM) || defined(_LIBCPP_NO_EXCEPTIONS)
 # define GC_ALLOCATOR_THROW_OR_ABORT() GC_abort_on_oom()
 #else
+// Use bad_alloc() directly instead of GC_throw_bad_alloc() call.
 # define GC_ALLOCATOR_THROW_OR_ABORT() throw std::bad_alloc()
 #endif
 
-GC_API void GC_CALL GC_throw_bad_alloc() {
-  GC_ALLOCATOR_THROW_OR_ABORT();
-}
-
-#if !defined(_MSC_VER) && !defined(__DMC__)
-
 # if !defined(GC_NEW_DELETE_THROW_NOT_NEEDED) \
     && !defined(GC_NEW_DELETE_NEED_THROW) && GC_GNUC_PREREQ(4, 2) \
     && (__cplusplus < 201103L || defined(__clang__))
@@ -53,7 +53,13 @@ GC_API void GC_CALL GC_throw_bad_alloc() {
 # endif
 
 # ifdef GC_NEW_DELETE_NEED_THROW
-#   define GC_DECL_NEW_THROW throw(std::bad_alloc)
+#   if __cplusplus >= 201703L || _MSVC_LANG >= 201703L
+      // The "dynamic exception" syntax had been deprecated in C++11
+      // and was removed in C++17.
+#     define GC_DECL_NEW_THROW noexcept(false)
+#   else
+#     define GC_DECL_NEW_THROW throw(std::bad_alloc)
+#   endif
 # else
 #   define GC_DECL_NEW_THROW /* empty */
 # endif
@@ -65,6 +71,23 @@ GC_API void GC_CALL GC_throw_bad_alloc() {
     return obj;
   }
 
+# ifdef _MSC_VER
+    // This new operator is used by VC++ in case of Debug builds.
+    void* operator new(size_t size, int /* nBlockUse */,
+                       const char* szFileName, int nLine)
+    {
+#     ifdef GC_DEBUG
+        void* obj = GC_debug_malloc_uncollectable(size, szFileName, nLine);
+#     else
+        void* obj = GC_MALLOC_UNCOLLECTABLE(size);
+        (void)szFileName; (void)nLine;
+#     endif
+      if (0 == obj)
+        GC_ALLOCATOR_THROW_OR_ABORT();
+      return obj;
+    }
+# endif // _MSC_VER
+
   void operator delete(void* obj) GC_NOEXCEPT {
     GC_FREE(obj);
   }
@@ -77,12 +100,21 @@ GC_API void GC_CALL GC_throw_bad_alloc() {
       return obj;
     }
 
+#   ifdef _MSC_VER
+      // This new operator is used by VC++ 7+ in Debug builds.
+      void* operator new[](size_t size, int nBlockUse,
+                           const char* szFileName, int nLine)
+      {
+        return operator new(size, nBlockUse, szFileName, nLine);
+      }
+#   endif // _MSC_VER
+
     void operator delete[](void* obj) GC_NOEXCEPT {
       GC_FREE(obj);
     }
 # endif // GC_OPERATOR_NEW_ARRAY
 
-# if __cplusplus > 201103L // C++14
+# if __cplusplus >= 201402L || _MSVC_LANG >= 201402L // C++14
     void operator delete(void* obj, size_t size) GC_NOEXCEPT {
       (void)size; // size is ignored
       GC_FREE(obj);
@@ -96,4 +128,4 @@ GC_API void GC_CALL GC_throw_bad_alloc() {
 #   endif
 # endif // C++14
 
-#endif // !_MSC_VER
+#endif // !_MSC_VER && !__DMC__ || GC_NO_INLINE_STD_NEW

+ 2 - 0
blitz.mod/bdwgc/gc_dlopen.c

@@ -46,7 +46,9 @@
     DCL_LOCK_STATE;
     LOCK();
     while (GC_incremental && GC_collection_in_progress()) {
+      ENTER_GC();
       GC_collect_a_little_inner(1000);
+      EXIT_GC();
     }
     ++GC_dont_gc;
     UNLOCK();

+ 8 - 20
blitz.mod/bdwgc/gcj_mlc.c

@@ -39,21 +39,12 @@
 #include "gc_gcj.h"
 #include "private/dbg_mlc.h"
 
-#ifdef GC_ASSERTIONS
-  GC_INNER /* variable is also used in thread_local_alloc.c */
-#else
-  STATIC
-#endif
-GC_bool GC_gcj_malloc_initialized = FALSE;
-
 int GC_gcj_kind = 0;    /* Object kind for objects with descriptors     */
                         /* in "vtable".                                 */
 int GC_gcj_debug_kind = 0;
                         /* The kind of objects that is always marked    */
                         /* with a mark proc call.                       */
 
-GC_INNER ptr_t * GC_gcjobjfreelist = NULL;
-
 STATIC struct GC_ms_entry * GC_gcj_fake_mark_proc(word * addr GC_ATTR_UNUSED,
                         struct GC_ms_entry *mark_stack_ptr,
                         struct GC_ms_entry * mark_stack_limit GC_ATTR_UNUSED,
@@ -77,11 +68,11 @@ GC_API void GC_CALL GC_init_gcj_malloc(int mp_index,
 
     GC_init();  /* In case it's not already done.       */
     LOCK();
-    if (GC_gcj_malloc_initialized) {
+    if (GC_gcjobjfreelist != NULL) {
+      /* Already initialized.   */
       UNLOCK();
       return;
     }
-    GC_gcj_malloc_initialized = TRUE;
 #   ifdef GC_IGNORE_GCJ_INFO
       /* This is useful for debugging on platforms with missing getenv(). */
 #     define ignore_gcj_info TRUE
@@ -96,30 +87,27 @@ GC_API void GC_CALL GC_init_gcj_malloc(int mp_index,
     if ((unsigned)mp_index >= GC_n_mark_procs)
         ABORT("GC_init_gcj_malloc: bad index");
     /* Set up object kind gcj-style indirect descriptor. */
-      GC_gcjobjfreelist = (ptr_t *)GC_new_free_list_inner();
-      if (ignore_gcj_info) {
+    GC_gcjobjfreelist = (ptr_t *)GC_new_free_list_inner();
+    if (ignore_gcj_info) {
         /* Use a simple length-based descriptor, thus forcing a fully   */
         /* conservative scan.                                           */
         GC_gcj_kind = GC_new_kind_inner((void **)GC_gcjobjfreelist,
                                         /* 0 | */ GC_DS_LENGTH,
                                         TRUE, TRUE);
-      } else {
+        GC_gcj_debug_kind = GC_gcj_kind;
+    } else {
         GC_gcj_kind = GC_new_kind_inner(
                         (void **)GC_gcjobjfreelist,
                         (((word)(-(signed_word)MARK_DESCR_OFFSET
                                  - GC_INDIR_PER_OBJ_BIAS))
                          | GC_DS_PER_OBJECT),
                         FALSE, TRUE);
-      }
-    /* Set up object kind for objects that require mark proc call.      */
-      if (ignore_gcj_info) {
-        GC_gcj_debug_kind = GC_gcj_kind;
-      } else {
+        /* Set up object kind for objects that require mark proc call.  */
         GC_gcj_debug_kind = GC_new_kind_inner(GC_new_free_list_inner(),
                                 GC_MAKE_PROC(mp_index,
                                              1 /* allocated with debug info */),
                                 FALSE, TRUE);
-      }
+    }
     UNLOCK();
 #   undef ignore_gcj_info
 }

+ 13 - 27
blitz.mod/bdwgc/headers.c

@@ -24,14 +24,6 @@
  * level tree.
  */
 
-STATIC bottom_index * GC_all_bottom_indices = 0;
-                        /* Pointer to the first (lowest address)        */
-                        /* bottom_index.  Assumes the lock is held.     */
-
-STATIC bottom_index * GC_all_bottom_indices_end = 0;
-                        /* Pointer to the last (highest address)        */
-                        /* bottom_index.  Assumes the lock is held.     */
-
 /* Non-macro version of header location routine */
 GC_INNER hdr * GC_find_header(ptr_t h)
 {
@@ -110,20 +102,15 @@ GC_INNER hdr *
 /* Routines to dynamically allocate collector data structures that will */
 /* never be freed.                                                      */
 
-static ptr_t scratch_free_ptr = 0;
-
-/* GC_scratch_last_end_ptr is end point of last obtained scratch area.  */
-/* GC_scratch_end_ptr is end point of current scratch area.             */
-
 GC_INNER ptr_t GC_scratch_alloc(size_t bytes)
 {
-    ptr_t result = scratch_free_ptr;
+    ptr_t result = GC_scratch_free_ptr;
     size_t bytes_to_get;
 
     bytes = ROUNDUP_GRANULE_SIZE(bytes);
     for (;;) {
-        scratch_free_ptr += bytes;
-        if ((word)scratch_free_ptr <= (word)GC_scratch_end_ptr) {
+        GC_scratch_free_ptr += bytes;
+        if ((word)GC_scratch_free_ptr <= (word)GC_scratch_end_ptr) {
             /* Unallocated space of scratch buffer has enough size. */
             return result;
         }
@@ -133,7 +120,7 @@ GC_INNER ptr_t GC_scratch_alloc(size_t bytes)
             result = (ptr_t)GET_MEM(bytes_to_get);
             GC_add_to_our_memory(result, bytes_to_get);
             /* Undo scratch free area pointer update; get memory directly. */
-            scratch_free_ptr -= bytes;
+            GC_scratch_free_ptr -= bytes;
             if (result != NULL) {
                 /* Update end point of last obtained area (needed only  */
                 /* by GC_register_dynamic_libraries for some targets).  */
@@ -149,39 +136,37 @@ GC_INNER ptr_t GC_scratch_alloc(size_t bytes)
         if (NULL == result) {
             WARN("Out of memory - trying to allocate requested amount"
                  " (%" WARN_PRIdPTR " bytes)...\n", (word)bytes);
-            scratch_free_ptr -= bytes; /* Undo free area pointer update */
+            GC_scratch_free_ptr -= bytes; /* Undo free area pointer update */
             bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(bytes);
             result = (ptr_t)GET_MEM(bytes_to_get);
             GC_add_to_our_memory(result, bytes_to_get);
             return result;
         }
         /* Update scratch area pointers and retry.      */
-        scratch_free_ptr = result;
-        GC_scratch_end_ptr = scratch_free_ptr + bytes_to_get;
+        GC_scratch_free_ptr = result;
+        GC_scratch_end_ptr = GC_scratch_free_ptr + bytes_to_get;
         GC_scratch_last_end_ptr = GC_scratch_end_ptr;
     }
 }
 
-static hdr * hdr_free_list = 0;
-
 /* Return an uninitialized header */
 static hdr * alloc_hdr(void)
 {
     hdr * result;
 
-    if (NULL == hdr_free_list) {
+    if (NULL == GC_hdr_free_list) {
         result = (hdr *)GC_scratch_alloc(sizeof(hdr));
     } else {
-        result = hdr_free_list;
-        hdr_free_list = (hdr *) (result -> hb_next);
+        result = GC_hdr_free_list;
+        GC_hdr_free_list = (hdr *) result -> hb_next;
     }
     return(result);
 }
 
 GC_INLINE void free_hdr(hdr * hhdr)
 {
-    hhdr -> hb_next = (struct hblk *) hdr_free_list;
-    hdr_free_list = hhdr;
+    hhdr -> hb_next = (struct hblk *) GC_hdr_free_list;
+    GC_hdr_free_list = hhdr;
 }
 
 #ifdef COUNT_HDR_CACHE_HITS
@@ -194,6 +179,7 @@ GC_INNER void GC_init_headers(void)
 {
     unsigned i;
 
+    GC_ASSERT(NULL == GC_all_nils);
     GC_all_nils = (bottom_index *)GC_scratch_alloc(sizeof(bottom_index));
     if (GC_all_nils == NULL) {
       GC_err_printf("Insufficient memory for GC_all_nils\n");

+ 18 - 5
blitz.mod/bdwgc/include/ec.h

@@ -1,5 +1,18 @@
-# ifndef EC_H
-# define EC_H
+/*
+ * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#ifndef EC_H
+#define EC_H
 
 # ifndef CORD_H
 #  include "cord.h"
@@ -61,8 +74,8 @@ void CORD_ec_flush_buf(CORD_ec x);
 
 /* Append a character to an extensible cord.    */
 #define CORD_ec_append(x, c) \
-                (((x)[0].ec_bufptr == (x)[0].ec_buf + CORD_BUFSZ ? \
-                        (CORD_ec_flush_buf(x), 0) : 0), \
+                ((void)((x)[0].ec_bufptr == (x)[0].ec_buf + CORD_BUFSZ \
+                        ? (CORD_ec_flush_buf(x), 0) : 0), \
                  (void)(*(x)[0].ec_bufptr++ = (c)))
 
 /* Append a cord to an extensible cord.  Structure remains shared with  */
@@ -73,4 +86,4 @@ void CORD_ec_append_cord(CORD_ec x, CORD s);
   } /* extern "C" */
 #endif
 
-# endif /* EC_H */
+#endif /* EC_H */

+ 157 - 59
blitz.mod/bdwgc/include/gc.h

@@ -5,7 +5,7 @@
  * Copyright 1999 by Hewlett-Packard Company.  All rights reserved.
  * Copyright (C) 2007 Free Software Foundation, Inc
  * Copyright (c) 2000-2011 by Hewlett-Packard Development Company.
- * Copyright (c) 2009-2018 Ivan Maidanski
+ * Copyright (c) 2009-2020 Ivan Maidanski
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -24,7 +24,6 @@
  * For better performance, also look at GC_MALLOC_ATOMIC, and
  * GC_enable_incremental.  If you need an action to be performed
  * immediately before an object is collected, look at GC_register_finalizer.
- * If you are using Solaris threads, look at the end of this file.
  * Everything else is best ignored unless you encounter performance
  * problems.
  */
@@ -90,21 +89,28 @@ GC_API GC_word GC_CALL GC_get_gc_no(void);
 #ifdef GC_THREADS
   GC_API GC_ATTR_DEPRECATED int GC_parallel;
                         /* GC is parallelized for performance on        */
-                        /* multiprocessors.  Currently set only         */
-                        /* implicitly if collector is built with        */
-                        /* PARALLEL_MARK defined and if either:         */
-                        /*  Env variable GC_NPROC is set to > 1, or     */
-                        /*  GC_NPROC is not set and this is an MP.      */
-                        /* If GC_parallel is on (non-zero), incremental */
-                        /* collection is only partially functional,     */
-                        /* and may not be desirable.  The getter does   */
+                        /* multiprocessors.  Set to a non-zero value    */
+                        /* only implicitly if collector is built with   */
+                        /* PARALLEL_MARK defined, and if either         */
+                        /* GC_MARKERS (or GC_NPROCS) environment        */
+                        /* variable is set to > 1, or multiple cores    */
+                        /* (processors) are available, or the client    */
+                        /* calls GC_set_markers_count() before the GC   */
+                        /* initialization.  The getter does             */
                         /* not use or need synchronization (i.e.        */
-                        /* acquiring the GC lock).  Starting from       */
-                        /* GC v7.3, GC_parallel value is equal to the   */
-                        /* number of marker threads minus one (i.e.     */
-                        /* number of existing parallel marker threads   */
-                        /* excluding the initiating one).               */
+                        /* acquiring the GC lock).  GC_parallel value   */
+                        /* is equal to the number of marker threads     */
+                        /* minus one (i.e. number of existing parallel  */
+                        /* marker threads excluding the initiating one).*/
   GC_API int GC_CALL GC_get_parallel(void);
+
+  /* Set the number of marker threads (including the initiating one)    */
+  /* to the desired value at start-up.  Zero value means the collector  */
+  /* is to decide.  Has no effect if called after GC initialization.    */
+  /* If the correct non-zero value is passed, then GC_parallel should   */
+  /* be set to the value minus one.  The function does not use any      */
+  /* synchronization.                                                   */
+  GC_API void GC_CALL GC_set_markers_count(unsigned);
 #endif
 
 
@@ -242,8 +248,8 @@ GC_API
 # ifndef GC_DONT_GC
     GC_ATTR_DEPRECATED
 # endif
-  int GC_dont_gc;       /* != 0 ==> Don't collect.  In versions 6.2a1+, */
-                        /* this overrides explicit GC_gcollect() calls. */
+  int GC_dont_gc;       /* != 0 ==> Do not collect.  This overrides     */
+                        /* explicit GC_gcollect() calls as well.        */
                         /* Used as a counter, so that nested enabling   */
                         /* and disabling work correctly.  Should        */
                         /* normally be updated with GC_enable() and     */
@@ -261,8 +267,7 @@ GC_API int GC_CALL GC_get_dont_expand(void);
 
 GC_API GC_ATTR_DEPRECATED int GC_use_entire_heap;
                 /* Causes the non-incremental collector to use the      */
-                /* entire heap before collecting.  This was the only    */
-                /* option for GC versions < 5.0.  This sometimes        */
+                /* entire heap before collecting.  This sometimes       */
                 /* results in more large block fragmentation, since     */
                 /* very large blocks will tend to get broken up         */
                 /* during each GC cycle.  It is likely to result in a   */
@@ -329,8 +334,8 @@ GC_API GC_ATTR_DEPRECATED GC_word GC_free_space_divisor;
                         /* GC_call_with_alloc_lock() is required to     */
                         /* avoid data races (if the value is modified   */
                         /* after the GC is put to multi-threaded mode). */
-                        /* In version 7.1 (and before), the setter      */
-                        /* returned the old value.                      */
+                        /* In GC v7.1 (and before), the setter returned */
+                        /* the old value.                               */
 GC_API void GC_CALL GC_set_free_space_divisor(GC_word);
 GC_API GC_word GC_CALL GC_get_free_space_divisor(void);
 
@@ -347,7 +352,7 @@ GC_API GC_word GC_CALL GC_get_max_retries(void);
 
 
 GC_API GC_ATTR_DEPRECATED char *GC_stackbottom;
-                                /* Cool end of user stack.              */
+                                /* The cold end (bottom) of user stack. */
                                 /* May be set in the client prior to    */
                                 /* calling any GC_ routines.  This      */
                                 /* avoids some overhead, and            */
@@ -378,9 +383,12 @@ GC_API int GC_CALL GC_get_dont_precollect(void);
 
 GC_API GC_ATTR_DEPRECATED unsigned long GC_time_limit;
                                /* If incremental collection is enabled, */
-                               /* We try to terminate collections       */
-                               /* after this many milliseconds.  Not a  */
-                               /* hard time bound.  Setting this to     */
+                               /* we try to terminate collections       */
+                               /* after this many milliseconds (plus    */
+                               /* the amount of nanoseconds as given in */
+                               /* the latest GC_set_time_limit_tv call, */
+                               /* if any).  Not a hard time bound.      */
+                               /* Setting this variable to              */
                                /* GC_TIME_UNLIMITED will essentially    */
                                /* disable incremental collection while  */
                                /* leaving generational collection       */
@@ -393,11 +401,46 @@ GC_API GC_ATTR_DEPRECATED unsigned long GC_time_limit;
                         /* GC_call_with_alloc_lock() is required to     */
                         /* avoid data races (if the value is modified   */
                         /* after the GC is put to multi-threaded mode). */
+                        /* The setter does not update the value of the  */
+                        /* nanosecond part of the time limit (it is     */
+                        /* zero unless ever set by GC_set_time_limit_tv */
+                        /* call).                                       */
 GC_API void GC_CALL GC_set_time_limit(unsigned long);
 GC_API unsigned long GC_CALL GC_get_time_limit(void);
 
+/* A portable type definition of time with a nanosecond precision.      */
+struct GC_timeval_s {
+  unsigned long tv_ms;  /* time in milliseconds */
+  unsigned long tv_nsec;/* nanoseconds fraction (<1000000) */
+};
+
 /* Public procedures */
 
+/* Set/get the time limit of the incremental collections.  This is      */
+/* similar to GC_set_time_limit and GC_get_time_limit but the time is   */
+/* provided with the nanosecond precision.  The value of tv_nsec part   */
+/* should be less than a million.  If the value of tv_ms part is        */
+/* GC_TIME_UNLIMITED then tv_nsec is ignored.  Initially, the value of  */
+/* tv_nsec part of the time limit is zero.  The functions do not use    */
+/* any synchronization.  Defined only if the library has been compiled  */
+/* without NO_CLOCK.                                                    */
+GC_API void GC_CALL GC_set_time_limit_tv(struct GC_timeval_s);
+GC_API struct GC_timeval_s GC_CALL GC_get_time_limit_tv(void);
+
+/* Set/get the minimum value of the ratio of allocated bytes since GC   */
+/* to the amount of finalizers created since that GC (value >           */
+/* GC_bytes_allocd / (GC_fo_entries - last_fo_entries)) which triggers  */
+/* the collection instead heap expansion.  The value has no effect in   */
+/* the GC incremental mode.  The default value is 10000 unless          */
+/* GC_ALLOCD_BYTES_PER_FINALIZER macro with a custom value is defined   */
+/* to build libgc.  The default value might be not the right choice for */
+/* clients where e.g. most objects have a finalizer.  Zero value        */
+/* effectively disables taking amount of finalizers in the decision     */
+/* whether to collect or not.  The functions do not use any             */
+/* synchronization.                                                     */
+GC_API void GC_CALL GC_set_allocd_bytes_per_finalizer(GC_word);
+GC_API GC_word GC_CALL GC_get_allocd_bytes_per_finalizer(void);
+
 /* Tell the collector to start various performance measurements.        */
 /* Only the total time taken by full collections is calculated, as      */
 /* of now.  And, currently, there is no way to stop the measurements.   */
@@ -452,8 +495,8 @@ GC_API int GC_CALL GC_get_max_prior_attempts(void);
 /* activities are not fully POSIX-compliant.)  GC_set_handle_fork       */
 /* instructs GC_init to setup GC fork handlers using pthread_atfork,    */
 /* the latter might fail (or, even, absent on some targets) causing     */
-/* abort at GC initialization.  Starting from 7.3alpha3, problems with  */
-/* missing (or failed) pthread_atfork() could be avoided by invocation  */
+/* abort at GC initialization.  Issues with missing (or failed)         */
+/* pthread_atfork() could be avoided by invocation                      */
 /* of GC_set_handle_fork(-1) at application start-up and surrounding    */
 /* each fork() with the relevant GC_atfork_prepare/parent/child calls.  */
 GC_API void GC_CALL GC_set_handle_fork(int);
@@ -599,6 +642,9 @@ GC_API void GC_CALL GC_set_max_heap_size(GC_word /* n */);
 GC_API void GC_CALL GC_exclude_static_roots(void * /* low_address */,
                                             void * /* high_address_plus_1 */);
 
+/* Clear the number of entries in the exclusion table.  Wizards only.   */
+GC_API void GC_CALL GC_clear_exclusion_table(void);
+
 /* Clear the set of root segments.  Wizards only.                       */
 GC_API void GC_CALL GC_clear_roots(void);
 
@@ -711,8 +757,6 @@ GC_API size_t GC_CALL GC_get_total_bytes(void);
 /* the allocator lock thus preventing data racing and returning the     */
 /* consistent result.)  Passing NULL pointer is allowed for any         */
 /* argument.  Returned (filled in) values are of word type.             */
-/* (This API function was introduced in GC v7.2alpha7 at the same time  */
-/* when GC_get_heap_size and the friends were made lock-free again.)    */
 GC_API void GC_CALL GC_get_heap_usage_safe(GC_word * /* pheap_size */,
                                            GC_word * /* pfree_bytes */,
                                            GC_word * /* punmapped_bytes */,
@@ -820,12 +864,11 @@ GC_API int GC_CALL GC_get_manual_vdb_allowed(void);
 /* dirty bits are available or most heap objects are pointer-free       */
 /* (atomic) or immutable.  Don't use in leak finding mode.  Ignored if  */
 /* GC_dont_gc is non-zero.  Only the generational piece of this is      */
-/* functional if GC_parallel is non-zero or if GC_time_limit is         */
-/* GC_TIME_UNLIMITED.  Causes thread-local variant of GC_gcj_malloc()   */
-/* to revert to locked allocation.  Must be called before any such      */
-/* GC_gcj_malloc() calls.  For best performance, should be called as    */
-/* early as possible.  On some platforms, calling it later may have     */
-/* adverse effects.                                                     */
+/* functional if GC_time_limit is set to GC_TIME_UNLIMITED.  Causes     */
+/* thread-local variant of GC_gcj_malloc() to revert to locked          */
+/* allocation.  Must be called before any such GC_gcj_malloc() calls.   */
+/* For best performance, should be called as early as possible.         */
+/* On some platforms, calling it later may have adverse effects.        */
 /* Safe to call before GC_INIT().  Includes a  GC_init() call.          */
 GC_API void GC_CALL GC_enable_incremental(void);
 
@@ -865,7 +908,7 @@ GC_API int GC_CALL GC_collect_a_little(void);
 /* it reduces the chance of the allocator not finding space for such    */
 /* an array, since it will try hard to avoid introducing such a false   */
 /* reference.)  On a SunOS 4.X or MS Windows system this is recommended */
-/* for arrays likely to be larger than 100K or so.  For other systems,  */
+/* for arrays likely to be larger than 100 KB or so.  For other systems,*/
 /* or if the collector is not configured to recognize all interior      */
 /* pointers, the threshold is normally much higher.                     */
 GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
@@ -914,11 +957,7 @@ GC_API void GC_CALL GC_debug_free(void *);
 GC_API void * GC_CALL GC_debug_realloc(void * /* old_object */,
                         size_t /* new_size_in_bytes */, GC_EXTRA_PARAMS)
                         /* 'realloc' attr */ GC_ATTR_ALLOC_SIZE(2);
-GC_API
-#if !defined(CPPCHECK)
-  GC_ATTR_DEPRECATED
-#endif
-void GC_CALL GC_debug_change_stubborn(const void *);
+GC_API GC_ATTR_DEPRECATED void GC_CALL GC_debug_change_stubborn(const void *);
 GC_API void GC_CALL GC_debug_end_stubborn_change(const void *)
                                                         GC_ATTR_NONNULL(1);
 
@@ -1339,7 +1378,7 @@ GC_API int GC_CALL GC_invoke_finalizers(void);
 /* GC_set_warn_proc can be used to redirect or filter warning messages. */
 /* p may not be a NULL pointer.  msg is printf format string (arg must  */
 /* match the format).  Both the setter and the getter acquire the GC    */
-/* lock (to avoid data races).  In version 7.1 (and before), the setter */
+/* lock (to avoid data races).  In GC v7.1 (and before), the setter     */
 /* returned the old warn_proc value.                                    */
 typedef void (GC_CALLBACK * GC_warn_proc)(char * /* msg */,
                                           GC_word /* arg */);
@@ -1391,6 +1430,18 @@ typedef GC_word GC_hidden_pointer;
 # define REVEAL_POINTER(p) GC_REVEAL_POINTER(p)
 #endif
 
+/* The routines to acquire/release the allocator lock.                  */
+/* The lock is not reentrant.  GC_alloc_unlock() should not be called   */
+/* unless the lock is acquired by the current thread.                   */
+#ifdef GC_THREADS
+  GC_API void GC_CALL GC_alloc_lock(void);
+  GC_API void GC_CALL GC_alloc_unlock(void);
+#else
+  /* No need for real locking if the client is single-threaded.         */
+# define GC_alloc_lock() (void)0
+# define GC_alloc_unlock() (void)0
+#endif /* !GC_THREADS */
+
 typedef void * (GC_CALLBACK * GC_fn_type)(void * /* client_data */);
 GC_API void * GC_CALL GC_call_with_alloc_lock(GC_fn_type /* fn */,
                                 void * /* client_data */) GC_ATTR_NONNULL(1);
@@ -1402,15 +1453,15 @@ GC_API void * GC_CALL GC_call_with_alloc_lock(GC_fn_type /* fn */,
 /* is to always make redundant registration safe.  In the short run,    */
 /* this is being implemented a platform at a time.                      */
 /* The interface is complicated by the fact that we probably will not   */
-/* ever be able to automatically determine the stack base for thread    */
+/* ever be able to automatically determine the stack bottom for thread  */
 /* stacks on all platforms.                                             */
 
-/* Structure representing the base of a thread stack.  On most          */
-/* platforms this contains just a single address.                       */
+/* Structure representing the bottom (cold end) of a thread stack.      */
+/* On most platforms this contains just a single address.               */
 struct GC_stack_base {
-  void * mem_base; /* Base of memory stack. */
+  void * mem_base;      /* the bottom of the general-purpose stack */
 # if defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
-    void * reg_base; /* Base of separate register stack. */
+    void * reg_base;    /* the bottom of the register stack */
 # endif
 };
 
@@ -1419,7 +1470,7 @@ typedef void * (GC_CALLBACK * GC_stack_base_func)(
 
 /* Call a function with a stack base structure corresponding to         */
 /* somewhere in the GC_call_with_stack_base frame.  This often can      */
-/* be used to provide a sufficiently accurate stack base.  And we       */
+/* be used to provide a sufficiently accurate stack bottom.  And we     */
 /* implement it everywhere.                                             */
 GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */,
                                         void * /* arg */) GC_ATTR_NONNULL(1);
@@ -1472,7 +1523,7 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */,
   /* registering of a thread (it should be called as late as possible). */
   GC_API void GC_CALL GC_allow_register_threads(void);
 
-  /* Register the current thread, with the indicated stack base, as     */
+  /* Register the current thread, with the indicated stack bottom, as   */
   /* a new thread whose stack(s) should be traced by the GC.  If it     */
   /* is not implicitly called by the GC, this must be called before a   */
   /* thread can allocate garbage collected memory, or assign pointers   */
@@ -1534,8 +1585,13 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */,
 /* the current thread (this means that the thread is not suspended and  */
 /* the thread's stack frames "belonging" to the functions in the        */
 /* "inactive" state are not scanned during garbage collections).  It is */
-/* allowed for fn to call GC_call_with_gc_active() (even recursively),  */
-/* thus temporarily toggling the collector's state back to "active".    */
+/* assumed that the collector is already initialized and the current    */
+/* thread is registered.  It is allowed for fn to call                  */
+/* GC_call_with_gc_active() (even recursively), thus temporarily        */
+/* toggling the collector's state back to "active".  The latter         */
+/* technique might be used to make stack scanning more precise (i.e.    */
+/* scan only stack frames of functions that allocate garbage collected  */
+/* memory and/or manipulate pointers to the garbage collected heap).    */
 GC_API void * GC_CALL GC_do_blocking(GC_fn_type /* fn */,
                                 void * /* client_data */) GC_ATTR_NONNULL(1);
 
@@ -1547,11 +1603,11 @@ GC_API void * GC_CALL GC_do_blocking(GC_fn_type /* fn */,
 /* initialized and the current thread is registered.  fn may toggle     */
 /* the collector thread's state temporarily to "inactive" one by using  */
 /* GC_do_blocking.  GC_call_with_gc_active() often can be used to       */
-/* provide a sufficiently accurate stack base.                          */
+/* provide a sufficiently accurate stack bottom.                        */
 GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type /* fn */,
                                 void * /* client_data */) GC_ATTR_NONNULL(1);
 
-/* Attempt to fill in the GC_stack_base structure with the stack base   */
+/* Attempt to fill in the GC_stack_base structure with the stack bottom */
 /* for this thread.  This appears to be required to implement anything  */
 /* like the JNI AttachCurrentThread in an environment in which new      */
 /* threads are not automatically registered with the collector.         */
@@ -1561,6 +1617,30 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type /* fn */,
 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *)
                                                         GC_ATTR_NONNULL(1);
 
+/* Fill in the GC_stack_base structure with the cold end (bottom) of    */
+/* the stack of the current thread (or coroutine).                      */
+/* Unlike GC_get_stack_base, it retrieves the value stored in the       */
+/* collector (which is initially set by the collector upon the thread   */
+/* is started or registered manually but it could be later updated by   */
+/* client using GC_set_stackbottom).  Returns the GC-internal non-NULL  */
+/* handle of the thread which could be passed to GC_set_stackbottom     */
+/* later.  It is assumed that the collector is already initialized and  */
+/* the thread is registered.  Acquires the GC lock to avoid data races. */
+GC_API void * GC_CALL GC_get_my_stackbottom(struct GC_stack_base *)
+                                                        GC_ATTR_NONNULL(1);
+
+/* Set the cool end of the user (coroutine) stack of the specified      */
+/* thread.  The GC thread handle is either the one returned by          */
+/* GC_get_my_stackbottom or NULL (the latter designates the current     */
+/* thread).  The caller should hold the GC lock (e.g. using             */
+/* GC_call_with_alloc_lock).  Also, the function could be used for      */
+/* setting GC_stackbottom value (the bottom of the primordial thread)   */
+/* before the collector is initialized (the GC lock is not needed to be */
+/* acquired in this case).                                              */
+GC_API void GC_CALL GC_set_stackbottom(void * /* gc_thread_handle */,
+                                       const struct GC_stack_base *)
+                                                        GC_ATTR_NONNULL(2);
+
 /* The following routines are primarily intended for use with a         */
 /* preprocessor which inserts calls to check C pointer arithmetic.      */
 /* They indicate failure by invoking the corresponding _print_proc.     */
@@ -1893,8 +1973,8 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
         /* Required at least if GC is in a DLL.  And doesn't hurt. */
 #elif defined(_AIX)
   extern int _data[], _end[];
-# define GC_DATASTART ((void *)((ulong)_data))
-# define GC_DATAEND ((void *)((ulong)_end))
+# define GC_DATASTART ((void *)_data)
+# define GC_DATAEND ((void *)_end)
 # define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND)
 #elif (defined(HOST_ANDROID) || defined(__ANDROID__)) \
       && defined(IGNORE_DYNAMIC_LOADING)
@@ -1937,6 +2017,14 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
 # define GC_INIT_CONF_MAX_RETRIES /* empty */
 #endif
 
+#if defined(GC_ALLOCD_BYTES_PER_FINALIZER) && !defined(CPPCHECK)
+  /* Set GC_allocd_bytes_per_finalizer to the desired value at start-up. */
+# define GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER \
+        GC_set_allocd_bytes_per_finalizer(GC_ALLOCD_BYTES_PER_FINALIZER)
+#else
+# define GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER /* empty */
+#endif
+
 #if defined(GC_FREE_SPACE_DIVISOR) && !defined(CPPCHECK)
   /* Set GC_free_space_divisor to the desired value at start-up */
 # define GC_INIT_CONF_FREE_SPACE_DIVISOR \
@@ -1953,12 +2041,20 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
 #endif
 
 #if defined(GC_TIME_LIMIT) && !defined(CPPCHECK)
-  /* Set GC_time_limit to the desired value at start-up */
+  /* Set GC_time_limit (in ms) to the desired value at start-up. */
 # define GC_INIT_CONF_TIME_LIMIT GC_set_time_limit(GC_TIME_LIMIT)
 #else
 # define GC_INIT_CONF_TIME_LIMIT /* empty */
 #endif
 
+#if defined(GC_MARKERS) && defined(GC_THREADS) && !defined(CPPCHECK)
+  /* Set the number of marker threads (including the initiating */
+  /* one) to the desired value at start-up.                     */
+# define GC_INIT_CONF_MARKERS GC_set_markers_count(GC_MARKERS)
+#else
+# define GC_INIT_CONF_MARKERS /* empty */
+#endif
+
 #if defined(GC_SIG_SUSPEND) && defined(GC_THREADS) && !defined(CPPCHECK)
 # define GC_INIT_CONF_SUSPEND_SIGNAL GC_set_suspend_signal(GC_SIG_SUSPEND)
 #else
@@ -2002,13 +2098,15 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
 
 /* Portable clients should call this at the program start-up.  More     */
 /* over, some platforms require this call to be done strictly from the  */
-/* primordial thread.                                                   */
+/* primordial thread.  Multiple invocations are harmless.               */
 #define GC_INIT() { GC_INIT_CONF_DONT_EXPAND; /* pre-init */ \
                     GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT; \
                     GC_INIT_CONF_MAX_RETRIES; \
+                    GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER; \
                     GC_INIT_CONF_FREE_SPACE_DIVISOR; \
                     GC_INIT_CONF_FULL_FREQ; \
                     GC_INIT_CONF_TIME_LIMIT; \
+                    GC_INIT_CONF_MARKERS; \
                     GC_INIT_CONF_SUSPEND_SIGNAL; \
                     GC_INIT_CONF_THR_RESTART_SIGNAL; \
                     GC_INIT_CONF_MAXIMUM_HEAP_SIZE; \
@@ -2017,8 +2115,8 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
                     GC_INIT_CONF_IGNORE_WARN; \
                     GC_INIT_CONF_INITIAL_HEAP_SIZE; }
 
-/* win32S may not free all resources on process exit.   */
-/* This explicitly deallocates the heap.                */
+/* win32S may not free all resources on process exit.                   */
+/* This explicitly deallocates the heap.  Defined only for Windows.     */
 GC_API void GC_CALL GC_win32_free_heap(void);
 
 #if defined(__SYMBIAN32__)

+ 0 - 24
blitz.mod/bdwgc/include/gc_allocator.h

@@ -43,35 +43,11 @@
 #include "gc.h"
 #include <new> // for placement new and bad_alloc
 
-#ifndef GC_ATTR_EXPLICIT
-# if (__cplusplus >= 201103L) || defined(CPPCHECK)
-#   define GC_ATTR_EXPLICIT explicit
-# else
-#   define GC_ATTR_EXPLICIT /* empty */
-# endif
-#endif
-
 #if !defined(GC_NO_MEMBER_TEMPLATES) && defined(_MSC_VER) && _MSC_VER <= 1200
   // MSVC++ 6.0 do not support member templates.
 # define GC_NO_MEMBER_TEMPLATES
 #endif
 
-#ifndef GC_NOEXCEPT
-# if defined(__DMC__) || (defined(__BORLANDC__) \
-        && (defined(_RWSTD_NO_EXCEPTIONS) || defined(_RWSTD_NO_EX_SPEC))) \
-     || (defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) \
-     || (defined(__WATCOMC__) && !defined(_CPPUNWIND))
-#   define GC_NOEXCEPT /* empty */
-#   ifndef GC_NEW_ABORTS_ON_OOM
-#     define GC_NEW_ABORTS_ON_OOM
-#   endif
-# elif __cplusplus >= 201103L
-#   define GC_NOEXCEPT noexcept
-# else
-#   define GC_NOEXCEPT throw()
-# endif
-#endif // !GC_NOEXCEPT
-
 #if defined(GC_NEW_ABORTS_ON_OOM) || defined(_LIBCPP_NO_EXCEPTIONS)
 # define GC_ALLOCATOR_THROW_OR_ABORT() GC_abort_on_oom()
 #else

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

@@ -4,6 +4,7 @@
  * Copyright (c) 1998 by Fergus Henderson.  All rights reserved.
  * Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
  * All rights reserved.
+ * Copyright (c) 2008-2020 Ivan Maidanski
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -176,13 +177,22 @@
 
 #if defined(GC_DLL) && !defined(GC_API)
 
-# if defined(__MINGW32__) || defined(__CEGCC__)
-#   if defined(GC_BUILD) || defined(__MINGW32_DELAY_LOAD__)
+# if defined(__CEGCC__)
+#   if defined(GC_BUILD)
 #     define GC_API __declspec(dllexport)
 #   else
 #     define GC_API __declspec(dllimport)
 #   endif
 
+# elif defined(__MINGW32__)
+#   if defined(__cplusplus) && defined(GC_BUILD)
+#     define GC_API extern __declspec(dllexport)
+#   elif defined(GC_BUILD) || defined(__MINGW32_DELAY_LOAD__)
+#     define GC_API __declspec(dllexport)
+#   else
+#     define GC_API extern __declspec(dllimport)
+#   endif
+
 # elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \
         || defined(__CYGWIN__)
 #   ifdef GC_BUILD
@@ -276,6 +286,14 @@
 # endif
 #endif
 
+#ifndef GC_ATTR_CONST
+# if GC_GNUC_PREREQ(4, 0)
+#   define GC_ATTR_CONST __attribute__((__const__))
+# else
+#   define GC_ATTR_CONST /* empty */
+# endif
+#endif
+
 #ifndef GC_ATTR_DEPRECATED
 # ifdef GC_BUILD
 #   undef GC_ATTR_DEPRECATED
@@ -404,4 +422,33 @@
 
 #endif /* GC_PTHREADS */
 
+#ifdef __cplusplus
+
+#ifndef GC_ATTR_EXPLICIT
+# if __cplusplus >= 201103L && !defined(__clang__) || _MSVC_LANG >= 201103L \
+     || defined(CPPCHECK)
+#   define GC_ATTR_EXPLICIT explicit
+# else
+#   define GC_ATTR_EXPLICIT /* empty */
+# endif
+#endif
+
+#ifndef GC_NOEXCEPT
+# if defined(__DMC__) || (defined(__BORLANDC__) \
+        && (defined(_RWSTD_NO_EXCEPTIONS) || defined(_RWSTD_NO_EX_SPEC))) \
+     || (defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) \
+     || (defined(__WATCOMC__) && !defined(_CPPUNWIND))
+#   define GC_NOEXCEPT /* empty */
+#   ifndef GC_NEW_ABORTS_ON_OOM
+#     define GC_NEW_ABORTS_ON_OOM
+#   endif
+# elif __cplusplus >= 201103L || _MSVC_LANG >= 201103L
+#   define GC_NOEXCEPT noexcept
+# else
+#   define GC_NOEXCEPT throw()
+# endif
+#endif
+
+#endif /* __cplusplus */
+
 #endif

+ 26 - 25
blitz.mod/bdwgc/include/gc_cpp.h

@@ -135,7 +135,7 @@ uses explicit invocation.
 5. GC name conflicts:
 
 Many other systems seem to use the identifier "GC" as an abbreviation
-for "Graphics Context".  Since version 5.0, GC placement has been replaced
+for "Graphics Context".  Thus, GC placement has been replaced
 by UseGC.  GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined.
 
 ****************************************************************************/
@@ -173,22 +173,6 @@ by UseGC.  GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined.
 # define GC_PLACEMENT_DELETE
 #endif
 
-#ifndef GC_NOEXCEPT
-# if defined(__DMC__) || (defined(__BORLANDC__) \
-        && (defined(_RWSTD_NO_EXCEPTIONS) || defined(_RWSTD_NO_EX_SPEC))) \
-     || (defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) \
-     || (defined(__WATCOMC__) && !defined(_CPPUNWIND))
-#   define GC_NOEXCEPT /* empty */
-#   ifndef GC_NEW_ABORTS_ON_OOM
-#     define GC_NEW_ABORTS_ON_OOM
-#   endif
-# elif __cplusplus >= 201103L
-#   define GC_NOEXCEPT noexcept
-# else
-#   define GC_NOEXCEPT throw()
-# endif
-#endif // !GC_NOEXCEPT
-
 #if defined(GC_NEW_ABORTS_ON_OOM) || defined(_LIBCPP_NO_EXCEPTIONS)
 # define GC_OP_NEW_OOM_CHECK(obj) \
                 do { if (!(obj)) GC_abort_on_oom(); } while (0)
@@ -306,14 +290,13 @@ inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
                               void*) GC_NOEXCEPT;
 #endif
 
+#ifndef GC_NO_INLINE_STD_NEW
+
 #if defined(_MSC_VER) || defined(__DMC__) \
-    || ((defined(__CYGWIN32__) || defined(__CYGWIN__) \
-        || defined(__MINGW32__)) && !defined(GC_BUILD) && !defined(GC_NOT_DLL))
-  // The following ensures that the system default operator new[] does not
-  // get undefined, which is what seems to happen on VC++ 6 for some reason
-  // if we define a multi-argument operator new[].
-  // There seems to be no way to redirect new in this environment without
-  // including this everywhere.
+    || ((defined(__BORLANDC__) || defined(__CYGWIN__) \
+         || defined(__CYGWIN32__) || defined(__MINGW32__) \
+         || defined(__WATCOMC__)) \
+        && !defined(GC_BUILD) && !defined(GC_NOT_DLL))
   // Inlining done to avoid mix up of new and delete operators by VC++ 9 (due
   // to arbitrary ordering during linking).
 
@@ -343,7 +326,7 @@ inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
     GC_FREE(obj);
   }
 
-# if __cplusplus > 201103L // C++14
+# if __cplusplus >= 201402L || _MSVC_LANG >= 201402L // C++14
     inline void operator delete(void* obj, size_t size) GC_NOEXCEPT {
       (void)size; // size is ignored
       GC_FREE(obj);
@@ -390,6 +373,24 @@ inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
 
 #endif // _MSC_VER
 
+#elif defined(_MSC_VER)
+  // The following ensures that the system default operator new[] does not
+  // get undefined, which is what seems to happen on VC++ 6 for some reason
+  // if we define a multi-argument operator new[].
+  // There seems to be no way to redirect new in this environment without
+  // including this everywhere.
+# ifdef GC_OPERATOR_NEW_ARRAY
+    void *operator new[](size_t size);
+    void operator delete[](void* obj);
+# endif
+
+  void* operator new(size_t size);
+  void operator delete(void* obj);
+
+  void* operator new(size_t size, int /* nBlockUse */,
+                     const char * szFileName, int nLine);
+#endif // GC_NO_INLINE_STD_NEW && _MSC_VER
+
 #ifdef GC_OPERATOR_NEW_ARRAY
   // The operator new for arrays, identical to the above.
   inline void* operator new[](size_t size, GC_NS_QUALIFY(GCPlacement) gcp,

+ 3 - 4
blitz.mod/bdwgc/include/gc_inline.h

@@ -167,10 +167,9 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
 /* Allocate n words (NOT BYTES).  X is made to point to the result.     */
 /* This should really only be used if GC_all_interior_pointers is       */
 /* not set, or DONT_ADD_BYTE_AT_END is set.  See above.                 */
-/* The semantics changed in version 7.0; we no longer lock, and         */
-/* the caller is responsible for supplying a cleared tiny_fl            */
-/* free list array.  For single-threaded applications, this may be      */
-/* a global array.                                                      */
+/* Does not acquire lock.  The caller is responsible for supplying      */
+/* a cleared tiny_fl free list array.  For single-threaded              */
+/* applications, this may be a global array.                            */
 # define GC_MALLOC_WORDS_KIND(result,n,tiny_fl,kind,init) \
     do { \
       size_t granules = GC_WORDS_TO_WHOLE_GRANULES(n); \

+ 18 - 7
blitz.mod/bdwgc/include/gc_mark.h

@@ -57,7 +57,7 @@
 /* case correctly somehow.                                              */
 #define GC_PROC_BYTES 100
 
-#ifdef GC_BUILD
+#if defined(GC_BUILD) || defined(NOT_GCBUILD)
   struct GC_ms_entry;
 #else
   struct GC_ms_entry { void *opaque; };
@@ -152,12 +152,23 @@ GC_API struct GC_ms_entry * GC_CALL GC_mark_and_push(void * /* obj */,
            (GC_word)(obj) <= (GC_word)GC_greatest_plausible_heap_addr ? \
            GC_mark_and_push(obj, msp, lim, src) : (msp))
 
-GC_API size_t GC_debug_header_size;
-       /* The size of the header added to objects allocated through    */
-       /* the GC_debug routines.                                       */
-       /* Defined as a variable so that client mark procedures don't   */
-       /* need to be recompiled for collector version changes.         */
-#define GC_USR_PTR_FROM_BASE(p) ((void *)((char *)(p) + GC_debug_header_size))
+/* The size of the header added to objects allocated through the        */
+/* GC_debug routines.  Defined as a function so that client mark        */
+/* procedures do not need to be recompiled for the collector library    */
+/* version changes.                                                     */
+GC_API GC_ATTR_CONST size_t GC_CALL GC_get_debug_header_size(void);
+#define GC_USR_PTR_FROM_BASE(p) \
+                ((void *)((char *)(p) + GC_get_debug_header_size()))
+
+/* The same but defined as a variable.  Exists only for the backward    */
+/* compatibility.  Some compilers do not accept "const" together with   */
+/* deprecated or dllimport attributes, so the symbol is exported as     */
+/* a non-constant one.                                                  */
+GC_API GC_ATTR_DEPRECATED
+# ifdef GC_BUILD
+    const
+# endif
+  size_t GC_debug_header_size;
 
 /* And some routines to support creation of new "kinds", e.g. with      */
 /* custom mark procedures, by language runtimes.                        */

+ 5 - 0
blitz.mod/bdwgc/include/gc_pthread_redirects.h

@@ -18,6 +18,9 @@
 /* Our pthread support normally needs to intercept a number of thread   */
 /* calls.  We arrange to do that here, if appropriate.                  */
 
+#ifndef GC_PTHREAD_REDIRECTS_H
+#define GC_PTHREAD_REDIRECTS_H
+
 /* Included from gc.h only.  Included only if GC_PTHREADS.              */
 #if defined(GC_H) && defined(GC_PTHREADS)
 
@@ -117,3 +120,5 @@
 #endif /* !GC_NO_THREAD_REDIRECTS */
 
 #endif /* GC_PTHREADS */
+
+#endif /* GC_PTHREAD_REDIRECTS_H */

+ 3 - 2
blitz.mod/bdwgc/include/gc_typed.h

@@ -105,8 +105,9 @@ GC_API GC_ATTR_MALLOC GC_ATTR_CALLOC_SIZE(1, 2) void * GC_CALL
         /* Returned object is cleared.                          */
 
 #ifdef GC_DEBUG
-# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) GC_MALLOC(bytes)
-# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) GC_MALLOC((n) * (bytes))
+# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) ((void)(d), GC_MALLOC(bytes))
+# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) \
+                        ((void)(d), GC_MALLOC((n) * (bytes)))
 #else
 # define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) \
                         GC_malloc_explicitly_typed(bytes, d)

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

@@ -29,8 +29,8 @@
 /* Eventually this one may become unnecessary.  For now we need */
 /* it to keep the old-style build process working.              */
 #define GC_TMP_VERSION_MAJOR 8
-#define GC_TMP_VERSION_MINOR 0
-#define GC_TMP_VERSION_MICRO 4 /* 8.0.4 */
+#define GC_TMP_VERSION_MINOR 1
+#define GC_TMP_VERSION_MICRO 0 /* 8.1.0 */
 
 #ifdef GC_VERSION_MAJOR
 # if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR \

+ 2 - 8
blitz.mod/bdwgc/include/private/gc_locks.h

@@ -61,13 +61,6 @@
 #  endif
 
 #  if defined(GC_WIN32_THREADS) && !defined(USE_PTHREAD_LOCKS)
-#    ifndef WIN32_LEAN_AND_MEAN
-#      define WIN32_LEAN_AND_MEAN 1
-#    endif
-#    define NOSERVICE
-     EXTERN_C_END
-#    include <windows.h>
-     EXTERN_C_BEGIN
 #    define NO_THREAD (DWORD)(-1)
      GC_EXTERN CRITICAL_SECTION GC_allocate_ml;
 #    ifdef GC_ASSERTIONS
@@ -183,6 +176,7 @@
        EXTERN_C_BEGIN
        GC_EXTERN pthread_mutex_t GC_allocate_ml;
 #      ifdef GC_ASSERTIONS
+         GC_INNER void GC_lock(void);
 #        define UNCOND_LOCK() { GC_ASSERT(I_DONT_HOLD_LOCK()); \
                                 GC_lock(); SET_LOCK_HOLDER(); }
 #        define UNCOND_UNLOCK() \
@@ -192,6 +186,7 @@
 #        if defined(NO_PTHREAD_TRYLOCK)
 #          define UNCOND_LOCK() pthread_mutex_lock(&GC_allocate_ml)
 #        else
+           GC_INNER void GC_lock(void);
 #          define UNCOND_LOCK() \
               { if (0 != pthread_mutex_trylock(&GC_allocate_ml)) \
                   GC_lock(); }
@@ -225,7 +220,6 @@
 #        define EXIT_GC() (void)(GC_collecting = FALSE)
 #      endif
 #    endif
-     GC_INNER void GC_lock(void);
 #  endif /* GC_PTHREADS */
 #  if defined(GC_ALWAYS_MULTITHREADED) \
       && (defined(USE_PTHREAD_LOCKS) || defined(USE_SPIN_LOCK))

+ 9 - 19
blitz.mod/bdwgc/include/private/gc_pmark.h

@@ -74,8 +74,6 @@ GC_EXTERN unsigned GC_n_mark_procs;
 /* Number of mark stack entries to discard on overflow. */
 #define GC_MARK_STACK_DISCARDS (INITIAL_MARK_STACK_SIZE/8)
 
-GC_EXTERN size_t GC_mark_stack_size;
-
 #ifdef PARALLEL_MARK
     /*
      * Allow multiple threads to participate in the marking process.
@@ -442,14 +440,6 @@ GC_INNER mse * GC_mark_from(mse * top, mse * bottom, mse *limit);
     } \
   } while (0)
 
-GC_EXTERN GC_bool GC_mark_stack_too_small;
-                                /* We need a larger mark stack.  May be */
-                                /* set by client supplied mark routines.*/
-
-typedef int mark_state_t;       /* Current state of marking, as follows:*/
-                                /* Used to remember where we are during */
-                                /* concurrent marking.                  */
-
                                 /* We say something is dirty if it was  */
                                 /* written since the last time we       */
                                 /* retrieved dirty bits.  We say it's   */
@@ -469,24 +459,24 @@ typedef int mark_state_t;       /* Current state of marking, as follows:*/
                                 /* being pushed.  "I" holds, except     */
                                 /* that grungy roots may point to       */
                                 /* unmarked objects, as may marked      */
-                                /* grungy objects above scan_ptr.       */
+                                /* grungy objects above GC_scan_ptr.    */
 
 #define MS_PUSH_UNCOLLECTABLE 2 /* "I" holds, except that marked        */
-                                /* uncollectible objects above scan_ptr */
-                                /* may point to unmarked objects.       */
-                                /* Roots may point to unmarked objects  */
+                                /* uncollectible objects above          */
+                                /* GC_scan_ptr may point to unmarked    */
+                                /* objects.  Roots may point to         */
+                                /* unmarked objects.                    */
 
 #define MS_ROOTS_PUSHED 3       /* "I" holds, mark stack may be nonempty. */
 
 #define MS_PARTIALLY_INVALID 4  /* "I" may not hold, e.g. because of    */
-                                /* the mark stack overflow.  However    */
-                                /* marked heap objects below scan_ptr   */
-                                /* point to marked or stacked objects.  */
+                                /* the mark stack overflow.  However,   */
+                                /* marked heap objects below            */
+                                /* GC_scan_ptr point to marked or       */
+                                /* stacked objects.                     */
 
 #define MS_INVALID 5            /* "I" may not hold.                    */
 
-GC_EXTERN mark_state_t GC_mark_state;
-
 EXTERN_C_END
 
 #endif  /* GC_PMARK_H */

+ 278 - 82
blitz.mod/bdwgc/include/private/gc_priv.h

@@ -3,7 +3,7 @@
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
  * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
- *
+ * Copyright (c) 2008-2020 Ivan Maidanski
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -22,11 +22,12 @@
 # include "config.h"
 #endif
 
-#ifndef GC_BUILD
+#if !defined(GC_BUILD) && !defined(NOT_GCBUILD)
 # define GC_BUILD
 #endif
 
-#if (defined(__linux__) || defined(__GLIBC__) || defined(__GNU__)) \
+#if (defined(__linux__) || defined(__GLIBC__) || defined(__GNU__) \
+     || (defined(__CYGWIN__) && (defined(GC_THREADS) || !defined(USE_MMAP)))) \
     && !defined(_GNU_SOURCE)
   /* Can't test LINUX, since this must be defined before other includes. */
 # define _GNU_SOURCE 1
@@ -166,6 +167,22 @@ typedef int GC_bool;
 # define REGISTER register
 #endif
 
+#if defined(CPPCHECK)
+# define MACRO_BLKSTMT_BEGIN {
+# define MACRO_BLKSTMT_END   }
+#else
+# define MACRO_BLKSTMT_BEGIN do {
+# define MACRO_BLKSTMT_END   } while (0)
+#endif
+
+#if defined(M68K) && defined(__GNUC__)
+  /* By default, __alignof__(word) is 2 on m68k.  Use this attribute to */
+  /* have proper word alignment (i.e. 4-byte on a 32-bit arch).         */
+# define GC_ATTR_WORD_ALIGNED __attribute__((__aligned__(sizeof(word))))
+#else
+# define GC_ATTR_WORD_ALIGNED /* empty */
+#endif
+
 #ifndef HEADERS_H
 # include "gc_hdrs.h"
 #endif
@@ -250,14 +267,22 @@ typedef int GC_bool;
 # define GC_API_PRIV GC_API
 #endif
 
-#if defined(THREADS) && !defined(NN_PLATFORM_CTR) \
-    && !defined(SN_TARGET_ORBIS) && !defined(SN_TARGET_PSP2)
+#if defined(THREADS) && !defined(NN_PLATFORM_CTR)
 # include "gc_atomic_ops.h"
 # ifndef AO_HAVE_compiler_barrier
 #   define AO_HAVE_compiler_barrier 1
 # endif
 #endif
 
+#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
+# ifndef WIN32_LEAN_AND_MEAN
+#   define WIN32_LEAN_AND_MEAN 1
+# endif
+# define NOSERVICE
+# include <windows.h>
+# include <winbase.h>
+#endif
+
 #include "gc_locks.h"
 
 #define GC_WORD_MAX (~(word)0)
@@ -314,7 +339,7 @@ typedef int GC_bool;
                     /*    by integers, etc.  Under SunOS 4.X with a     */
                     /*    statically linked libc, we empirically        */
                     /*    observed that it would be difficult to        */
-                    /*    allocate individual objects larger than 100K. */
+                    /*    allocate individual objects > 100 KB.         */
                     /*    Even if only smaller objects are allocated,   */
                     /*    more swap space is likely to be needed.       */
                     /*    Fortunately, much of this will never be       */
@@ -437,23 +462,39 @@ EXTERN_C_END
                   x = rusage.ru_utime; \
                 } while (0)
 # define MS_TIME_DIFF(a,b) ((unsigned long)((long)(a.tv_sec-b.tv_sec) * 1000 \
-                                    + (long)(a.tv_usec-b.tv_usec) / 1000))
+                + (long)(a.tv_usec - b.tv_usec) / 1000 \
+                - (a.tv_usec < b.tv_usec \
+                   && (long)(a.tv_usec - b.tv_usec) % 1000 != 0 ? 1 : 0)))
                             /* "a" time is expected to be not earlier than  */
                             /* "b" one; the result has unsigned long type.  */
-#elif defined(MSWIN32) || defined(MSWINCE)
-# ifndef WIN32_LEAN_AND_MEAN
-#   define WIN32_LEAN_AND_MEAN 1
-# endif
-# define NOSERVICE
-# include <windows.h>
-# include <winbase.h>
-# define CLOCK_TYPE DWORD
-# ifdef MSWINRT_FLAVOR
-#   define GET_TIME(x) (void)(x = (DWORD)GetTickCount64())
+# define NS_FRAC_TIME_DIFF(a, b) ((unsigned long) \
+                ((a.tv_usec < b.tv_usec \
+                  && (long)(a.tv_usec - b.tv_usec) % 1000 != 0 ? 1000L : 0) \
+                 + (long)(a.tv_usec - b.tv_usec) % 1000) * 1000)
+                        /* The total time difference could be computed as   */
+                        /* MS_TIME_DIFF(a,b)*1000000+NS_FRAC_TIME_DIFF(a,b).*/
+
+#elif defined(MSWIN32) || defined(MSWINCE) || defined(WINXP_USE_PERF_COUNTER)
+# if defined(MSWINRT_FLAVOR) || defined(WINXP_USE_PERF_COUNTER)
+#   define CLOCK_TYPE ULONGLONG
+#   define GET_TIME(x) \
+                do { \
+                  LARGE_INTEGER freq, tc; \
+                  if (!QueryPerformanceFrequency(&freq) \
+                      || !QueryPerformanceCounter(&tc)) \
+                    ABORT("QueryPerformanceCounter requires WinXP+"); \
+                  x = (CLOCK_TYPE)((double)tc.QuadPart/freq.QuadPart * 1e9); \
+                } while (0)
+                /* TODO: Call QueryPerformanceFrequency once at GC init. */
+#   define MS_TIME_DIFF(a, b) ((unsigned long)(((a) - (b)) / 1000000UL))
+#   define NS_FRAC_TIME_DIFF(a, b) ((unsigned long)(((a) - (b)) % 1000000UL))
 # else
+#   define CLOCK_TYPE DWORD
 #   define GET_TIME(x) (void)(x = GetTickCount())
-# endif
-# define MS_TIME_DIFF(a,b) ((unsigned long)((a)-(b)))
+#   define MS_TIME_DIFF(a, b) ((unsigned long)((a) - (b)))
+#   define NS_FRAC_TIME_DIFF(a, b) 0UL
+# endif /* !WINXP_USE_PERF_COUNTER */
+
 #elif defined(NN_PLATFORM_CTR)
 # define CLOCK_TYPE long long
   EXTERN_C_BEGIN
@@ -462,7 +503,35 @@ EXTERN_C_END
   EXTERN_C_END
 # define GET_TIME(x) (void)(x = n3ds_get_system_tick())
 # define MS_TIME_DIFF(a,b) ((unsigned long)n3ds_convert_tick_to_ms((a)-(b)))
-#else /* !BSD_TIME && !NN_PLATFORM_CTR && !MSWIN32 && !MSWINCE */
+# define NS_FRAC_TIME_DIFF(a, b) 0UL /* TODO: implement it */
+
+#elif defined(NINTENDO_SWITCH) \
+      || (((defined(LINUX) && defined(__USE_POSIX199309)) \
+           || defined(CYGWIN32)) && defined(_POSIX_TIMERS))
+# include <time.h>
+# define CLOCK_TYPE struct timespec
+# define CLOCK_TYPE_INITIALIZER { 0, 0 }
+# if defined(_POSIX_MONOTONIC_CLOCK) && !defined(NINTENDO_SWITCH)
+#   define GET_TIME(x) \
+                do { \
+                  if (clock_gettime(CLOCK_MONOTONIC, &x) == -1) \
+                    ABORT("clock_gettime failed"); \
+                } while (0)
+# else
+#   define GET_TIME(x) \
+                do { \
+                  if (clock_gettime(CLOCK_REALTIME, &x) == -1) \
+                    ABORT("clock_gettime failed"); \
+                } while (0)
+# endif
+# define MS_TIME_DIFF(a, b) \
+    /* a.tv_nsec - b.tv_nsec is in range -1e9 to 1e9 exclusively */ \
+    ((unsigned long)((a).tv_nsec + (1000000L*1000 - (b).tv_nsec)) / 1000000UL \
+     + ((unsigned long)((a).tv_sec - (b).tv_sec) * 1000UL) - 1000UL)
+# define NS_FRAC_TIME_DIFF(a, b) \
+    ((unsigned long)((a).tv_nsec + (1000000L*1000 - (b).tv_nsec)) % 1000000UL)
+
+#else /* !BSD_TIME && !NINTENDO_SWITCH && !NN_PLATFORM_CTR && !MSWIN32 */
 # include <time.h>
 # if defined(FREEBSD) && !defined(CLOCKS_PER_SEC)
 #   include <machine/limits.h>
@@ -487,6 +556,13 @@ EXTERN_C_END
         : ((unsigned long)((a) - (b)) * 1000) / (unsigned long)CLOCKS_PER_SEC)
   /* Avoid using double type since some targets (like ARM) might        */
   /* require -lm option for double-to-long conversion.                  */
+# define NS_FRAC_TIME_DIFF(a, b) (CLOCKS_PER_SEC <= 1000 ? 0UL \
+    : (unsigned long)(CLOCKS_PER_SEC <= (clock_t)1000000UL \
+        ? (((a) - (b)) * ((clock_t)1000000UL / CLOCKS_PER_SEC) % 1000) * 1000 \
+        : (CLOCKS_PER_SEC <= (clock_t)1000000UL * 1000 \
+            ? ((a) - (b)) * ((clock_t)1000000UL * 1000 / CLOCKS_PER_SEC) \
+            : (((a) - (b)) * (clock_t)1000000UL * 1000) / CLOCKS_PER_SEC) \
+          % (clock_t)1000000UL))
 #endif /* !BSD_TIME && !MSWIN32 */
 # ifndef CLOCK_TYPE_INITIALIZER
     /* This is used to initialize CLOCK_TYPE variables (to some value)  */
@@ -601,21 +677,21 @@ EXTERN_C_BEGIN
 /* literals.  C_msg should not contain format specifiers.  Arguments    */
 /* should match their format specifiers.                                */
 #define ABORT_ARG1(C_msg, C_fmt, arg1) \
-                do { \
+                MACRO_BLKSTMT_BEGIN \
                   GC_INFOLOG_PRINTF(C_msg /* + */ C_fmt "\n", arg1); \
                   ABORT(C_msg); \
-                } while (0)
+                MACRO_BLKSTMT_END
 #define ABORT_ARG2(C_msg, C_fmt, arg1, arg2) \
-                do { \
+                MACRO_BLKSTMT_BEGIN \
                   GC_INFOLOG_PRINTF(C_msg /* + */ C_fmt "\n", arg1, arg2); \
                   ABORT(C_msg); \
-                } while (0)
+                MACRO_BLKSTMT_END
 #define ABORT_ARG3(C_msg, C_fmt, arg1, arg2, arg3) \
-                do { \
+                MACRO_BLKSTMT_BEGIN \
                   GC_INFOLOG_PRINTF(C_msg /* + */ C_fmt "\n", \
                                     arg1, arg2, arg3); \
                   ABORT(C_msg); \
-                } while (0)
+                MACRO_BLKSTMT_END
 
 /* Same as ABORT but does not have 'no-return' attribute.       */
 /* ABORT on a dummy condition (which is always true).           */
@@ -836,16 +912,16 @@ EXTERN_C_BEGIN
 /* Heap block size, bytes. Should be power of 2.                */
 /* Incremental GC with MPROTECT_VDB currently requires the      */
 /* page size to be a multiple of HBLKSIZE.  Since most modern   */
-/* architectures support variable page sizes down to 4K, and    */
-/* X86 is generally 4K, we now default to 4K, except for        */
-/*   Alpha: Seems to be used with 8K pages.                     */
+/* architectures support variable page sizes down to 4 KB, and  */
+/* X86 is generally 4 KB, we now default to 4 KB, except for    */
+/*   Alpha: Seems to be used with 8 KB pages.                   */
 /*   SMALL_CONFIG: Want less block-level fragmentation.         */
 #ifndef HBLKSIZE
 # if defined(LARGE_CONFIG) || !defined(SMALL_CONFIG)
 #   ifdef ALPHA
 #     define CPP_LOG_HBLKSIZE 13
 #   elif defined(SN_TARGET_ORBIS) || defined(SN_TARGET_PSP2)
-#     define CPP_LOG_HBLKSIZE 16    /* page size is set to 64K  */
+#     define CPP_LOG_HBLKSIZE 16    /* page size is set to 64 KB */
 #   else
 #     define CPP_LOG_HBLKSIZE 12
 #   endif
@@ -934,27 +1010,27 @@ EXTERN_C_BEGIN
 # ifdef LARGE_CONFIG
 #   if CPP_WORDSZ == 32
 #     define LOG_PHT_ENTRIES 20 /* Collisions likely at 1M blocks,      */
-                                /* which is >= 4GB.  Each table takes   */
-                                /* 128KB, some of which may never be    */
+                                /* which is >= 4 GB.  Each table takes  */
+                                /* 128 KB, some of which may never be   */
                                 /* touched.                             */
 #   else
 #     define LOG_PHT_ENTRIES 21 /* Collisions likely at 2M blocks,      */
-                                /* which is >= 8GB.  Each table takes   */
-                                /* 256KB, some of which may never be    */
+                                /* which is >= 8 GB.  Each table takes  */
+                                /* 256 KB, some of which may never be   */
                                 /* touched.                             */
 #   endif
 # elif !defined(SMALL_CONFIG)
 #   define LOG_PHT_ENTRIES  18   /* Collisions are likely if heap grows */
-                                 /* to more than 256K hblks >= 1GB.     */
-                                 /* Each hash table occupies 32K bytes. */
+                                 /* to more than 256K hblks >= 1 GB.    */
+                                 /* Each hash table occupies 32 KB.     */
                                  /* Even for somewhat smaller heaps,    */
                                  /* say half that, collisions may be an */
                                  /* issue because we blacklist          */
                                  /* addresses outside the heap.         */
 # else
 #   define LOG_PHT_ENTRIES  15   /* Collisions are likely if heap grows */
-                                 /* to more than 32K hblks = 128MB.     */
-                                 /* Each hash table occupies 4K bytes.  */
+                                 /* to more than 32K hblks (128 MB).    */
+                                 /* Each hash table occupies 4 KB.      */
 # endif
 # define PHT_ENTRIES ((word)1 << LOG_PHT_ENTRIES)
 # define PHT_SIZE (PHT_ENTRIES >> LOGWL)
@@ -1200,12 +1276,12 @@ struct roots {
 #   if defined(PARALLEL_MARK) && (defined(MSWIN32) || defined(CYGWIN32))
 #     define MAX_HEAP_SECTS 384
 #   else
-#     define MAX_HEAP_SECTS 128         /* Roughly 256MB (128*2048*1K)  */
+#     define MAX_HEAP_SECTS 128         /* Roughly 256 MB (128*2048*1024) */
 #   endif
 # elif CPP_WORDSZ > 32
-#   define MAX_HEAP_SECTS 1024          /* Roughly 8GB                  */
+#   define MAX_HEAP_SECTS 1024          /* Roughly 8 GB */
 # else
-#   define MAX_HEAP_SECTS 512           /* Roughly 4GB                  */
+#   define MAX_HEAP_SECTS 512           /* Roughly 4 GB */
 # endif
 #endif /* !MAX_HEAP_SECTS */
 
@@ -1216,6 +1292,39 @@ typedef struct GC_ms_entry {
                         /* as described in gc_mark.h.                   */
 } mse;
 
+typedef int mark_state_t;   /* Current state of marking, as follows:    */
+                            /* Used to remember where we are during     */
+                            /* concurrent marking.                      */
+
+struct disappearing_link;
+struct finalizable_object;
+
+struct dl_hashtbl_s {
+    struct disappearing_link **head;
+    word entries;
+    unsigned log_size;
+};
+
+struct fnlz_roots_s {
+  struct finalizable_object **fo_head;
+  /* List of objects that should be finalized now: */
+  struct finalizable_object *finalize_now;
+};
+
+union toggle_ref_u {
+  /* The lowest bit is used to distinguish between choices.     */
+  void *strong_ref;
+  GC_hidden_pointer weak_ref;
+};
+
+/* Extended descriptors.  GC_typed_mark_proc understands these. */
+/* These are used for simple objects that are larger than what  */
+/* can be described by a BITMAP_BITS sized bitmap.              */
+typedef struct {
+    word ed_bitmap;     /* lsb corresponds to first word.       */
+    GC_bool ed_continued;       /* next entry is continuation.  */
+} typed_ext_descr_t;
+
 /* Lists of all heap blocks and free lists      */
 /* as well as other random data structures      */
 /* that should not be scanned by the            */
@@ -1231,8 +1340,8 @@ typedef struct GC_ms_entry {
 /* be pointers are also put here.               */
 /* The main fields should precede any           */
 /* conditionally included fields, so that       */
-/* gc_inl.h will work even if a different set   */
-/* of macros is defined when the client is      */
+/* gc_inline.h will work even if a different    */
+/* set of macros is defined when the client is  */
 /* compiled.                                    */
 
 struct _GC_arrays {
@@ -1276,8 +1385,19 @@ struct _GC_arrays {
         /* Bytes of memory explicitly deallocated while         */
         /* finalizers were running.  Used to approximate memory */
         /* explicitly deallocated by finalizers.                */
+  bottom_index *_all_bottom_indices;
+        /* Pointer to the first (lowest address) bottom_index;  */
+        /* assumes the lock is held.                            */
+  bottom_index *_all_bottom_indices_end;
+        /* Pointer to the last (highest address) bottom_index;  */
+        /* assumes the lock is held.                            */
+  ptr_t _scratch_free_ptr;
+  hdr *_hdr_free_list;
   ptr_t _scratch_end_ptr;
+        /* GC_scratch_end_ptr is end point of the current scratch area. */
   ptr_t _scratch_last_end_ptr;
+        /* GC_scratch_last_end_ptr is the end point of the last */
+        /* obtained scratch area.                               */
         /* Used by headers.c, and can easily appear to point to */
         /* heap.  Also used by GC_register_dynamic_libraries(). */
   mse *_mark_stack;
@@ -1303,10 +1423,97 @@ struct _GC_arrays {
 #   define GC_unmapped_bytes 0
 # endif
   bottom_index * _all_nils;
+# define GC_scan_ptr GC_arrays._scan_ptr
+  struct hblk * _scan_ptr;
+# ifdef PARALLEL_MARK
+#   define GC_main_local_mark_stack GC_arrays._main_local_mark_stack
+    mse *_main_local_mark_stack;
+#   define GC_first_nonempty GC_arrays._first_nonempty
+    volatile AO_t _first_nonempty;
+                        /* Lowest entry on mark stack that may be       */
+                        /* nonempty. Updated only by initiating thread. */
+# endif
+# define GC_mark_stack_size GC_arrays._mark_stack_size
+  size_t _mark_stack_size;
+# define GC_mark_state GC_arrays._mark_state
+  mark_state_t _mark_state; /* Initialized to MS_NONE (0). */
+# define GC_mark_stack_too_small GC_arrays._mark_stack_too_small
+  GC_bool _mark_stack_too_small;
+                        /* We need a larger mark stack.  May be set by  */
+                        /* client supplied mark routines.               */
+# define GC_objects_are_marked GC_arrays._objects_are_marked
+  GC_bool _objects_are_marked;
+                /* Are there collectible marked objects in the heap?    */
 # ifdef ENABLE_TRACE
 #   define GC_trace_addr GC_arrays._trace_addr
     ptr_t _trace_addr;
 # endif
+# define GC_n_heap_sects GC_arrays._n_heap_sects
+  word _n_heap_sects;   /* Number of separately added heap sections.    */
+# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
+#   define GC_n_heap_bases GC_arrays._n_heap_bases
+    word _n_heap_bases; /* See GC_heap_bases.   */
+# endif
+# ifdef USE_PROC_FOR_LIBRARIES
+#   define GC_n_memory GC_arrays._n_memory
+    word _n_memory;     /* Number of GET_MEM allocated memory sections. */
+# endif
+# ifdef GC_GCJ_SUPPORT
+#   define GC_gcjobjfreelist GC_arrays._gcjobjfreelist
+    ptr_t *_gcjobjfreelist;
+# endif
+# define GC_fo_entries GC_arrays._fo_entries
+  word _fo_entries;
+# ifndef GC_NO_FINALIZATION
+#   define GC_dl_hashtbl GC_arrays._dl_hashtbl
+#   define GC_fnlz_roots GC_arrays._fnlz_roots
+#   define GC_log_fo_table_size GC_arrays._log_fo_table_size
+#   ifndef GC_LONG_REFS_NOT_NEEDED
+#     define GC_ll_hashtbl GC_arrays._ll_hashtbl
+      struct dl_hashtbl_s _ll_hashtbl;
+#   endif
+    struct dl_hashtbl_s _dl_hashtbl;
+    struct fnlz_roots_s _fnlz_roots;
+    unsigned _log_fo_table_size;
+#   ifndef GC_TOGGLE_REFS_NOT_NEEDED
+#     define GC_toggleref_arr GC_arrays._toggleref_arr
+#     define GC_toggleref_array_size GC_arrays._toggleref_array_size
+#     define GC_toggleref_array_capacity GC_arrays._toggleref_array_capacity
+      union toggle_ref_u *_toggleref_arr;
+      size_t _toggleref_array_size;
+      size_t _toggleref_array_capacity;
+#   endif
+# endif
+# ifdef TRACE_BUF
+#   define GC_trace_buf_ptr GC_arrays._trace_buf_ptr
+    int _trace_buf_ptr;
+# endif
+# ifdef ENABLE_DISCLAIM
+#   define GC_finalized_kind GC_arrays._finalized_kind
+    int _finalized_kind;
+# endif
+# define n_root_sets GC_arrays._n_root_sets
+# define GC_excl_table_entries GC_arrays._excl_table_entries
+  int _n_root_sets;     /* GC_static_roots[0..n_root_sets) contains the */
+                        /* valid root sets.                             */
+  size_t _excl_table_entries;   /* Number of entries in use.    */
+# ifdef THREADS
+#   define GC_roots_were_cleared GC_arrays._roots_were_cleared
+    GC_bool _roots_were_cleared;
+# endif
+# define GC_explicit_typing_initialized GC_arrays._explicit_typing_initialized
+# define GC_ed_size GC_arrays._ed_size
+# define GC_avail_descr GC_arrays._avail_descr
+# define GC_ext_descriptors GC_arrays._ext_descriptors
+# ifdef AO_HAVE_load_acquire
+    volatile AO_t _explicit_typing_initialized;
+# else
+    GC_bool _explicit_typing_initialized;
+# endif
+  size_t _ed_size;      /* Current size of above arrays.        */
+  size_t _avail_descr;  /* Next available slot.                 */
+  typed_ext_descr_t *_ext_descriptors;  /* Points to array of extended  */
+                                        /* descriptors.                 */
   GC_mark_proc _mark_procs[MAX_MARK_PROCS];
         /* Table of user-defined mark procedures.  There is     */
         /* a small number of these, which can be referenced     */
@@ -1431,6 +1638,10 @@ GC_API_PRIV GC_FAR struct _GC_arrays GC_arrays;
 #define GC_modws_valid_offsets GC_arrays._modws_valid_offsets
 #define GC_prev_heap_addr GC_arrays._prev_heap_addr
 #define GC_requested_heapsize GC_arrays._requested_heapsize
+#define GC_all_bottom_indices GC_arrays._all_bottom_indices
+#define GC_all_bottom_indices_end GC_arrays._all_bottom_indices_end
+#define GC_scratch_free_ptr GC_arrays._scratch_free_ptr
+#define GC_hdr_free_list GC_arrays._hdr_free_list
 #define GC_scratch_end_ptr GC_arrays._scratch_end_ptr
 #define GC_scratch_last_end_ptr GC_arrays._scratch_last_end_ptr
 #define GC_size_map GC_arrays._size_map
@@ -1515,14 +1726,6 @@ GC_EXTERN struct obj_kind {
 
 GC_EXTERN unsigned GC_n_kinds;
 
-GC_EXTERN word GC_n_heap_sects; /* Number of separately added heap      */
-                                /* sections.                            */
-
-#ifdef USE_PROC_FOR_LIBRARIES
-  GC_EXTERN word GC_n_memory;   /* Number of GET_MEM allocated memory   */
-                                /* sections.                            */
-#endif
-
 GC_EXTERN size_t GC_page_size;
 
 /* Round up allocation size to a multiple of a page size.       */
@@ -1538,8 +1741,7 @@ GC_EXTERN size_t GC_page_size;
 #endif
 
 #if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
-  struct _SYSTEM_INFO;
-  GC_EXTERN struct _SYSTEM_INFO GC_sysinfo;
+  GC_EXTERN SYSTEM_INFO GC_sysinfo;
   GC_INNER GC_bool GC_is_heap_base(void *p);
 #endif
 
@@ -1739,11 +1941,9 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
   /* pointer to the top of the corresponding memory stack.              */
   ptr_t GC_save_regs_in_stack(void);
 #endif
-                        /* Push register contents onto mark stack.      */
 
-#if defined(MSWIN32) || defined(MSWINCE)
-  void __cdecl GC_push_one(word p);
-#else
+                        /* Push register contents onto mark stack.      */
+#if defined(AMIGA) || defined(MACOS) || defined(GC_DARWIN_THREADS)
   void GC_push_one(word p);
                               /* If p points to an object, mark it    */
                               /* and push contents on the mark stack  */
@@ -1753,6 +1953,11 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
                               /* stack.                               */
 #endif
 
+#ifdef GC_WIN32_THREADS
+  /* Same as GC_push_one but for a sequence of registers.       */
+  GC_INNER void GC_push_many_regs(const word *regs, unsigned count);
+#endif
+
 #if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS)
   GC_INNER void GC_mark_and_push_stack(ptr_t p, ptr_t source);
                                 /* Ditto, omits plausibility test       */
@@ -1861,10 +2066,13 @@ GC_INNER void GC_scratch_recycle_inner(void *ptr, size_t bytes);
                                 /* Reuse the memory region by the heap. */
 
 /* Heap block layout maps: */
-GC_INNER GC_bool GC_add_map_entry(size_t sz);
+#ifdef MARK_BIT_PER_GRANULE
+  GC_INNER GC_bool GC_add_map_entry(size_t sz);
                                 /* Add a heap block map for objects of  */
                                 /* size sz to obj_map.                  */
                                 /* Return FALSE on failure.             */
+#endif
+
 GC_INNER void GC_register_displacement_inner(size_t offset);
                                 /* Version of GC_register_displacement  */
                                 /* that assumes lock is already held.   */
@@ -1903,7 +2111,7 @@ GC_INNER void GC_freehblk(struct hblk * p);
                                 /* Deallocate a heap block and mark it  */
                                 /* as invalid.                          */
 
-/*  Misc GC: */
+/*  Miscellaneous GC routines.  */
 GC_INNER GC_bool GC_expand_hp_inner(word n);
 GC_INNER void GC_start_reclaim(GC_bool abort_if_found);
                                 /* Restore unmarked objects to free     */
@@ -2208,8 +2416,6 @@ void GC_print_hblkfreelist(void);
 void GC_print_heap_sects(void);
 void GC_print_static_roots(void);
 
-extern word GC_fo_entries; /* should be visible in extra/MacOS.c */
-
 #ifdef KEEP_BACK_PTRS
    GC_INNER void GC_store_back_pointer(ptr_t source, ptr_t dest);
    GC_INNER void GC_marked_for_finalization(ptr_t dest);
@@ -2241,7 +2447,7 @@ GC_API void GC_CALL GC_noop1(word);
 GC_API_PRIV void GC_printf(const char * format, ...)
                         GC_ATTR_FORMAT_PRINTF(1, 2);
                         /* A version of printf that doesn't allocate,   */
-                        /* 1K total output length.                      */
+                        /* 1 KB total output length.                    */
                         /* (We use sprintf.  Hopefully that doesn't     */
                         /* allocate for long arguments.)                */
 GC_API_PRIV void GC_err_printf(const char * format, ...)
@@ -2315,15 +2521,15 @@ GC_EXTERN signed_word GC_bytes_found;
 #endif
 
 #ifdef THREADS
-# if defined(MSWIN32) || defined(MSWINCE) || defined(MSWIN_XBOX1)
+# if (defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE)
     GC_EXTERN CRITICAL_SECTION GC_write_cs; /* defined in misc.c */
-# endif
-# if defined(GC_ASSERTIONS) && (defined(MSWIN32) || defined(MSWINCE))
-    GC_EXTERN GC_bool GC_write_disabled;
+#   ifdef GC_ASSERTIONS
+      GC_EXTERN GC_bool GC_write_disabled;
                                 /* defined in win32_threads.c;  */
                                 /* protected by GC_write_cs.    */
 
-# endif
+#   endif
+# endif /* MSWIN32 || MSWINCE */
 # if defined(GC_DISABLE_INCREMENTAL) || defined(HAVE_LOCKFREE_AO_OR)
 #   define GC_acquire_dirty_lock() (void)0
 #   define GC_release_dirty_lock() (void)0
@@ -2352,24 +2558,11 @@ GC_EXTERN signed_word GC_bytes_found;
   GC_INNER void GC_mark_thread_local_free_lists(void);
 #endif
 
-#ifdef GC_GCJ_SUPPORT
-# ifdef GC_ASSERTIONS
-    GC_EXTERN GC_bool GC_gcj_malloc_initialized; /* defined in gcj_mlc.c */
-# endif
-  GC_EXTERN ptr_t * GC_gcjobjfreelist;
-#endif
-
-#ifdef MPROTECT_VDB
-# ifdef GWW_VDB
+#if defined(MPROTECT_VDB) && defined(GWW_VDB)
     GC_INNER GC_bool GC_gww_dirty_init(void);
                         /* Returns TRUE if GetWriteWatch is available.  */
                         /* May be called repeatedly.                    */
-# endif
-# ifdef USE_MUNMAP
-    GC_INNER GC_bool GC_mprotect_dirty_init(void);
-    GC_INNER GC_bool GC_has_unmapped_memory(void);
-# endif
-#endif /* MPROTECT_VDB */
+#endif
 
 #if defined(CHECKSUMS) || defined(PROC_VDB)
   GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk * h);
@@ -2548,6 +2741,9 @@ GC_INNER void *GC_store_debug_info_inner(void *p, word sz, const char *str,
                         /* Number of mark threads we would like to have */
                         /* excluding the initiating thread.             */
 
+  GC_EXTERN GC_bool GC_parallel_mark_disabled;
+                        /* A flag to temporarily avoid parallel marking.*/
+
   /* The mark lock and condition variable.  If the GC lock is also      */
   /* acquired, the GC lock must be acquired first.  The mark lock is    */
   /* used to both protect some variables used by the parallel           */

+ 267 - 191
blitz.mod/bdwgc/include/private/gcconfig.h

@@ -109,19 +109,6 @@ EXTERN_C_BEGIN
 #   define LINUX
 # endif
 
-/* And one for QNX: */
-# if defined(__QNX__)
-#    define I386
-#    define OS_TYPE "QNX"
-#    define SA_RESTART 0
-#    define HEURISTIC1
-     extern char etext[];
-     extern int _end[];
-#    define DATASTART ((ptr_t)(etext))
-#    define DATAEND ((ptr_t)(_end))
-#    define mach_type_known
-# endif
-
 /* And one for NetBSD: */
 # if defined(__NetBSD__)
 #    define NETBSD
@@ -160,7 +147,8 @@ EXTERN_C_BEGIN
 # if defined(__aarch64__)
 #    define AARCH64
 #    if !defined(LINUX) && !defined(DARWIN) && !defined(FREEBSD) \
-        && !defined(NETBSD) && !defined(NN_BUILD_TARGET_PLATFORM_NX)
+        && !defined(NETBSD) && !defined(NN_BUILD_TARGET_PLATFORM_NX) \
+        && !defined(OPENBSD)
 #      define NOSYS
 #      define mach_type_known
 #    endif
@@ -196,6 +184,10 @@ EXTERN_C_BEGIN
 #    define ARM32
 #    define mach_type_known
 # endif
+# if defined(OPENBSD) && defined(__aarch64__)
+#    define AARCH64
+#    define mach_type_known
+# endif
 # if defined(OPENBSD) && defined(__sh__)
 #    define SH
 #    define mach_type_known
@@ -229,7 +221,7 @@ EXTERN_C_BEGIN
 #    endif
 #    define mach_type_known
 # endif
-# if defined(__NetBSD__) && defined(__vax__)
+# if defined(NETBSD) && defined(__vax__)
 #    define VAX
 #    define mach_type_known
 # endif
@@ -246,11 +238,15 @@ EXTERN_C_BEGIN
 #        define IRIX5   /* or IRIX 6.X */
 #      endif
 #    endif /* !LINUX */
-#    if defined(__NetBSD__) && defined(__MIPSEL__)
+#    if defined(NETBSD) && defined(__MIPSEL__)
 #      undef ULTRIX
 #    endif
 #    define mach_type_known
 # endif
+# if defined(__QNX__)
+#   define I386
+#   define mach_type_known
+# endif
 # if defined(__NIOS2__) || defined(__NIOS2) || defined(__nios2__)
 #   define NIOS2 /* Altera NIOS2 */
 #   define mach_type_known
@@ -262,7 +258,7 @@ EXTERN_C_BEGIN
 # if defined(DGUX) && (defined(i386) || defined(__i386__))
 #    define I386
 #    ifndef _USING_DGUX
-#    define _USING_DGUX
+#      define _USING_DGUX
 #    endif
 #    define mach_type_known
 # endif
@@ -298,8 +294,7 @@ EXTERN_C_BEGIN
 #   define SOLARIS
 #   define mach_type_known
 # elif defined(sparc) && defined(unix) && !defined(sun) && !defined(linux) \
-       && !defined(__OpenBSD__) && !defined(__NetBSD__) \
-       && !defined(__FreeBSD__) && !defined(__DragonFly__)
+       && !defined(FREEBSD) && !defined(NETBSD) && !defined(OPENBSD)
 #   define SPARC
 #   define DRSNX
 #   define mach_type_known
@@ -309,7 +304,7 @@ EXTERN_C_BEGIN
 #   define AIX
 #   define mach_type_known
 # endif
-# if defined(__NetBSD__) && defined(__sparc__)
+# if defined(NETBSD) && defined(__sparc__)
 #   define SPARC
 #   define mach_type_known
 # endif
@@ -433,9 +428,8 @@ EXTERN_C_BEGIN
 #   define MACOS
 #   define mach_type_known
 # endif
-# if defined(__OpenBSD__) && defined(__powerpc__)
+# if defined(OPENBSD) && defined(__powerpc__)
 #   define POWERPC
-#   define OPENBSD
 #   define mach_type_known
 # endif
 # if defined(DARWIN)
@@ -471,16 +465,15 @@ EXTERN_C_BEGIN
 #   define NEXT
 #   define mach_type_known
 # endif
-# if defined(__OpenBSD__) && (defined(i386) || defined(__i386__))
+# if defined(OPENBSD) && (defined(i386) || defined(__i386__))
 #   define I386
-#   define OPENBSD
 #   define mach_type_known
 # endif
-# if defined(__NetBSD__) && (defined(i386) || defined(__i386__))
+# if defined(NETBSD) && (defined(i386) || defined(__i386__))
 #   define I386
 #   define mach_type_known
 # endif
-# if defined(__NetBSD__) && defined(__x86_64__)
+# if defined(NETBSD) && defined(__x86_64__)
 #    define X86_64
 #    define mach_type_known
 # endif
@@ -786,7 +779,7 @@ EXTERN_C_BEGIN
  * cause failures on alpha*-*-* with -msmall-data or -fpic or mips-*-*
  * without any special options.
  *
- * STACKBOTTOM is the cool end of the stack, which is usually the
+ * STACKBOTTOM is the cold end of the stack, which is usually the
  * highest address in the stack.
  * Under PCR or OS/2, we have other ways of finding thread stacks.
  * For each machine, the following should:
@@ -796,8 +789,8 @@ EXTERN_C_BEGIN
  *      LINUX_STACKBOTTOM
  *      HEURISTIC1
  *      HEURISTIC2
- * If STACKBOTTOM is defined, then its value will be used directly as the
- * stack base.  If LINUX_STACKBOTTOM is defined, then it will be determined
+ * If STACKBOTTOM is defined, then its value will be used directly (as the
+ * stack bottom).  If LINUX_STACKBOTTOM is defined, then it will be determined
  * with a method appropriate for most Linux systems.  Currently we look
  * first for __libc_stack_end (currently only if USE_LIBC_PRIVATES is
  * defined), and if that fails read it from /proc.  (If USE_LIBC_PRIVATES
@@ -896,23 +889,8 @@ EXTERN_C_BEGIN
 #   define DATAEND (ptr_t)ALIGNMENT
 # endif
 
-# ifdef __EMSCRIPTEN__
-#   define OS_TYPE "EMSCRIPTEN"
-#   define CPP_WORDSZ 32
-#   define ALIGNMENT 4
-#   define DATASTART (ptr_t)ALIGNMENT
-#   define DATAEND (ptr_t)ALIGNMENT
-    /* Since JavaScript/asm.js/WebAssembly is not able to access the    */
-    /* function call stack or the local data stack, it is not possible  */
-    /* for GC to perform its stack walking operation to find roots on   */
-    /* the stack.  To work around that, the clients generally only do   */
-    /* BDWGC steps when the stack is empty so it is known that there    */
-    /* are no objects that would be found on the stack, and BDWGC is    */
-    /* compiled with stack walking disabled.                            */
-#   define STACK_NOT_SCANNED
-# endif
-
 # define STACK_GRAN 0x1000000
+
 # ifdef M68K
 #   define MACH_TYPE "M68K"
 #   define ALIGNMENT 2
@@ -943,7 +921,9 @@ EXTERN_C_BEGIN
 #   ifdef LINUX
 #       define OS_TYPE "LINUX"
 #       define LINUX_STACKBOTTOM
-#       define MPROTECT_VDB
+#       if !defined(REDIRECT_MALLOC)
+#         define MPROTECT_VDB
+#       endif
 #       ifdef __ELF__
 #         define DYNAMIC_LOADING
           EXTERN_C_END
@@ -998,7 +978,7 @@ EXTERN_C_BEGIN
 #   endif
 # endif
 
-# if defined(POWERPC)
+# ifdef POWERPC
 #   define MACH_TYPE "POWERPC"
 #   ifdef MACOS
 #     define ALIGNMENT 2  /* Still necessary?  Could it be 4?   */
@@ -1113,9 +1093,7 @@ EXTERN_C_BEGIN
 #       define SIG_SUSPEND SIGUSR1
 #       define SIG_THR_RESTART SIGUSR2
 #       define FREEBSD_STACKBOTTOM
-#       ifdef __ELF__
-#           define DYNAMIC_LOADING
-#       endif
+#       define DYNAMIC_LOADING
         extern char etext[];
 #       define DATASTART GC_FreeBSDGetDataStart(0x1000, (ptr_t)etext)
 #       define DATASTART_USES_BSDGETDATASTART
@@ -1129,6 +1107,7 @@ EXTERN_C_BEGIN
 #     define DYNAMIC_LOADING
 #   endif
 #   ifdef SN_TARGET_PS3
+#     define OS_TYPE "SN_TARGET_PS3"
 #     define NO_GETENV
 #     define CPP_WORDSZ 32
 #     define ALIGNMENT 4
@@ -1337,9 +1316,7 @@ EXTERN_C_BEGIN
 #       define SIG_SUSPEND SIGUSR1
 #       define SIG_THR_RESTART SIGUSR2
 #       define FREEBSD_STACKBOTTOM
-#       ifdef __ELF__
-#           define DYNAMIC_LOADING
-#       endif
+#       define DYNAMIC_LOADING
         extern char etext[];
         extern char edata[];
 #       if !defined(CPPCHECK)
@@ -1373,6 +1350,28 @@ EXTERN_C_BEGIN
 #       define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff))
 #       define STACKBOTTOM ((ptr_t)0x3ffff000)
 #   endif
+#   if defined(__EMSCRIPTEN__)
+#     define OS_TYPE "EMSCRIPTEN"
+#     define DATASTART (ptr_t)ALIGNMENT
+#     define DATAEND (ptr_t)ALIGNMENT
+      /* Since JavaScript/asm.js/WebAssembly is not able to access the  */
+      /* function call stack or the local data stack, it's not possible */
+      /* for GC to perform its stack walking operation to find roots on */
+      /* the stack.  To work around that, the clients generally only do */
+      /* BDWGC steps when the stack is empty so it is known that there  */
+      /* are no objects that would be found on the stack, and BDWGC is  */
+      /* compiled with stack walking disabled.                          */
+#     define STACK_NOT_SCANNED
+#   endif
+#   if defined(__QNX__)
+#     define OS_TYPE "QNX"
+#     define SA_RESTART 0
+#     define HEURISTIC1
+      extern char etext[];
+      extern int _end[];
+#     define DATASTART ((ptr_t)etext)
+#     define DATAEND ((ptr_t)_end)
+#   endif
 #   ifdef HAIKU
 #     define OS_TYPE "HAIKU"
       EXTERN_C_END
@@ -1468,7 +1467,7 @@ EXTERN_C_BEGIN
 #   ifdef LINUX
 #       define OS_TYPE "LINUX"
 #       define LINUX_STACKBOTTOM
-#       if !defined(GC_LINUX_THREADS) || !defined(REDIRECT_MALLOC)
+#       if !defined(REDIRECT_MALLOC)
 #           define MPROTECT_VDB
 #       else
             /* We seem to get random errors in incremental mode,        */
@@ -1477,7 +1476,7 @@ EXTERN_C_BEGIN
 #       endif
 #       define HEAP_START (ptr_t)0x1000
                 /* This encourages mmap to give us low addresses,       */
-                /* thus allowing the heap to grow to ~3GB               */
+                /* thus allowing the heap to grow to ~3 GB.             */
 #       ifdef __ELF__
 #           define DYNAMIC_LOADING
             EXTERN_C_END
@@ -1545,13 +1544,18 @@ EXTERN_C_BEGIN
 #   endif
 #   ifdef CYGWIN32
 #       define OS_TYPE "CYGWIN32"
+#       define WOW64_THREAD_CONTEXT_WORKAROUND
+#       define RETRY_GET_THREAD_CONTEXT
 #       define DATASTART ((ptr_t)GC_DATASTART)  /* From gc.h */
 #       define DATAEND   ((ptr_t)GC_DATAEND)
-#       undef STACK_GRAN
-#       define STACK_GRAN 0x10000
-#       ifdef USE_MMAP
-#         define NEED_FIND_LIMIT
-#         define USE_MMAP_ANON
+#       ifdef USE_WINALLOC
+#         define GWW_VDB
+#       else
+#         /* MPROTECT_VDB does not work, it leads to a spurious exit.   */
+#         ifdef USE_MMAP
+#           define NEED_FIND_LIMIT
+#           define USE_MMAP_ANON
+#         endif
 #       endif
 #   endif
 #   ifdef INTERIX
@@ -1575,6 +1579,8 @@ EXTERN_C_BEGIN
 #   endif
 #   ifdef MSWIN32
 #       define OS_TYPE "MSWIN32"
+#       define WOW64_THREAD_CONTEXT_WORKAROUND
+#       define RETRY_GET_THREAD_CONTEXT
                 /* STACKBOTTOM and DATASTART are handled specially in   */
                 /* os_dep.c.                                            */
 #       define MPROTECT_VDB
@@ -1831,7 +1837,7 @@ EXTERN_C_BEGIN
 #       define ALIGNMENT 4
 #       define DATAEND /* not needed */
 #   endif
-#   if defined(NETBSD)
+#   ifdef NETBSD
 #     define OS_TYPE "NETBSD"
 #     define ALIGNMENT 4
 #     define HEURISTIC2
@@ -1847,7 +1853,8 @@ EXTERN_C_BEGIN
 #  endif
 #  ifdef OPENBSD
 #     define OS_TYPE "OPENBSD"
-#     define ALIGNMENT 4
+#     define CPP_WORDSZ 64 /* all OpenBSD/mips platforms are 64-bit */
+#     define ALIGNMENT 8
 #     ifndef GC_OPENBSD_THREADS
         EXTERN_C_END
 #       include <sys/param.h>
@@ -1859,8 +1866,8 @@ EXTERN_C_BEGIN
 #         define HEURISTIC2
 #       endif
 #     endif
-      extern int _fdata[];
-#     define DATASTART ((ptr_t)_fdata)
+      extern int __data_start[];
+#     define DATASTART ((ptr_t)__data_start)
       extern int _end[];
 #     define DATAEND ((ptr_t)(&_end))
 #     define DYNAMIC_LOADING
@@ -1874,9 +1881,7 @@ EXTERN_C_BEGIN
 #    define SIG_SUSPEND SIGUSR1
 #    define SIG_THR_RESTART SIGUSR2
 #    define FREEBSD_STACKBOTTOM
-#    ifdef __ELF__
-#      define DYNAMIC_LOADING
-#    endif
+#    define DYNAMIC_LOADING
      extern char etext[];
 #    define DATASTART GC_FreeBSDGetDataStart(0x1000, (ptr_t)etext)
 #    define DATASTART_USES_BSDGETDATASTART
@@ -1946,6 +1951,9 @@ EXTERN_C_BEGIN
 #     define OS_TYPE "HPUX"
       extern int __data_start[];
 #     define DATASTART ((ptr_t)(__data_start))
+#     ifdef USE_MMAP
+#       define USE_MMAP_ANON
+#     endif
 #     ifdef USE_HPUX_FIXED_STACKBOTTOM
         /* The following appears to work for 7xx systems running HP/UX  */
         /* 9.xx.  Furthermore, it might result in much faster           */
@@ -1954,13 +1962,22 @@ EXTERN_C_BEGIN
         /* default, since it may not work on older machine/OS           */
         /* combinations. (Thanks to Raymond X.T. Nijssen for uncovering */
         /* this.)                                                       */
+        /* This technique also doesn't work with HP/UX 11.xx.  The      */
+        /* stack size is settable using the kernel maxssiz variable,    */
+        /* and in 11.23 and latter, the size can be set dynamically.    */
+        /* It also doesn't handle SHMEM_MAGIC binaries which have       */
+        /* stack and data in the first quadrant.                        */
 #       define STACKBOTTOM ((ptr_t)0x7b033000) /* from /etc/conf/h/param.h */
-#     else
+#     elif defined(USE_ENVIRON_POINTER)
         /* Gustavo Rodriguez-Rivera suggested changing HEURISTIC2       */
         /* to this.  Note that the GC must be initialized before the    */
-        /* first putenv call.                                           */
+        /* first putenv call.  Unfortunately, some clients do not obey. */
         extern char ** environ;
 #       define STACKBOTTOM ((ptr_t)environ)
+#     elif !defined(HEURISTIC2)
+        /* This uses pst_vm_status support. */
+#       define HPUX_MAIN_STACKBOTTOM
+#       define NEED_FIND_LIMIT
 #     endif
 #     define DYNAMIC_LOADING
       EXTERN_C_END
@@ -2044,9 +2061,7 @@ EXTERN_C_BEGIN
 #       define SIG_THR_RESTART SIGUSR2
                 /* SIGTSTP and SIGCONT could be used alternatively.     */
 #       define FREEBSD_STACKBOTTOM
-#       ifdef __ELF__
-#           define DYNAMIC_LOADING
-#       endif
+#       define DYNAMIC_LOADING
 /* Handle unmapped hole alpha*-*-freebsd[45]* puts between etext and edata. */
         extern char etext[];
         extern char edata[];
@@ -2096,9 +2111,11 @@ EXTERN_C_BEGIN
 #       endif
         extern int _end[];
 #       define DATAEND ((ptr_t)(_end))
-#       define MPROTECT_VDB
+#       if !defined(REDIRECT_MALLOC)
+#           define MPROTECT_VDB
                 /* Has only been superficially tested.  May not */
                 /* work on all versions.                        */
+#       endif
 #   endif
 # endif
 
@@ -2120,6 +2137,9 @@ EXTERN_C_BEGIN
 #       define OS_TYPE "HPUX"
         extern int __data_start[];
 #       define DATASTART ((ptr_t)(__data_start))
+#       ifdef USE_MMAP
+#         define USE_MMAP_ANON
+#       endif
         /* Gustavo Rodriguez-Rivera suggested changing HEURISTIC2       */
         /* to this.  Note that the GC must be initialized before the    */
         /* first putenv call.                                           */
@@ -2161,8 +2181,10 @@ EXTERN_C_BEGIN
           /* statically linked executables and an undefined reference   */
           /* to _DYNAMIC                                                */
 #       endif
-#       define MPROTECT_VDB
+#       if !defined(REDIRECT_MALLOC)
+#         define MPROTECT_VDB
                 /* Requires Linux 2.3.47 or later.      */
+#       endif
         extern int _end[];
 #       define DATAEND ((ptr_t)(_end))
 #       ifdef __GNUC__
@@ -2183,17 +2205,6 @@ EXTERN_C_BEGIN
 #         endif /* __INTEL_COMPILER */
 #       endif
 #   endif
-#   ifdef CYGWIN32
-#       define OS_TYPE "CYGWIN32"
-#       define DATASTART ((ptr_t)GC_DATASTART)  /* From gc.h */
-#       define DATAEND   ((ptr_t)GC_DATAEND)
-#       undef STACK_GRAN
-#       define STACK_GRAN 0x10000
-#       ifdef USE_MMAP
-#         define NEED_FIND_LIMIT
-#         define USE_MMAP_ANON
-#       endif
-#   endif
 #   ifdef MSWIN32
       /* FIXME: This is a very partial guess.  There is no port, yet.   */
 #     define OS_TYPE "MSWIN32"
@@ -2218,7 +2229,7 @@ EXTERN_C_BEGIN
 #       define DATASTART ((ptr_t)((((word)(etext) + 0x3fffff) & ~0x3fffff) \
                                   + 0x10000))
 #   endif
-#   ifdef  DGUX
+#   ifdef DGUX
 #       define OS_TYPE "DGUX"
         ptr_t GC_SysVGetDataStart(size_t, ptr_t);
 #       define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)etext)
@@ -2248,14 +2259,14 @@ EXTERN_C_BEGIN
 # ifdef S390
 #   define MACH_TYPE "S390"
 #   ifndef __s390x__
-#   define ALIGNMENT 4
-#   define CPP_WORDSZ 32
+#     define ALIGNMENT 4
+#     define CPP_WORDSZ 32
 #   else
-#   define ALIGNMENT 8
-#   define CPP_WORDSZ 64
-#   ifndef HBLKSIZE
-#     define HBLKSIZE 4096
-#   endif
+#     define ALIGNMENT 8
+#     define CPP_WORDSZ 64
+#     ifndef HBLKSIZE
+#       define HBLKSIZE 4096
+#     endif
 #   endif
 #   ifdef LINUX
 #       define OS_TYPE "LINUX"
@@ -2285,6 +2296,9 @@ EXTERN_C_BEGIN
 #   ifdef LINUX
 #     define OS_TYPE "LINUX"
 #     define LINUX_STACKBOTTOM
+#     if !defined(REDIRECT_MALLOC)
+#       define MPROTECT_VDB
+#     endif
 #     define DYNAMIC_LOADING
 #     if defined(HOST_ANDROID)
 #       define SEARCH_FOR_DATA_START
@@ -2304,7 +2318,9 @@ EXTERN_C_BEGIN
 #     define DATAEND   ((ptr_t)get_end())
 #     define STACKBOTTOM ((ptr_t)0x16fdfffff)
 #     define USE_MMAP_ANON
-#     define MPROTECT_VDB
+      /* MPROTECT_VDB causes use of non-public API like exc_server,     */
+      /* this could be a reason for blocking the client application in  */
+      /* the store.                                                     */
       EXTERN_C_END
 #     include <unistd.h>
       EXTERN_C_BEGIN
@@ -2322,9 +2338,7 @@ EXTERN_C_BEGIN
 #       define MPROTECT_VDB
 #     endif
 #     define FREEBSD_STACKBOTTOM
-#     ifdef __ELF__
-#       define DYNAMIC_LOADING
-#     endif
+#     define DYNAMIC_LOADING
       extern char etext[];
 #     define DATASTART GC_FreeBSDGetDataStart(0x1000, (ptr_t)etext)
 #     define DATASTART_USES_BSDGETDATASTART
@@ -2337,7 +2351,28 @@ EXTERN_C_BEGIN
 #     define ELF_CLASS ELFCLASS64
 #     define DYNAMIC_LOADING
 #   endif
+#   ifdef OPENBSD
+#     define OS_TYPE "OPENBSD"
+#     define ELF_CLASS ELFCLASS64
+#     ifndef GC_OPENBSD_THREADS
+        EXTERN_C_END
+#       include <sys/param.h>
+#       include <uvm/uvm_extern.h>
+        EXTERN_C_BEGIN
+#       ifdef USRSTACK
+#         define STACKBOTTOM ((ptr_t)USRSTACK)
+#       else
+#         define HEURISTIC2
+#       endif
+#     endif
+      extern int __data_start[];
+#     define DATASTART ((ptr_t)__data_start)
+      extern int _end[];
+#     define DATAEND ((ptr_t)(&_end))
+#     define DYNAMIC_LOADING
+#   endif
 #   ifdef NINTENDO_SWITCH
+#     define OS_TYPE "NINTENDO_SWITCH"
       extern int __bss_end[];
 #     define NO_HANDLE_FORK 1
 #     define DATASTART (ptr_t)ALIGNMENT /* cannot be null */
@@ -2345,6 +2380,13 @@ EXTERN_C_BEGIN
       void *switch_get_stack_bottom(void);
 #     define STACKBOTTOM ((ptr_t)switch_get_stack_bottom())
 #   endif
+#   ifdef MSWIN32   /* UWP */
+#     define OS_TYPE "MSWIN32"
+      /* TODO: Enable GWW_VDB and/or MPROTECT_VDB */
+#     ifndef DATAEND
+#       define DATAEND  /* not needed */
+#     endif
+#   endif
 #   ifdef NOSYS
       /* __data_start is usually defined in the target linker script.   */
       extern int __data_start[];
@@ -2377,19 +2419,19 @@ EXTERN_C_BEGIN
 #   ifdef LINUX
 #       define OS_TYPE "LINUX"
 #       define LINUX_STACKBOTTOM
-#       undef STACK_GRAN
-#       define STACK_GRAN 0x10000000
-#       ifdef __ELF__
-#           define DYNAMIC_LOADING
-            EXTERN_C_END
-#           include <features.h>
-            EXTERN_C_BEGIN
-#           if defined(__GLIBC__) && __GLIBC__ >= 2 \
+#       if !defined(REDIRECT_MALLOC)
+#           define MPROTECT_VDB
+#       endif
+#       define DYNAMIC_LOADING
+        EXTERN_C_END
+#       include <features.h>
+        EXTERN_C_BEGIN
+#       if defined(__GLIBC__) && __GLIBC__ >= 2 \
                 || defined(HOST_ANDROID) || defined(HOST_TIZEN)
-#                define SEARCH_FOR_DATA_START
-#           else
-                 extern char **__environ;
-#                define DATASTART ((ptr_t)(&__environ))
+#           define SEARCH_FOR_DATA_START
+#       else
+            extern char **__environ;
+#           define DATASTART ((ptr_t)(&__environ))
                               /* hideous kludge: __environ is the first */
                               /* word in crt0.o, and delimits the start */
                               /* of the data segment, no matter which   */
@@ -2398,13 +2440,9 @@ EXTERN_C_BEGIN
                               /* would include .rodata, which may       */
                               /* contain large read-only data tables    */
                               /* that we'd rather not scan.             */
-#           endif
-            extern int _end[];
-#           define DATAEND ((ptr_t)(_end))
-#       else
-            extern int etext[];
-#           define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff))
 #       endif
+        extern int _end[];
+#       define DATAEND ((ptr_t)(_end))
 #   endif
 #   ifdef MSWINCE
 #     define OS_TYPE "MSWINCE"
@@ -2419,9 +2457,7 @@ EXTERN_C_BEGIN
 #     define SIG_SUSPEND SIGUSR1
 #     define SIG_THR_RESTART SIGUSR2
 #     define FREEBSD_STACKBOTTOM
-#     ifdef __ELF__
-#       define DYNAMIC_LOADING
-#     endif
+#     define DYNAMIC_LOADING
       extern char etext[];
 #     define DATASTART GC_FreeBSDGetDataStart(0x1000, (ptr_t)etext)
 #     define DATASTART_USES_BSDGETDATASTART
@@ -2435,7 +2471,7 @@ EXTERN_C_BEGIN
 #     define DATAEND   ((ptr_t)get_end())
 #     define STACKBOTTOM ((ptr_t)0x30000000)
 #     define USE_MMAP_ANON
-#     define MPROTECT_VDB
+      /* MPROTECT_VDB causes use of non-public API.     */
       EXTERN_C_END
 #     include <unistd.h>
       EXTERN_C_BEGIN
@@ -2467,6 +2503,7 @@ EXTERN_C_BEGIN
 #     define DYNAMIC_LOADING
 #   endif
 #   ifdef SN_TARGET_PSP2
+#     define OS_TYPE "SN_TARGET_PSP2"
 #     define NO_HANDLE_FORK 1
 #     define DATASTART (ptr_t)ALIGNMENT
 #     define DATAEND (ptr_t)ALIGNMENT
@@ -2474,6 +2511,7 @@ EXTERN_C_BEGIN
 #     define STACKBOTTOM ((ptr_t)psp2_get_stack_bottom())
 #   endif
 #   ifdef NN_PLATFORM_CTR
+#     define OS_TYPE "NN_PLATFORM_CTR"
       extern unsigned char Image$$ZI$$ZI$$Base[];
 #     define DATASTART (ptr_t)(Image$$ZI$$ZI$$Base)
       extern unsigned char Image$$ZI$$ZI$$Limit[];
@@ -2481,6 +2519,13 @@ EXTERN_C_BEGIN
       void *n3ds_get_stack_bottom(void);
 #     define STACKBOTTOM ((ptr_t)n3ds_get_stack_bottom())
 #   endif
+#   ifdef MSWIN32   /* UWP */
+#     define OS_TYPE "MSWIN32"
+      /* TODO: Enable GWW_VDB and/or MPROTECT_VDB */
+#     ifndef DATAEND
+#       define DATAEND  /* not needed */
+#     endif
+#   endif
 #   ifdef NOSYS
       /* __data_start is usually defined in the target linker script.  */
       extern int __data_start[];
@@ -2495,12 +2540,14 @@ EXTERN_C_BEGIN
 #   define MACH_TYPE "CRIS"
 #   define CPP_WORDSZ 32
 #   define ALIGNMENT 1
-#   define OS_TYPE "LINUX"
-#   define DYNAMIC_LOADING
-#   define LINUX_STACKBOTTOM
-#   define SEARCH_FOR_DATA_START
+#   ifdef LINUX
+#     define OS_TYPE "LINUX"
+#     define DYNAMIC_LOADING
+#     define LINUX_STACKBOTTOM
+#     define SEARCH_FOR_DATA_START
       extern int _end[];
-#   define DATAEND ((ptr_t)(_end))
+#     define DATAEND ((ptr_t)(_end))
+#   endif
 # endif
 
 # if defined(SH) && !defined(SH4)
@@ -2548,21 +2595,25 @@ EXTERN_C_BEGIN
 
 # ifdef SH4
 #   define MACH_TYPE "SH4"
-#   define OS_TYPE "MSWINCE"
 #   define ALIGNMENT 4
-#   define DATAEND /* not needed */
+#   ifdef MSWINCE
+#     define OS_TYPE "MSWINCE"
+#     define DATAEND /* not needed */
+#   endif
 # endif
 
 # ifdef AVR32
 #   define MACH_TYPE "AVR32"
 #   define CPP_WORDSZ 32
 #   define ALIGNMENT 4
-#   define OS_TYPE "LINUX"
-#   define DYNAMIC_LOADING
-#   define LINUX_STACKBOTTOM
-#   define SEARCH_FOR_DATA_START
-    extern int _end[];
-#   define DATAEND ((ptr_t)(_end))
+#   ifdef LINUX
+#     define OS_TYPE "LINUX"
+#     define DYNAMIC_LOADING
+#     define LINUX_STACKBOTTOM
+#     define SEARCH_FOR_DATA_START
+      extern int _end[];
+#     define DATAEND ((ptr_t)(_end))
+#   endif
 # endif
 
 # ifdef M32R
@@ -2572,8 +2623,6 @@ EXTERN_C_BEGIN
 #   ifdef LINUX
 #     define OS_TYPE "LINUX"
 #     define LINUX_STACKBOTTOM
-#     undef STACK_GRAN
-#     define STACK_GRAN 0x10000000
 #     define DYNAMIC_LOADING
 #     define SEARCH_FOR_DATA_START
       extern int _end[];
@@ -2597,6 +2646,7 @@ EXTERN_C_BEGIN
 #     define CACHE_LINE_SIZE 64
 #   endif
 #   ifdef SN_TARGET_ORBIS
+#     define OS_TYPE "SN_TARGET_ORBIS"
 #     define DATASTART (ptr_t)ALIGNMENT
 #     define DATAEND (ptr_t)ALIGNMENT
       void *ps4_get_stack_bottom(void);
@@ -2625,25 +2675,20 @@ EXTERN_C_BEGIN
 #   ifdef LINUX
 #       define OS_TYPE "LINUX"
 #       define LINUX_STACKBOTTOM
-#       if !defined(GC_LINUX_THREADS) || !defined(REDIRECT_MALLOC)
+#       if !defined(REDIRECT_MALLOC)
 #           define MPROTECT_VDB
 #       else
             /* We seem to get random errors in incremental mode,        */
             /* possibly because Linux threads is itself a malloc client */
             /* and can't deal with the signals.                         */
 #       endif
-#       ifdef __ELF__
-#           define DYNAMIC_LOADING
-            EXTERN_C_END
-#           include <features.h>
-            EXTERN_C_BEGIN
-#           define SEARCH_FOR_DATA_START
-            extern int _end[];
-#           define DATAEND ((ptr_t)(_end))
-#       else
-             extern int etext[];
-#            define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff))
-#       endif
+#       define DYNAMIC_LOADING
+        EXTERN_C_END
+#       include <features.h>
+        EXTERN_C_BEGIN
+#       define SEARCH_FOR_DATA_START
+        extern int _end[];
+#       define DATAEND ((ptr_t)(_end))
 #       if defined(__GLIBC__) && !defined(__UCLIBC__)
           /* A workaround for GCF (Google Cloud Function) which does    */
           /* not support mmap() for "/dev/zero".  Should not cause any  */
@@ -2700,9 +2745,7 @@ EXTERN_C_BEGIN
                 /* SIGTSTP and SIGCONT could be used alternatively.     */
 #       endif
 #       define FREEBSD_STACKBOTTOM
-#       ifdef __ELF__
-#           define DYNAMIC_LOADING
-#       endif
+#       define DYNAMIC_LOADING
         extern char etext[];
 #       define DATASTART GC_FreeBSDGetDataStart(0x1000, (ptr_t)etext)
 #       define DATASTART_USES_BSDGETDATASTART
@@ -2710,13 +2753,9 @@ EXTERN_C_BEGIN
 #   ifdef NETBSD
 #       define OS_TYPE "NETBSD"
 #       define HEURISTIC2
-#       ifdef __ELF__
-            extern ptr_t GC_data_start;
-#           define DATASTART GC_data_start
-#           define DYNAMIC_LOADING
-#       else
-#           define SEARCH_FOR_DATA_START
-#       endif
+        extern ptr_t GC_data_start;
+#       define DATASTART GC_data_start
+#       define DYNAMIC_LOADING
 #   endif
 #   ifdef HAIKU
 #     define OS_TYPE "HAIKU"
@@ -2776,7 +2815,26 @@ EXTERN_C_BEGIN
 #         define HEAP_START DATAEND
 #       endif
 #   endif
+#   ifdef CYGWIN32
+#       define OS_TYPE "CYGWIN32"
+#       define RETRY_GET_THREAD_CONTEXT
+#       ifdef USE_WINALLOC
+#         define GWW_VDB
+#       else
+#         if defined(THREAD_LOCAL_ALLOC)
+            /* TODO: For an unknown reason, thread-local allocations    */
+            /* lead to spurious process exit after the fault handler is */
+            /* once invoked.                                            */
+#         else
+#           define MPROTECT_VDB
+#         endif
+#         ifdef USE_MMAP
+#           define USE_MMAP_ANON
+#         endif
+#       endif
+#   endif
 #   ifdef MSWIN_XBOX1
+#     define OS_TYPE "MSWIN_XBOX1"
 #     define NO_GETENV
 #     define DATASTART (ptr_t)ALIGNMENT
 #     define DATAEND (ptr_t)ALIGNMENT
@@ -2797,6 +2855,7 @@ EXTERN_C_BEGIN
 #   endif
 #   ifdef MSWIN32
 #       define OS_TYPE "MSWIN32"
+#       define RETRY_GET_THREAD_CONTEXT
                 /* STACKBOTTOM and DATASTART are handled specially in   */
                 /* os_dep.c.                                            */
 #       if !defined(__GNUC__) || defined(__INTEL_COMPILER) \
@@ -2817,26 +2876,22 @@ EXTERN_C_BEGIN
 #   define MACH_TYPE "HEXAGON"
 #   define ALIGNMENT 4
 #   ifdef LINUX
-#       define OS_TYPE "LINUX"
-#       define LINUX_STACKBOTTOM
+#     define OS_TYPE "LINUX"
+#     define LINUX_STACKBOTTOM
+#     if !defined(REDIRECT_MALLOC)
 #       define MPROTECT_VDB
-#       ifdef __ELF__
-#           define DYNAMIC_LOADING
-            EXTERN_C_END
-#           include <features.h>
-            EXTERN_C_BEGIN
-#           if defined(__GLIBC__) && __GLIBC__ >= 2
-#               define SEARCH_FOR_DATA_START
-#           else
-#               error Unknown Hexagon libc configuration
-#           endif
-            extern int _end[];
-#           define DATAEND ((ptr_t)(_end))
-#       elif !defined(CPPCHECK)
-#           error Bad Hexagon Linux configuration
-#       endif
-#   else
-#       error Unknown Hexagon OS configuration
+#     endif
+#     define DYNAMIC_LOADING
+      EXTERN_C_END
+#     include <features.h>
+      EXTERN_C_BEGIN
+#     if defined(__GLIBC__)
+#       define SEARCH_FOR_DATA_START
+#     elif !defined(CPPCHECK)
+#       error Unknown Hexagon libc configuration
+#     endif
+      extern int _end[];
+#     define DATAEND ((ptr_t)(_end))
 #   endif
 # endif
 
@@ -2879,7 +2934,7 @@ EXTERN_C_BEGIN
 #   define ALIGNMENT (CPP_WORDSZ/8)
 #   ifdef LINUX
 #     define OS_TYPE "LINUX"
-      extern int __data_start[];
+      extern int __data_start[] __attribute__((__weak__));
 #     define DATASTART ((ptr_t)__data_start)
 #     define LINUX_STACKBOTTOM
 #     define DYNAMIC_LOADING
@@ -2891,10 +2946,14 @@ EXTERN_C_BEGIN
 # define USE_LIBC_PRIVATES
 #endif
 
+#ifdef NO_RETRY_GET_THREAD_CONTEXT
+# undef RETRY_GET_THREAD_CONTEXT
+#endif
+
 #if defined(LINUX_STACKBOTTOM) && defined(NO_PROC_STAT) \
     && !defined(USE_LIBC_PRIVATES)
     /* This combination will fail, since we have no way to get  */
-    /* the stack base.  Use HEURISTIC2 instead.                 */
+    /* the stack bottom.  Use HEURISTIC2 instead.               */
 #   undef LINUX_STACKBOTTOM
 #   define HEURISTIC2
     /* This may still fail on some architectures like IA64.     */
@@ -3100,8 +3159,12 @@ EXTERN_C_BEGIN
 # undef USE_MMAP
 #endif
 
-#if defined(LINUX) || defined(FREEBSD) || defined(SOLARIS) || defined(IRIX5) \
-    || ((defined(USE_MMAP) || defined(USE_MUNMAP)) && !defined(USE_WINALLOC))
+#if defined(DARWIN) || defined(FREEBSD) || defined(HAIKU) \
+    || defined(IRIX5) || defined(LINUX) || defined(NETBSD) \
+    || defined(OPENBSD) || defined(SOLARIS) \
+    || ((defined(CYGWIN32) || defined(USE_MMAP) || defined(USE_MUNMAP)) \
+        && !defined(USE_WINALLOC))
+  /* Try both sbrk and mmap, in that order.     */
 # define MMAP_SUPPORTED
 #endif
 
@@ -3137,15 +3200,11 @@ EXTERN_C_BEGIN
 # undef MPROTECT_VDB
 #endif
 
-#if defined(USE_MUNMAP) && defined(GWW_VDB)
-# undef MPROTECT_VDB  /* TODO: Cannot deal with address space holes. */
-  /* Else if MPROTECT_VDB is available but not GWW_VDB then decide      */
-  /* whether to disable memory unmapping or mprotect-based virtual      */
-  /* dirty bits at runtime when GC_enable_incremental is called.        */
+#if defined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS)
+  /* Incremental GC is incompatible with /proc roots.   */
+# undef MPROTECT_VDB
 #endif
 
-/* PARALLEL_MARK does not cause undef MPROTECT_VDB any longer.  */
-
 #if defined(MPROTECT_VDB) && defined(GC_PREFER_MPROTECT_VDB)
   /* Choose MPROTECT_VDB manually (if multiple strategies available).   */
 # undef PCR_VDB
@@ -3158,6 +3217,10 @@ EXTERN_C_BEGIN
 # undef MPROTECT_VDB
 #endif
 
+#if defined(MPROTECT_VDB) && !defined(MSWIN32) && !defined(MSWINCE)
+# include <signal.h> /* for SA_SIGINFO, SIGBUS */
+#endif
+
 #if defined(SIGBUS) && !defined(HAVE_SIGBUS) && !defined(CPPCHECK)
 # define HAVE_SIGBUS
 #endif
@@ -3166,7 +3229,8 @@ EXTERN_C_BEGIN
 # define NO_SA_SIGACTION
 #endif
 
-#if defined(NO_SA_SIGACTION) && defined(MPROTECT_VDB) && !defined(DARWIN) \
+#if (defined(NO_SA_SIGACTION) || defined(GC_NO_SIGSETJMP)) \
+    && defined(MPROTECT_VDB) && !defined(DARWIN) \
     && !defined(MSWIN32) && !defined(MSWINCE)
 # undef MPROTECT_VDB
 #endif
@@ -3209,8 +3273,8 @@ EXTERN_C_BEGIN
 #endif
 
 #ifndef STATIC
-# ifndef NO_DEBUGGING
-#   define STATIC /* ignore to aid profiling and possibly debugging     */
+# ifdef GC_ASSERTIONS
+#   define STATIC /* ignore to aid debugging (or profiling) */
 # else
 #   define STATIC static
 # endif
@@ -3292,10 +3356,14 @@ EXTERN_C_BEGIN
 # error Invalid config: PARALLEL_MARK requires GC_THREADS
 #endif
 
+#if defined(GWW_VDB) && !defined(USE_WINALLOC) && !defined(CPPCHECK)
+# error Invalid config: GWW_VDB requires USE_WINALLOC
+#endif
+
 #if (((defined(MSWIN32) || defined(MSWINCE)) && !defined(__GNUC__)) \
         || (defined(MSWIN32) && defined(I386)) /* for Win98 */ \
         || (defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS))) \
-     && !defined(NO_WRAP_MARK_SOME)
+    && !defined(NO_CRT) && !defined(NO_WRAP_MARK_SOME)
   /* Under rare conditions, we may end up marking from nonexistent      */
   /* memory.  Hence we need to be prepared to recover by running        */
   /* GC_mark_some with a suitable handler in place.                     */
@@ -3399,6 +3467,14 @@ EXTERN_C_BEGIN
 # define NO_GETENV_WIN32
 #endif
 
+#if !defined(MSGBOX_ON_ERROR) && !defined(NO_MSGBOX_ON_ERROR) \
+    && !defined(SMALL_CONFIG) && defined(MSWIN32) \
+    && !defined(MSWINRT_FLAVOR) && !defined(MSWIN_XBOX1)
+  /* Show Windows message box with "OK" button on a GC fatal error.     */
+  /* Client application is terminated once the user clicks the button.  */
+# define MSGBOX_ON_ERROR
+#endif
+
 #ifndef STRTOULL
 # if defined(_WIN64) && !defined(__GNUC__)
 #   define STRTOULL _strtoui64

+ 2 - 2
blitz.mod/bdwgc/include/private/pthread_support.h

@@ -71,7 +71,7 @@ typedef struct GC_Thread_Rep {
       volatile AO_t suspended_ext;  /* Thread was suspended externally. */
 #   endif
 
-    unsigned char flags;
+    unsigned char flags;        /* Protected by GC lock.                */
 #       define FINISHED 1       /* Thread has exited.                   */
 #       define DETACHED 2       /* Thread is treated as detached.       */
                                 /* Thread may really be detached, or    */
@@ -132,7 +132,7 @@ typedef struct GC_Thread_Rep {
                                 /* and detach.                          */
 
 #   ifdef THREAD_LOCAL_ALLOC
-        struct thread_local_freelists tlfs;
+        struct thread_local_freelists tlfs GC_ATTR_WORD_ALIGNED;
 #   endif
 } * GC_thread;
 

+ 14 - 1
blitz.mod/bdwgc/include/private/specific.h

@@ -1,3 +1,16 @@
+/*
+ * Copyright (c) 2000 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
 /*
  * This is a reimplementation of a subset of the pthread_getspecific/setspecific
  * interface. This appears to outperform the standard linuxthreads one
@@ -67,7 +80,7 @@ typedef struct thread_specific_entry {
 /* only as a backup.                                                    */
 
 /* Return the "quick thread id".  Default version.  Assumes page size,  */
-/* or at least thread stack separation, is at least 4K.                 */
+/* or at least thread stack separation, is at least 4 KB.               */
 /* Must be defined so that it never returns 0.  (Page 0 can't really be */
 /* part of any stack, since that would make 0 a valid stack pointer.)   */
 #define quick_thread_id() (((word)GC_approx_sp()) >> 12)

+ 3 - 9
blitz.mod/bdwgc/include/private/thread_local_alloc.h

@@ -55,8 +55,9 @@ EXTERN_C_BEGIN
 # elif (defined(LINUX) && !defined(ARM32) && !defined(AVR32) \
          && GC_GNUC_PREREQ(3, 3) \
          && !(defined(__clang__) && defined(HOST_ANDROID))) \
-       || (defined(FREEBSD) && defined(__GLIBC__) /* kFreeBSD */ \
-            && GC_GNUC_PREREQ(4, 4)) \
+       || (defined(FREEBSD) \
+           || (defined(NETBSD) && __NetBSD_Version__ >= 600000000 /* 6.0 */) \
+            && (GC_GNUC_PREREQ(4, 4) || GC_CLANG_PREREQ(3, 9))) \
        || (defined(HOST_ANDROID) && defined(ARM32) \
             && (GC_GNUC_PREREQ(4, 6) || GC_CLANG_PREREQ_FULL(3, 8, 256229)))
 #   define USE_COMPILER_TLS
@@ -133,13 +134,6 @@ typedef struct thread_local_freelists {
 # define GC_remove_specific_after_fork(key, t) (void)0
   typedef void * GC_key_t;
 #elif defined(USE_WIN32_SPECIFIC)
-# ifndef WIN32_LEAN_AND_MEAN
-#   define WIN32_LEAN_AND_MEAN 1
-# endif
-# define NOSERVICE
-  EXTERN_C_END
-# include <windows.h>
-  EXTERN_C_BEGIN
 # define GC_getspecific TlsGetValue
 # define GC_setspecific(key, v) !TlsSetValue(key, v)
         /* We assume 0 == success, msft does the opposite.      */

+ 7 - 0
blitz.mod/bdwgc/libatomic_ops/.gitattributes

@@ -0,0 +1,7 @@
+# Git repo attributes.
+
+# Ensure all text files have normalized (LF) line endings in the repository.
+* text=auto
+
+# Note: "core.eol" configuration variable controls which line endings to use
+# for the normalized files in the working directory (the default is native).

+ 83 - 0
blitz.mod/bdwgc/libatomic_ops/.gitignore

@@ -0,0 +1,83 @@
+# Ignored files in libatomic_ops Git repo.
+
+Makefile
+
+/pkgconfig/atomic_ops.pc
+/pkgconfig/atomic_ops-uninstalled.pc
+/autom4te.cache/
+/config.cache
+/config.log
+/config.status
+/libatomic_ops-*
+
+*.a
+*.dll
+*.exe
+*.gcda
+*.gch
+*.gcno
+*.la
+*.lib
+*.lo
+*.o
+*.obj
+*.so
+
+/out/
+
+/src/.deps/
+/src/.dirstamp
+/src/.libs/
+/src/config.h
+/src/config.h.in~
+/src/stamp-h1
+
+/tests/.deps/
+/tests/.dirstamp
+/tests/.libs/
+/tests/core
+/tests/list_atomic.i
+/tests/test_atomic
+/tests/test_atomic_generalized
+/tests/test_atomic_pthreads
+/tests/test_malloc
+/tests/test_stack
+
+# External library (without trailing slash to allow symlinks):
+/pthreads-w32*
+
+# These files are generated by autoreconf:
+/aclocal.m4
+/compile
+/config.guess
+/config.sub
+/configure
+/depcomp
+/install-sh
+/missing
+/mkinstalldirs
+/src/config.h.in
+/test-driver
+Makefile.in
+
+# Generated by libtoolize:
+/libtool
+/ltmain.sh
+/m4/*.m4
+
+# These files are generated by make check:
+/tests/list_atomic.c
+/tests/test_atomic_include.h
+/tests/test*.log
+/tests/test*.trs
+
+# Code analysis tools:
+*.c.gcov
+*.h.gcov
+*.sancov
+/.sv*-dir
+/cov-int
+/coverage.info
+/pvs-project.log
+/pvs-project.tasks
+/strace_out

+ 701 - 0
blitz.mod/bdwgc/libatomic_ops/.travis.yml

@@ -0,0 +1,701 @@
+language: c
+os: linux
+
+jobs:
+  include:
+  - compiler: clang
+  - compiler: gcc
+  - os: osx
+  - env:
+    - COVERITY_SCAN_BRANCH=1
+    addons:
+      coverity_scan:
+        project:
+          name: ivmai/libatomic_ops
+          version: 7.7.0
+        notification_email: [email protected]
+        branch_pattern: master
+        build_command_prepend: CFLAGS=-march=native ./configure
+        build_command: make -j check CFLAGS_EXTRA=-DLINT2
+  - env:
+    - MAKEFILE_TARGET=dist
+  - compiler: clang
+    env:
+    - CFLAGS_EXTRA="-O3 -march=native"
+    - CONF_OPTIONS="--enable-assertions"
+  - compiler: gcc
+    env:
+    - CFLAGS_EXTRA="-O3 -march=native"
+    - CONF_OPTIONS="--enable-assertions"
+  - os: osx
+    env:
+    - CFLAGS_EXTRA="-O3 -march=native -D AO_USE_ALMOST_LOCK_FREE"
+    - CONF_OPTIONS="--enable-assertions"
+  - compiler: clang
+    env:
+    - CFLAGS_EXTRA="-march=native -std=c11"
+  - compiler: clang
+    env:
+    - CFLAGS_EXTRA="-O3 -march=native -std=c11 -D AO_BL_SIZE=4 -D DEFAULT_NTHREADS=32"
+  - compiler: gcc
+    env:
+    - CFLAGS_EXTRA="-march=native -D _FORTIFY_SOURCE=2 -std=c89"
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    compiler: clang
+    env:
+    - CFLAGS_EXTRA="-m32"
+    - CONF_OPTIONS="--enable-assertions"
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    compiler: clang
+    env:
+    - CFLAGS_EXTRA="-m32 -O3 -march=native"
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    compiler: clang
+    env:
+    - CFLAGS_EXTRA="-m32 -march=native"
+    - CONF_OPTIONS="--disable-atomic-intrinsics"
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    compiler: gcc
+    env:
+    - CFLAGS_EXTRA="-m32 -march=native -D AO_USE_ALMOST_LOCK_FREE"
+    - CONF_OPTIONS="--enable-assertions"
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    compiler: gcc
+    env:
+    - CFLAGS_EXTRA="-m32 -march=native"
+    - CONF_OPTIONS="--disable-atomic-intrinsics"
+  - os: osx
+    env:
+    - CFLAGS_EXTRA="-m32 -march=native -D _FORTIFY_SOURCE=2"
+    - CONF_OPTIONS="--enable-assertions"
+  - compiler: gcc
+    env:
+    - CFLAGS_EXTRA="-D AO_GENERALIZE_ASM_BOOL_CAS -D AO_USE_NANOSLEEP -D AO_USE_NO_SIGNALS"
+    - CONF_OPTIONS="--enable-assertions"
+  - compiler: clang
+    env:
+    - CFLAGS_EXTRA="-D AO_STACK_PREFER_CAS_DOUBLE -D AO_USE_PTHREAD_DEFS"
+    - CONF_OPTIONS="--enable-assertions"
+  - compiler: clang
+    env:
+    - CFLAGS_EXTRA="-D DONT_USE_MMAP -O3"
+    - CONF_OPTIONS="--enable-assertions --enable-shared"
+  - addons:
+      apt:
+        packages:
+        - clang-9
+        sources:
+        - ubuntu-toolchain-r-test
+        - sourceline: "deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main"
+          key_url: https://apt.llvm.org/llvm-snapshot.gpg.key
+    compiler: clang-9
+    env:
+    - CFLAGS_EXTRA="-O3 -march=native"
+  - addons:
+      apt:
+        packages:
+        - gcc-9
+        sources:
+        - ubuntu-toolchain-r-test
+    compiler: gcc-9
+    env:
+    - CFLAGS_EXTRA="-O3 -march=native"
+  - addons:
+      apt:
+        packages:
+        - gcc-9
+        sources:
+        - ubuntu-toolchain-r-test
+    compiler: gcc-9
+    env:
+    - CFLAGS_EXTRA="-O3 -march=native"
+  - addons:
+      apt:
+        packages:
+        - gcc-9
+        - gcc-9-multilib
+        sources:
+        - ubuntu-toolchain-r-test
+    compiler: gcc-9
+    env:
+    - CFLAGS_EXTRA="-m32 -O3 -march=native"
+  - addons:
+      apt:
+        packages:
+        - gcc-9
+        - gcc-9-multilib
+        sources:
+        - ubuntu-toolchain-r-test
+    compiler: gcc-9
+    env:
+    - CFLAGS_EXTRA="-mx32 -march=native -D _FORTIFY_SOURCE=2"
+    - CONF_OPTIONS="--enable-assertions --enable-shared"
+  - addons:
+      apt:
+        packages:
+        - gcc-9
+        - gcc-9-multilib
+        sources:
+        - ubuntu-toolchain-r-test
+    compiler: gcc-9
+    env:
+    - CFLAGS_EXTRA="-mx32 -march=native"
+    - CONF_OPTIONS="--disable-atomic-intrinsics --disable-docs"
+  - addons:
+      apt:
+        packages:
+        - clang-9
+        sources:
+        - ubuntu-toolchain-r-test
+        - sourceline: "deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main"
+          key_url: https://apt.llvm.org/llvm-snapshot.gpg.key
+    compiler: clang-9
+    env:
+    - CFLAGS_EXTRA="-fsanitize=address -D AO_USE_ALMOST_LOCK_FREE -fno-omit-frame-pointer"
+    - TESTS_CUSTOM_RUN=true
+  - addons:
+      apt:
+        packages:
+        - clang-9
+        sources:
+        - ubuntu-toolchain-r-test
+        - sourceline: "deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main"
+          key_url: https://apt.llvm.org/llvm-snapshot.gpg.key
+    compiler: clang-9
+    env:
+    - CFLAGS_EXTRA="-fsanitize=address -march=native -fno-common -fno-omit-frame-pointer"
+    - CONF_OPTIONS="--enable-assertions"
+  - compiler: gcc
+    env:
+    - CFLAGS_EXTRA="-fsanitize=address -fno-omit-frame-pointer -D AO_USE_ALMOST_LOCK_FREE -D USE_STANDARD_MALLOC"
+    - CONF_OPTIONS="--enable-assertions"
+  - addons:
+      apt:
+        packages:
+        - gcc-9
+        - gcc-9-multilib
+        sources:
+        - ubuntu-toolchain-r-test
+    compiler: gcc-9
+    env:
+    - CFLAGS_EXTRA="-fsanitize=address -m32 -march=native -fno-omit-frame-pointer"
+    - LDFLAGS="-fuse-ld=gold"
+  - os: osx
+    env:
+    - CFLAGS_EXTRA="-fsanitize=address -m32 -fno-omit-frame-pointer"
+  - addons:
+      apt:
+        packages:
+        - clang-9
+        sources:
+        - ubuntu-toolchain-r-test
+        - sourceline: "deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main"
+          key_url: https://apt.llvm.org/llvm-snapshot.gpg.key
+    compiler: clang-9
+    env:
+    - CFLAGS_EXTRA="-fsanitize=memory,undefined -march=native -fno-omit-frame-pointer"
+    - TESTS_CUSTOM_RUN=true
+  - compiler: clang
+    env:
+    - CFLAGS_EXTRA="-fsanitize=thread -D AO_USE_ALMOST_LOCK_FREE -fno-omit-frame-pointer"
+  - addons:
+      apt:
+        packages:
+        - clang-9
+        sources:
+        - ubuntu-toolchain-r-test
+        - sourceline: "deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main"
+          key_url: https://apt.llvm.org/llvm-snapshot.gpg.key
+    compiler: clang-9
+    env:
+    - CFLAGS_EXTRA="-fsanitize=thread -march=native -fno-omit-frame-pointer"
+    - CONF_OPTIONS="--enable-assertions"
+  - compiler: clang
+    env:
+    - CONF_OPTIONS="--disable-atomic-intrinsics"
+    - CFLAGS_EXTRA="-march=native"
+  - addons:
+      apt:
+        packages:
+        - lcov
+    compiler: gcc
+    env:
+    - CONF_OPTIONS="--enable-gcov --enable-shared"
+    - REPORT_COVERAGE=true
+    - CFLAGS_EXTRA="-march=native -D DEBUG_RUN_ONE_TEST -D VERBOSE"
+  - env:
+    - CPPCHECK_ENABLE="-j16 -q --enable=information,performance,portability,style,warning"
+    - MAKEFILE_TARGET=all
+  - env:
+    - CPPCHECK_ENABLE="-q --enable=unusedFunction -D AO_TEST_EMULATION"
+    - MAKEFILE_TARGET=all
+  - compiler: clang
+    env:
+    - CSA_CHECK=true
+    - MAKEFILE_TARGET=all
+    - CFLAGS_EXTRA="-D AO_TRACE_MALLOC -D HAVE_MMAP -D VERBOSE"
+  - compiler: clang
+    env:
+    - CFLAGS_EXTRA="-x c++ -march=native -D VERBOSE"
+    - CONF_OPTIONS="--enable-assertions"
+    - MAKEFILE_TARGET=all
+  - compiler: gcc
+    env:
+    - CC_FOR_CHECK=g++
+    - MAKEFILE_TARGET=all
+  - addons:
+      apt:
+        packages:
+        - musl-tools
+    compiler: musl-gcc
+    env:
+    - CFLAGS_EXTRA="-march=native"
+    - CONF_OPTIONS="--enable-assertions"
+  - addons:
+      apt:
+        packages:
+        - gcc-mingw-w64
+    compiler: x86_64-w64-mingw32-gcc
+    env:
+    - CONF_OPTIONS="--host=x86_64-w64-mingw32 --enable-shared"
+    - MAKEFILE_TARGET=all
+  - addons:
+      apt:
+        packages:
+        - gcc-mingw-w64
+    compiler: i686-w64-mingw32-gcc
+    env:
+    - CONF_OPTIONS="--host=i686-w64-mingw32"
+    - MAKEFILE_TARGET=all
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=aarch64-linux
+    - CFLAGS_EXTRA="-mabi=ilp32"
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=alpha-linux
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=arm-linux-gnueabi
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=arm-linux-gnueabi
+    - CFLAGS_EXTRA="-D AO_DISABLE_GCC_ATOMICS"
+  - addons:
+      apt:
+        packages:
+        - gcc-4.6
+        - gcc-multilib
+        sources:
+        - ubuntu-toolchain-r-test
+    compiler: gcc-4.6
+    env:
+    - CROSS_GCC_VER=4.2.4
+    - NOLIBC_ARCH_ABI=avr32-linux
+    - NOLIBC_DELIM=_
+    - CFLAGS_EXTRA="-fno-strict-aliasing"
+  - addons:
+      apt:
+        packages:
+        - gcc-4.6
+        - gcc-multilib
+        sources:
+        - ubuntu-toolchain-r-test
+    compiler: gcc-4.6
+    env:
+    - CROSS_GCC_VER=4.6.3
+    - NOLIBC_ARCH_ABI=cris-linux
+    - NOLIBC_DELIM=_
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=hppa-linux
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=ia64-linux
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=m68k-linux
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=mips-linux
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=mips-linux
+    - CFLAGS_EXTRA="-D AO_DISABLE_GCC_ATOMICS"
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=mips64-linux
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=nios2-linux
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=powerpc-linux
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=powerpc-linux
+    - CFLAGS_EXTRA="-D AO_DISABLE_GCC_ATOMICS"
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=powerpc64-linux
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=riscv32-linux
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=riscv64-linux
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=s390-linux
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=sh2-linux
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=sh4-linux
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=sparc-linux
+    - CFLAGS_EXTRA="-D AO_NO_SPARC_V9"
+  - addons:
+      apt:
+        packages:
+        - gcc-multilib
+    env:
+    - CROSS_GCC_VER=8.1.0
+    - NOLIBC_ARCH_ABI=sparc64-linux
+  - addons:
+      apt:
+        packages:
+        - gcc-4.6
+        - gcc-multilib
+        sources:
+        - ubuntu-toolchain-r-test
+    compiler: gcc-4.6
+    env:
+    - CROSS_GCC_VER=4.6.2
+    - NOLIBC_ARCH_ABI=tilegx-linux
+    - NOLIBC_DELIM=_
+  - arch: arm64
+    compiler: clang
+  - arch: arm64
+    compiler: gcc
+  - addons:
+      apt:
+        packages:
+        - clang-8
+        sources:
+        - ubuntu-toolchain-r-test
+    arch: arm64
+    compiler: clang-8
+    env:
+    - CFLAGS_EXTRA="-O3"
+    - CONF_OPTIONS="--enable-assertions"
+    - TESTS_CUSTOM_RUN=true
+  - addons:
+      apt:
+        packages:
+        - clang-8
+        sources:
+        - ubuntu-toolchain-r-test
+    arch: arm64
+    compiler: clang-8
+    env:
+    - CFLAGS_EXTRA="-O3 -D AO_AARCH64_ASM_LOAD_STORE_CAS -D AO_PREFER_BUILTIN_ATOMICS"
+    - TESTS_CUSTOM_RUN=true
+  - addons:
+      apt:
+        packages:
+        - gcc-9
+        sources:
+        - ubuntu-toolchain-r-test
+    arch: arm64
+    compiler: gcc-9
+    env:
+    - CFLAGS_EXTRA="-O3 -march=native"
+    - CONF_OPTIONS="--enable-shared"
+    - TESTS_CUSTOM_RUN=true
+  - addons:
+      apt:
+        packages:
+        - clang-8
+        sources:
+        - ubuntu-toolchain-r-test
+    arch: arm64
+    compiler: clang-8
+    env:
+    - CFLAGS_EXTRA="-fsanitize=address -fno-omit-frame-pointer"
+    - TESTS_CUSTOM_RUN=true
+  - addons:
+      apt:
+        packages:
+        - musl-tools
+    arch: arm64
+    compiler: musl-gcc
+    env:
+    - CFLAGS_EXTRA="-O3"
+    - TESTS_CUSTOM_RUN=true
+  - arch: ppc64le
+    compiler: clang
+  - arch: ppc64le
+    compiler: gcc
+  - arch: ppc64le
+    compiler: clang
+    env:
+    - CFLAGS_EXTRA="-O3"
+    - CONF_OPTIONS="--enable-assertions --disable-atomic-intrinsics"
+    - TESTS_CUSTOM_RUN=true
+  - arch: ppc64le
+    compiler: gcc
+    env:
+    - CFLAGS_EXTRA="-O3"
+    - CONF_OPTIONS="--disable-atomic-intrinsics"
+    - TESTS_CUSTOM_RUN=true
+  - addons:
+      apt:
+        packages:
+        - clang-8
+        sources:
+        - ubuntu-toolchain-r-test
+    arch: ppc64le
+    compiler: clang-8
+    env:
+    - CFLAGS_EXTRA="-O3"
+    - CONF_OPTIONS="--enable-assertions --enable-shared"
+    - TESTS_CUSTOM_RUN=true
+  - addons:
+      apt:
+        packages:
+        - gcc-9
+        sources:
+        - ubuntu-toolchain-r-test
+    arch: ppc64le
+    compiler: gcc-9
+    env:
+    - CFLAGS_EXTRA="-O3"
+    - TESTS_CUSTOM_RUN=true
+  - arch: s390x
+    compiler: clang
+  - arch: s390x
+    compiler: gcc
+  - addons:
+      apt:
+        packages:
+        - clang-8
+        sources:
+        - ubuntu-toolchain-r-test
+    arch: s390x
+    compiler: clang-8
+    env:
+    - CFLAGS_EXTRA="-O3"
+    - CONF_OPTIONS="--enable-assertions --enable-shared"
+    - TESTS_CUSTOM_RUN=true
+  - addons:
+      apt:
+        packages:
+        - gcc-9
+        sources:
+        - ubuntu-toolchain-r-test
+    arch: s390x
+    compiler: gcc-9
+    env:
+    - CFLAGS_EXTRA="-O3"
+    - TESTS_CUSTOM_RUN=true
+  - env:
+    - MAKEFILE_TARGET=distcheck
+    - AUTOMAKE_VER=1.15
+    - M4_VER=1.4.18
+    - LIBTOOL_VER=2.4.6
+
+before_install:
+- if [[ "$CPPCHECK_ENABLE" != "" ]]; then
+    CPPCHECK_VER=main;
+    git clone --depth=3 https://github.com/danmar/cppcheck.git
+            ~/cppcheck -b $CPPCHECK_VER;
+    make --directory ~/cppcheck -j8 CXXFLAGS="-O3 -march=native -D NDEBUG";
+  fi
+- if [[ "$CROSS_GCC_VER" != "" ]]; then
+    if [[ "$NOLIBC_DELIM" == "" ]]; then NOLIBC_DELIM=-; fi;
+    BUILD_ARCH=x86_64;
+    TAR_FOLDER_URL=https://www.kernel.org/pub/tools/crosstool/files/bin/$BUILD_ARCH/$CROSS_GCC_VER;
+    TARFILE=$BUILD_ARCH-gcc-$CROSS_GCC_VER-nolibc$NOLIBC_DELIM$NOLIBC_ARCH_ABI.tar.xz;
+    wget -O - $TAR_FOLDER_URL/$TARFILE | tar xf - --xz --directory ~;
+    CROSS_CC=~/gcc-$CROSS_GCC_VER-nolibc/$NOLIBC_ARCH_ABI/bin/$NOLIBC_ARCH_ABI-gcc;
+    export C_INCLUDE_PATH=/usr/include;
+    MAKEFILE_TARGET=check-nolink;
+  fi
+- if [[ "$AUTOMAKE_VER" != "" || "$LIBTOOL_VER" != "" || "$M4_VER" != "" ]]; then
+    GNUTOOLS_ROOT=`pwd`/../gnu-tools;
+    export PATH=$GNUTOOLS_ROOT/bin:$PATH;
+    GNU_DOWNLOAD_SITE=https://ftp.gnu.org/gnu;
+  fi
+- if [[ "$M4_VER" != "" ]]; then
+    M4_XZ_URL=$GNU_DOWNLOAD_SITE/m4/m4-$M4_VER.tar.xz;
+    wget -O - $M4_XZ_URL | tar xf - --xz --directory ~;
+    (cd ~/m4-$M4_VER && ./configure --prefix=$GNUTOOLS_ROOT && make -j check && make install);
+  fi
+- if [[ "$LIBTOOL_VER" != "" ]]; then
+    LIBTOOL_XZ_URL=$GNU_DOWNLOAD_SITE/libtool/libtool-$LIBTOOL_VER.tar.xz;
+    wget -O - $LIBTOOL_XZ_URL | tar xf - --xz --directory ~;
+    (cd ~/libtool-$LIBTOOL_VER && ./configure --prefix=$GNUTOOLS_ROOT && make -j && make install);
+  fi
+- if [[ "$AUTOMAKE_VER" != "" ]]; then
+    AUTOMAKE_XZ_URL=$GNU_DOWNLOAD_SITE/automake/automake-$AUTOMAKE_VER.tar.xz;
+    wget -O - $AUTOMAKE_XZ_URL | tar xf - --xz --directory ~;
+    (cd ~/automake-$AUTOMAKE_VER && ./configure --prefix=$GNUTOOLS_ROOT && make -j && make install);
+  fi
+- if [[ "$MAKEFILE_TARGET" == "dist"* ]]; then
+    autoconf --version;
+    automake --version;
+    m4 --version;
+    libtool --version || true;
+  fi
+- if [[ "$MAKEFILE_TARGET" == "" ]]; then MAKEFILE_TARGET=check; fi
+
+install:
+- "./autogen.sh"
+- if [[ "$REPORT_COVERAGE" == true ]]; then gem install coveralls-lcov; fi
+
+script:
+- if [[ "$COVERITY_SCAN_BRANCH" != 1 ]]; then
+    ./configure $CONF_OPTIONS --enable-werror;
+  fi
+- if [[ "$CSA_CHECK" != true && "$CPPCHECK_ENABLE" == ""
+        && "$COVERITY_SCAN_BRANCH" != 1 ]]; then
+    cat src/config.h;
+  fi
+- if [[ "$CROSS_GCC_VER" != "" ]]; then CC=$CROSS_CC; fi
+- if [[ "$COVERITY_SCAN_BRANCH" != 1 ]]; then
+    make -j $MAKEFILE_TARGET CC=$CC CFLAGS_EXTRA="$CFLAGS_EXTRA"
+            LDFLAGS="$LDFLAGS";
+  fi
+- if [[ "$CC_FOR_CHECK" != "" ]]; then
+    make check CC=$CC_FOR_CHECK CFLAGS_EXTRA="$CFLAGS_EXTRA";
+  fi
+- if [ -f tests/test_atomic.log ]; then cat tests/test_atomic*.log; fi
+- if [[ "$CSA_CHECK" == true ]]; then
+    ${CC} --analyze -Xanalyzer -analyzer-output=text -Werror -I src
+          $CFLAGS_EXTRA tests/*.c src/*.c;
+  fi
+- if [[ "$CPPCHECK_ENABLE" != "" ]]; then
+    ~/cppcheck/cppcheck -f --error-exitcode=2 -D CPPCHECK -I src
+        $CPPCHECK_ENABLE src/*.c tests/test_malloc.c tests/test_stack.c;
+  fi
+- if [[ "$TESTS_CUSTOM_RUN" == true ]]; then
+    ASAN_OPTIONS="detect_leaks=1" UBSAN_OPTIONS="halt_on_error=1"
+        make -C tests check-without-test-driver;
+  fi
+
+after_success:
+- if [[ "$REPORT_COVERAGE" == true ]]; then
+    lcov --capture --directory src --directory tests --output-file coverage.info;
+    lcov --remove coverage.info '/usr/*' 'tests/*' --output-file coverage.info;
+    lcov --list coverage.info;
+    coveralls-lcov --repo-token ${COVERALLS_TOKEN} coverage.info;
+    bash <(curl -s https://codecov.io/bash);
+  fi
+
+deploy:
+  provider: releases
+  edge: true
+  file: libatomic_ops-*.tar.gz
+  file_glob: true
+  on:
+    condition: $MAKEFILE_TARGET = distcheck
+    repo: ivmai/libatomic_ops
+    tags: true

+ 2 - 0
blitz.mod/bdwgc/libatomic_ops/AUTHORS

@@ -3,6 +3,7 @@ imported from the Boehm-Demers-Weiser GC, where it was contributed
 by many others.
 Currently maintained by Ivan Maidanski.
 
+Alexey Pavlov <[email protected]>
 Andreas Tobler <[email protected]>
 Andrew Agno <[email protected]>
 Andy Li <[email protected]>
@@ -16,6 +17,7 @@ Earl Chew <[email protected]>
 Emmanuel Stapf <[email protected]>
 Fabrizio Fabbri <[email protected]>
 Frank Schaefer <[email protected]>
+Frederic Recoules <[email protected]>
 Gilles Talis <[email protected]>
 Gregory Farnum <[email protected]>
 H.J. Lu <[email protected]>

+ 24 - 0
blitz.mod/bdwgc/libatomic_ops/ChangeLog

@@ -1,4 +1,19 @@
 
+== [7.6.12] (not released yet) ==
+
+* Describe double_compare_and_swap operation in README_details
+* Document CAS operations better in README_details
+* Fix gcc/sunc x86 AO_compare_double_and_swap_double missing side effect
+* Fix library name in README_details
+* Refactor gcc x86 memory constraints
+* Refine and reformat description of size prefix in README_details
+* Remove outdated notes in README_details
+* Replace x86 setz instruction by asm flag output operand (gcc)
+* Support MSYS host (configure)
+* Turn off compare_double_and_swap_double_full PIC hack for GCC 5+ (x86)
+* Update README_win32 to match Makefile.msft
+
+
 == [7.6.10] 2019-03-01 ==
 
 * Eliminate 'my_chunk_ptr-AO_initial_heap out of bounds' cppcheck warning
@@ -150,6 +165,12 @@ Also, includes 7.4.8 changes
 Also, includes 7.4.6 changes
 
 
+== [7.4.16] (not released yet) ==
+
+* Fix gcc/sunc x86 AO_compare_double_and_swap_double missing side effect
+* Fix library name in README_details
+
+
 == [7.4.14] 2019-03-01 ==
 
 * Fix 'AO_*_TS_T is not defined' compiler warnings (GCC-8)
@@ -370,6 +391,9 @@ Also, includes 7.2 changes
 == [7.2j] (not released yet) ==
 
 * Fix a typo in arm_v6.h
+* Fix asm constraints of primitives in sunc/x86_64.h
+* Fix gcc/sunc x86 AO_compare_double_and_swap_double missing side effect
+* Fix library name in README details
 
 
 == [7.2i] 2017-12-21 ==

+ 10 - 2
blitz.mod/bdwgc/libatomic_ops/README.md

@@ -2,7 +2,15 @@
 
 IN NEW CODE, PLEASE USE C11 OR C++14 STANDARD ATOMICS INSTEAD OF THIS PACKAGE.
 
-This is version 7.6.10 of libatomic_ops.
+[![Travis-CI build status](https://travis-ci.org/ivmai/libatomic_ops.svg?branch=master)](https://travis-ci.org/ivmai/libatomic_ops)
+[![AppVeyor CI build status](https://ci.appveyor.com/api/projects/status/github/ivmai/libatomic_ops?branch=master&svg=true)](https://ci.appveyor.com/project/ivmai/libatomic-ops)
+[![Codecov.io](https://codecov.io/github/ivmai/libatomic_ops/coverage.svg?branch=master)](https://codecov.io/github/ivmai/libatomic_ops?branch=master)
+[![Coveralls test coverage status](https://coveralls.io/repos/ivmai/libatomic_ops/badge.png?branch=master)](https://coveralls.io/github/ivmai/libatomic_ops)
+[![Coverity Scan build status](https://scan.coverity.com/projects/10809/badge.svg)](https://scan.coverity.com/projects/ivmai-libatomic_ops)
+[![LGTM Code Quality: Cpp](https://img.shields.io/lgtm/grade/cpp/g/ivmai/libatomic_ops.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/ivmai/libatomic_ops/context:cpp)
+[![LGTM Total Alerts](https://img.shields.io/lgtm/alerts/g/ivmai/libatomic_ops.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/ivmai/libatomic_ops/alerts)
+
+This is version 7.7.0 (next release development) of libatomic_ops.
 
 
 ## Download
@@ -99,7 +107,7 @@ GitHub.
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
  * Copyright (c) 1999-2011 Hewlett-Packard Development Company, L.P.
- * Copyright (c) 2008-2018 Ivan Maidanski
+ * Copyright (c) 2008-2019 Ivan Maidanski
 
 The file armcc/arm_v6.h is also
 

+ 26 - 0
blitz.mod/bdwgc/libatomic_ops/appveyor.yml

@@ -0,0 +1,26 @@
+version: 7.7.0-{build}
+
+clone_depth: 50
+
+environment:
+  MS_SDK_VER: v7.1
+  matrix:
+  - CPU: x86
+    BLD: debug
+    CFLAGS_EXTRA: -DAO_ASSUME_VISTA -DAO_USE_PENTIUM4_INSTRS
+  - CPU: x86
+    BLD: release
+  - CPU: x64
+    BLD: debug
+    CFLAGS_EXTRA: -DAO_CMPXCHG16B_AVAILABLE
+  - CPU: x64
+    BLD: release
+
+install:
+  - cmd: '"C:\Program Files\Microsoft SDKs\Windows\%MS_SDK_VER%\Bin\SetEnv.cmd" /%CPU% /%BLD%'
+
+build_script:
+  - cmd: cd src && nmake -f Makefile.msft clean all CFLAGS_EXTRA="%CFLAGS_EXTRA%" && cd ..
+
+test_script:
+  - cmd: cd src && nmake -f Makefile.msft check-noautogen CFLAGS_EXTRA="%CFLAGS_EXTRA%"

+ 4 - 4
blitz.mod/bdwgc/libatomic_ops/configure.ac

@@ -1,5 +1,5 @@
 # Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P.
-# Copyright (c) 2009-2018 Ivan Maidanski
+# Copyright (c) 2009-2019 Ivan Maidanski
 #
 # THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 # OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -12,7 +12,7 @@
 
 dnl Process this file with autoconf to produce configure.
 
-AC_INIT([libatomic_ops],[7.6.10],https://github.com/ivmai/libatomic_ops/issues)
+AC_INIT([libatomic_ops],[7.7.0],https://github.com/ivmai/libatomic_ops/issues)
 
 AC_PREREQ(2.61)
 AC_CANONICAL_TARGET([])
@@ -42,7 +42,7 @@ if test "$GCC" = yes; then
   fi
 
   case "$host" in
-    *-*-cygwin* | *-*-mingw*)
+    *-*-cygwin* | *-*-mingw* | *-*-msys*)
       # Cygwin and Mingw[-w32/64] do not need -fPIC.
       AC_MSG_RESULT([not needed])
       ;;
@@ -219,7 +219,7 @@ if test x$have_pthreads = xtrue; then
       # against it.
       THREADDLLIBS=
       ;;
-    *-*-mingw*)
+    *-*-mingw* | *-*-msys*)
       # Use Win32 threads for tests anyway.
       THREADDLLIBS=
       # Skip test_atomic_pthreads.

+ 31 - 35
blitz.mod/bdwgc/libatomic_ops/doc/README_details.txt

@@ -13,7 +13,7 @@ are normally built.  On Windows, read README_win32.txt instead.
 are implemented by header files included from it.  It is sometimes
 necessary, and always recommended to also link against libatomic_ops.a.
 To use the almost non-blocking stack or malloc implementations,
-see the corresponding README files, and also link against libatomic_gpl.a
+see the corresponding README files, and also link against libatomic_ops_gpl.a
 before linking against libatomic_ops.a.
 
 OVERVIEW:
@@ -26,9 +26,9 @@ similar goals, since they usually do not handle differences in memory
 barrier styles with sufficient generality.
 
 If this is included after defining AO_REQUIRE_CAS, then the package makes
-an attempt to emulate AO_compare_and_swap* (single-width) in a way that (at
-least on Linux) should still be async-signal-safe.  As a result, most other
-atomic operations will then be defined using the compare-and-swap
+an attempt to emulate [fetch_]compare_and_swap* (single-width) in a way that,
+at least on Linux, should still be async-signal-safe.  As a result, most
+other atomic operations may then be defined using the compare-and-swap
 emulation.  This emulation is slow, since it needs to disable signals.
 And it needs to block in case of contention.  If you care about performance
 on a platform that can't directly provide compare-and-swap, there are
@@ -48,31 +48,25 @@ to use.  Current real implementations appear to be much better behaved.)
 We of course are in no position to guarantee that future processors
 (even HPs) will continue to behave this way, though we hope they will.
 
-This is a work in progress.  Corrections/additions for other platforms are
-greatly appreciated.  It passes rudimentary tests on X86, Itanium, and
-Alpha.
+Corrections/additions for other platforms are greatly appreciated.
 
 OPERATIONS:
 
-Most operations operate on values of type AO_t, which are unsigned integers
-whose size matches that of pointers on the given architecture.  Exceptions
-are:
+Most operations handle values of type AO_t, which are unsigned integers
+whose size matches that of pointers on the given architecture.  Additionally,
+on most supported architectures the operations are also implemented to handle
+smaller integers types; such operations are indicated by the appropriate size
+prefix:
+- char_... Operates on unsigned char values;
+- short_... Operates on unsigned short values;
+- int_... Operates on unsigned int values.
 
-- AO_test_and_set operates on AO_TS_t, which is whatever size the hardware
-supports with good performance.  In some cases this is the length of a cache
-line.  In some cases it is a byte.  In many cases it is equivalent to AO_t.
+The notable exception is AO_test_and_set operating only on AO_TS_t, which is
+whatever size the hardware supports with good performance.  In some cases this
+is the length of a cache line, in some other cases it is a byte.  In many
+cases AO_TS_t is equivalent to AO_t.
 
-- A few operations are implemented on smaller or larger size integers.
-Such operations are indicated by the appropriate prefix:
-
-AO_char_... Operates on unsigned char values.
-AO_short_... Operates on unsigned short values.
-AO_int_... Operates on unsigned int values.
-
-(Currently a very limited selection of these is implemented.  We're
-working on it.)
-
-The defined operations are all of the form AO_[<size>_]<op><barrier>(<args>).
+The defined operations are all of the form AO_[<size>]<op><barrier>(<args>).
 
 The <op> component specifies an atomic memory operation.  It may be
 one of the following, where the corresponding argument and result types
@@ -98,11 +92,12 @@ void xor(volatile AO_t *addr, AO_t value)
         Atomically 'xor' value into *addr.
 int compare_and_swap(volatile AO_t * addr, AO_t old_val, AO_t new_val)
         Atomically compare *addr to old_val, and replace *addr by new_val
-        if the first comparison succeeds.  Returns nonzero if the comparison
-        succeeded and *addr was updated.
+        if the first comparison succeeds; returns nonzero if the comparison
+        succeeded and *addr was updated; cannot fail spuriously.
 AO_t fetch_compare_and_swap(volatile AO_t * addr, AO_t old_val, AO_t new_val)
         Atomically compare *addr to old_val, and replace *addr by new_val
-        if the first comparison succeeds; returns the original value of *addr.
+        if the first comparison succeeds; returns the original value of *addr;
+        cannot fail spuriously.
 AO_TS_VAL_t test_and_set(volatile AO_TS_t * addr)
         Atomically read the binary value at *addr, and set it.  AO_TS_VAL_t
         is an enumeration type which includes two values AO_TS_SET and
@@ -138,7 +133,11 @@ int compare_and_swap_double(volatile AO_double_t * addr,
 where AO_double_t is a structure containing AO_val1 and AO_val2 fields,
 both of type AO_t.  For compare_and_swap_double, we compare against
 the val1 field.  AO_double_t exists only if AO_HAVE_double_t
-is defined.
+is defined.  If this type is available then the following operation is
+provided for convenience, fully equivalent to compare_double_and_swap_double:
+
+int double_compare_and_swap(volatile AO_double_t * addr,
+                            AO_double_t old_val, AO_double_t new_val)
 
 Please note that AO_double_t (and AO_stack_t) variables should be properly
 aligned (8-byte alignment on 32-bit targets, 16-byte alignment on 64-bit ones)
@@ -148,7 +147,8 @@ passed (as a reference) to the primitive.  Global and static variables should
 already have proper alignment automatically but automatic variables (i.e.
 located on the stack) might be misaligned because the stack might be
 word-aligned (e.g. 4-byte stack alignment is the default one for x86).
-Luckily, stack-allocated AO variables is a rare case in practice.
+Luckily, stack-allocated AO variables operated atomically are used rarely
+in practice.
 
 ORDERING CONSTRAINTS:
 
@@ -195,8 +195,8 @@ _dd_acquire_read: Ordered with respect to later reads that are data
 We assume that if a store is data-dependent on a previous load, then
 the two are always implicitly ordered.
 
-It is possible to test whether AO_<op><barrier> is available on the
-current platform by checking whether AO_HAVE_<op>_<barrier> is defined
+It is possible to test whether AO_[<size>]<op><barrier> is available on the
+target platform by checking whether AO_HAVE_[<size>]<op><barrier> is defined
 as a macro.
 
 Note that we generally don't implement operations that are either
@@ -224,10 +224,6 @@ constraints, and if and how we can guarantee sequential consistency.
 Dd_acquire_read is very hard or impossible to define in a way that cannot
 be invalidated by reasonably standard compiler transformations.
 
-There is probably no good reason to provide operations on standard
-integer types, since those may have the wrong alignment constraints.
-
-
 Example:
 
 If you want to initialize an object, and then "publish" a pointer to it

+ 5 - 8
blitz.mod/bdwgc/libatomic_ops/doc/README_win32.txt

@@ -1,19 +1,16 @@
 Most of the atomic_ops functionality is available under Win32 with
-the Microsoft tools, but the build process currently is considerably more
-primitive than on Linux/Unix platforms.
+the Microsoft tools, but the build process is more primitive than that on
+Linux/Unix platforms.
 
 To build:
-
 1) Go to the src directory in the distribution.
 2) Make sure the Microsoft command-line tools (e.g. nmake) are available.
-3) Run "nmake -f Makefile.msft".  This should run some tests, which
-may print warnings about the types of the "Interlocked" functions.
-I haven't been able to make all versions of VC++ happy.  If you know
-how to, please send a patch.
+3) Run "nmake -f Makefile.msft check".  This should build libatomic_ops_gpl.lib
+and run some tests.
 4) To compile applications, you will need to retain or copy the following
 pieces from the resulting src directory contents:
         "atomic_ops.h" - Header file defining low-level primitives.  This
-                         includes files from:
+                         includes files from the following folder.
         "atomic_ops"- Subdirectory containing implementation header files.
         "atomic_ops_stack.h" - Header file describing almost lock-free stack.
         "atomic_ops_malloc.h" - Header file describing almost lock-free malloc.

+ 3 - 0
blitz.mod/bdwgc/libatomic_ops/m4/.gitignore

@@ -0,0 +1,3 @@
+# Place holder to keep this directory in the Git repository.
+*
+!.gitignore

+ 2 - 2
blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/ao_version.h

@@ -34,5 +34,5 @@
 
 /* The version here should match that in configure.ac and README.       */
 #define AO_VERSION_MAJOR 7
-#define AO_VERSION_MINOR 6
-#define AO_VERSION_MICRO 10 /* 7.6.10 */
+#define AO_VERSION_MINOR 7
+#define AO_VERSION_MICRO 0 /* 7.7.0 */

+ 64 - 0
blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/sysdeps/gcc/generic-arithm.h

@@ -15,6 +15,8 @@
  *
  */
 
+#ifndef AO_NO_char_ARITHM
+
 AO_INLINE unsigned/**/char
 AO_char_fetch_and_add(volatile unsigned/**/char *addr, unsigned/**/char incr)
 {
@@ -48,6 +50,8 @@ AO_char_fetch_and_add(volatile unsigned/**/char *addr, unsigned/**/char incr)
   }
 # define AO_HAVE_char_xor
 #endif
+
+#endif /* !AO_NO_char_ARITHM */
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
@@ -65,6 +69,8 @@ AO_char_fetch_and_add(volatile unsigned/**/char *addr, unsigned/**/char incr)
  *
  */
 
+#ifndef AO_NO_short_ARITHM
+
 AO_INLINE unsigned/**/short
 AO_short_fetch_and_add(volatile unsigned/**/short *addr, unsigned/**/short incr)
 {
@@ -98,6 +104,8 @@ AO_short_fetch_and_add(volatile unsigned/**/short *addr, unsigned/**/short incr)
   }
 # define AO_HAVE_short_xor
 #endif
+
+#endif /* !AO_NO_short_ARITHM */
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
@@ -115,6 +123,8 @@ AO_short_fetch_and_add(volatile unsigned/**/short *addr, unsigned/**/short incr)
  *
  */
 
+#ifndef AO_NO_int_ARITHM
+
 AO_INLINE unsigned
 AO_int_fetch_and_add(volatile unsigned *addr, unsigned incr)
 {
@@ -148,6 +158,8 @@ AO_int_fetch_and_add(volatile unsigned *addr, unsigned incr)
   }
 # define AO_HAVE_int_xor
 #endif
+
+#endif /* !AO_NO_int_ARITHM */
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
@@ -165,6 +177,8 @@ AO_int_fetch_and_add(volatile unsigned *addr, unsigned incr)
  *
  */
 
+#ifndef AO_NO_ARITHM
+
 AO_INLINE AO_t
 AO_fetch_and_add(volatile AO_t *addr, AO_t incr)
 {
@@ -198,6 +212,8 @@ AO_fetch_and_add(volatile AO_t *addr, AO_t incr)
   }
 # define AO_HAVE_xor
 #endif
+
+#endif /* !AO_NO_ARITHM */
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
@@ -215,6 +231,8 @@ AO_fetch_and_add(volatile AO_t *addr, AO_t incr)
  *
  */
 
+#ifndef AO_NO_char_ARITHM
+
 AO_INLINE unsigned/**/char
 AO_char_fetch_and_add_acquire(volatile unsigned/**/char *addr, unsigned/**/char incr)
 {
@@ -248,6 +266,8 @@ AO_char_fetch_and_add_acquire(volatile unsigned/**/char *addr, unsigned/**/char
   }
 # define AO_HAVE_char_xor_acquire
 #endif
+
+#endif /* !AO_NO_char_ARITHM */
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
@@ -265,6 +285,8 @@ AO_char_fetch_and_add_acquire(volatile unsigned/**/char *addr, unsigned/**/char
  *
  */
 
+#ifndef AO_NO_short_ARITHM
+
 AO_INLINE unsigned/**/short
 AO_short_fetch_and_add_acquire(volatile unsigned/**/short *addr, unsigned/**/short incr)
 {
@@ -298,6 +320,8 @@ AO_short_fetch_and_add_acquire(volatile unsigned/**/short *addr, unsigned/**/sho
   }
 # define AO_HAVE_short_xor_acquire
 #endif
+
+#endif /* !AO_NO_short_ARITHM */
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
@@ -315,6 +339,8 @@ AO_short_fetch_and_add_acquire(volatile unsigned/**/short *addr, unsigned/**/sho
  *
  */
 
+#ifndef AO_NO_int_ARITHM
+
 AO_INLINE unsigned
 AO_int_fetch_and_add_acquire(volatile unsigned *addr, unsigned incr)
 {
@@ -348,6 +374,8 @@ AO_int_fetch_and_add_acquire(volatile unsigned *addr, unsigned incr)
   }
 # define AO_HAVE_int_xor_acquire
 #endif
+
+#endif /* !AO_NO_int_ARITHM */
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
@@ -365,6 +393,8 @@ AO_int_fetch_and_add_acquire(volatile unsigned *addr, unsigned incr)
  *
  */
 
+#ifndef AO_NO_ARITHM
+
 AO_INLINE AO_t
 AO_fetch_and_add_acquire(volatile AO_t *addr, AO_t incr)
 {
@@ -398,6 +428,8 @@ AO_fetch_and_add_acquire(volatile AO_t *addr, AO_t incr)
   }
 # define AO_HAVE_xor_acquire
 #endif
+
+#endif /* !AO_NO_ARITHM */
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
@@ -415,6 +447,8 @@ AO_fetch_and_add_acquire(volatile AO_t *addr, AO_t incr)
  *
  */
 
+#ifndef AO_NO_char_ARITHM
+
 AO_INLINE unsigned/**/char
 AO_char_fetch_and_add_release(volatile unsigned/**/char *addr, unsigned/**/char incr)
 {
@@ -448,6 +482,8 @@ AO_char_fetch_and_add_release(volatile unsigned/**/char *addr, unsigned/**/char
   }
 # define AO_HAVE_char_xor_release
 #endif
+
+#endif /* !AO_NO_char_ARITHM */
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
@@ -465,6 +501,8 @@ AO_char_fetch_and_add_release(volatile unsigned/**/char *addr, unsigned/**/char
  *
  */
 
+#ifndef AO_NO_short_ARITHM
+
 AO_INLINE unsigned/**/short
 AO_short_fetch_and_add_release(volatile unsigned/**/short *addr, unsigned/**/short incr)
 {
@@ -498,6 +536,8 @@ AO_short_fetch_and_add_release(volatile unsigned/**/short *addr, unsigned/**/sho
   }
 # define AO_HAVE_short_xor_release
 #endif
+
+#endif /* !AO_NO_short_ARITHM */
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
@@ -515,6 +555,8 @@ AO_short_fetch_and_add_release(volatile unsigned/**/short *addr, unsigned/**/sho
  *
  */
 
+#ifndef AO_NO_int_ARITHM
+
 AO_INLINE unsigned
 AO_int_fetch_and_add_release(volatile unsigned *addr, unsigned incr)
 {
@@ -548,6 +590,8 @@ AO_int_fetch_and_add_release(volatile unsigned *addr, unsigned incr)
   }
 # define AO_HAVE_int_xor_release
 #endif
+
+#endif /* !AO_NO_int_ARITHM */
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
@@ -565,6 +609,8 @@ AO_int_fetch_and_add_release(volatile unsigned *addr, unsigned incr)
  *
  */
 
+#ifndef AO_NO_ARITHM
+
 AO_INLINE AO_t
 AO_fetch_and_add_release(volatile AO_t *addr, AO_t incr)
 {
@@ -598,6 +644,8 @@ AO_fetch_and_add_release(volatile AO_t *addr, AO_t incr)
   }
 # define AO_HAVE_xor_release
 #endif
+
+#endif /* !AO_NO_ARITHM */
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
@@ -615,6 +663,8 @@ AO_fetch_and_add_release(volatile AO_t *addr, AO_t incr)
  *
  */
 
+#ifndef AO_NO_char_ARITHM
+
 AO_INLINE unsigned/**/char
 AO_char_fetch_and_add_full(volatile unsigned/**/char *addr, unsigned/**/char incr)
 {
@@ -648,6 +698,8 @@ AO_char_fetch_and_add_full(volatile unsigned/**/char *addr, unsigned/**/char inc
   }
 # define AO_HAVE_char_xor_full
 #endif
+
+#endif /* !AO_NO_char_ARITHM */
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
@@ -665,6 +717,8 @@ AO_char_fetch_and_add_full(volatile unsigned/**/char *addr, unsigned/**/char inc
  *
  */
 
+#ifndef AO_NO_short_ARITHM
+
 AO_INLINE unsigned/**/short
 AO_short_fetch_and_add_full(volatile unsigned/**/short *addr, unsigned/**/short incr)
 {
@@ -698,6 +752,8 @@ AO_short_fetch_and_add_full(volatile unsigned/**/short *addr, unsigned/**/short
   }
 # define AO_HAVE_short_xor_full
 #endif
+
+#endif /* !AO_NO_short_ARITHM */
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
@@ -715,6 +771,8 @@ AO_short_fetch_and_add_full(volatile unsigned/**/short *addr, unsigned/**/short
  *
  */
 
+#ifndef AO_NO_int_ARITHM
+
 AO_INLINE unsigned
 AO_int_fetch_and_add_full(volatile unsigned *addr, unsigned incr)
 {
@@ -748,6 +806,8 @@ AO_int_fetch_and_add_full(volatile unsigned *addr, unsigned incr)
   }
 # define AO_HAVE_int_xor_full
 #endif
+
+#endif /* !AO_NO_int_ARITHM */
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
@@ -765,6 +825,8 @@ AO_int_fetch_and_add_full(volatile unsigned *addr, unsigned incr)
  *
  */
 
+#ifndef AO_NO_ARITHM
+
 AO_INLINE AO_t
 AO_fetch_and_add_full(volatile AO_t *addr, AO_t incr)
 {
@@ -798,3 +860,5 @@ AO_fetch_and_add_full(volatile AO_t *addr, AO_t incr)
   }
 # define AO_HAVE_xor_full
 #endif
+
+#endif /* !AO_NO_ARITHM */

+ 4 - 0
blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/sysdeps/gcc/generic-arithm.template

@@ -15,6 +15,8 @@
  *
  */
 
+#ifndef AO_NO_XSIZE_ARITHM
+
 AO_INLINE XCTYPE
 AO_XSIZE_fetch_and_add_XBAR(volatile XCTYPE *addr, XCTYPE incr)
 {
@@ -48,3 +50,5 @@ AO_XSIZE_fetch_and_add_XBAR(volatile XCTYPE *addr, XCTYPE incr)
   }
 # define AO_HAVE_XSIZE_xor_XBAR
 #endif
+
+#endif /* !AO_NO_XSIZE_ARITHM */

+ 1 - 1
blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/sysdeps/gcc/powerpc.h

@@ -138,7 +138,7 @@ AO_store_release(volatile AO_t *addr, AO_t value)
 /* only cost us a load immediate instruction.                           */
 AO_INLINE AO_TS_VAL_t
 AO_test_and_set(volatile AO_TS_t *addr) {
-/* Completely untested.  And we should be using smaller objects anyway. */
+  /* TODO: And we should be using smaller objects anyway.       */
   AO_t oldval;
   AO_t temp = 1; /* locked value */
 

+ 16 - 6
blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/sysdeps/gcc/riscv.h

@@ -9,14 +9,24 @@
  * modified is included with the above copyright notice.
  */
 
-/* As of gcc-7.2.0, some __GCC_HAVE_SYNC_COMPARE_AND_SWAP_n are missing. */
-/* The operations are lock-free (even for the types smaller than word).  */
-#define AO_GCC_FORCE_HAVE_CAS
+#if defined(__clang__) || defined(AO_PREFER_BUILTIN_ATOMICS)
+  /* All __GCC_HAVE_SYNC_COMPARE_AND_SWAP_n macros are still missing.   */
+  /* The operations are lock-free even for the types smaller than word. */
+# define AO_GCC_FORCE_HAVE_CAS
+#else
 
-/* While double-word atomic operations are provided by the compiler     */
-/* (which requires -latomic currently), they are not lock-free as       */
-/* riscv itself does not have the double-word atomic operations.        */
+  /* As of gcc-7.5, CAS and arithmetic atomic operations for char and   */
+  /* short are supported by the compiler but require -latomic flag.     */
+# if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1)
+#   define AO_NO_char_ARITHM
+# endif
+# if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2)
+#   define AO_NO_short_ARITHM
+# endif
+#endif /* !__clang__ */
 
 #include "generic.h"
 
 #undef AO_GCC_FORCE_HAVE_CAS
+#undef AO_NO_char_ARITHM
+#undef AO_NO_short_ARITHM

+ 12 - 2
blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/sysdeps/gcc/s390.h

@@ -15,7 +15,15 @@
  *
  */
 
-/* FIXME: untested.                                             */
+#if (AO_GNUC_PREREQ(5, 4) || AO_CLANG_PREREQ(8, 0)) && defined(__s390x__) \
+    && !defined(AO_DISABLE_GCC_ATOMICS)
+  /* Probably, it could be enabled for earlier clang/gcc versions.      */
+  /* But, e.g., clang-3.8.0 produces a backend error for AtomicFence.   */
+
+# include "generic.h"
+
+#else /* AO_DISABLE_GCC_ATOMICS */
+
 /* The relevant documentation appears to be at                  */
 /* http://publibz.boulder.ibm.com/epubs/pdf/dz9zr003.pdf        */
 /* around page 5-96.  Apparently:                               */
@@ -35,7 +43,7 @@
 #include "../ordered_except_wr.h"
 
 #include "../test_and_set_t_is_ao_t.h"
-/* FIXME: Is there a way to do byte-sized test-and-set? */
+/* TODO: Is there a way to do byte-sized test-and-set? */
 
 /* TODO: AO_nop_full should probably be implemented directly.   */
 /* It appears that certain BCR instructions have that effect.   */
@@ -79,4 +87,6 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr,
 }
 #define AO_HAVE_fetch_compare_and_swap_full
 
+#endif /* AO_DISABLE_GCC_ATOMICS */
+
 /* TODO: Add double-wide operations for 32-bit executables.       */

+ 112 - 60
blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/sysdeps/gcc/x86.h

@@ -125,8 +125,9 @@
   {
     AO_t result;
 
-    __asm__ __volatile__ ("lock; xadd %0, %1" :
-                        "=r" (result), "=m" (*p) : "0" (incr), "m" (*p)
+    __asm__ __volatile__ ("lock; xadd %0, %1"
+                        : "=r" (result), "+m" (*p)
+                        : "0" (incr)
                         : "memory");
     return result;
   }
@@ -138,8 +139,9 @@ AO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)
 {
   unsigned char result;
 
-  __asm__ __volatile__ ("lock; xaddb %0, %1" :
-                        "=q" (result), "=m" (*p) : "0" (incr), "m" (*p)
+  __asm__ __volatile__ ("lock; xaddb %0, %1"
+                        : "=q" (result), "+m" (*p)
+                        : "0" (incr)
                         : "memory");
   return result;
 }
@@ -150,8 +152,9 @@ AO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)
 {
   unsigned short result;
 
-  __asm__ __volatile__ ("lock; xaddw %0, %1" :
-                        "=r" (result), "=m" (*p) : "0" (incr), "m" (*p)
+  __asm__ __volatile__ ("lock; xaddw %0, %1"
+                        : "=r" (result), "+m" (*p)
+                        : "0" (incr)
                         : "memory");
   return result;
 }
@@ -161,8 +164,9 @@ AO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)
   AO_INLINE void
   AO_and_full (volatile AO_t *p, AO_t value)
   {
-    __asm__ __volatile__ ("lock; and %1, %0" :
-                        "=m" (*p) : "r" (value), "m" (*p)
+    __asm__ __volatile__ ("lock; and %1, %0"
+                        : "+m" (*p)
+                        : "r" (value)
                         : "memory");
   }
 # define AO_HAVE_and_full
@@ -170,8 +174,9 @@ AO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)
   AO_INLINE void
   AO_or_full (volatile AO_t *p, AO_t value)
   {
-    __asm__ __volatile__ ("lock; or %1, %0" :
-                        "=m" (*p) : "r" (value), "m" (*p)
+    __asm__ __volatile__ ("lock; or %1, %0"
+                        : "+m" (*p)
+                        : "r" (value)
                         : "memory");
   }
 # define AO_HAVE_or_full
@@ -179,8 +184,9 @@ AO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)
   AO_INLINE void
   AO_xor_full (volatile AO_t *p, AO_t value)
   {
-    __asm__ __volatile__ ("lock; xor %1, %0" :
-                        "=m" (*p) : "r" (value), "m" (*p)
+    __asm__ __volatile__ ("lock; xor %1, %0"
+                        : "+m" (*p)
+                        : "r" (value)
                         : "memory");
   }
 # define AO_HAVE_xor_full
@@ -192,8 +198,9 @@ AO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)
 AO_INLINE void
 AO_char_and_full (volatile unsigned char *p, unsigned char value)
 {
-  __asm__ __volatile__ ("lock; andb %1, %0" :
-                        "=m" (*p) : "r" (value), "m" (*p)
+  __asm__ __volatile__ ("lock; andb %1, %0"
+                        : "+m" (*p)
+                        : "r" (value)
                         : "memory");
 }
 #define AO_HAVE_char_and_full
@@ -201,8 +208,9 @@ AO_char_and_full (volatile unsigned char *p, unsigned char value)
 AO_INLINE void
 AO_char_or_full (volatile unsigned char *p, unsigned char value)
 {
-  __asm__ __volatile__ ("lock; orb %1, %0" :
-                        "=m" (*p) : "r" (value), "m" (*p)
+  __asm__ __volatile__ ("lock; orb %1, %0"
+                        : "+m" (*p)
+                        : "r" (value)
                         : "memory");
 }
 #define AO_HAVE_char_or_full
@@ -210,8 +218,9 @@ AO_char_or_full (volatile unsigned char *p, unsigned char value)
 AO_INLINE void
 AO_char_xor_full (volatile unsigned char *p, unsigned char value)
 {
-  __asm__ __volatile__ ("lock; xorb %1, %0" :
-                        "=m" (*p) : "r" (value), "m" (*p)
+  __asm__ __volatile__ ("lock; xorb %1, %0"
+                        : "+m" (*p)
+                        : "r" (value)
                         : "memory");
 }
 #define AO_HAVE_char_xor_full
@@ -219,8 +228,9 @@ AO_char_xor_full (volatile unsigned char *p, unsigned char value)
 AO_INLINE void
 AO_short_and_full (volatile unsigned short *p, unsigned short value)
 {
-  __asm__ __volatile__ ("lock; andw %1, %0" :
-                        "=m" (*p) : "r" (value), "m" (*p)
+  __asm__ __volatile__ ("lock; andw %1, %0"
+                        : "+m" (*p)
+                        : "r" (value)
                         : "memory");
 }
 #define AO_HAVE_short_and_full
@@ -228,8 +238,9 @@ AO_short_and_full (volatile unsigned short *p, unsigned short value)
 AO_INLINE void
 AO_short_or_full (volatile unsigned short *p, unsigned short value)
 {
-  __asm__ __volatile__ ("lock; orw %1, %0" :
-                        "=m" (*p) : "r" (value), "m" (*p)
+  __asm__ __volatile__ ("lock; orw %1, %0"
+                        : "+m" (*p)
+                        : "r" (value)
                         : "memory");
 }
 #define AO_HAVE_short_or_full
@@ -237,8 +248,9 @@ AO_short_or_full (volatile unsigned short *p, unsigned short value)
 AO_INLINE void
 AO_short_xor_full (volatile unsigned short *p, unsigned short value)
 {
-  __asm__ __volatile__ ("lock; xorw %1, %0" :
-                        "=m" (*p) : "r" (value), "m" (*p)
+  __asm__ __volatile__ ("lock; xorw %1, %0"
+                        : "+m" (*p)
+                        : "r" (value)
                         : "memory");
 }
 #define AO_HAVE_short_xor_full
@@ -250,8 +262,8 @@ AO_test_and_set_full(volatile AO_TS_t *addr)
   unsigned char oldval;
   /* Note: the "xchg" instruction does not need a "lock" prefix */
   __asm__ __volatile__ ("xchgb %0, %1"
-                        : "=q" (oldval), "=m" (*addr)
-                        : "0" ((unsigned char)0xff), "m" (*addr)
+                        : "=q" (oldval), "+m" (*addr)
+                        : "0" ((unsigned char)0xff)
                         : "memory");
   return (AO_TS_VAL_t)oldval;
 }
@@ -270,10 +282,19 @@ AO_test_and_set_full(volatile AO_TS_t *addr)
                 /* variables are protected.                             */
 #   else
       char result;
-      __asm__ __volatile__ ("lock; cmpxchg %3, %0; setz %1"
-                        : "=m" (*addr), "=a" (result)
-                        : "m" (*addr), "r" (new_val), "a" (old)
+#     if defined(__GCC_ASM_FLAG_OUTPUTS__)
+        AO_t dummy;
+
+        __asm__ __volatile__ ("lock; cmpxchg %3, %0"
+                        : "+m" (*addr), "=@ccz" (result), "=a" (dummy)
+                        : "r" (new_val), "a" (old)
+                        : "memory");
+#     else
+        __asm__ __volatile__ ("lock; cmpxchg %2, %0; setz %1"
+                        : "+m" (*addr), "=a" (result)
+                        : "r" (new_val), "a" (old)
                         : "memory");
+#     endif
       return (int)result;
 #   endif
   }
@@ -289,9 +310,9 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
                                        /* empty protection list */);
 # else
     AO_t fetched_val;
-    __asm__ __volatile__ ("lock; cmpxchg %3, %4"
-                        : "=a" (fetched_val), "=m" (*addr)
-                        : "a" (old_val), "r" (new_val), "m" (*addr)
+    __asm__ __volatile__ ("lock; cmpxchg %3, %1"
+                        : "=a" (fetched_val), "+m" (*addr)
+                        : "a" (old_val), "r" (new_val)
                         : "memory");
     return fetched_val;
 # endif
@@ -309,9 +330,9 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
 #   else
       unsigned char fetched_val;
 
-      __asm__ __volatile__ ("lock; cmpxchgb %3, %4"
-                            : "=a" (fetched_val), "=m" (*addr)
-                            : "a" (old_val), "q" (new_val), "m" (*addr)
+      __asm__ __volatile__ ("lock; cmpxchgb %3, %1"
+                            : "=a" (fetched_val), "+m" (*addr)
+                            : "a" (old_val), "q" (new_val)
                             : "memory");
       return fetched_val;
 #   endif
@@ -329,9 +350,9 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
 #   else
       unsigned short fetched_val;
 
-      __asm__ __volatile__ ("lock; cmpxchgw %3, %4"
-                            : "=a" (fetched_val), "=m" (*addr)
-                            : "a" (old_val), "r" (new_val), "m" (*addr)
+      __asm__ __volatile__ ("lock; cmpxchgw %3, %1"
+                            : "=a" (fetched_val), "+m" (*addr)
+                            : "a" (old_val), "r" (new_val)
                             : "memory");
       return fetched_val;
 #   endif
@@ -350,9 +371,9 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
 #     else
         unsigned int fetched_val;
 
-        __asm__ __volatile__ ("lock; cmpxchgl %3, %4"
-                            : "=a" (fetched_val), "=m" (*addr)
-                            : "a" (old_val), "r" (new_val), "m" (*addr)
+        __asm__ __volatile__ ("lock; cmpxchgl %3, %1"
+                            : "=a" (fetched_val), "+m" (*addr)
+                            : "a" (old_val), "r" (new_val)
                             : "memory");
         return fetched_val;
 #     endif
@@ -366,8 +387,8 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
       unsigned int result;
 
       __asm__ __volatile__ ("lock; xaddl %0, %1"
-                            : "=r" (result), "=m" (*p)
-                            : "0" (incr), "m" (*p)
+                            : "=r" (result), "+m" (*p)
+                            : "0" (incr)
                             : "memory");
       return result;
     }
@@ -377,7 +398,8 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
     AO_int_and_full (volatile unsigned int *p, unsigned int value)
     {
       __asm__ __volatile__ ("lock; andl %1, %0"
-                            : "=m" (*p) : "r" (value), "m" (*p)
+                            : "+m" (*p)
+                            : "r" (value)
                             : "memory");
     }
 #   define AO_HAVE_int_and_full
@@ -386,7 +408,8 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
     AO_int_or_full (volatile unsigned int *p, unsigned int value)
     {
       __asm__ __volatile__ ("lock; orl %1, %0"
-                            : "=m" (*p) : "r" (value), "m" (*p)
+                            : "+m" (*p)
+                            : "r" (value)
                             : "memory");
     }
 #   define AO_HAVE_int_or_full
@@ -395,7 +418,8 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
     AO_int_xor_full (volatile unsigned int *p, unsigned int value)
     {
       __asm__ __volatile__ ("lock; xorl %1, %0"
-                            : "=m" (*p) : "r" (value), "m" (*p)
+                            : "+m" (*p)
+                            : "r" (value)
                             : "memory");
     }
 #   define AO_HAVE_int_xor_full
@@ -443,9 +467,12 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
                                          AO_t new_val1, AO_t new_val2)
   {
     char result;
-#   ifdef __PIC__
+#   if defined(__PIC__) && !(AO_GNUC_PREREQ(5, 1) || AO_CLANG_PREREQ(4, 0))
       AO_t saved_ebx;
+      AO_t dummy;
 
+      /* The following applies to an ancient GCC (and, probably, it was   */
+      /* never needed for Clang):                                         */
       /* If PIC is turned on, we cannot use ebx as it is reserved for the */
       /* GOT pointer.  We should save and restore ebx.  The proposed      */
       /* solution is not so efficient as the older alternatives using     */
@@ -461,8 +488,9 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
                              "lock; cmpxchg8b (%%edi)\n\t"
                              "mov %2, %%ebx\n\t" /* restore ebx */
                              "setz %1"
-                        : "=m" (*addr), "=a" (result), "=m" (saved_ebx)
-                        : "m" (*addr), "d" (old_val2), "a" (old_val1),
+                        : "+m" (*addr), "=a" (result),
+                          "=m" (saved_ebx), "=d" (dummy)
+                        : "d" (old_val2), "a" (old_val1),
                           "c" (new_val2), "m" (new_val1)
                         : "%edi", "memory");
 #     else
@@ -478,20 +506,33 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
                              "mov %2, %%ebx\n\t" /* restore ebx */
                              "mov %3, %%edi\n\t" /* restore edi */
                              "setz %1"
-                        : "=m" (*addr), "=a" (result),
-                          "=m" (saved_ebx), "=m" (saved_edi)
-                        : "m" (*addr), "d" (old_val2), "a" (old_val1),
-                          "c" (new_val2), "m" (new_val1) : "memory");
+                        : "+m" (*addr), "=a" (result),
+                          "=m" (saved_ebx), "=m" (saved_edi), "=d" (dummy)
+                        : "d" (old_val2), "a" (old_val1),
+                          "c" (new_val2), "m" (new_val1)
+                        : "memory");
 #     endif
 #   else
       /* For non-PIC mode, this operation could be simplified (and be   */
-      /* faster) by using ebx as new_val1 (GCC would refuse to compile  */
+      /* faster) by using ebx as new_val1.  Reuse of the PIC hard       */
+      /* register, instead of using a fixed register, is implemented    */
+      /* in Clang and GCC 5.1+, at least. (Older GCC refused to compile */
       /* such code for PIC mode).                                       */
-      __asm__ __volatile__ ("lock; cmpxchg8b %0; setz %1"
-                        : "=m" (*addr), "=a" (result)
-                        : "m" (*addr), "d" (old_val2), "a" (old_val1),
+#     if defined(__GCC_ASM_FLAG_OUTPUTS__)
+        __asm__ __volatile__ ("lock; cmpxchg8b %0"
+                        : "+m" (*addr), "=@ccz" (result),
+                          "+d" (old_val2), "+a" (old_val1)
+                        : "c" (new_val2), "b" (new_val1)
+                        : "memory");
+#     else
+        AO_t dummy; /* an output for clobbered edx */
+
+        __asm__ __volatile__ ("lock; cmpxchg8b %0; setz %1"
+                        : "+m" (*addr), "=a" (result), "=d" (dummy)
+                        : "d" (old_val2), "a" (old_val1),
                           "c" (new_val2), "b" (new_val1)
                         : "memory");
+#     endif
 #   endif
     return (int) result;
   }
@@ -553,11 +594,22 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
                                          AO_t new_val1, AO_t new_val2)
   {
     char result;
-    __asm__ __volatile__("lock; cmpxchg16b %0; setz %1"
-                        : "=m"(*addr), "=a"(result)
-                        : "m"(*addr), "d" (old_val2), "a" (old_val1),
+
+#   if defined(__GCC_ASM_FLAG_OUTPUTS__)
+      __asm__ __volatile__("lock; cmpxchg16b %0"
+                        : "+m" (*addr), "=@ccz" (result),
+                          "+d" (old_val2), "+a" (old_val1)
+                        : "c" (new_val2), "b" (new_val1)
+                        : "memory");
+#   else
+      AO_t dummy; /* an output for clobbered rdx */
+
+      __asm__ __volatile__("lock; cmpxchg16b %0; setz %1"
+                        : "+m" (*addr), "=a" (result), "=d" (dummy)
+                        : "d" (old_val2), "a" (old_val1),
                           "c" (new_val2), "b" (new_val1)
                         : "memory");
+#   endif
     return (int) result;
   }
 # define AO_HAVE_compare_double_and_swap_double_full

+ 5 - 2
blitz.mod/bdwgc/libatomic_ops/src/atomic_ops/sysdeps/sunc/x86.h

@@ -176,10 +176,11 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
                                            AO_t old_val1, AO_t old_val2,
                                            AO_t new_val1, AO_t new_val2)
     {
+      AO_t dummy;   /* an output for clobbered edx */
       char result;
 
       __asm__ __volatile__ ("lock; cmpxchg8b %0; setz %1"
-                        : "+m" (*addr), "=a" (result)
+                        : "+m" (*addr), "=a" (result), "=d" (dummy)
                         : "d" (old_val2), "a" (old_val1),
                           "c" (new_val2), "b" (new_val1)
                         : "memory");
@@ -215,9 +216,11 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
                                             AO_t old_val1, AO_t old_val2,
                                             AO_t new_val1, AO_t new_val2)
     {
+      AO_t dummy;
       char result;
+
       __asm__ __volatile__ ("lock; cmpxchg16b %0; setz %1"
-                        : "+m" (*addr), "=a" (result)
+                        : "+m" (*addr), "=a" (result), "=d" (dummy)
                         : "d" (old_val2), "a" (old_val1),
                           "c" (new_val2), "b" (new_val1)
                         : "memory");

+ 3 - 0
blitz.mod/bdwgc/mach_dep.c

@@ -298,6 +298,9 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
         /* force callee-save registers and register windows onto        */
         /* the stack.                                                   */
         __builtin_unwind_init();
+#     elif defined(NO_CRT) && defined(MSWIN32)
+        CONTEXT ctx;
+        RtlCaptureContext(&ctx);
 #     else
         /* Generic code                          */
         /* The idea is due to Parag Patel at HP. */

+ 14 - 8
blitz.mod/bdwgc/malloc.c

@@ -52,8 +52,11 @@ GC_INNER ptr_t GC_alloc_large(size_t lb, int k, unsigned flags)
       LOCK();
     }
     /* Do our share of marking work */
-        if (GC_incremental && !GC_dont_gc)
+        if (GC_incremental && !GC_dont_gc) {
+            ENTER_GC();
             GC_collect_a_little_inner((int)n_blocks);
+            EXIT_GC();
+        }
     h = GC_allochblk(lb, k, flags);
 #   ifdef USE_MUNMAP
         if (0 == h) {
@@ -381,14 +384,11 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_generic_malloc_uncollectable(
         }
         GC_ASSERT(0 == op || GC_is_marked(op));
     } else {
-        hdr * hhdr;
-
-        op = GC_generic_malloc(lb, k);
-        if (NULL == op)
-            return NULL;
+      op = GC_generic_malloc(lb, k);
+      if (op /* != NULL */) { /* CPPCHECK */
+        hdr * hhdr = HDR(op);
 
         GC_ASSERT(((word)op & (HBLKSIZE - 1)) == 0); /* large block */
-        hhdr = HDR(op);
         /* We don't need the lock here, since we have an undisguised    */
         /* pointer.  We do need to hold the lock while we adjust        */
         /* mark bits.                                                   */
@@ -401,6 +401,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_generic_malloc_uncollectable(
 #       endif
         hhdr -> hb_n_marks = 1;
         UNLOCK();
+      }
     }
     return op;
 }
@@ -564,8 +565,13 @@ GC_API void GC_CALL GC_free(void * p)
     struct obj_kind * ok;
     DCL_LOCK_STATE;
 
-    if (p == 0) return;
+    if (p /* != NULL */) {
+        /* CPPCHECK */
+    } else {
         /* Required by ANSI.  It's not my fault ...     */
+        return;
+    }
+
 #   ifdef LOG_ALLOCS
       GC_log_printf("GC_free(%p) after GC #%lu\n",
                     p, (unsigned long)GC_gc_no);

+ 13 - 18
blitz.mod/bdwgc/mallocx.c

@@ -27,13 +27,7 @@
 #include <stdio.h>
 #include <string.h>
 
-#ifdef MSWINCE
-# ifndef WIN32_LEAN_AND_MEAN
-#   define WIN32_LEAN_AND_MEAN 1
-# endif
-# define NOSERVICE
-# include <windows.h>
-#else
+#ifndef MSWINCE
 # include <errno.h>
 #endif
 
@@ -349,8 +343,7 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t lb, int k, void **result)
         struct hblk * hbp;
         hdr * hhdr;
 
-        rlh += lg;
-        while ((hbp = *rlh) != 0) {
+        for (rlh += lg; (hbp = *rlh) != NULL; ) {
             hhdr = HDR(hbp);
             *rlh = hhdr -> hb_next;
             GC_ASSERT(hhdr -> hb_sz == lb);
@@ -441,7 +434,7 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t lb, int k, void **result)
     /* Next try to allocate a new block worth of objects of this size.  */
     {
         struct hblk *h = GC_allochblk(lb, k, 0);
-        if (h != 0) {
+        if (h /* != NULL */) { /* CPPCHECK */
           if (IS_UNCOLLECTABLE(k)) GC_set_hdr_marks(HDR(h));
           GC_bytes_allocd += HBLKSIZE - HBLKSIZE % lb;
 #         ifdef PARALLEL_MARK
@@ -610,15 +603,17 @@ GC_API GC_ATTR_MALLOC char * GC_CALL GC_strndup(const char *str, size_t size)
   }
 #endif /* GC_REQUIRE_WCSDUP */
 
-GC_API void * GC_CALL GC_malloc_stubborn(size_t lb)
-{
-  return GC_malloc(lb);
-}
+#ifndef CPPCHECK
+  GC_API void * GC_CALL GC_malloc_stubborn(size_t lb)
+  {
+    return GC_malloc(lb);
+  }
 
-GC_API void GC_CALL GC_change_stubborn(const void *p GC_ATTR_UNUSED)
-{
-  /* Empty. */
-}
+  GC_API void GC_CALL GC_change_stubborn(const void *p GC_ATTR_UNUSED)
+  {
+    /* Empty. */
+  }
+#endif /* !CPPCHECK */
 
 GC_API void GC_CALL GC_end_stubborn_change(const void *p)
 {

+ 93 - 118
blitz.mod/bdwgc/mark.c

@@ -2,6 +2,7 @@
  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 2000 by Hewlett-Packard Company.  All rights reserved.
+ * Copyright (c) 2008-2020 Ivan Maidanski
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -56,10 +57,6 @@ GC_API void GC_CALL GC_noop1(word x)
     GC_noop_sink = x;
 }
 
-/* mark_proc GC_mark_procs[MAX_MARK_PROCS] = {0} -- declared in gc_priv.h */
-
-GC_INNER unsigned GC_n_mark_procs = GC_RESERVED_MARK_PROCS;
-
 /* Initialize GC_obj_kinds properly and standard free lists properly.   */
 /* This must be done statically since they may be accessed before       */
 /* GC_init is called.                                                   */
@@ -84,8 +81,6 @@ GC_INNER struct obj_kind GC_obj_kinds[MAXOBJKINDS] = {
 # endif
 };
 
-GC_INNER unsigned GC_n_kinds = GC_N_KINDS_INITIAL_VALUE;
-
 # ifndef INITIAL_MARK_STACK_SIZE
 #   define INITIAL_MARK_STACK_SIZE (1*HBLKSIZE)
                 /* INITIAL_MARK_STACK_SIZE * sizeof(mse) should be a    */
@@ -103,34 +98,19 @@ GC_INNER unsigned GC_n_kinds = GC_N_KINDS_INITIAL_VALUE;
                                 /* Used for logging only.               */
 #endif
 
-GC_INNER size_t GC_mark_stack_size = 0;
-
 #ifdef PARALLEL_MARK
-  STATIC volatile AO_t GC_first_nonempty = 0;
-        /* Lowest entry on mark stack   */
-        /* that may be nonempty.        */
-        /* Updated only by initiating   */
-        /* thread.                      */
+  GC_INNER GC_bool GC_parallel_mark_disabled = FALSE;
 #endif
 
-GC_INNER mark_state_t GC_mark_state = MS_NONE;
-
-GC_INNER GC_bool GC_mark_stack_too_small = FALSE;
-
-static struct hblk * scan_ptr;
-
-STATIC GC_bool GC_objects_are_marked = FALSE;
-                /* Are there collectible marked objects in the heap?    */
-
 /* Is a collection in progress?  Note that this can return true in the  */
-/* nonincremental case, if a collection has been abandoned and the      */
+/* non-incremental case, if a collection has been abandoned and the     */
 /* mark state is now MS_INVALID.                                        */
 GC_INNER GC_bool GC_collection_in_progress(void)
 {
     return(GC_mark_state != MS_NONE);
 }
 
-/* clear all mark bits in the header */
+/* Clear all mark bits in the header.   */
 GC_INNER void GC_clear_hdr_marks(hdr *hhdr)
 {
   size_t last_bit;
@@ -171,9 +151,7 @@ GC_INNER void GC_set_hdr_marks(hdr *hhdr)
 #   endif
 }
 
-/*
- * Clear all mark bits associated with block h.
- */
+/* Clear all mark bits associated with block h. */
 static void clear_marks_for_block(struct hblk *h, word dummy GC_ATTR_UNUSED)
 {
     hdr * hhdr = HDR(h);
@@ -185,7 +163,7 @@ static void clear_marks_for_block(struct hblk *h, word dummy GC_ATTR_UNUSED)
     GC_clear_hdr_marks(hhdr);
 }
 
-/* Slow but general routines for setting/clearing/asking about mark bits */
+/* Slow but general routines for setting/clearing/asking about mark bits. */
 GC_API void GC_CALL GC_set_mark_bit(const void *p)
 {
     struct hblk *h = HBLKPTR(p);
@@ -231,17 +209,15 @@ GC_API int GC_CALL GC_is_marked(const void *p)
     return (int)mark_bit_from_hdr(hhdr, bit_no); /* 0 or 1 */
 }
 
-/*
- * Clear mark bits in all allocated heap blocks.  This invalidates
- * the marker invariant, and sets GC_mark_state to reflect this.
- * (This implicitly starts marking to reestablish the invariant.)
- */
+/* Clear mark bits in all allocated heap blocks.  This invalidates the  */
+/* marker invariant, and sets GC_mark_state to reflect this.  (This     */
+/* implicitly starts marking to reestablish the invariant.)             */
 GC_INNER void GC_clear_marks(void)
 {
     GC_apply_to_all_blocks(clear_marks_for_block, (word)0);
     GC_objects_are_marked = FALSE;
     GC_mark_state = MS_INVALID;
-    scan_ptr = 0;
+    GC_scan_ptr = NULL;
 }
 
 /* Initiate a garbage collection.  Initiates a full collection if the   */
@@ -253,28 +229,23 @@ GC_INNER void GC_initiate_gc(void)
         if (GC_incremental) {
 #         ifdef CHECKSUMS
             GC_read_dirty(FALSE);
+            GC_check_dirty();
 #         else
             GC_read_dirty(GC_mark_state == MS_INVALID);
 #         endif
         }
-#   endif
-#   ifdef CHECKSUMS
-        if (GC_incremental) GC_check_dirty();
-#   endif
-#   if !defined(GC_DISABLE_INCREMENTAL)
         GC_n_rescuing_pages = 0;
 #   endif
     if (GC_mark_state == MS_NONE) {
         GC_mark_state = MS_PUSH_RESCUERS;
     } else if (GC_mark_state != MS_INVALID) {
         ABORT("Unexpected state");
-    } /* else this is really a full collection, and mark        */
-      /* bits are invalid.                                      */
-    scan_ptr = 0;
+    } /* Else this is really a full collection, and mark bits are invalid. */
+    GC_scan_ptr = NULL;
 }
 
 #ifdef PARALLEL_MARK
-    STATIC void GC_do_parallel_mark(void); /* initiate parallel marking. */
+    STATIC void GC_do_parallel_mark(void); /* Initiate parallel marking. */
 #endif /* PARALLEL_MARK */
 
 #ifdef GC_DISABLE_INCREMENTAL
@@ -324,8 +295,8 @@ static void alloc_mark_stack(size_t);
                 MARK_FROM_MARK_STACK();
                 break;
             } else {
-                scan_ptr = GC_push_next_marked_dirty(scan_ptr);
-                if (scan_ptr == 0) {
+                GC_scan_ptr = GC_push_next_marked_dirty(GC_scan_ptr);
+                if (NULL == GC_scan_ptr) {
 #                 if !defined(GC_DISABLE_INCREMENTAL)
                     GC_COND_LOG_PRINTF("Marked from %lu dirty pages\n",
                                        (unsigned long)GC_n_rescuing_pages);
@@ -350,8 +321,8 @@ static void alloc_mark_stack(size_t);
                 MARK_FROM_MARK_STACK();
                 break;
             } else {
-                scan_ptr = GC_push_next_marked_uncollectable(scan_ptr);
-                if (scan_ptr == 0) {
+                GC_scan_ptr = GC_push_next_marked_uncollectable(GC_scan_ptr);
+                if (NULL == GC_scan_ptr) {
                     GC_push_roots(TRUE, cold_gc_frame);
                     GC_objects_are_marked = TRUE;
                     if (GC_mark_state != MS_INVALID) {
@@ -363,15 +334,13 @@ static void alloc_mark_stack(size_t);
 
         case MS_ROOTS_PUSHED:
 #           ifdef PARALLEL_MARK
-              /* In the incremental GC case, this currently doesn't     */
-              /* quite do the right thing, since it runs to             */
-              /* completion.  On the other hand, starting a             */
-              /* parallel marker is expensive, so perhaps it is         */
-              /* the right thing?                                       */
               /* Eventually, incremental marking should run             */
               /* asynchronously in multiple threads, without grabbing   */
               /* the allocation lock.                                   */
-                if (GC_parallel) {
+              /* For now, parallel marker is disabled if there is       */
+              /* a chance that marking could be interrupted by          */
+              /* a client-supplied time limit or custom stop function.  */
+                if (GC_parallel && !GC_parallel_mark_disabled) {
                   GC_do_parallel_mark();
                   GC_ASSERT((word)GC_mark_stack_top < (word)GC_first_nonempty);
                   GC_mark_stack_top = GC_mark_stack - 1;
@@ -406,7 +375,7 @@ static void alloc_mark_stack(size_t);
                 MARK_FROM_MARK_STACK();
                 break;
             }
-            if (scan_ptr == 0 && GC_mark_state == MS_INVALID) {
+            if (NULL == GC_scan_ptr && GC_mark_state == MS_INVALID) {
                 /* About to start a heap scan for marked objects. */
                 /* Mark stack is empty.  OK to reallocate.        */
                 if (GC_mark_stack_too_small) {
@@ -414,8 +383,8 @@ static void alloc_mark_stack(size_t);
                 }
                 GC_mark_state = MS_PARTIALLY_INVALID;
             }
-            scan_ptr = GC_push_next_marked(scan_ptr);
-            if (scan_ptr == 0 && GC_mark_state == MS_PARTIALLY_INVALID) {
+            GC_scan_ptr = GC_push_next_marked(GC_scan_ptr);
+            if (NULL == GC_scan_ptr && GC_mark_state == MS_PARTIALLY_INVALID) {
                 GC_push_roots(TRUE, cold_gc_frame);
                 GC_objects_are_marked = TRUE;
                 if (GC_mark_state != MS_INVALID) {
@@ -502,7 +471,8 @@ static void alloc_mark_stack(size_t);
         /* to the exception case; our results are invalid and we have   */
         /* to start over.  This cannot be prevented since we can't      */
         /* block in DllMain.                                            */
-        if (GC_started_thread_while_stopped()) goto handle_ex;
+        if (GC_started_thread_while_stopped())
+          goto handle_thr_start;
 #     endif
      rm_handler:
       return ret_val;
@@ -539,10 +509,10 @@ static void alloc_mark_stack(size_t);
           goto handle_ex;
 #     if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
         if (GC_started_thread_while_stopped())
-          goto handle_ex;
+          goto handle_thr_start;
 #     endif
     rm_handler:
-      /* Uninstall the exception handler */
+      /* Uninstall the exception handler.       */
       __asm__ __volatile__ ("mov %0, %%fs:0" : : "r" (er.ex_reg.prev));
       return ret_val;
 
@@ -553,10 +523,12 @@ static void alloc_mark_stack(size_t);
       /* thread that is in the process of exiting, and disappears       */
       /* while we are marking it.  This seems extremely difficult to    */
       /* avoid otherwise.                                               */
-      if (GC_incremental) {
-        WARN("Incremental GC incompatible with /proc roots\n", 0);
-        /* I'm not sure if this could still work ...    */
-      }
+#     ifndef DEFAULT_VDB
+        if (GC_auto_incremental) {
+          WARN("Incremental GC incompatible with /proc roots\n", 0);
+          /* I'm not sure if this could still work ...  */
+        }
+#     endif
       GC_setup_temporary_fault_handler();
       if(SETJMP(GC_jmp_buf) != 0) goto handle_ex;
       ret_val = GC_mark_some_inner(cold_gc_frame);
@@ -573,11 +545,15 @@ handle_ex:
 
         /* Warn about it at most once per collection. */
         if (warned_gc_no != GC_gc_no) {
-          warned_gc_no = GC_gc_no;
           WARN("Caught ACCESS_VIOLATION in marker;"
                " memory mapping disappeared\n", 0);
+          warned_gc_no = GC_gc_no;
         }
       }
+#   if (defined(MSWIN32) || defined(MSWINCE)) && defined(GC_WIN32_THREADS) \
+       && !defined(GC_PTHREADS)
+      handle_thr_start:
+#   endif
       /* We have bad roots on the stack.  Discard mark stack.   */
       /* Rescan from marked objects.  Redetermine roots.        */
 #     ifdef REGISTER_LIBRARIES_EARLY
@@ -586,8 +562,7 @@ handle_ex:
         STOP_WORLD();
 #     endif
       GC_invalidate_mark_state();
-      scan_ptr = 0;
-
+      GC_scan_ptr = NULL;
       ret_val = FALSE;
       goto rm_handler;  /* Back to platform-specific code. */
   }
@@ -634,7 +609,7 @@ GC_ATTR_NO_SANITIZE_ADDR GC_ATTR_NO_SANITIZE_MEMORY GC_ATTR_NO_SANITIZE_THREAD
 GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
                             mse *mark_stack_limit)
 {
-  signed_word credit = HBLKSIZE;  /* Remaining credit for marking work  */
+  signed_word credit = HBLKSIZE;  /* Remaining credit for marking work. */
   ptr_t current_p;      /* Pointer to current candidate ptr.            */
   word current;         /* Candidate pointer.                           */
   ptr_t limit = 0;      /* (Incl) limit of current candidate range.     */
@@ -647,7 +622,7 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
 
   GC_objects_are_marked = TRUE;
   INIT_HDR_CACHE;
-# ifdef OS2 /* Use untweaked version to circumvent compiler problem */
+# ifdef OS2 /* Use untweaked version to circumvent compiler problem.    */
     while ((word)mark_stack_top >= (word)mark_stack && credit >= 0)
 # else
     while (((((word)mark_stack_top - (word)mark_stack) | (word)credit)
@@ -657,8 +632,8 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
     current_p = mark_stack_top -> mse_start;
     descr = mark_stack_top -> mse_descr.w;
   retry:
-    /* current_p and descr describe the current object.         */
-    /* *mark_stack_top is vacant.                               */
+    /* current_p and descr describe the current object.                 */
+    /* (*mark_stack_top) is vacant.                                     */
     /* The following is 0 only for small objects described by a simple  */
     /* length descriptor.  For many applications this is the common     */
     /* case, so we try to detect it quickly.                            */
@@ -684,7 +659,7 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
 
               mark_stack_top -> mse_start = current_p;
               mark_stack_top -> mse_descr.w = new_size + sizeof(word);
-                                        /* makes sure we handle         */
+                                        /* Makes sure we handle         */
                                         /* misaligned pointers.         */
               mark_stack_top++;
 #             ifdef ENABLE_TRACE
@@ -793,13 +768,14 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
           }
           if (0 == descr) {
               /* Can happen either because we generated a 0 descriptor  */
-              /* or we saw a pointer to a free object.          */
+              /* or we saw a pointer to a free object.                  */
               mark_stack_top--;
               continue;
           }
           goto retry;
       }
-    } else /* Small object with length descriptor */ {
+    } else {
+      /* Small object with length descriptor.   */
       mark_stack_top--;
 #     ifndef SMALL_CONFIG
         if (descr < sizeof(word))
@@ -901,11 +877,11 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
 
 #ifdef PARALLEL_MARK
 
-STATIC GC_bool GC_help_wanted = FALSE;  /* Protected by mark lock       */
+STATIC GC_bool GC_help_wanted = FALSE;  /* Protected by mark lock.      */
 STATIC unsigned GC_helper_count = 0;    /* Number of running helpers.   */
-                                        /* Protected by mark lock       */
+                                        /* Protected by mark lock.      */
 STATIC unsigned GC_active_count = 0;    /* Number of active helpers.    */
-                                        /* Protected by mark lock       */
+                                        /* Protected by mark lock.      */
                                         /* May increase and decrease    */
                                         /* within each mark cycle.  But */
                                         /* once it returns to 0, it     */
@@ -913,8 +889,6 @@ STATIC unsigned GC_active_count = 0;    /* Number of active helpers.    */
 
 GC_INNER word GC_mark_no = 0;
 
-static mse *main_local_mark_stack;
-
 #ifdef LINT2
 # define LOCAL_MARK_STACK_SIZE (HBLKSIZE / 8)
 #else
@@ -935,17 +909,17 @@ GC_INNER void GC_wait_for_markers_init(void)
 
   /* Allocate the local mark stack for the thread that holds GC lock.   */
 # ifndef CAN_HANDLE_FORK
-    GC_ASSERT(NULL == main_local_mark_stack);
+    GC_ASSERT(NULL == GC_main_local_mark_stack);
 # else
-    if (NULL == main_local_mark_stack)
+    if (NULL == GC_main_local_mark_stack)
 # endif
   {
     size_t bytes_to_get =
                 ROUNDUP_PAGESIZE_IF_MMAP(LOCAL_MARK_STACK_SIZE * sizeof(mse));
-    main_local_mark_stack = (mse *)GET_MEM(bytes_to_get);
-    if (NULL == main_local_mark_stack)
+    GC_main_local_mark_stack = (mse *)GET_MEM(bytes_to_get);
+    if (NULL == GC_main_local_mark_stack)
       ABORT("Insufficient memory for main local_mark_stack");
-    GC_add_to_our_memory((ptr_t)main_local_mark_stack, bytes_to_get);
+    GC_add_to_our_memory((ptr_t)GC_main_local_mark_stack, bytes_to_get);
   }
 
   /* Reuse marker lock and builders count to synchronize        */
@@ -963,7 +937,7 @@ GC_INNER void GC_wait_for_markers_init(void)
 /* Steal mark stack entries starting at mse low into mark stack local   */
 /* until we either steal mse high, or we have max entries.              */
 /* Return a pointer to the top of the local mark stack.                 */
-/* *next is replaced by a pointer to the next unscanned mark stack      */
+/* (*next) is replaced by a pointer to the next unscanned mark stack    */
 /* entry.                                                               */
 STATIC mse * GC_steal_mark_stack(mse * low, mse * high, mse * local,
                                  unsigned max, mse **next)
@@ -1142,7 +1116,7 @@ STATIC void GC_mark_local(mse *local_mark_stack, int id)
             if (0 == n_on_stack) {
                 GC_active_count--;
                 GC_ASSERT(GC_active_count <= GC_helper_count);
-                /* Other markers may redeposit objects  */
+                /* Other markers may redeposit objects          */
                 /* on the stack.                                */
                 if (0 == GC_active_count) GC_notify_all_marker();
                 while (GC_active_count > 0
@@ -1169,7 +1143,7 @@ STATIC void GC_mark_local(mse *local_mark_stack, int id)
                     if (need_to_notify) GC_notify_all_marker();
                     return;
                 }
-                /* else there's something on the stack again, or        */
+                /* Else there's something on the stack again, or        */
                 /* another helper may push something.                   */
                 GC_active_count++;
                 GC_ASSERT(GC_active_count > 0);
@@ -1214,13 +1188,13 @@ STATIC void GC_do_parallel_mark(void)
     GC_help_wanted = TRUE;
     GC_notify_all_marker();
         /* Wake up potential helpers.   */
-    GC_mark_local(main_local_mark_stack, 0);
+    GC_mark_local(GC_main_local_mark_stack, 0);
     GC_help_wanted = FALSE;
     /* Done; clean up.  */
     while (GC_helper_count > 0) {
       GC_wait_marker();
     }
-    /* GC_helper_count cannot be incremented while GC_help_wanted == FALSE */
+    /* GC_helper_count cannot be incremented while not GC_help_wanted.  */
     GC_VERBOSE_LOG_PRINTF("Finished marking for mark phase number %lu\n",
                           (unsigned long)GC_mark_no);
     GC_mark_no++;
@@ -1271,9 +1245,8 @@ GC_INNER void GC_scratch_recycle_inner(void *ptr, size_t bytes)
     if (page_offset != 0)
       displ = GC_page_size - page_offset;
     recycled_bytes = (bytes - displ) & ~(GC_page_size - 1);
-    GC_COND_LOG_PRINTF("Recycle %lu/%lu scratch-allocated bytes at %p\n",
-                       (unsigned long)recycled_bytes, (unsigned long)bytes,
-                       ptr);
+    GC_COND_LOG_PRINTF("Recycle %lu scratch-allocated bytes at %p\n",
+                       (unsigned long)recycled_bytes, ptr);
     if (recycled_bytes > 0)
       GC_add_to_heap((struct hblk *)((word)ptr + displ), recycled_bytes);
   }
@@ -1300,7 +1273,7 @@ static void alloc_mark_stack(size_t n)
     if (GC_mark_stack != NULL) {
         if (new_stack != 0) {
           if (recycle_old) {
-            /* Recycle old space */
+            /* Recycle old space.       */
             GC_scratch_recycle_inner(GC_mark_stack,
                         GC_mark_stack_size * sizeof(struct GC_ms_entry));
           }
@@ -1396,7 +1369,7 @@ GC_API void GC_CALL GC_push_all(void *bottom, void *top)
         if ((*dirty_fn)(h)) {
             if ((word)(GC_mark_stack_top - GC_mark_stack)
                 > 3 * GC_mark_stack_size / 4) {
-                /* Danger of mark stack overflow */
+                /* Danger of mark stack overflow.       */
                 GC_push_all(h, top);
                 return;
             } else {
@@ -1435,14 +1408,21 @@ GC_API void GC_CALL GC_push_all(void *bottom, void *top)
   }
 #endif /* GC_DISABLE_INCREMENTAL */
 
-#if defined(MSWIN32) || defined(MSWINCE)
-  void __cdecl GC_push_one(word p)
-#else
+#if defined(AMIGA) || defined(MACOS) || defined(GC_DARWIN_THREADS)
   void GC_push_one(word p)
-#endif
-{
+  {
     GC_PUSH_ONE_STACK(p, MARKED_FROM_REGISTER);
-}
+  }
+#endif
+
+#ifdef GC_WIN32_THREADS
+  GC_INNER void GC_push_many_regs(const word *regs, unsigned count)
+  {
+    unsigned i;
+    for (i = 0; i < count; i++)
+      GC_PUSH_ONE_STACK(regs[i], MARKED_FROM_REGISTER);
+  }
+#endif
 
 GC_API struct GC_ms_entry * GC_CALL GC_mark_and_push(void *obj,
                                                 mse *mark_stack_ptr,
@@ -1483,12 +1463,13 @@ GC_API struct GC_ms_entry * GC_CALL GC_mark_and_push(void *obj,
 
     PREFETCH(p);
     GET_HDR(p, hhdr);
-    if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr), FALSE)
-        && (NULL == hhdr
+    if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr), FALSE)) {
+      if (NULL == hhdr
             || (r = (ptr_t)GC_base(p)) == NULL
-            || (hhdr = HDR(r)) == NULL)) {
+            || (hhdr = HDR(r)) == NULL) {
         GC_ADD_TO_BLACK_LIST_STACK(p, source);
         return;
+      }
     }
     if (EXPECT(HBLK_IS_FREE(hhdr), FALSE)) {
         GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
@@ -1521,9 +1502,7 @@ struct trace_entry {
     word bytes_allocd;
     word arg1;
     word arg2;
-} GC_trace_buf[TRACE_ENTRIES];
-
-int GC_trace_buf_ptr = 0;
+} GC_trace_buf[TRACE_ENTRIES] = { { NULL, 0, 0, 0, 0 } };
 
 void GC_add_trace_entry(char *kind, word arg1, word arg2)
 {
@@ -1567,11 +1546,8 @@ GC_API void GC_CALL GC_print_trace(word gc_no)
 
 #endif /* TRACE_BUF */
 
-/*
- * A version of GC_push_all that treats all interior pointers as valid
- * and scans the entire region immediately, in case the contents
- * change.
- */
+/* A version of GC_push_all that treats all interior pointers as valid  */
+/* and scans the entire region immediately, in case the contents change.*/
 GC_ATTR_NO_SANITIZE_ADDR GC_ATTR_NO_SANITIZE_MEMORY GC_ATTR_NO_SANITIZE_THREAD
 GC_API void GC_CALL GC_push_all_eager(void *bottom, void *top)
 {
@@ -1585,8 +1561,8 @@ GC_API void GC_CALL GC_push_all_eager(void *bottom, void *top)
 #   define GC_least_plausible_heap_addr least_ha
 
     if (top == 0) return;
-    /* check all pointers in range and push if they appear      */
-    /* to be valid.                                             */
+
+    /* Check all pointers in range and push if they appear to be valid. */
       lim = t - 1 /* longword */;
       for (p = b; (word)p <= (word)lim;
            p = (word *)(((ptr_t)p) + ALIGNMENT)) {
@@ -1707,7 +1683,7 @@ STATIC void GC_push_marked1(struct hblk *h, hdr *hhdr)
     p = (word *)(h->hb_body);
     plim = (word *)(((word)h) + HBLKSIZE);
 
-    /* go through all words in block */
+    /* Go through all words in block.   */
         while ((word)p < (word)plim) {
             word mark_word = *mark_word_addr++;
             word *q = p;
@@ -1757,7 +1733,7 @@ STATIC void GC_push_marked2(struct hblk *h, hdr *hhdr)
     p = (word *)(h->hb_body);
     plim = (word *)(((word)h) + HBLKSIZE);
 
-    /* go through all words in block */
+    /* Go through all words in block.   */
         while ((word)p < (word)plim) {
             word mark_word = *mark_word_addr++;
             word *q = p;
@@ -1808,7 +1784,7 @@ STATIC void GC_push_marked4(struct hblk *h, hdr *hhdr)
     p = (word *)(h->hb_body);
     plim = (word *)(((word)h) + HBLKSIZE);
 
-    /* go through all words in block */
+    /* Go through all words in block.   */
         while ((word)p < (word)plim) {
             word mark_word = *mark_word_addr++;
             word *q = p;
@@ -1840,7 +1816,7 @@ STATIC void GC_push_marked4(struct hblk *h, hdr *hhdr)
 
 #endif /* USE_PUSH_MARKED_ACCELERATORS */
 
-/* Push all objects reachable from marked objects in the given block */
+/* Push all objects reachable from marked objects in the given block.   */
 STATIC void GC_push_marked(struct hblk *h, hdr *hhdr)
 {
     word sz = hhdr -> hb_sz;
@@ -1900,7 +1876,6 @@ STATIC void GC_push_marked(struct hblk *h, hdr *hhdr)
 /* Unconditionally mark from all objects which have not been reclaimed. */
 /* This is useful in order to retain pointers which are reachable from  */
 /* the disclaim notifiers.                                              */
-/*                                                                      */
 /* To determine whether an object has been reclaimed, we require that   */
 /* any live object has a non-zero as one of the two lowest bits of the  */
 /* first word.  On the other hand, a reclaimed object is a members of   */
@@ -1975,7 +1950,7 @@ STATIC struct hblk * GC_push_next_marked(struct hblk *h)
 }
 
 #ifndef GC_DISABLE_INCREMENTAL
-  /* Identical to above, but mark only from dirty pages   */
+  /* Identical to above, but mark only from dirty pages.        */
   STATIC struct hblk * GC_push_next_marked_dirty(struct hblk *h)
   {
     hdr * hhdr = HDR(h);

+ 97 - 115
blitz.mod/bdwgc/mark_rts.c

@@ -36,9 +36,6 @@ struct roots GC_static_roots[MAX_ROOT_SETS];
 
 int GC_no_dls = 0;      /* Register dynamic library data segments.      */
 
-static int n_root_sets = 0;
-        /* GC_static_roots[0..n_root_sets) contains the valid root sets. */
-
 #if !defined(NO_DEBUGGING) || defined(GC_ASSERTIONS)
   /* Should return the same value as GC_root_size.      */
   GC_INNER word GC_compute_root_size(void)
@@ -271,15 +268,15 @@ void GC_add_roots_inner(ptr_t b, ptr_t e, GC_bool tmp)
     n_root_sets++;
 }
 
-static GC_bool roots_were_cleared = FALSE;
-
 GC_API void GC_CALL GC_clear_roots(void)
 {
     DCL_LOCK_STATE;
 
     if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
     LOCK();
-    roots_were_cleared = TRUE;
+#   ifdef THREADS
+      GC_roots_were_cleared = TRUE;
+#   endif
     n_root_sets = 0;
     GC_root_size = 0;
 #   if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
@@ -502,8 +499,11 @@ STATIC void GC_remove_tmp_roots(void)
 GC_INNER ptr_t GC_approx_sp(void)
 {
     volatile word sp;
-#   if defined(CPPCHECK) || (__GNUC__ >= 4 /* GC_GNUC_PREREQ(4, 0) */ \
-                             && !defined(STACK_NOT_SCANNED))
+#   if defined(S390) && !defined(CPPCHECK) && (__clang_major__ < 8)
+        /* Workaround a crash in SystemZTargetLowering of libLLVM-3.8.  */
+        sp = (word)&sp;
+#   elif defined(CPPCHECK) || (__GNUC__ >= 4 /* GC_GNUC_PREREQ(4, 0) */ \
+                               && !defined(STACK_NOT_SCANNED))
         /* TODO: Use GC_GNUC_PREREQ after fixing a bug in cppcheck. */
         sp = (word)__builtin_frame_address(0);
 #   else
@@ -529,7 +529,10 @@ struct exclusion GC_excl_table[MAX_EXCLUSIONS];
                                         -- address order.
 */
 
-STATIC size_t GC_excl_table_entries = 0;/* Number of entries in use.      */
+GC_API void GC_CALL GC_clear_exclusion_table(void)
+{
+    GC_excl_table_entries = 0;
+}
 
 /* Return the first exclusion range that includes an address >= start_addr */
 /* Assumes the exclusion table contains at least one entry (namely the     */
@@ -537,8 +540,10 @@ STATIC size_t GC_excl_table_entries = 0;/* Number of entries in use.      */
 STATIC struct exclusion * GC_next_exclusion(ptr_t start_addr)
 {
     size_t low = 0;
-    size_t high = GC_excl_table_entries - 1;
+    size_t high;
 
+    GC_ASSERT(GC_excl_table_entries > 0);
+    high = GC_excl_table_entries - 1;
     while (high > low) {
         size_t mid = (low + high) >> 1;
 
@@ -773,27 +778,19 @@ STATIC void GC_push_all_stack_part_eager_sections(ptr_t lo, ptr_t hi,
 
 #endif /* !THREADS */
 
-                        /* Push enough of the current stack eagerly to  */
-                        /* ensure that callee-save registers saved in   */
-                        /* GC frames are scanned.                       */
-                        /* In the non-threads case, schedule entire     */
-                        /* stack for scanning.                          */
-                        /* The second argument is a pointer to the      */
-                        /* (possibly null) thread context, for          */
-                        /* (currently hypothetical) more precise        */
-                        /* stack scanning.                              */
-/*
- * In the absence of threads, push the stack contents.
- * In the presence of threads, push enough of the current stack
- * to ensure that callee-save registers saved in collector frames have been
- * seen.
- * TODO: Merge it with per-thread stuff.
- */
+/* Push enough of the current stack eagerly to ensure that callee-save  */
+/* registers saved in GC frames are scanned.  In the non-threads case,  */
+/* schedule entire stack for scanning.  The 2nd argument is a pointer   */
+/* to the (possibly null) thread context, for (currently hypothetical)  */
+/* more precise stack scanning.  In the presence of threads, push       */
+/* enough of the current stack to ensure that callee-save registers     */
+/* saved in collector frames have been seen.                            */
+/* TODO: Merge it with per-thread stuff. */
 STATIC void GC_push_current_stack(ptr_t cold_gc_frame,
                                   void * context GC_ATTR_UNUSED)
 {
 #   if defined(THREADS)
-        if (0 == cold_gc_frame) return;
+        /* cold_gc_frame is non-NULL.   */
 #       ifdef STACK_GROWS_DOWN
           GC_push_all_eager(GC_approx_sp(), cold_gc_frame);
           /* For IA64, the register stack backing store is handled      */
@@ -838,27 +835,6 @@ STATIC void GC_push_current_stack(ptr_t cold_gc_frame,
 
 GC_INNER void (*GC_push_typed_structures)(void) = 0;
 
-                        /* Push GC internal roots.  These are normally  */
-                        /* included in the static data segment, and     */
-                        /* Thus implicitly pushed.  But we must do this */
-                        /* explicitly if normal root processing is      */
-                        /* disabled.                                    */
-/*
- * Push GC internal roots.  Only called if there is some reason to believe
- * these would not otherwise get registered.
- */
-STATIC void GC_push_gc_structures(void)
-{
-#   ifndef GC_NO_FINALIZATION
-      GC_push_finalizer_structures();
-#   endif
-#   if defined(THREADS)
-      GC_push_thread_structures();
-#   endif
-    if( GC_push_typed_structures )
-      GC_push_typed_structures();
-}
-
 GC_INNER void GC_cond_register_dynamic_libraries(void)
 {
 # if (defined(DYNAMIC_LOADING) && !defined(MSWIN_XBOX1)) \
@@ -873,85 +849,91 @@ GC_INNER void GC_cond_register_dynamic_libraries(void)
 
 STATIC void GC_push_regs_and_stack(ptr_t cold_gc_frame)
 {
+#   ifdef THREADS
+      if (NULL == cold_gc_frame)
+        return; /* GC_push_all_stacks should push registers and stack */
+#   endif
     GC_with_callee_saves_pushed(GC_push_current_stack, cold_gc_frame);
 }
 
-/*
- * Call the mark routines (GC_push_one for a single pointer,
- * GC_push_conditional on groups of pointers) on every top level
- * accessible pointer.
- * If all is FALSE, arrange to push only possibly altered values.
- * Cold_gc_frame is an address inside a GC frame that
- * remains valid until all marking is complete.
- * A zero value indicates that it's OK to miss some
- * register values.
- */
+/* Call the mark routines (GC_push_one for a single pointer,            */
+/* GC_push_conditional on groups of pointers) on every top level        */
+/* accessible pointer.  If all is false, arrange to push only possibly  */
+/* altered values.  Cold_gc_frame is an address inside a GC frame that  */
+/* remains valid until all marking is complete; a NULL value indicates  */
+/* that it is OK to miss some register values.  Called with the         */
+/* allocation lock held.                                                */
 GC_INNER void GC_push_roots(GC_bool all, ptr_t cold_gc_frame GC_ATTR_UNUSED)
 {
     int i;
     unsigned kind;
 
-    /*
-     * Next push static data.  This must happen early on, since it's
-     * not robust against mark stack overflow.
-     */
-     /* Re-register dynamic libraries, in case one got added.           */
-     /* There is some argument for doing this as late as possible,      */
-     /* especially on win32, where it can change asynchronously.        */
-     /* In those cases, we do it here.  But on other platforms, it's    */
-     /* not safe with the world stopped, so we do it earlier.           */
-#      if !defined(REGISTER_LIBRARIES_EARLY)
-         GC_cond_register_dynamic_libraries();
-#      endif
-
-     /* Mark everything in static data areas                             */
-       for (i = 0; i < n_root_sets; i++) {
-         GC_push_conditional_with_exclusions(
+    /* Next push static data.  This must happen early on, since it is   */
+    /* not robust against mark stack overflow.                          */
+    /* Re-register dynamic libraries, in case one got added.            */
+    /* There is some argument for doing this as late as possible,       */
+    /* especially on win32, where it can change asynchronously.         */
+    /* In those cases, we do it here.  But on other platforms, it's     */
+    /* not safe with the world stopped, so we do it earlier.            */
+#   if !defined(REGISTER_LIBRARIES_EARLY)
+        GC_cond_register_dynamic_libraries();
+#   endif
+
+    /* Mark everything in static data areas.                            */
+    for (i = 0; i < n_root_sets; i++) {
+        GC_push_conditional_with_exclusions(
                              GC_static_roots[i].r_start,
                              GC_static_roots[i].r_end, all);
-       }
-
-     /* Mark all free list header blocks, if those were allocated from  */
-     /* the garbage collected heap.  This makes sure they don't         */
-     /* disappear if we are not marking from static data.  It also      */
-     /* saves us the trouble of scanning them, and possibly that of     */
-     /* marking the freelists.                                          */
-       for (kind = 0; kind < GC_n_kinds; kind++) {
-         void *base = GC_base(GC_obj_kinds[kind].ok_freelist);
-         if (0 != base) {
-           GC_set_mark_bit(base);
-         }
-       }
-
-     /* Mark from GC internal roots if those might otherwise have       */
-     /* been excluded.                                                  */
-       if (GC_no_dls || roots_were_cleared) {
-           GC_push_gc_structures();
-       }
-
-     /* Mark thread local free lists, even if their mark        */
-     /* descriptor excludes the link field.                     */
-     /* If the world is not stopped, this is unsafe.  It is     */
-     /* also unnecessary, since we will do this again with the  */
-     /* world stopped.                                          */
-#      if defined(THREAD_LOCAL_ALLOC)
-         if (GC_world_stopped) GC_mark_thread_local_free_lists();
-#      endif
-
-    /*
-     * Now traverse stacks, and mark from register contents.
-     * These must be done last, since they can legitimately overflow
-     * the mark stack.
-     * This is usually done by saving the current context on the
-     * stack, and then just tracing from the stack.
-     */
-#    ifndef STACK_NOT_SCANNED
-       GC_push_regs_and_stack(cold_gc_frame);
-#    endif
-
-    if (GC_push_other_roots != 0) (*GC_push_other_roots)();
+    }
+
+    /* Mark all free list header blocks, if those were allocated from   */
+    /* the garbage collected heap.  This makes sure they don't          */
+    /* disappear if we are not marking from static data.  It also       */
+    /* saves us the trouble of scanning them, and possibly that of      */
+    /* marking the freelists.                                           */
+    for (kind = 0; kind < GC_n_kinds; kind++) {
+        void *base = GC_base(GC_obj_kinds[kind].ok_freelist);
+        if (base != NULL) {
+            GC_set_mark_bit(base);
+        }
+    }
+
+    /* Mark from GC internal roots if those might otherwise have        */
+    /* been excluded.                                                   */
+#   ifndef GC_NO_FINALIZATION
+        GC_push_finalizer_structures();
+#   endif
+#   ifdef THREADS
+        if (GC_no_dls || GC_roots_were_cleared)
+            GC_push_thread_structures();
+#   endif
+    if (GC_push_typed_structures)
+        GC_push_typed_structures();
+
+    /* Mark thread local free lists, even if their mark        */
+    /* descriptor excludes the link field.                     */
+    /* If the world is not stopped, this is unsafe.  It is     */
+    /* also unnecessary, since we will do this again with the  */
+    /* world stopped.                                          */
+#   if defined(THREAD_LOCAL_ALLOC)
+        if (GC_world_stopped)
+            GC_mark_thread_local_free_lists();
+#   endif
+
+    /* Now traverse stacks, and mark from register contents.    */
+    /* These must be done last, since they can legitimately     */
+    /* overflow the mark stack.  This is usually done by saving */
+    /* the current context on the stack, and then just tracing  */
+    /* from the stack.                                          */
+#   ifndef STACK_NOT_SCANNED
+        GC_push_regs_and_stack(cold_gc_frame);
+#   endif
+
+    if (GC_push_other_roots != 0) {
         /* In the threads case, this also pushes thread stacks. */
         /* Note that without interior pointer recognition lots  */
         /* of stuff may have been pushed already, and this      */
         /* should be careful about mark stack overflows.        */
+        (*GC_push_other_roots)();
+    }
 }

+ 138 - 68
blitz.mod/bdwgc/misc.c

@@ -2,6 +2,7 @@
  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved.
+ * Copyright (c) 2008-2020 Ivan Maidanski
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -27,21 +28,17 @@
 # include <sys/syscall.h>
 #endif
 
-#if defined(MSWIN32) || defined(MSWINCE) \
-    || (defined(CYGWIN32) && defined(GC_READ_ENV_FILE))
-# ifndef WIN32_LEAN_AND_MEAN
-#   define WIN32_LEAN_AND_MEAN 1
-# endif
-# define NOSERVICE
-# include <windows.h>
-#endif
-
-#if defined(UNIX_LIKE) || defined(CYGWIN32) || defined(SYMBIAN)
+#if defined(UNIX_LIKE) || defined(CYGWIN32) || defined(SYMBIAN) \
+    || (defined(CONSOLE_LOG) && defined(MSWIN32))
 # include <fcntl.h>
 # include <sys/types.h>
 # include <sys/stat.h>
 #endif
 
+#if defined(CONSOLE_LOG) && defined(MSWIN32) && defined(_MSC_VER)
+# include <io.h>
+#endif
+
 #ifdef NONSTOP
 # include <floss.h>
 #endif
@@ -78,6 +75,10 @@
 
 GC_FAR struct _GC_arrays GC_arrays /* = { 0 } */;
 
+GC_INNER unsigned GC_n_mark_procs = GC_RESERVED_MARK_PROCS;
+
+GC_INNER unsigned GC_n_kinds = GC_N_KINDS_INITIAL_VALUE;
+
 GC_INNER GC_bool GC_debugging_started = FALSE;
                 /* defined here so we don't have to load dbg_mlc.o */
 
@@ -314,7 +315,11 @@ STATIC void GC_init_size_map(void)
       }
       /* Make sure the recursive call is not a tail call, and the bzero */
       /* call is not recognized as dead code.                           */
-      GC_noop1(COVERT_DATAFLOW(dummy));
+#     if defined(CPPCHECK)
+        GC_noop1(dummy[0]);
+#     else
+        GC_noop1(COVERT_DATAFLOW(dummy));
+#     endif
       return(arg);
     }
 # endif /* !ASM_CLEAR_CODE */
@@ -745,8 +750,8 @@ GC_API int GC_CALL GC_is_init_called(void)
   return GC_is_initialized;
 }
 
-#if (defined(MSWIN32) || defined(MSWINCE) || defined(MSWIN_XBOX1)) \
-    && defined(THREADS)
+#if defined(GC_WIN32_THREADS) \
+    && ((defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE))
   GC_INNER CRITICAL_SECTION GC_write_cs;
 #endif
 
@@ -805,19 +810,20 @@ GC_API int GC_CALL GC_is_init_called(void)
 
 #if !defined(OS2) && !defined(MACOS) && !defined(GC_ANDROID_LOG) \
     && !defined(NN_PLATFORM_CTR) && !defined(NINTENDO_SWITCH) \
-    && !defined(MSWIN32) && !defined(MSWINCE)
+    && (!defined(MSWIN32) || defined(CONSOLE_LOG)) && !defined(MSWINCE)
   STATIC int GC_stdout = GC_DEFAULT_STDOUT_FD;
   STATIC int GC_stderr = GC_DEFAULT_STDERR_FD;
   STATIC int GC_log = GC_DEFAULT_STDERR_FD;
 
-  GC_API void GC_CALL GC_set_log_fd(int fd)
-  {
-    GC_log = fd;
-  }
+# ifndef MSWIN32
+    GC_API void GC_CALL GC_set_log_fd(int fd)
+    {
+      GC_log = fd;
+    }
+# endif
 #endif
 
-#if defined(MSWIN32) && !defined(MSWINRT_FLAVOR) && !defined(MSWIN_XBOX1) \
-    && !defined(SMALL_CONFIG)
+#ifdef MSGBOX_ON_ERROR
   STATIC void GC_win32_MessageBoxA(const char *msg, const char *caption,
                                    unsigned flags)
   {
@@ -830,13 +836,13 @@ GC_API int GC_CALL GC_is_init_called(void)
       if (hU32) {
         FARPROC pfn = GetProcAddress(hU32, "MessageBoxA");
         if (pfn)
-          (void)(*(int (WINAPI *)(HWND, LPCSTR, LPCSTR, UINT))pfn)(
+          (void)(*(int (WINAPI *)(HWND, LPCSTR, LPCSTR, UINT))(word)pfn)(
                               NULL /* hWnd */, msg, caption, flags);
         (void)FreeLibrary(hU32);
       }
 #   endif
   }
-#endif /* MSWIN32 */
+#endif /* MSGBOX_ON_ERROR */
 
 #if defined(THREADS) && defined(UNIX_LIKE) && !defined(NO_GETCONTEXT)
   static void callee_saves_pushed_dummy_fn(ptr_t data GC_ATTR_UNUSED,
@@ -957,21 +963,22 @@ GC_API void GC_CALL GC_init(void)
 #     else
         {
 #         ifndef MSWINCE
-            BOOL (WINAPI *pfn)(LPCRITICAL_SECTION, DWORD) = 0;
+            FARPROC pfn = 0;
             HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll"));
             if (hK32)
-              pfn = (BOOL (WINAPI *)(LPCRITICAL_SECTION, DWORD))
-                      GetProcAddress(hK32,
-                                     "InitializeCriticalSectionAndSpinCount");
+              pfn = GetProcAddress(hK32,
+                                   "InitializeCriticalSectionAndSpinCount");
             if (pfn) {
-              pfn(&GC_allocate_ml, SPIN_COUNT);
+              (*(BOOL (WINAPI *)(LPCRITICAL_SECTION, DWORD))(word)pfn)(
+                                &GC_allocate_ml, SPIN_COUNT);
             } else
 #         endif /* !MSWINCE */
           /* else */ InitializeCriticalSection(&GC_allocate_ml);
         }
 #     endif
-#   endif /* GC_WIN32_THREADS */
-#   if (defined(MSWIN32) || defined(MSWINCE)) && defined(THREADS)
+#   endif /* GC_WIN32_THREADS && !GC_PTHREADS */
+#   if defined(GC_WIN32_THREADS) \
+       && ((defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE))
       InitializeCriticalSection(&GC_write_cs);
 #   endif
     GC_setpagesize();
@@ -995,6 +1002,7 @@ GC_API void GC_CALL GC_init(void)
 #     endif
 #   endif
 #   if ((defined(UNIX_LIKE) && !defined(GC_ANDROID_LOG)) \
+        || (defined(CONSOLE_LOG) && defined(MSWIN32)) \
         || defined(CYGWIN32) || defined(SYMBIAN)) && !defined(SMALL_CONFIG)
         {
           char * file_name = TRUSTED_STRING(GETENV("GC_LOG_FILE"));
@@ -1005,7 +1013,11 @@ GC_API void GC_CALL GC_init(void)
             if (0 != file_name)
 #         endif
           {
-            int log_d = open(file_name, O_CREAT | O_WRONLY | O_APPEND, 0644);
+#           if defined(_MSC_VER)
+              int log_d = _open(file_name, O_CREAT | O_WRONLY | O_APPEND);
+#           else
+              int log_d = open(file_name, O_CREAT | O_WRONLY | O_APPEND, 0644);
+#           endif
             if (log_d < 0) {
               GC_err_printf("Failed to open %s as log file\n", file_name);
             } else {
@@ -1087,15 +1099,12 @@ GC_API void GC_CALL GC_init(void)
         }
       }
 #   endif
-#   ifndef GC_DISABLE_INCREMENTAL
+#   if !defined(GC_DISABLE_INCREMENTAL) && !defined(NO_CLOCK)
       {
         char * time_limit_string = GETENV("GC_PAUSE_TIME_TARGET");
         if (0 != time_limit_string) {
           long time_limit = atol(time_limit_string);
-          if (time_limit < 5) {
-            WARN("GC_PAUSE_TIME_TARGET environment variable value too small "
-                 "or bad syntax: Ignoring\n", 0);
-          } else {
+          if (time_limit > 0) {
             GC_time_limit = time_limit;
           }
         }
@@ -1186,7 +1195,7 @@ GC_API void GC_CALL GC_init(void)
 #   if defined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS)
         WARN("USE_PROC_FOR_LIBRARIES + GC_LINUX_THREADS performs poorly.\n", 0);
         /* If thread stacks are cached, they tend to be scanned in      */
-        /* entirety as part of the root set.  This wil grow them to     */
+        /* entirety as part of the root set.  This will grow them to    */
         /* maximum size, and is generally not desirable.                */
 #   endif
 #   if defined(SEARCH_FOR_DATA_START)
@@ -1233,6 +1242,7 @@ GC_API void GC_CALL GC_init(void)
 #   ifndef GC_DISABLE_INCREMENTAL
       if (GC_incremental || 0 != GETENV("GC_ENABLE_INCREMENTAL")) {
 #       if defined(BASE_ATOMIC_OPS_EMULATED) || defined(CHECKSUMS) \
+           || defined(REDIRECT_MALLOC) || defined(REDIRECT_MALLOC_IN_HEADER) \
            || defined(SMALL_CONFIG)
           /* TODO: Implement CHECKSUMS for manual VDB. */
 #       else
@@ -1379,7 +1389,8 @@ GC_API void GC_CALL GC_enable_incremental(void)
           LOCK();
         } else {
 #         if !defined(BASE_ATOMIC_OPS_EMULATED) && !defined(CHECKSUMS) \
-             && !defined(SMALL_CONFIG)
+             && !defined(REDIRECT_MALLOC) \
+             && !defined(REDIRECT_MALLOC_IN_HEADER) && !defined(SMALL_CONFIG)
             if (manual_vdb_allowed) {
               GC_manual_vdb = TRUE;
               GC_incremental = TRUE;
@@ -1435,14 +1446,16 @@ GC_API void GC_CALL GC_enable_incremental(void)
     if (GC_is_initialized) {
       /* Prevent duplicate resource close.  */
       GC_is_initialized = FALSE;
-#     if defined(THREADS) && (defined(MSWIN32) || defined(MSWINCE))
-        DeleteCriticalSection(&GC_write_cs);
+#     if defined(GC_WIN32_THREADS) && (defined(MSWIN32) || defined(MSWINCE))
+#       if !defined(CONSOLE_LOG) || defined(MSWINCE)
+          DeleteCriticalSection(&GC_write_cs);
+#       endif
         DeleteCriticalSection(&GC_allocate_ml);
 #     endif
     }
   }
 
-#if defined(MSWIN32) || defined(MSWINCE)
+#if (defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE)
 
 # if defined(_MSC_VER) && defined(_DEBUG) && !defined(MSWINCE)
 #   include <crtdbg.h>
@@ -1552,7 +1565,11 @@ GC_API void GC_CALL GC_enable_incremental(void)
 
 # else
     TCHAR *logPath;
-    BOOL appendToFile = FALSE;
+#   if defined(NO_GETENV_WIN32) && defined(CPPCHECK)
+#     define appendToFile FALSE
+#   else
+      BOOL appendToFile = FALSE;
+#   endif
 #   if !defined(NO_GETENV_WIN32) || !defined(OLD_WIN32_LOG_FILE)
       TCHAR pathBuf[_MAX_PATH + 0x10]; /* buffer for path + ext */
 
@@ -1597,6 +1614,7 @@ GC_API void GC_CALL GC_enable_incremental(void)
                                   /* Seek to file end (ignoring any error) */
       }
 #   endif
+#   undef appendToFile
 # endif
     return hFile;
   }
@@ -1635,7 +1653,7 @@ GC_API void GC_CALL GC_enable_incremental(void)
 #       endif
       }
       res = WriteFile(GC_log, buf, (DWORD)len, &written, NULL);
-#     if defined(_MSC_VER) && defined(_DEBUG)
+#     if defined(_MSC_VER) && defined(_DEBUG) && !defined(NO_CRT)
 #         ifdef MSWINCE
               /* There is no CrtDbgReport() in WinCE */
               {
@@ -1700,18 +1718,25 @@ GC_API void GC_CALL GC_enable_incremental(void)
 # define WRITE(level, buf, unused_len) \
                 __android_log_write(level, GC_ANDROID_LOG_TAG, buf)
 
-# elif defined(NN_PLATFORM_CTR)
-    int n3ds_log_write(const char* text, int length);
-#   define WRITE(level, buf, len) n3ds_log_write(buf, len)
-# elif defined(NINTENDO_SWITCH)
-    int switch_log_write(const char* text, int length);
-#   define WRITE(level, buf, len) switch_log_write(buf, len)
+#elif defined(NN_PLATFORM_CTR)
+  int n3ds_log_write(const char* text, int length);
+# define WRITE(level, buf, len) n3ds_log_write(buf, len)
+
+#elif defined(NINTENDO_SWITCH)
+  int switch_log_write(const char* text, int length);
+# define WRITE(level, buf, len) switch_log_write(buf, len)
 
 #else
-# if !defined(AMIGA) && !defined(MSWIN_XBOX1) && !defined(SN_TARGET_ORBIS) \
-     && !defined(SN_TARGET_PSP2) && !defined(__CC_ARM)
-#   include <unistd.h>
-# endif
+
+# if !defined(SN_TARGET_ORBIS) && !defined(SN_TARGET_PSP2)
+#   if !defined(AMIGA) && !defined(MSWIN32) && !defined(MSWIN_XBOX1) \
+       && !defined(__CC_ARM)
+#     include <unistd.h>
+#   endif
+#   if !defined(ECOS) && !defined(NOSYS)
+#     include <errno.h>
+#   endif
+# endif /* !SN_TARGET_ORBIS && !SN_TARGET_PSP2 */
 
   STATIC int GC_write(int fd, const char *buf, size_t len)
   {
@@ -1733,11 +1758,16 @@ GC_API void GC_CALL GC_enable_incremental(void)
 #        ifdef GC_SOLARIS_THREADS
              int result = syscall(SYS_write, fd, buf + bytes_written,
                                              len - bytes_written);
+#        elif defined(_MSC_VER)
+             int result = _write(fd, buf + bytes_written,
+                                 (unsigned)(len - bytes_written));
 #        else
              int result = write(fd, buf + bytes_written, len - bytes_written);
 #        endif
 
          if (-1 == result) {
+             if (EAGAIN == errno) /* Resource temporarily unavailable */
+               continue;
              RESTORE_CANCEL(cancel_state);
              return(result);
          }
@@ -1749,7 +1779,7 @@ GC_API void GC_CALL GC_enable_incremental(void)
   }
 
 # define WRITE(f, buf, len) GC_write(f, buf, len)
-#endif /* !MSWIN32 && !OS2 && !MACOS && !GC_ANDROID_LOG */
+#endif /* !MSWINCE && !OS2 && !MACOS && !GC_ANDROID_LOG */
 
 #define BUFSZ 1024
 
@@ -1793,8 +1823,13 @@ void GC_printf(const char *format, ...)
         (void)WRITE(GC_stdout, buf, strlen(buf));
         /* Ignore errors silently.      */
 #     else
-        if (WRITE(GC_stdout, buf, strlen(buf)) < 0)
+        if (WRITE(GC_stdout, buf, strlen(buf)) < 0
+#           if defined(CYGWIN32) || (defined(CONSOLE_LOG) && defined(MSWIN32))
+              && GC_stdout != GC_DEFAULT_STDOUT_FD
+#           endif
+           ) {
           ABORT("write to stdout failed");
+        }
 #     endif
     }
 }
@@ -1815,8 +1850,13 @@ void GC_log_printf(const char *format, ...)
 #   ifdef NACL
       (void)WRITE(GC_log, buf, strlen(buf));
 #   else
-      if (WRITE(GC_log, buf, strlen(buf)) < 0)
+      if (WRITE(GC_log, buf, strlen(buf)) < 0
+#         if defined(CYGWIN32) || (defined(CONSOLE_LOG) && defined(MSWIN32))
+            && GC_log != GC_DEFAULT_STDERR_FD
+#         endif
+         ) {
         ABORT("write to GC log failed");
+      }
 #   endif
 }
 
@@ -1912,7 +1952,7 @@ GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void)
 #   endif
 
     if (msg != NULL) {
-#     if defined(MSWIN32) && !defined(MSWINRT_FLAVOR) && !defined(MSWIN_XBOX1)
+#     ifdef MSGBOX_ON_ERROR
         GC_win32_MessageBoxA(msg, "Fatal error in GC", MB_ICONERROR | MB_OK);
         /* Also duplicate msg to GC log file.   */
 #     endif
@@ -1921,8 +1961,8 @@ GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void)
       /* Avoid calling GC_err_printf() here, as GC_on_abort() could be  */
       /* called from it.  Note 1: this is not an atomic output.         */
       /* Note 2: possible write errors are ignored.                     */
-#     if defined(THREADS) && defined(GC_ASSERTIONS) \
-         && (defined(MSWIN32) || defined(MSWINCE))
+#     if defined(GC_WIN32_THREADS) && defined(GC_ASSERTIONS) \
+         && ((defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE))
         if (!GC_write_disabled)
 #     endif
       {
@@ -2019,6 +2059,7 @@ GC_API unsigned GC_CALL GC_new_kind_inner(void **fl, GC_word descr,
 {
     unsigned result = GC_n_kinds;
 
+    GC_ASSERT(NONNULL_ARG_NOT_NULL(fl));
     GC_ASSERT(adjust == FALSE || adjust == TRUE);
     /* If an object is not needed to be cleared (when moved to the      */
     /* free list) then its descriptor should be zero to denote          */
@@ -2027,6 +2068,7 @@ GC_API unsigned GC_CALL GC_new_kind_inner(void **fl, GC_word descr,
     GC_ASSERT(clear == TRUE
               || (descr == 0 && adjust == FALSE && clear == FALSE));
     if (result < MAXOBJKINDS) {
+      GC_ASSERT(result > 0);
       GC_n_kinds++;
       GC_obj_kinds[result].ok_freelist = fl;
       GC_obj_kinds[result].ok_reclaim_list = 0;
@@ -2127,7 +2169,7 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
     struct GC_traced_stack_sect_s stacksect;
     GC_ASSERT(GC_is_initialized);
 
-    /* Adjust our stack base value (this could happen if        */
+    /* Adjust our stack bottom pointer (this could happen if    */
     /* GC_get_main_stack_base() is unimplemented or broken for  */
     /* the platform).                                           */
     if ((word)GC_stackbottom HOTTER_THAN (word)(&stacksect))
@@ -2199,16 +2241,32 @@ STATIC void GC_do_blocking_inner(ptr_t data, void * context GC_ATTR_UNUSED)
     GC_blocked_sp = NULL;
 }
 
+  GC_API void GC_CALL GC_set_stackbottom(void *gc_thread_handle,
+                                         const struct GC_stack_base *sb)
+  {
+    GC_ASSERT(sb -> mem_base != NULL);
+    GC_ASSERT(NULL == gc_thread_handle || &GC_stackbottom == gc_thread_handle);
+    GC_ASSERT(NULL == GC_blocked_sp
+              && NULL == GC_traced_stack_sect); /* for now */
+    (void)gc_thread_handle;
+
+    GC_stackbottom = (char *)sb->mem_base;
+#   ifdef IA64
+      GC_register_stackbottom = (ptr_t)sb->reg_base;
+#   endif
+  }
+
+  GC_API void * GC_CALL GC_get_my_stackbottom(struct GC_stack_base *sb)
+  {
+    GC_ASSERT(GC_is_initialized);
+    sb -> mem_base = GC_stackbottom;
+#   ifdef IA64
+      sb -> reg_base = GC_register_stackbottom;
+#   endif
+    return &GC_stackbottom; /* gc_thread_handle */
+  }
 #endif /* !THREADS */
 
-/* Wrapper for functions that are likely to block (or, at least, do not */
-/* allocate garbage collected memory and/or manipulate pointers to the  */
-/* garbage collected heap) for an appreciable length of time.           */
-/* In the single threaded case, GC_do_blocking() (together              */
-/* with GC_call_with_gc_active()) might be used to make stack scanning  */
-/* more precise (i.e. scan only stack frames of functions that allocate */
-/* garbage collected memory and/or manipulate pointers to the garbage   */
-/* collected heap).                                                     */
 GC_API void * GC_CALL GC_do_blocking(GC_fn_type fn, void * client_data)
 {
     struct blocking_data my_data;
@@ -2243,7 +2301,7 @@ GC_API void * GC_CALL GC_do_blocking(GC_fn_type fn, void * client_data)
     }
 #   ifndef NO_CLOCK
       /* Note that the time is wrapped in ~49 days if sizeof(long)==4.  */
-      GC_printf("Time since GC init: %lu msecs\n",
+      GC_printf("Time since GC init: %lu ms\n",
                 MS_TIME_DIFF(current_time, GC_init_time));
 #   endif
 
@@ -2293,6 +2351,18 @@ GC_API GC_word GC_CALL GC_get_gc_no(void)
     return GC_parallel;
   }
 
+  GC_API void GC_CALL GC_alloc_lock(void)
+  {
+    DCL_LOCK_STATE;
+    LOCK();
+  }
+
+  GC_API void GC_CALL GC_alloc_unlock(void)
+  {
+    /* no DCL_LOCK_STATE */
+    UNLOCK();
+  }
+
   GC_INNER GC_on_thread_event_proc GC_on_thread_event = 0;
 
   GC_API void GC_CALL GC_set_on_thread_event(GC_on_thread_event_proc fn)

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

@@ -18,7 +18,7 @@
 /*
  * This file contains the functions:
  *      ptr_t GC_build_flXXX(h, old_fl)
- *      void GC_new_hblk(size)
+ *      void GC_new_hblk(size, kind)
  */
 
 #include <stdio.h>

+ 1 - 0
blitz.mod/bdwgc/obj_map.c

@@ -35,6 +35,7 @@ GC_API void GC_CALL GC_register_displacement(size_t offset)
 
 GC_INNER void GC_register_displacement_inner(size_t offset)
 {
+    GC_ASSERT(I_HOLD_LOCK());
     if (offset >= VALID_OFFSET_SZ) {
         ABORT("Bad argument to GC_register_displacement");
     }

+ 200 - 150
blitz.mod/bdwgc/os_dep.c

@@ -3,6 +3,7 @@
  * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
  * Copyright (c) 1999 by Hewlett-Packard Company.  All rights reserved.
+ * Copyright (c) 2008-2020 Ivan Maidanski
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -50,16 +51,6 @@
 # undef GC_AMIGA_DEF
 #endif
 
-#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
-# ifndef WIN32_LEAN_AND_MEAN
-#   define WIN32_LEAN_AND_MEAN 1
-# endif
-# define NOSERVICE
-# include <windows.h>
-  /* It's not clear this is completely kosher under Cygwin.  But it     */
-  /* allows us to get a working GC_get_stack_base.                      */
-#endif
-
 #ifdef MACOS
 # include <Processes.h>
 #endif
@@ -209,7 +200,12 @@ GC_INNER char * GC_get_maps(void)
             int f;
 
             while (maps_size >= maps_buf_sz) {
-              GC_scratch_recycle_no_gww(maps_buf, maps_buf_sz);
+#             ifdef LINT2
+                /* Workaround passing tainted maps_buf to a tainted sink. */
+                GC_noop1((word)maps_buf);
+#             else
+                GC_scratch_recycle_no_gww(maps_buf, maps_buf_sz);
+#             endif
               /* Grow only by powers of 2, since we leak "too small" buffers.*/
               while (maps_size >= maps_buf_sz) maps_buf_sz *= 2;
               maps_buf = GC_scratch_alloc(maps_buf_sz);
@@ -231,13 +227,13 @@ GC_INNER char * GC_get_maps(void)
             maps_size = 0;
             do {
                 result = GC_repeat_read(f, maps_buf, maps_buf_sz-1);
-                if (result <= 0)
-                  break;
+                if (result <= 0) {
+                    close(f);
+                    return 0;
+                }
                 maps_size += result;
             } while ((size_t)result == maps_buf_sz-1);
             close(f);
-            if (result <= 0)
-              return 0;
 #           ifdef THREADS
               if (maps_size > old_maps_size) {
                 /* This might be caused by e.g. thread creation. */
@@ -303,10 +299,12 @@ GC_INNER char * GC_get_maps(void)
     GC_ASSERT(*p == 'r' || *p == '-');
     *prot = (char *)p;
     /* Skip past protection field to offset field */
-       while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
+    while (!isspace(*p)) ++p;
+    while (isspace(*p)) p++;
     GC_ASSERT(isxdigit(*p));
     /* Skip past offset field, which we ignore */
-          while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
+    while (!isspace(*p)) ++p;
+    while (isspace(*p)) p++;
     maj_dev_start = p;
     GC_ASSERT(isxdigit(*maj_dev_start));
     *maj_dev = strtoul((char *)maj_dev_start, NULL, 16);
@@ -429,8 +427,12 @@ GC_INNER char * GC_get_maps(void)
   {
     ptr_t data_end = DATAEND;
 
-#   if (defined(LINUX) || defined(HURD)) && !defined(IGNORE_PROG_DATA_START)
+#   if (defined(LINUX) || defined(HURD)) && defined(USE_PROG_DATA_START)
       /* Try the easy approaches first: */
+      /* However, this may lead to wrong data start value if libgc  */
+      /* code is put into a shared library (directly or indirectly) */
+      /* which is linked with -Bsymbolic-functions option.  Thus,   */
+      /* the following is not used by default.                      */
       if (COVERT_DATAFLOW(__data_start) != 0) {
         GC_data_start = (ptr_t)(__data_start);
       } else {
@@ -574,12 +576,13 @@ GC_INNER char * GC_get_maps(void)
     return(result);
   }
 
+  static volatile int firstpass;
+
   /* Return first addressable location > p or bound.    */
   /* Requires the allocation lock.                      */
   STATIC ptr_t GC_skip_hole_openbsd(ptr_t p, ptr_t bound)
   {
     static volatile ptr_t result;
-    static volatile int firstpass;
 
     struct sigaction act;
     word pgsz = (word)sysconf(_SC_PAGESIZE);
@@ -710,7 +713,7 @@ GC_INNER size_t GC_page_size = 0;
   GC_INNER void GC_setpagesize(void)
   {
     GetSystemInfo(&GC_sysinfo);
-#   if defined(CYGWIN32) && defined(USE_MUNMAP)
+#   if defined(CYGWIN32) && (defined(MPROTECT_VDB) || defined(USE_MUNMAP))
       /* Allocations made with mmap() are aligned to the allocation     */
       /* granularity, which (at least on 64-bit Windows OS) is not the  */
       /* same as the page size.  Probably a separate variable could     */
@@ -967,6 +970,7 @@ GC_INNER size_t GC_page_size = 0;
     /* the smallest location q s.t. [q,p) is addressable (!up). */
     /* We assume that p (up) or p-1 (!up) is addressable.       */
     /* Requires allocation lock.                                */
+    GC_ATTR_NO_SANITIZE_ADDR
     STATIC ptr_t GC_find_limit_with_bound(ptr_t p, GC_bool up, ptr_t bound)
     {
         static volatile ptr_t result;
@@ -1018,6 +1022,29 @@ GC_INNER size_t GC_page_size = 0;
     }
 # endif /* NEED_FIND_LIMIT || USE_PROC_FOR_LIBRARIES */
 
+#ifdef HPUX_MAIN_STACKBOTTOM
+# include <sys/param.h>
+# include <sys/pstat.h>
+
+  STATIC ptr_t GC_hpux_main_stack_base(void)
+  {
+    struct pst_vm_status vm_status;
+    int i = 0;
+
+    while (pstat_getprocvm(&vm_status, sizeof(vm_status), 0, i++) == 1) {
+      if (vm_status.pst_type == PS_STACK)
+        return (ptr_t)vm_status.pst_vaddr;
+    }
+
+    /* Old way to get the stack bottom. */
+#   ifdef STACK_GROWS_UP
+      return (ptr_t)GC_find_limit(GC_approx_sp(), /* up= */ FALSE);
+#   else /* not HP_PA */
+      return (ptr_t)GC_find_limit(GC_approx_sp(), TRUE);
+#   endif
+  }
+#endif /* HPUX_MAIN_STACKBOTTOM */
+
 #ifdef HPUX_STACKBOTTOM
 
 #include <sys/param.h>
@@ -1078,9 +1105,7 @@ GC_INNER size_t GC_page_size = 0;
       result = backing_store_base_from_proc();
       if (0 == result) {
           result = (ptr_t)GC_find_limit(GC_save_regs_in_stack(), FALSE);
-          /* Now seems to work better than constant displacement        */
-          /* heuristic used in 6.X versions.  The latter seems to       */
-          /* fail for 2.6 kernels.                                      */
+          /* This works better than a constant displacement heuristic.  */
       }
       return result;
     }
@@ -1088,7 +1113,7 @@ GC_INNER size_t GC_page_size = 0;
 
   STATIC ptr_t GC_linux_main_stack_base(void)
   {
-    /* We read the stack base value from /proc/self/stat.  We do this   */
+    /* We read the stack bottom value from /proc/self/stat.  We do this */
     /* using direct I/O system calls in order to avoid calling malloc   */
     /* in case REDIRECT_MALLOC is defined.                              */
 #   ifndef STAT_READ
@@ -1249,18 +1274,20 @@ GC_INNER size_t GC_page_size = 0;
 #   ifdef STACKBOTTOM
       result = STACKBOTTOM;
 #   else
-#     define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
 #     ifdef HEURISTIC1
+#       define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
 #       ifdef STACK_GROWS_DOWN
           result = (ptr_t)(((word)GC_approx_sp() + STACKBOTTOM_ALIGNMENT_M1)
                            & ~STACKBOTTOM_ALIGNMENT_M1);
 #       else
           result = (ptr_t)((word)GC_approx_sp() & ~STACKBOTTOM_ALIGNMENT_M1);
 #       endif
+#     elif defined(HPUX_MAIN_STACKBOTTOM)
+        result = GC_hpux_main_stack_base();
 #     elif defined(LINUX_STACKBOTTOM)
-         result = GC_linux_main_stack_base();
+        result = GC_linux_main_stack_base();
 #     elif defined(FREEBSD_STACKBOTTOM)
-         result = GC_freebsd_main_stack_base();
+        result = GC_freebsd_main_stack_base();
 #     elif defined(HEURISTIC2)
         {
           ptr_t sp = GC_approx_sp();
@@ -1292,7 +1319,9 @@ GC_INNER size_t GC_page_size = 0;
           result = (ptr_t)(signed_word)(-sizeof(ptr_t));
 #     endif
 #   endif
-    GC_ASSERT((word)GC_approx_sp() HOTTER_THAN (word)result);
+#   if !defined(CPPCHECK)
+      GC_ASSERT((word)GC_approx_sp() HOTTER_THAN (word)result);
+#   endif
     return(result);
   }
 # define GET_MAIN_STACKBASE_SPECIAL
@@ -1434,8 +1463,8 @@ GC_INNER size_t GC_page_size = 0;
 
     if (!stackbase_main_self && thr_main() != 0)
       {
-        /* Cache the stack base value for the primordial thread (this   */
-        /* is done during GC_init, so there is no race).                */
+        /* Cache the stack bottom pointer for the primordial thread     */
+        /* (this is done during GC_init, so there is no race).          */
         stackbase_main_ss_sp = s.ss_sp;
         stackbase_main_self = self;
       }
@@ -1457,7 +1486,7 @@ GC_INNER size_t GC_page_size = 0;
 
 #ifndef HAVE_GET_STACK_BASE
 # ifdef NEED_FIND_LIMIT
-    /* Retrieve stack base.                                             */
+    /* Retrieve the stack bottom.                                       */
     /* Using the GC_find_limit version is risky.                        */
     /* On IA64, for example, there is no guard page between the         */
     /* stack of one thread and the register backing store of the        */
@@ -1613,10 +1642,10 @@ void GC_register_data_segments(void)
     typedef UINT (WINAPI * GetWriteWatch_type)(
                                 DWORD, PVOID, GC_ULONG_PTR /* SIZE_T */,
                                 PVOID *, GC_ULONG_PTR *, PULONG);
-    static GetWriteWatch_type GetWriteWatch_func;
+    static FARPROC GetWriteWatch_func;
     static DWORD GetWriteWatch_alloc_flag;
 
-#   define GC_GWW_AVAILABLE() (GetWriteWatch_func != NULL)
+#   define GC_GWW_AVAILABLE() (GetWriteWatch_func != 0)
 
     static void detect_GetWriteWatch(void)
     {
@@ -1658,8 +1687,7 @@ void GC_register_data_segments(void)
         hK32 = GetModuleHandle(TEXT("kernel32.dll"));
 #     endif
       if (hK32 != (HMODULE)0 &&
-          (GetWriteWatch_func = (GetWriteWatch_type)GetProcAddress(hK32,
-                                                "GetWriteWatch")) != NULL) {
+          (GetWriteWatch_func = GetProcAddress(hK32, "GetWriteWatch")) != 0) {
         /* Also check whether VirtualAlloc accepts MEM_WRITE_WATCH,   */
         /* as some versions of kernel32.dll have one but not the      */
         /* other, making the feature completely broken.               */
@@ -1671,26 +1699,25 @@ void GC_register_data_segments(void)
           GC_ULONG_PTR count = 16;
           DWORD page_size;
           /* Check that it actually works.  In spite of some            */
-          /* documentation it actually seems to exist on W2K.           */
+          /* documentation it actually seems to exist on Win2K.         */
           /* This test may be unnecessary, but ...                      */
-          if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET,
-                                 page, GC_page_size,
-                                 pages,
-                                 &count,
-                                 &page_size) != 0) {
+          if ((*(GetWriteWatch_type)(word)GetWriteWatch_func)(
+                                        WRITE_WATCH_FLAG_RESET, page,
+                                        GC_page_size, pages, &count,
+                                        &page_size) != 0) {
             /* GetWriteWatch always fails. */
-            GetWriteWatch_func = NULL;
+            GetWriteWatch_func = 0;
           } else {
             GetWriteWatch_alloc_flag = MEM_WRITE_WATCH;
           }
           VirtualFree(page, 0 /* dwSize */, MEM_RELEASE);
         } else {
           /* GetWriteWatch will be useless. */
-          GetWriteWatch_func = NULL;
+          GetWriteWatch_func = 0;
         }
       }
 #     ifndef SMALL_CONFIG
-        if (GetWriteWatch_func == NULL) {
+        if (!GetWriteWatch_func) {
           GC_COND_LOG_PRINTF("Did not find a usable GetWriteWatch()\n");
         } else {
           GC_COND_LOG_PRINTF("Using GetWriteWatch()\n");
@@ -1719,7 +1746,7 @@ void GC_register_data_segments(void)
         /* assembly code to do that right.                              */
 
   GC_INNER GC_bool GC_wnt = FALSE;
-         /* This is a Windows NT derivative, i.e. NT, W2K, XP or later. */
+         /* This is a Windows NT derivative, i.e. NT, Win2K, XP or later. */
 
   GC_INNER void GC_init_win32(void)
   {
@@ -1768,7 +1795,7 @@ void GC_register_data_segments(void)
   }
 # endif /* MSWIN32 */
 
-# ifndef REDIRECT_MALLOC
+# if defined(USE_WINALLOC) && !defined(REDIRECT_MALLOC)
   /* We maintain a linked list of AllocationBase values that we know    */
   /* correspond to malloc heap sections.  Currently this is only called */
   /* during a GC.  But there is some hope that for long running         */
@@ -1780,7 +1807,6 @@ void GC_register_data_segments(void)
 
   STATIC size_t GC_max_root_size = 100000; /* Appr. largest root size.  */
 
-# ifdef USE_WINALLOC
   /* In the long run, a better data structure would also be nice ...    */
   STATIC struct GC_malloc_heap_list {
     void * allocation_base;
@@ -1843,24 +1869,35 @@ void GC_register_data_segments(void)
     new_l -> next = GC_malloc_heap_l;
     GC_malloc_heap_l = new_l;
   }
-# endif /* USE_WINALLOC */
 
-# endif /* !REDIRECT_MALLOC */
+  /* Free all the linked list nodes. Could be invoked at process exit   */
+  /* to avoid memory leak complains of a dynamic code analysis tool.    */
+  STATIC void GC_free_malloc_heap_list(void)
+  {
+    struct GC_malloc_heap_list *q = GC_malloc_heap_l;
 
-  STATIC word GC_n_heap_bases = 0;      /* See GC_heap_bases.   */
+    GC_malloc_heap_l = NULL;
+    while (q != NULL) {
+      struct GC_malloc_heap_list *next = q -> next;
+      free(q);
+      q = next;
+    }
+  }
+# endif /* USE_WINALLOC && !REDIRECT_MALLOC */
 
   /* Is p the start of either the malloc heap, or of one of our */
   /* heap sections?                                             */
   GC_INNER GC_bool GC_is_heap_base(void *p)
   {
-     unsigned i;
-#    ifndef REDIRECT_MALLOC
-       if (GC_root_size > GC_max_root_size) GC_max_root_size = GC_root_size;
-#      ifdef USE_WINALLOC
-         if (GC_is_malloc_heap_base(p)) return TRUE;
-#      endif
+     int i;
+
+#    if defined(USE_WINALLOC) && !defined(REDIRECT_MALLOC)
+       if (GC_root_size > GC_max_root_size)
+         GC_max_root_size = GC_root_size;
+       if (GC_is_malloc_heap_base(p))
+         return TRUE;
 #    endif
-     for (i = 0; i < GC_n_heap_bases; i++) {
+     for (i = 0; i < (int)GC_n_heap_bases; i++) {
          if (GC_heap_bases[i] == p) return TRUE;
      }
      return FALSE;
@@ -2334,8 +2371,8 @@ void * os2_alloc(size_t bytes)
                                 GC_pages_executable ? PAGE_EXECUTE_READWRITE :
                                                       PAGE_READWRITE);
         if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
-            /* If I read the documentation correctly, this can  */
-            /* only happen if HBLKSIZE > 64k or not a power of 2.       */
+            /* If I read the documentation correctly, this can          */
+            /* only happen if HBLKSIZE > 64 KB or not a power of 2.     */
         if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
         if (result == NULL) return NULL;
         GC_heap_bases[GC_n_heap_bases] = result;
@@ -2370,7 +2407,7 @@ void * os2_alloc(size_t bytes)
     DWORD GC_mem_top_down = MEM_TOP_DOWN;
                            /* Use GC_USE_MEM_TOP_DOWN for better 64-bit */
                            /* testing.  Otherwise all addresses tend to */
-                           /* end up in first 4GB, hiding bugs.         */
+                           /* end up in first 4 GB, hiding bugs.        */
 # else
 #   define GC_mem_top_down 0
 # endif /* !GC_USE_MEM_TOP_DOWN */
@@ -2431,39 +2468,49 @@ void * os2_alloc(size_t bytes)
 # endif /* USE_WINALLOC */
     if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
         /* If I read the documentation correctly, this can      */
-        /* only happen if HBLKSIZE > 64k or not a power of 2.   */
+        /* only happen if HBLKSIZE > 64 KB or not a power of 2. */
     if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
     if (0 != result) GC_heap_bases[GC_n_heap_bases++] = result;
     return(result);
   }
+#endif /* USE_WINALLOC || CYGWIN32 */
 
+#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32) \
+    || defined(MSWIN_XBOX1)
   GC_API void GC_CALL GC_win32_free_heap(void)
   {
-#   ifndef MSWINRT_FLAVOR
+#   if defined(USE_WINALLOC) && !defined(REDIRECT_MALLOC) \
+       && !defined(MSWIN_XBOX1)
+      GC_free_malloc_heap_list();
+#   endif
+#   if (defined(USE_WINALLOC) && !defined(MSWIN_XBOX1) \
+        && !defined(MSWINCE)) || defined(CYGWIN32)
+#     ifndef MSWINRT_FLAVOR
+#       ifndef CYGWIN32
+          if (GLOBAL_ALLOC_TEST)
+#       endif
+        {
+          while (GC_n_heap_bases-- > 0) {
+#           ifdef CYGWIN32
+              /* FIXME: Is it OK to use non-GC free() here? */
+#           else
+              GlobalFree(GC_heap_bases[GC_n_heap_bases]);
+#           endif
+            GC_heap_bases[GC_n_heap_bases] = 0;
+          }
+          return;
+        }
+#     endif /* !MSWINRT_FLAVOR */
 #     ifndef CYGWIN32
-        if (GLOBAL_ALLOC_TEST)
-#     endif
-      {
-        while (GC_n_heap_bases-- > 0) {
-#         ifdef CYGWIN32
-            /* FIXME: Is it OK to use non-GC free() here? */
-#         else
-            GlobalFree(GC_heap_bases[GC_n_heap_bases]);
-#         endif
+        /* Avoiding VirtualAlloc leak.  */
+        while (GC_n_heap_bases > 0) {
+          VirtualFree(GC_heap_bases[--GC_n_heap_bases], 0, MEM_RELEASE);
           GC_heap_bases[GC_n_heap_bases] = 0;
         }
-        return;
-      }
-#   endif
-#   ifndef CYGWIN32
-      /* Avoiding VirtualAlloc leak. */
-      while (GC_n_heap_bases > 0) {
-        VirtualFree(GC_heap_bases[--GC_n_heap_bases], 0, MEM_RELEASE);
-        GC_heap_bases[GC_n_heap_bases] = 0;
-      }
-#   endif
+#     endif
+#   endif /* USE_WINALLOC || CYGWIN32 */
   }
-#endif /* USE_WINALLOC || CYGWIN32 */
+#endif /* Windows */
 
 #ifdef AMIGA
 # define GC_AMIGA_AM
@@ -2560,9 +2607,12 @@ GC_INNER void GC_unmap(ptr_t start, size_t bytes)
       /* We immediately remap it to prevent an intervening mmap from    */
       /* accidentally grabbing the same address space.                  */
       {
-#       ifdef CYGWIN32
-          /* Calling mmap() with the new protection flags on an         */
-          /* existing memory map with MAP_FIXED is broken on Cygwin.    */
+#       if defined(AIX) || defined(CYGWIN32) || defined(HAIKU) \
+           || defined(HPUX)
+          /* On AIX, mmap(PROT_NONE) fails with ENOMEM unless the       */
+          /* environment variable XPG_SUS_ENV is set to ON.             */
+          /* On Cygwin, calling mmap() with the new protection flags on */
+          /* an existing memory map with MAP_FIXED is broken.           */
           /* However, calling mprotect() on the given address range     */
           /* with PROT_NONE seems to work fine.                         */
           if (mprotect(start_addr, len, PROT_NONE))
@@ -2688,7 +2738,8 @@ GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2,
 #   else
       if (len != 0) {
         /* Immediately remap as above. */
-#       ifdef CYGWIN32
+#       if defined(AIX) || defined(CYGWIN32) || defined(HAIKU) \
+           || defined(HPUX)
           if (mprotect(start_addr, len, PROT_NONE))
             ABORT("mprotect(PROT_NONE) failed");
 #       else
@@ -2874,8 +2925,8 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void)
         count = GC_GWW_BUF_LEN;
         /* GetWriteWatch is documented as returning non-zero when it    */
         /* fails, but the documentation doesn't explicitly say why it   */
-        /* would fail or what its behaviour will be if it fails.        */
-        /* It does appear to fail, at least on recent W2K instances, if */
+        /* would fail or what its behavior will be if it fails.  It     */
+        /* does appear to fail, at least on recent Win2K instances, if  */
         /* the underlying memory was not allocated with the appropriate */
         /* flag.  This is common if GC_enable_incremental is called     */
         /* shortly after GC initialization.  To avoid modifying the     */
@@ -2886,12 +2937,11 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void)
         /* loop condition. Since each partial call will reset the       */
         /* status of some pages, this should eventually terminate even  */
         /* in the overflow case.                                        */
-        if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET,
-                               GC_heap_sects[i].hs_start,
-                               GC_heap_sects[i].hs_bytes,
-                               pages,
-                               &count,
-                               &page_size) != 0) {
+        if ((*(GetWriteWatch_type)(word)GetWriteWatch_func)(
+                                        WRITE_WATCH_FLAG_RESET,
+                                        GC_heap_sects[i].hs_start,
+                                        GC_heap_sects[i].hs_bytes,
+                                        pages, &count, &page_size) != 0) {
           static int warn_count = 0;
           struct hblk * start = (struct hblk *)GC_heap_sects[i].hs_start;
           static struct hblk *last_warned = 0;
@@ -3073,11 +3123,13 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void)
 #ifndef DARWIN
   STATIC SIG_HNDLR_PTR GC_old_segv_handler = 0;
                         /* Also old MSWIN32 ACCESS_VIOLATION filter */
-# if !defined(MSWIN32) && !defined(MSWINCE)
+# if defined(FREEBSD) || defined(HPUX) || defined(HURD) || defined(LINUX)
     STATIC SIG_HNDLR_PTR GC_old_bus_handler = 0;
-#   if defined(FREEBSD) || defined(HURD) || defined(HPUX)
+#   ifndef LINUX
       STATIC GC_bool GC_old_bus_handler_used_si = FALSE;
 #   endif
+# endif
+# if !defined(MSWIN32) && !defined(MSWINCE)
     STATIC GC_bool GC_old_segv_handler_used_si = FALSE;
 # endif /* !MSWIN32 */
 #endif /* !DARWIN */
@@ -3278,33 +3330,8 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void)
 # endif
 #endif /* !DARWIN */
 
-#ifdef USE_MUNMAP
-  /* MPROTECT_VDB cannot deal with address space holes (for now),   */
-  /* so if the collector is configured with both MPROTECT_VDB and   */
-  /* USE_MUNMAP then, as a work around, select only one of them     */
-  /* during GC_init or GC_enable_incremental.                       */
-  GC_INNER GC_bool GC_dirty_init(void)
-  {
-    if (GC_unmap_threshold != 0) {
-      if (GETENV("GC_UNMAP_THRESHOLD") != NULL
-          || GETENV("GC_FORCE_UNMAP_ON_GCOLLECT") != NULL
-          || GC_has_unmapped_memory()) {
-        WARN("Can't maintain mprotect-based dirty bits"
-             " in case of unmapping\n", 0);
-        return FALSE;
-      }
-      GC_unmap_threshold = 0; /* in favor of incremental collection */
-      WARN("Memory unmapping is disabled as incompatible"
-           " with MPROTECT_VDB\n", 0);
-    }
-    return GC_mprotect_dirty_init();
-  }
-#else
-# define GC_mprotect_dirty_init GC_dirty_init
-#endif /* !USE_MUNMAP */
-
 #if !defined(DARWIN)
-  GC_INNER GC_bool GC_mprotect_dirty_init(void)
+  GC_INNER GC_bool GC_dirty_init(void)
   {
 #   if !defined(MSWIN32) && !defined(MSWINCE)
       struct sigaction act, oldact;
@@ -3359,9 +3386,6 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void)
 #       endif
       } else {
         GC_old_bus_handler = (SIG_HNDLR_PTR)(signed_word)oldact.sa_handler;
-#       if !defined(LINUX)
-          GC_old_bus_handler_used_si = FALSE;
-#       endif
       }
       if (GC_old_bus_handler == (SIG_HNDLR_PTR)(signed_word)SIG_IGN) {
         WARN("Previously ignored bus error!?\n", 0);
@@ -4043,6 +4067,9 @@ STATIC void *GC_mprotect_thread(void *arg)
     msg.data[0] = 0;
 # endif
 
+# if defined(HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID)
+    (void)pthread_setname_np("GC-mprotect");
+# endif
 # if defined(THREADS) && !defined(GC_NO_THREADS_DISCOVERY)
     GC_darwin_register_mach_handler_thread(mach_thread_self());
 # endif
@@ -4135,7 +4162,7 @@ STATIC void *GC_mprotect_thread(void *arg)
   }
 #endif /* BROKEN_EXCEPTION_HANDLING */
 
-GC_INNER GC_bool GC_mprotect_dirty_init(void)
+GC_INNER GC_bool GC_dirty_init(void)
 {
   kern_return_t r;
   mach_port_t me;
@@ -4225,6 +4252,9 @@ GC_INNER GC_bool GC_mprotect_dirty_init(void)
       }
     }
 # endif /* BROKEN_EXCEPTION_HANDLING  */
+# if defined(CPPCHECK)
+    GC_noop1((word)GC_ports.os_callback[0]);
+# endif
   return TRUE;
 }
 
@@ -4446,6 +4476,7 @@ catch_exception_raise(mach_port_t exception_port GC_ATTR_UNUSED,
 #ifndef HAVE_INCREMENTAL_PROTECTION_NEEDS
   GC_API int GC_CALL GC_incremental_protection_needs(void)
   {
+    GC_ASSERT(GC_is_initialized);
     return GC_PROTECTS_NONE;
   }
 #endif /* !HAVE_INCREMENTAL_PROTECTION_NEEDS */
@@ -4622,7 +4653,11 @@ GC_INNER void GC_save_callers(struct callinfo info[NFRAMES])
 #endif
 
    for (; !((word)fp HOTTER_THAN (word)frame)
-          && !((word)GC_stackbottom HOTTER_THAN (word)fp)
+#         ifndef THREADS
+            && !((word)GC_stackbottom HOTTER_THAN (word)fp)
+#         elif defined(STACK_GROWS_UP)
+            && fp != NULL
+#         endif
           && nframes < NFRAMES;
         fp = (struct frame *)((long) fp -> FR_SAVFP + BIAS), nframes++) {
 #     if NARGS > 0
@@ -4650,7 +4685,6 @@ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES])
 {
     int i;
     static int reentry_count = 0;
-    GC_bool stop = FALSE;
     DCL_LOCK_STATE;
 
     /* FIXME: This should probably use a different lock, so that we     */
@@ -4664,8 +4698,13 @@ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES])
 #   else
       GC_err_printf("\tCall chain at allocation:\n");
 #   endif
-    for (i = 0; i < NFRAMES && !stop; i++) {
-        if (info[i].ci_pc == 0) break;
+    for (i = 0; i < NFRAMES; i++) {
+#       if defined(LINUX) && !defined(SMALL_CONFIG)
+          GC_bool stop = FALSE;
+#       endif
+
+        if (0 == info[i].ci_pc)
+          break;
 #       if NARGS > 0
         {
           int j;
@@ -4705,7 +4744,7 @@ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES])
           }
 #         if defined(LINUX) && !defined(SMALL_CONFIG)
             /* Try for a line number. */
-            {
+            do {
                 FILE *pipe;
 #               define EXE_SZ 100
                 static char exe_name[EXE_SZ];
@@ -4719,16 +4758,18 @@ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES])
                 char preload_buf[PRELOAD_SZ];
                 static GC_bool found_exe_name = FALSE;
                 static GC_bool will_fail = FALSE;
-                int ret_code;
+
                 /* Try to get it via a hairy and expensive scheme.      */
                 /* First we get the name of the executable:             */
-                if (will_fail) goto out;
+                if (will_fail)
+                  break;
                 if (!found_exe_name) {
-                  ret_code = readlink("/proc/self/exe", exe_name, EXE_SZ);
+                  int ret_code = readlink("/proc/self/exe", exe_name, EXE_SZ);
+
                   if (ret_code < 0 || ret_code >= EXE_SZ
                       || exe_name[0] != '/') {
                     will_fail = TRUE;   /* Don't try again. */
-                    goto out;
+                    break;
                   }
                   exe_name[ret_code] = '\0';
                   found_exe_name = TRUE;
@@ -4745,7 +4786,7 @@ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES])
                   size_t old_len = strlen(old_preload);
                   if (old_len >= PRELOAD_SZ) {
                     will_fail = TRUE;
-                    goto out;
+                    break;
                   }
                   BCOPY(old_preload, preload_buf, old_len + 1);
                   unsetenv ("LD_PRELOAD");
@@ -4755,21 +4796,22 @@ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES])
                     && 0 != setenv ("LD_PRELOAD", preload_buf, 0)) {
                   WARN("Failed to reset LD_PRELOAD\n", 0);
                 }
-                if (pipe == NULL
-                    || (result_len = fread(result_buf, 1,
-                                           RESULT_SZ - 1, pipe)) == 0) {
-                  if (pipe != NULL) pclose(pipe);
+                if (NULL == pipe) {
                   will_fail = TRUE;
-                  goto out;
+                  break;
+                }
+                result_len = fread(result_buf, 1, RESULT_SZ - 1, pipe);
+                (void)pclose(pipe);
+                if (0 == result_len) {
+                  will_fail = TRUE;
+                  break;
                 }
                 if (result_buf[result_len - 1] == '\n') --result_len;
                 result_buf[result_len] = 0;
                 if (result_buf[0] == '?'
                     || (result_buf[result_len-2] == ':'
-                        && result_buf[result_len-1] == '0')) {
-                    pclose(pipe);
-                    goto out;
-                }
+                        && result_buf[result_len-1] == '0'))
+                  break;
                 /* Get rid of embedded newline, if any.  Test for "main" */
                 {
                   char * nl = strchr(result_buf, '\n');
@@ -4778,8 +4820,10 @@ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES])
                     *nl = ':';
                   }
                   if (strncmp(result_buf, "main",
-                              nl != NULL ? (size_t)(nl - result_buf)
-                                         : result_len) == 0) {
+                              nl != NULL
+                                ? (size_t)((word)nl /* a cppcheck workaround */
+                                           - COVERT_DATAFLOW(result_buf))
+                                : result_len) == 0) {
                     stop = TRUE;
                   }
                 }
@@ -4790,10 +4834,12 @@ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES])
                                  " [0x%lx]", (unsigned long)info[i].ci_pc);
                   result_buf[sizeof(result_buf) - 1] = '\0';
                 }
+#               if defined(CPPCHECK)
+                  GC_noop1((unsigned char)name[0]);
+                                /* name computed previously is discarded */
+#               endif
                 name = result_buf;
-                pclose(pipe);
-                out:;
-            }
+            } while (0);
 #         endif /* LINUX */
           GC_err_printf("\t\t%s\n", name);
 #         if defined(GC_HAVE_BUILTIN_BACKTRACE) \
@@ -4802,6 +4848,10 @@ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES])
               free(sym_name);   /* May call GC_[debug_]free; that's OK  */
 #         endif
         }
+#       if defined(LINUX) && !defined(SMALL_CONFIG)
+          if (stop)
+            break;
+#       endif
     }
     LOCK();
       --reentry_count;

+ 9 - 8
blitz.mod/bdwgc/pthread_stop_world.c

@@ -4,6 +4,7 @@
  * Copyright (c) 1998 by Fergus Henderson.  All rights reserved.
  * Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
  * All rights reserved.
+ * Copyright (c) 2008-2020 Ivan Maidanski
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -1179,17 +1180,17 @@ GC_INNER void GC_start_world(void)
                     /* the list of functions which synchronize memory). */
 #   endif
     n_live_threads = GC_restart_all();
-#   ifndef GC_OPENBSD_UTHREADS
+#   ifdef GC_OPENBSD_UTHREADS
+      (void)n_live_threads;
+#   elif defined(GC_NETBSD_THREADS_WORKAROUND)
       if (GC_retry_signals)
         n_live_threads = resend_lost_signals(n_live_threads, GC_restart_all);
-#     ifdef GC_NETBSD_THREADS_WORKAROUND
-        suspend_restart_barrier(n_live_threads);
-#     else
-        if (GC_retry_signals)
-          suspend_restart_barrier(n_live_threads);
-#     endif
+      suspend_restart_barrier(n_live_threads);
 #   else
-      (void)n_live_threads;
+      if (GC_retry_signals) {
+        n_live_threads = resend_lost_signals(n_live_threads, GC_restart_all);
+        suspend_restart_barrier(n_live_threads);
+      }
 #   endif
 #   ifdef DEBUG_THREADS
       GC_log_printf("World started\n");

+ 150 - 44
blitz.mod/bdwgc/pthread_support.c

@@ -3,6 +3,7 @@
  * Copyright (c) 1996 by Silicon Graphics.  All rights reserved.
  * Copyright (c) 1998 by Fergus Henderson.  All rights reserved.
  * Copyright (c) 2000-2005 by Hewlett-Packard Company.  All rights reserved.
+ * Copyright (c) 2008-2020 Ivan Maidanski
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -253,8 +254,10 @@
 
 # define INIT_REAL_SYMS() if (EXPECT(GC_syms_initialized, TRUE)) {} \
                             else GC_init_real_syms()
+# define ASSERT_SYMS_INITIALIZED() GC_ASSERT(GC_syms_initialized)
 #else
 # define INIT_REAL_SYMS() (void)0
+# define ASSERT_SYMS_INITIALIZED() GC_ASSERT(parallel_initialized)
 #endif
 
 static GC_bool parallel_initialized = FALSE;
@@ -335,6 +338,40 @@ static ptr_t marker_sp[MAX_MARKERS - 1] = {0};
   }
 #endif /* GC_DARWIN_THREADS */
 
+#ifdef HAVE_PTHREAD_SETNAME_NP_WITH_TID_AND_ARG /* NetBSD */
+  static void set_marker_thread_name(unsigned id)
+  {
+    int err = pthread_setname_np(pthread_self(), "GC-marker-%zu",
+                                 (void*)(size_t)id);
+    if (err != 0)
+      WARN("pthread_setname_np failed, errno = %" WARN_PRIdPTR "\n", err);
+  }
+#elif defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID) \
+      || defined(HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID)
+  static void set_marker_thread_name(unsigned id)
+  {
+    char name_buf[16];  /* pthread_setname_np may fail for longer names */
+    int len = sizeof("GC-marker-") - 1;
+
+    /* Compose the name manually as snprintf may be unavailable or      */
+    /* "%u directive output may be truncated" warning may occur.        */
+    BCOPY("GC-marker-", name_buf, len);
+    if (id >= 10)
+      name_buf[len++] = (char)('0' + (id / 10) % 10);
+    name_buf[len] = (char)('0' + id % 10);
+    name_buf[len + 1] = '\0';
+
+#   ifdef HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID /* iOS, OS X */
+      (void)pthread_setname_np(name_buf);
+#   else /* Linux, Solaris, etc. */
+      if (pthread_setname_np(pthread_self(), name_buf) != 0)
+        WARN("pthread_setname_np failed\n", 0);
+#   endif
+  }
+#else
+# define set_marker_thread_name(id) (void)(id)
+#endif
+
 STATIC void * GC_mark_thread(void * id)
 {
   word my_mark_no = 0;
@@ -344,6 +381,7 @@ STATIC void * GC_mark_thread(void * id)
   DISABLE_CANCEL(cancel_state);
                          /* Mark threads are not cancellable; they      */
                          /* should be invisible to client.              */
+  set_marker_thread_name((unsigned)(word)id);
   marker_sp[(word)id] = GC_approx_sp();
 # ifdef IA64
     marker_bsp[(word)id] = GC_save_regs_in_stack();
@@ -1181,7 +1219,18 @@ static void fork_child_proc(void)
 
 #ifdef PARALLEL_MARK
   static void setup_mark_lock(void);
-#endif
+
+  static unsigned required_markers_cnt = 0;
+                        /* The default value (0) means the number of    */
+                        /* markers should be selected automatically.    */
+#endif /* PARALLEL_MARK */
+
+GC_API void GC_CALL GC_set_markers_count(unsigned markers GC_ATTR_UNUSED)
+{
+# ifdef PARALLEL_MARK
+    required_markers_cnt = markers < MAX_MARKERS ? markers : MAX_MARKERS;
+# endif
+}
 
 GC_INNER void GC_thr_init(void)
 {
@@ -1271,7 +1320,7 @@ GC_INNER void GC_thr_init(void)
 #   ifdef PARALLEL_MARK
       {
         char * markers_string = GETENV("GC_MARKERS");
-        int markers;
+        int markers = required_markers_cnt;
 
         if (markers_string != NULL) {
           markers = atoi(markers_string);
@@ -1280,7 +1329,10 @@ GC_INNER void GC_thr_init(void)
                  "; using maximum threads\n", (signed_word)markers);
             markers = MAX_MARKERS;
           }
-        } else {
+        } else if (0 == markers) {
+          /* Unless the client sets the desired number of       */
+          /* parallel markers, it is determined based on the    */
+          /* number of CPU cores.                               */
           markers = GC_nprocs;
 #         if defined(GC_MIN_MARKERS) && !defined(CPPCHECK)
             /* This is primarily for targets without getenv().  */
@@ -1302,8 +1354,6 @@ GC_INNER void GC_thr_init(void)
       GC_COND_LOG_PRINTF(
                 "Single marker thread, turning off parallel marking\n");
     } else {
-      /* Disable true incremental collection, but generational is OK.   */
-      GC_time_limit = GC_TIME_UNLIMITED;
       setup_mark_lock();
     }
 # endif
@@ -1392,6 +1442,9 @@ GC_INNER void GC_do_blocking_inner(ptr_t data, void * context GC_ATTR_UNUSED)
     UNLOCK();
     d -> client_data = (d -> fn)(d -> client_data);
     LOCK();   /* This will block if the world is stopped.       */
+#   if defined(CPPCHECK)
+      GC_noop1((word)&me->thread_blocked);
+#   endif
     me -> thread_blocked = FALSE;
 #   if defined(GC_DARWIN_THREADS) && !defined(DARWIN_DONT_PARSE_STACK)
         if (topOfStackUnset)
@@ -1400,6 +1453,62 @@ GC_INNER void GC_do_blocking_inner(ptr_t data, void * context GC_ATTR_UNUSED)
     UNLOCK();
 }
 
+GC_API void GC_CALL GC_set_stackbottom(void *gc_thread_handle,
+                                       const struct GC_stack_base *sb)
+{
+    GC_thread t = (GC_thread)gc_thread_handle;
+
+    GC_ASSERT(sb -> mem_base != NULL);
+    if (!EXPECT(GC_is_initialized, TRUE)) {
+        GC_ASSERT(NULL == t);
+    } else {
+        GC_ASSERT(I_HOLD_LOCK());
+        if (NULL == t) /* current thread? */
+            t = GC_lookup_thread(pthread_self());
+        GC_ASSERT((t -> flags & FINISHED) == 0);
+        GC_ASSERT(!(t -> thread_blocked)
+                  && NULL == t -> traced_stack_sect); /* for now */
+
+        if ((t -> flags & MAIN_THREAD) == 0) {
+            t -> stack_end = (ptr_t)sb->mem_base;
+#           ifdef IA64
+                t -> backing_store_end = (ptr_t)sb->reg_base;
+#           endif
+            return;
+        }
+        /* Otherwise alter the stack bottom of the primordial thread.   */
+    }
+
+    GC_stackbottom = (char*)sb->mem_base;
+#   ifdef IA64
+        GC_register_stackbottom = (ptr_t)sb->reg_base;
+#   endif
+}
+
+GC_API void * GC_CALL GC_get_my_stackbottom(struct GC_stack_base *sb)
+{
+    pthread_t self = pthread_self();
+    GC_thread me;
+    DCL_LOCK_STATE;
+
+    LOCK();
+    me = GC_lookup_thread(self);
+    /* The thread is assumed to be registered.  */
+    if ((me -> flags & MAIN_THREAD) == 0) {
+        sb -> mem_base = me -> stack_end;
+#       ifdef IA64
+            sb -> reg_base = me -> backing_store_end;
+#       endif
+    } else {
+        sb -> mem_base = GC_stackbottom;
+#       ifdef IA64
+            sb -> reg_base = GC_register_stackbottom;
+#       endif
+    }
+    UNLOCK();
+    return (void *)me; /* gc_thread_handle */
+}
+
 /* GC_call_with_gc_active() has the opposite to GC_do_blocking()        */
 /* functionality.  It might be called from a user function invoked by   */
 /* GC_do_blocking() to temporarily back allow calling any GC function   */
@@ -1415,7 +1524,7 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
     LOCK();   /* This will block if the world is stopped.       */
     me = GC_lookup_thread(self);
 
-    /* Adjust our stack base value (this could happen unless    */
+    /* Adjust our stack bottom value (this could happen unless  */
     /* GC_get_stack_base() was used which returned GC_SUCCESS). */
     if ((me -> flags & MAIN_THREAD) == 0) {
       GC_ASSERT(me -> stack_end != NULL);
@@ -1455,6 +1564,9 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
     GC_ASSERT(me -> traced_stack_sect == &stacksect);
 
     /* Restore original "stack section".        */
+#   if defined(CPPCHECK)
+      GC_noop1((word)me->traced_stack_sect);
+#   endif
     LOCK();
     me -> traced_stack_sect = stacksect.prev;
 #   ifdef IA64
@@ -1551,7 +1663,7 @@ GC_INNER_PTHRSTART void GC_thread_exit_proc(void *arg)
     GC_thread t;
     DCL_LOCK_STATE;
 
-    INIT_REAL_SYMS();
+    ASSERT_SYMS_INITIALIZED();
     LOCK();
     t = GC_lookup_thread(thread);
     /* This is guaranteed to be the intended one, since the thread id   */
@@ -1587,7 +1699,7 @@ GC_INNER_PTHRSTART void GC_thread_exit_proc(void *arg)
     GC_thread t;
     DCL_LOCK_STATE;
 
-    INIT_REAL_SYMS();
+    ASSERT_SYMS_INITIALIZED();
     LOCK();
     t = GC_lookup_thread(thread);
     UNLOCK();
@@ -1720,6 +1832,9 @@ GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
     me = GC_lookup_thread(self);
     if (0 == me) {
         me = GC_register_my_thread_inner(sb, self);
+#       if defined(CPPCHECK)
+          GC_noop1(me->flags);
+#       endif
         me -> flags |= DETACHED;
           /* Treat as detached, since we do not need to worry about     */
           /* pointer results.                                           */
@@ -1827,7 +1942,7 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread(
     int result;
     int detachstate;
     word my_flags = 0;
-    struct start_info * si;
+    struct start_info si;
     DCL_LOCK_STATE;
         /* This is otherwise saved only in an area mmapped by the thread */
         /* library, which isn't visible to the collector.                */
@@ -1837,21 +1952,13 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread(
     /* responsibility.                                                  */
 
     INIT_REAL_SYMS();
-    LOCK();
-    si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info),
-                                                 NORMAL);
-    UNLOCK();
     if (!EXPECT(parallel_initialized, TRUE))
       GC_init_parallel();
-    if (EXPECT(0 == si, FALSE) &&
-        (si = (struct start_info *)
-                (*GC_get_oom_fn())(sizeof(struct start_info))) == 0)
-      return(ENOMEM);
-    if (sem_init(&(si -> registered), GC_SEM_INIT_PSHARED, 0) != 0)
+    if (sem_init(&si.registered, GC_SEM_INIT_PSHARED, 0) != 0)
       ABORT("sem_init failed");
 
-    si -> start_routine = start_routine;
-    si -> arg = arg;
+    si.start_routine = start_routine;
+    si.arg = arg;
     LOCK();
     if (!EXPECT(GC_thr_initialized, TRUE))
       GC_thr_init();
@@ -1891,19 +1998,19 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread(
         pthread_attr_getdetachstate(attr, &detachstate);
     }
     if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
-    si -> flags = my_flags;
+    si.flags = my_flags;
     UNLOCK();
 #   ifdef DEBUG_THREADS
       GC_log_printf("About to start new thread from thread %p\n",
                     (void *)pthread_self());
 #   endif
     set_need_to_lock();
-    result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, si);
+    result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine,
+                                       &si);
 
     /* Wait until child has been added to the thread table.             */
-    /* This also ensures that we hold onto si until the child is done   */
-    /* with it.  Thus it doesn't matter whether it is otherwise         */
-    /* visible to the collector.                                        */
+    /* This also ensures that we hold onto the stack-allocated si until */
+    /* the child is done with it.                                       */
     if (0 == result) {
         IF_CANCEL(int cancel_state;)
 
@@ -1913,7 +2020,7 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread(
 #       endif
         DISABLE_CANCEL(cancel_state);
                 /* pthread_create is not a cancellation point. */
-        while (0 != sem_wait(&(si -> registered))) {
+        while (0 != sem_wait(&si.registered)) {
 #           if defined(GC_HAIKU_THREADS)
               /* To workaround some bug in Haiku semaphores. */
               if (EACCES == errno) continue;
@@ -1922,11 +2029,7 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread(
         }
         RESTORE_CANCEL(cancel_state);
     }
-    sem_destroy(&(si -> registered));
-    LOCK();
-    GC_INTERNAL_FREE(si);
-    UNLOCK();
-
+    sem_destroy(&si.registered);
     return(result);
   }
 #endif /* !SN_TARGET_ORBIS && !SN_TARGET_PSP2 */
@@ -2092,7 +2195,7 @@ yield:
 #       define SLEEP_THRESHOLD 12
                 /* Under Linux very short sleeps tend to wait until     */
                 /* the current time quantum expires.  On old Linux      */
-                /* kernels nanosleep (<= 2 msecs) just spins.           */
+                /* kernels nanosleep (<= 2 ms) just spins.              */
                 /* (Under 2.4, this happens only for real-time          */
                 /* processes.)  We want to minimize both behaviors      */
                 /* here.                                                */
@@ -2102,7 +2205,7 @@ yield:
             struct timespec ts;
 
             if (i > 24) i = 24;
-                        /* Don't wait for more than about 15 msecs,     */
+                        /* Don't wait for more than about 15 ms,        */
                         /* even under extreme contention.               */
             ts.tv_sec = 0;
             ts.tv_nsec = 1 << i;
@@ -2111,22 +2214,25 @@ yield:
     }
 }
 
-#else  /* !USE_SPIN_LOCK */
+#elif defined(USE_PTHREAD_LOCKS)
 
-GC_INNER void GC_lock(void)
-{
-#ifndef NO_PTHREAD_TRYLOCK
-    if (1 == GC_nprocs || is_collecting()) {
+# ifndef NO_PTHREAD_TRYLOCK
+    GC_INNER void GC_lock(void)
+    {
+      if (1 == GC_nprocs || is_collecting()) {
         pthread_mutex_lock(&GC_allocate_ml);
-    } else {
+      } else {
         GC_generic_lock(&GC_allocate_ml);
+      }
     }
-#else  /* !NO_PTHREAD_TRYLOCK */
-    pthread_mutex_lock(&GC_allocate_ml);
-#endif /* !NO_PTHREAD_TRYLOCK */
-}
+# elif defined(GC_ASSERTIONS)
+    GC_INNER void GC_lock(void)
+    {
+      pthread_mutex_lock(&GC_allocate_ml);
+    }
+# endif
 
-#endif /* !USE_SPIN_LOCK */
+#endif /* !USE_SPIN_LOCK && USE_PTHREAD_LOCKS */
 
 #ifdef PARALLEL_MARK
 

+ 12 - 7
blitz.mod/bdwgc/reclaim.c

@@ -426,6 +426,9 @@ STATIC void GC_reclaim_block(struct hblk *hbp, word report_if_found)
                 }
 #             endif
               blocks = OBJ_SZ_TO_BLOCKS(sz);
+#             if defined(CPPCHECK)
+                GC_noop1((word)&blocks);
+#             endif
               if (blocks > 1) {
                 GC_large_allocd_bytes -= blocks * HBLKSIZE;
               }
@@ -710,9 +713,10 @@ GC_INNER void GC_continue_reclaim(word sz /* granules */, int kind)
     struct hblk ** rlh = ok -> ok_reclaim_list;
     void **flh = &(ok -> ok_freelist[sz]);
 
-    if (rlh == 0) return;       /* No blocks of this kind.      */
-    rlh += sz;
-    while ((hbp = *rlh) != 0) {
+    if (NULL == rlh)
+        return; /* No blocks of this kind.      */
+
+    for (rlh += sz; (hbp = *rlh) != NULL; ) {
         hhdr = HDR(hbp);
         *rlh = hhdr -> hb_next;
         GC_reclaim_small_nonempty_block(hbp, hhdr -> hb_sz, FALSE);
@@ -751,8 +755,7 @@ GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old)
         rlp = ok -> ok_reclaim_list;
         if (rlp == 0) continue;
         for (sz = 1; sz <= MAXOBJGRANULES; sz++) {
-            rlh = rlp + sz;
-            while ((hbp = *rlh) != 0) {
+            for (rlh = rlp + sz; (hbp = *rlh) != NULL; ) {
                 if (stop_func != (GC_stop_func)0 && (*stop_func)()) {
                     return(FALSE);
                 }
@@ -773,8 +776,10 @@ GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old)
         CLOCK_TYPE done_time;
 
         GET_TIME(done_time);
-        GC_verbose_log_printf("Disposing of reclaim lists took %lu msecs\n",
-                              MS_TIME_DIFF(done_time,start_time));
+        GC_verbose_log_printf(
+                        "Disposing of reclaim lists took %lu ms %lu ns\n",
+                        MS_TIME_DIFF(done_time, start_time),
+                        NS_FRAC_TIME_DIFF(done_time, start_time));
       }
 #   endif
     return(TRUE);

+ 2 - 3
blitz.mod/bdwgc/specific.c

@@ -51,7 +51,7 @@ GC_INNER int GC_key_create_inner(tsd ** key_ptr)
 GC_INNER int GC_setspecific(tsd * key, void * value)
 {
     pthread_t self = pthread_self();
-    int hash_val = HASH(self);
+    unsigned hash_val = HASH(self);
     volatile tse * entry;
 
     GC_ASSERT(I_HOLD_LOCK());
@@ -138,8 +138,7 @@ GC_INNER void * GC_slow_getspecific(tsd * key, word qtid,
                                     tse * volatile * cache_ptr)
 {
     pthread_t self = pthread_self();
-    unsigned hash_val = HASH(self);
-    tse *entry = key->hash[hash_val].p;
+    tse *entry = key->hash[HASH(self)].p;
 
     GC_ASSERT(qtid != INVALID_QTID);
     while (entry != NULL && !THREAD_EQUAL(entry->thread, self)) {

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

@@ -223,7 +223,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_gcj_malloc(size_t bytes,
     void *result;
     void **tiny_fl;
 
-    GC_ASSERT(GC_gcj_malloc_initialized);
+    GC_ASSERT(GC_gcjobjfreelist != NULL);
     tiny_fl = ((GC_tlfs)GC_getspecific(GC_thread_key))->gcj_freelists;
     GC_FAST_MALLOC_GRANS(result, granules, tiny_fl, DIRECT_GRANULES,
                          GC_gcj_kind,

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

@@ -50,20 +50,12 @@ STATIC int GC_array_kind = 0;
                         /* Object kind for objects with complex         */
                         /* descriptors and GC_array_mark_proc.          */
 
-/* Extended descriptors.  GC_typed_mark_proc understands these. */
-/* These are used for simple objects that are larger than what  */
-/* can be described by a BITMAP_BITS sized bitmap.              */
-typedef struct {
-        word ed_bitmap; /* lsb corresponds to first word.       */
-        GC_bool ed_continued;   /* next entry is continuation.  */
-} ext_descr;
-
 /* Array descriptors.  GC_array_mark_proc understands these.    */
 /* We may eventually need to add provisions for headers and     */
 /* trailers.  Hence we provide for tree structured descriptors, */
 /* though we don't really use them currently.                   */
 
-    struct LeafDescriptor {     /* Describes simple array       */
+struct LeafDescriptor {         /* Describes simple array.      */
         word ld_tag;
 #       define LEAF_TAG 1
         size_t ld_size;         /* bytes per element            */
@@ -71,21 +63,21 @@ typedef struct {
         size_t ld_nelements;    /* Number of elements.          */
         GC_descr ld_descriptor; /* A simple length, bitmap,     */
                                 /* or procedure descriptor.     */
-    };
+};
 
-    struct ComplexArrayDescriptor {
+struct ComplexArrayDescriptor {
         word ad_tag;
 #       define ARRAY_TAG 2
         size_t ad_nelements;
         union ComplexDescriptor * ad_element_descr;
-    };
+};
 
-    struct SequenceDescriptor {
+struct SequenceDescriptor {
         word sd_tag;
 #       define SEQUENCE_TAG 3
         union ComplexDescriptor * sd_first;
         union ComplexDescriptor * sd_second;
-    };
+};
 
 typedef union ComplexDescriptor {
     struct LeafDescriptor ld;
@@ -94,24 +86,11 @@ typedef union ComplexDescriptor {
 } complex_descriptor;
 #define TAG ad.ad_tag
 
-STATIC ext_descr * GC_ext_descriptors = NULL;
-                                        /* Points to array of extended  */
-                                        /* descriptors.                 */
-
-STATIC size_t GC_ed_size = 0;   /* Current size of above arrays.        */
 #define ED_INITIAL_SIZE 100
 
-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.                 */
 
-#ifdef AO_HAVE_load_acquire
-  STATIC volatile AO_t GC_explicit_typing_initialized = FALSE;
-#else
-  STATIC GC_bool GC_explicit_typing_initialized = FALSE;
-#endif
-
 STATIC void GC_push_typed_structures_proc(void)
 {
   GC_PUSH_ALL_SYM(GC_ext_descriptors);
@@ -132,7 +111,7 @@ STATIC signed_word GC_add_ext_descriptor(const word * bm, word nbits)
 
     LOCK();
     while (GC_avail_descr + nwords >= GC_ed_size) {
-        ext_descr * newExtD;
+        typed_ext_descr_t *newExtD;
         size_t new_size;
         word ed_size = GC_ed_size;
 
@@ -146,14 +125,15 @@ STATIC signed_word GC_add_ext_descriptor(const word * bm, word nbits)
             new_size = 2 * ed_size;
             if (new_size > MAX_ENV) return(-1);
         }
-        newExtD = (ext_descr *)GC_malloc_atomic(new_size * sizeof(ext_descr));
+        newExtD = (typed_ext_descr_t*)GC_malloc_atomic(new_size
+                                                * sizeof(typed_ext_descr_t));
         if (NULL == newExtD)
             return -1;
         LOCK();
         if (ed_size == GC_ed_size) {
             if (GC_avail_descr != 0) {
                 BCOPY(GC_ext_descriptors, newExtD,
-                      GC_avail_descr * sizeof(ext_descr));
+                      GC_avail_descr * sizeof(typed_ext_descr_t));
             }
             GC_ed_size = new_size;
             GC_ext_descriptors = newExtD;
@@ -332,8 +312,6 @@ GC_make_sequence_descriptor(complex_descriptor *first,
     return((complex_descriptor *)result);
 }
 
-STATIC ptr_t * GC_eobjfreelist = NULL;
-
 STATIC mse * GC_typed_mark_proc(word * addr, mse * mark_stack_ptr,
                                 mse * mark_stack_limit, word env);
 
@@ -346,9 +324,7 @@ STATIC void GC_init_explicit_typing(void)
 
     GC_STATIC_ASSERT(sizeof(struct LeafDescriptor) % sizeof(word) == 0);
     /* Set up object kind with simple indirect descriptor. */
-      GC_eobjfreelist = (ptr_t *)GC_new_free_list_inner();
-      GC_explicit_kind = GC_new_kind_inner(
-                            (void **)GC_eobjfreelist,
+      GC_explicit_kind = GC_new_kind_inner(GC_new_free_list_inner(),
                             (WORDS_TO_BYTES((word)-1) | GC_DS_PER_OBJECT),
                             TRUE, TRUE);
                 /* Descriptors are in the last word of the object. */
@@ -625,10 +601,13 @@ GC_API GC_ATTR_MALLOC void * GC_CALL
     GC_ASSERT(GC_explicit_typing_initialized);
     lb = SIZET_SAT_ADD(lb, TYPD_EXTRA_BYTES);
     if (SMALL_OBJ(lb)) {
+        void **opp;
+
         GC_DBG_COLLECT_AT_MALLOC(lb);
         LOCK();
         lg = GC_size_map[lb];
-        op = GC_eobjfreelist[lg];
+        opp = &GC_obj_kinds[GC_explicit_kind].ok_freelist[lg];
+        op = (ptr_t)(*opp);
         if (EXPECT(0 == op, FALSE)) {
             UNLOCK();
             op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
@@ -636,7 +615,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL
             /* See the comment in GC_malloc_explicitly_typed.   */
             lg = BYTES_TO_GRANULES(GC_size(op));
         } else {
-            GC_eobjfreelist[lg] = (ptr_t)obj_link(op);
+            *opp = obj_link(op);
             obj_link(op) = 0;
             GC_bytes_allocd += GRANULES_TO_BYTES((word)lg);
             UNLOCK();

+ 440 - 160
blitz.mod/bdwgc/win32_threads.c

@@ -4,6 +4,7 @@
  * Copyright (c) 1998 by Fergus Henderson.  All rights reserved.
  * Copyright (c) 2000-2008 by Hewlett-Packard Development Company.
  * All rights reserved.
+ * Copyright (c) 2008-2020 Ivan Maidanski
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -19,12 +20,6 @@
 
 #if defined(GC_WIN32_THREADS)
 
-#ifndef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN 1
-#endif
-#define NOSERVICE
-#include <windows.h>
-
 #ifdef THREAD_LOCAL_ALLOC
 # include "private/thread_local_alloc.h"
 #endif /* THREAD_LOCAL_ALLOC */
@@ -74,9 +69,29 @@
 
 #endif /* !GC_PTHREADS && !MSWINCE */
 
+/* PUSHED_REGS_COUNT is the number of copied registers in copy_ptr_regs. */
+static ptr_t copy_ptr_regs(word *regs, const CONTEXT *pcontext);
+#if defined(I386)
+# ifdef WOW64_THREAD_CONTEXT_WORKAROUND
+#   define PUSHED_REGS_COUNT 9
+# else
+#   define PUSHED_REGS_COUNT 7
+# endif
+#elif defined(X86_64) || defined(SHx)
+# define PUSHED_REGS_COUNT 15
+#elif defined(ARM32)
+# define PUSHED_REGS_COUNT 13
+#elif defined(AARCH64)
+# define PUSHED_REGS_COUNT 30
+#elif defined(MIPS) || defined(ALPHA)
+# define PUSHED_REGS_COUNT 28
+#elif defined(PPC)
+# define PUSHED_REGS_COUNT 29
+#endif
+
 /* DllMain-based thread registration is currently incompatible  */
 /* with thread-local allocation, pthreads and WinCE.            */
-#if (defined(GC_DLL) || defined(GC_INSIDE_DLL)) \
+#if (defined(GC_DLL) || defined(GC_INSIDE_DLL)) && !defined(NO_CRT) \
         && !defined(GC_NO_THREADS_DISCOVERY) && !defined(MSWINCE) \
         && !defined(THREAD_LOCAL_ALLOC) && !defined(GC_PTHREADS)
 
@@ -166,8 +181,6 @@ GC_API void GC_CALL GC_use_threads_discovery(void)
 # endif
 }
 
-STATIC DWORD GC_main_thread = 0;
-
 #define ADDR_LIMIT ((ptr_t)GC_WORD_MAX)
 
 struct GC_Thread_Rep {
@@ -216,6 +229,11 @@ struct GC_Thread_Rep {
 # ifdef IA64
     ptr_t backing_store_end;
     ptr_t backing_store_ptr;
+# elif defined(I386)
+    ptr_t initial_stack_base;
+                        /* The cold end of the stack saved by   */
+                        /* GC_record_stack_base (never modified */
+                        /* by GC_set_stackbottom).              */
 # endif
 
   ptr_t thread_blocked_sp;      /* Protected by GC lock.                */
@@ -254,29 +272,34 @@ struct GC_Thread_Rep {
 # ifdef THREAD_LOCAL_ALLOC
     struct thread_local_freelists tlfs;
 # endif
+
+# ifdef RETRY_GET_THREAD_CONTEXT
+    ptr_t context_sp;
+    word context_regs[PUSHED_REGS_COUNT];
+                        /* Populated as part of GC_suspend() as         */
+                        /* resume/suspend loop may be needed for the    */
+                        /* call to GetThreadContext() to succeed.       */
+# endif
 };
 
 typedef struct GC_Thread_Rep * GC_thread;
 typedef volatile struct GC_Thread_Rep * GC_vthread;
 
 #ifndef GC_NO_THREADS_DISCOVERY
+  STATIC DWORD GC_main_thread = 0;
+
+  /* We track thread attachments while the world is supposed to be      */
+  /* stopped.  Unfortunately, we cannot stop them from starting, since  */
+  /* blocking in DllMain seems to cause the world to deadlock.  Thus,   */
+  /* we have to recover if we notice this in the middle of marking.     */
+  STATIC volatile AO_t GC_attached_thread = FALSE;
+
   /* We assumed that volatile ==> memory ordering, at least among       */
   /* volatiles.  This code should consistently use atomic_ops.          */
   STATIC volatile GC_bool GC_please_stop = FALSE;
 #elif defined(GC_ASSERTIONS)
   STATIC GC_bool GC_please_stop = FALSE;
-#endif
-
-/*
- * We track thread attachments while the world is supposed to be stopped.
- * Unfortunately, we can't stop them from starting, since blocking in
- * DllMain seems to cause the world to deadlock.  Thus we have to recover
- * If we notice this in the middle of marking.
- */
-
-#ifndef GC_NO_THREADS_DISCOVERY
-  STATIC volatile AO_t GC_attached_thread = FALSE;
-#endif
+#endif /* GC_NO_THREADS_DISCOVERY && GC_ASSERTIONS */
 
 #if defined(WRAP_MARK_SOME) && !defined(GC_PTHREADS)
   /* Return TRUE if an thread was attached since we last asked or */
@@ -320,7 +343,7 @@ STATIC volatile LONG GC_max_thread_index = 0;
 
 /* And now the version used if GC_win32_dll_threads is not set. */
 /* This is a chained hash table, with much of the code borrowed */
-/* From the Posix implementation.                               */
+/* from the Posix implementation.                               */
 #ifndef THREAD_TABLE_SZ
 # define THREAD_TABLE_SZ 256    /* Power of 2 (for speed). */
 #endif
@@ -329,8 +352,8 @@ STATIC volatile LONG GC_max_thread_index = 0;
 STATIC GC_thread GC_threads[THREAD_TABLE_SZ];
 
 /* It may not be safe to allocate when we register the first thread.    */
-/* Thus we allocated one statically.  It does not contain any field we  */
-/* need to push ("next" and "status" fields are unused).                */
+/* Thus we allocated one statically.  It does not contain any pointer   */
+/* field we need to push ("next" and "status" fields are unused).       */
 static struct GC_Thread_Rep first_thread;
 static GC_bool first_thread_used = FALSE;
 
@@ -379,6 +402,8 @@ GC_INLINE void GC_record_stack_base(GC_vthread me,
   me -> stack_base = (ptr_t)sb->mem_base;
 # ifdef IA64
     me -> backing_store_end = (ptr_t)sb->reg_base;
+# elif defined(I386)
+    me -> initial_stack_base = (ptr_t)sb->mem_base;
 # endif
   if (me -> stack_base == NULL)
     ABORT("Bad stack base in GC_register_my_thread");
@@ -670,6 +695,10 @@ STATIC void GC_delete_gc_thread_no_free(GC_vthread t)
       /* see GC_stop_world() for the information.                       */
       t -> stack_base = 0;
       t -> id = 0;
+      t -> suspended = FALSE;
+#     ifdef RETRY_GET_THREAD_CONTEXT
+        t -> context_sp = NULL;
+#     endif
       AO_store_release(&t->tm.in_use, FALSE);
     } else
 # endif
@@ -764,6 +793,9 @@ GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
   if (me == 0) {
 #   ifdef GC_PTHREADS
       me = GC_register_my_thread_inner(sb, thread_id);
+#     if defined(CPPCHECK)
+        GC_noop1(me->flags);
+#     endif
       me -> flags |= DETACHED;
           /* Treat as detached, since we do not need to worry about     */
           /* pointer results.                                           */
@@ -912,11 +944,15 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
   LOCK();   /* This will block if the world is stopped.         */
   me = GC_lookup_thread_inner(thread_id);
   CHECK_LOOKUP_MY_THREAD(me);
-  /* Adjust our stack base value (this could happen unless      */
+  /* Adjust our stack bottom pointer (this could happen unless  */
   /* GC_get_stack_base() was used which returned GC_SUCCESS).   */
   GC_ASSERT(me -> stack_base != NULL);
-  if ((word)me->stack_base < (word)(&stacksect))
+  if ((word)me->stack_base < (word)(&stacksect)) {
     me -> stack_base = (ptr_t)(&stacksect);
+#   if defined(I386)
+      me -> initial_stack_base = me -> stack_base;
+#   endif
+  }
 
   if (me -> thread_blocked_sp == NULL) {
     /* We are not inside GC_do_blocking() - do nothing more.    */
@@ -960,6 +996,53 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
   return client_data; /* result */
 }
 
+GC_API void GC_CALL GC_set_stackbottom(void *gc_thread_handle,
+                                       const struct GC_stack_base *sb)
+{
+  GC_thread t = (GC_thread)gc_thread_handle;
+
+  GC_ASSERT(sb -> mem_base != NULL);
+  if (!EXPECT(GC_is_initialized, TRUE)) {
+    GC_ASSERT(NULL == t);
+    GC_stackbottom = (char *)sb->mem_base;
+#   ifdef IA64
+      GC_register_stackbottom = (ptr_t)sb->reg_base;
+#   endif
+    return;
+  }
+
+  GC_ASSERT(I_HOLD_LOCK());
+  if (NULL == t) { /* current thread? */
+    t = GC_lookup_thread_inner(GetCurrentThreadId());
+    CHECK_LOOKUP_MY_THREAD(t);
+  }
+  GC_ASSERT(!KNOWN_FINISHED(t));
+  GC_ASSERT(NULL == t -> thread_blocked_sp
+            && NULL == t -> traced_stack_sect); /* for now */
+  t -> stack_base = (ptr_t)sb->mem_base;
+  t -> last_stack_min = ADDR_LIMIT; /* reset the known minimum */
+# ifdef IA64
+    t -> backing_store_end = (ptr_t)sb->reg_base;
+# endif
+}
+
+GC_API void * GC_CALL GC_get_my_stackbottom(struct GC_stack_base *sb)
+{
+  DWORD thread_id = GetCurrentThreadId();
+  GC_thread me;
+  DCL_LOCK_STATE;
+
+  LOCK();
+  me = GC_lookup_thread_inner(thread_id);
+  CHECK_LOOKUP_MY_THREAD(me); /* the thread is assumed to be registered */
+  sb -> mem_base = me -> stack_base;
+# ifdef IA64
+    sb -> reg_base = me -> backing_store_end;
+# endif
+  UNLOCK();
+  return (void *)me; /* gc_thread_handle */
+}
+
 #ifdef GC_PTHREADS
 
   /* A quick-and-dirty cache of the mapping between pthread_t   */
@@ -1166,48 +1249,112 @@ void GC_push_thread_structures(void)
 # endif
 }
 
+#ifdef WOW64_THREAD_CONTEXT_WORKAROUND
+# ifndef CONTEXT_EXCEPTION_ACTIVE
+#   define CONTEXT_EXCEPTION_ACTIVE    0x08000000
+#   define CONTEXT_EXCEPTION_REQUEST   0x40000000
+#   define CONTEXT_EXCEPTION_REPORTING 0x80000000
+# endif
+  static BOOL isWow64;  /* Is running 32-bit code on Win64?     */
+# define GET_THREAD_CONTEXT_FLAGS (isWow64 \
+                        ? CONTEXT_INTEGER | CONTEXT_CONTROL \
+                          | CONTEXT_EXCEPTION_REQUEST | CONTEXT_SEGMENTS \
+                        : CONTEXT_INTEGER | CONTEXT_CONTROL)
+#else
+# define GET_THREAD_CONTEXT_FLAGS (CONTEXT_INTEGER | CONTEXT_CONTROL)
+#endif /* !WOW64_THREAD_CONTEXT_WORKAROUND */
+
 /* Suspend the given thread, if it's still active.      */
 STATIC void GC_suspend(GC_thread t)
 {
 # ifndef MSWINCE
-    /* Apparently the Windows 95 GetOpenFileName call creates           */
-    /* a thread that does not properly get cleaned up, and              */
-    /* SuspendThread on its descriptor may provoke a crash.             */
-    /* This reduces the probability of that event, though it still      */
-    /* appears there's a race here.                                     */
     DWORD exitCode;
+# endif
+# ifdef RETRY_GET_THREAD_CONTEXT
+    int retry_cnt = 0;
+#   define MAX_SUSPEND_THREAD_RETRIES (1000 * 1000)
+# endif
+
+# ifdef DEBUG_THREADS
+    GC_log_printf("Suspending 0x%x\n", (int)t->id);
 # endif
   UNPROTECT_THREAD(t);
-# ifndef MSWINCE
-    if (GetExitCodeThread(t -> handle, &exitCode) &&
-        exitCode != STILL_ACTIVE) {
+  GC_acquire_dirty_lock();
+
+# ifdef MSWINCE
+    /* SuspendThread() will fail if thread is running kernel code.      */
+    while (SuspendThread(THREAD_HANDLE(t)) == (DWORD)-1) {
+      GC_release_dirty_lock();
+      Sleep(10); /* in millis */
+      GC_acquire_dirty_lock();
+    }
+# elif defined(RETRY_GET_THREAD_CONTEXT)
+    for (;;) {
+      /* Apparently the Windows 95 GetOpenFileName call creates         */
+      /* a thread that does not properly get cleaned up, and            */
+      /* SuspendThread on its descriptor may provoke a crash.           */
+      /* This reduces the probability of that event, though it still    */
+      /* appears there is a race here.                                  */
+      if (GetExitCodeThread(t -> handle, &exitCode)
+          && exitCode != STILL_ACTIVE) {
+        GC_release_dirty_lock();
+#       ifdef GC_PTHREADS
+          t -> stack_base = 0; /* prevent stack from being pushed */
+#       else
+          /* This breaks pthread_join on Cygwin, which is guaranteed to */
+          /* only see user threads.                                     */
+          GC_ASSERT(GC_win32_dll_threads);
+          GC_delete_gc_thread_no_free(t);
+#       endif
+        return;
+      }
+
+      if (SuspendThread(t->handle) != (DWORD)-1) {
+        CONTEXT context;
+
+        context.ContextFlags = GET_THREAD_CONTEXT_FLAGS;
+        if (GetThreadContext(t->handle, &context)) {
+          /* TODO: WoW64 extra workaround: if CONTEXT_EXCEPTION_ACTIVE  */
+          /* then Sleep(1) and retry.                                   */
+          t->context_sp = copy_ptr_regs(t->context_regs, &context);
+          break; /* success; the context pointer registers are saved */
+        }
+
+        /* Resume the thread, try to suspend it in a better location.   */
+        if (ResumeThread(t->handle) == (DWORD)-1)
+          ABORT("ResumeThread failed in suspend loop");
+      }
+      if (retry_cnt > 1) {
+        GC_release_dirty_lock();
+        Sleep(0); /* yield */
+        GC_acquire_dirty_lock();
+      }
+      if (++retry_cnt >= MAX_SUSPEND_THREAD_RETRIES)
+        ABORT("SuspendThread loop failed"); /* something must be wrong */
+    }
+# else
+    if (GetExitCodeThread(t -> handle, &exitCode)
+        && exitCode != STILL_ACTIVE) {
+      GC_release_dirty_lock();
 #     ifdef GC_PTHREADS
         t -> stack_base = 0; /* prevent stack from being pushed */
 #     else
-        /* this breaks pthread_join on Cygwin, which is guaranteed to  */
-        /* only see user pthreads                                      */
         GC_ASSERT(GC_win32_dll_threads);
         GC_delete_gc_thread_no_free(t);
 #     endif
       return;
     }
-# endif
-  GC_acquire_dirty_lock();
-# ifdef MSWINCE
-    /* SuspendThread() will fail if thread is running kernel code.      */
-    while (SuspendThread(THREAD_HANDLE(t)) == (DWORD)-1)
-      Sleep(10); /* in millis */
-# else
     if (SuspendThread(t -> handle) == (DWORD)-1)
       ABORT("SuspendThread failed");
-# endif /* !MSWINCE */
+# endif
   t -> suspended = (unsigned char)TRUE;
   GC_release_dirty_lock();
   if (GC_on_thread_event)
     GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED, THREAD_HANDLE(t));
 }
 
-#if defined(GC_ASSERTIONS) && (defined(MSWIN32) || defined(MSWINCE))
+#if defined(GC_ASSERTIONS) \
+    && ((defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE))
   GC_INNER GC_bool GC_write_disabled = FALSE;
                 /* TRUE only if GC_stop_world() acquired GC_write_cs.   */
 #endif
@@ -1232,18 +1379,16 @@ GC_INNER void GC_stop_world(void)
 # if !defined(GC_NO_THREADS_DISCOVERY) || defined(GC_ASSERTIONS)
     GC_please_stop = TRUE;
 # endif
-# ifndef CYGWIN32
-#   ifndef MSWIN_XBOX1
-      GC_ASSERT(!GC_write_disabled);
-#   endif
+# if (defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE)
+    GC_ASSERT(!GC_write_disabled);
     EnterCriticalSection(&GC_write_cs);
-# endif
-# if defined(GC_ASSERTIONS) && (defined(MSWIN32) || defined(MSWINCE))
     /* It's not allowed to call GC_printf() (and friends) here down to  */
     /* LeaveCriticalSection (same applies recursively to GC_suspend,    */
     /* GC_delete_gc_thread_no_free, GC_get_max_thread_index, GC_size    */
     /* and GC_remove_protection).                                       */
-    GC_write_disabled = TRUE;
+#   ifdef GC_ASSERTIONS
+      GC_write_disabled = TRUE;
+#   endif
 # endif
 # ifndef GC_NO_THREADS_DISCOVERY
     if (GC_win32_dll_threads) {
@@ -1276,10 +1421,10 @@ GC_INNER void GC_stop_world(void)
       }
     }
   }
-# if defined(GC_ASSERTIONS) && (defined(MSWIN32) || defined(MSWINCE))
-    GC_write_disabled = FALSE;
-# endif
-# ifndef CYGWIN32
+# if (defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE)
+#   ifdef GC_ASSERTIONS
+      GC_write_disabled = FALSE;
+#   endif
     LeaveCriticalSection(&GC_write_cs);
 # endif
 # ifdef PARALLEL_MARK
@@ -1302,6 +1447,9 @@ GC_INNER void GC_start_world(void)
     for (i = 0; i <= my_max; i++) {
       GC_thread t = (GC_thread)(dll_thread_table + i);
       if (t -> suspended) {
+#       ifdef DEBUG_THREADS
+          GC_log_printf("Resuming 0x%x\n", (int)t->id);
+#       endif
         GC_ASSERT(t -> stack_base != 0 && t -> id != thread_id);
         if (ResumeThread(THREAD_HANDLE(t)) == (DWORD)-1)
           ABORT("ResumeThread failed");
@@ -1309,6 +1457,7 @@ GC_INNER void GC_start_world(void)
         if (GC_on_thread_event)
           GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, THREAD_HANDLE(t));
       }
+      /* Else thread is unregistered or not suspended. */
     }
   } else {
     GC_thread t;
@@ -1317,6 +1466,9 @@ GC_INNER void GC_start_world(void)
     for (i = 0; i < THREAD_TABLE_SZ; i++) {
       for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
         if (t -> suspended) {
+#         ifdef DEBUG_THREADS
+            GC_log_printf("Resuming 0x%x\n", (int)t->id);
+#         endif
           GC_ASSERT(t -> stack_base != 0 && t -> id != thread_id);
           if (ResumeThread(THREAD_HANDLE(t)) == (DWORD)-1)
             ABORT("ResumeThread failed");
@@ -1324,6 +1476,11 @@ GC_INNER void GC_start_world(void)
           t -> suspended = FALSE;
           if (GC_on_thread_event)
             GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, THREAD_HANDLE(t));
+        } else {
+#         ifdef DEBUG_THREADS
+            GC_log_printf("Not resuming thread 0x%x as it is not suspended\n",
+                          (int)t->id);
+#         endif
         }
       }
     }
@@ -1386,89 +1543,25 @@ static GC_bool may_be_in_stack(ptr_t s)
           && !(last_info.Protect & PAGE_GUARD);
 }
 
-#if defined(I386)
-  static BOOL isWow64;  /* Is running 32-bit code on Win64?     */
-#endif
-
-STATIC word GC_push_stack_for(GC_thread thread, DWORD me)
-{
-  ptr_t sp, stack_min;
-
-  struct GC_traced_stack_sect_s *traced_stack_sect =
-                                      thread -> traced_stack_sect;
-  if (thread -> id == me) {
-    GC_ASSERT(thread -> thread_blocked_sp == NULL);
-    sp = GC_approx_sp();
-  } else if ((sp = thread -> thread_blocked_sp) == NULL) {
-              /* Use saved sp value for blocked threads. */
-    /* For unblocked threads call GetThreadContext().   */
-    CONTEXT context;
-#   if defined(I386)
-#     ifndef CONTEXT_EXCEPTION_ACTIVE
-#       define CONTEXT_EXCEPTION_ACTIVE    0x08000000
-#       define CONTEXT_EXCEPTION_REQUEST   0x40000000
-#       define CONTEXT_EXCEPTION_REPORTING 0x80000000
-#     endif
-
-      if (isWow64) {
-        context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL
-                                | CONTEXT_EXCEPTION_REQUEST
-                                | CONTEXT_SEGMENTS;
-      } else
-#   endif
-    /* else */ {
-      context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
-    }
-    if (!GetThreadContext(THREAD_HANDLE(thread), &context))
-      ABORT("GetThreadContext failed");
-
-    /* Push all registers that might point into the heap.  Frame        */
-    /* pointer registers are included in case client code was           */
-    /* compiled with the 'omit frame pointer' optimization.             */
-#   define PUSH1(reg) GC_push_one((word)context.reg)
+/* Copy all registers that might point into the heap.  Frame    */
+/* pointer registers are included in case client code was       */
+/* compiled with the 'omit frame pointer' optimization.         */
+/* The context register values are stored to regs argument      */
+/* which is expected to be of PUSHED_REGS_COUNT length exactly. */
+/* The functions returns the context stack pointer value.       */
+static ptr_t copy_ptr_regs(word *regs, const CONTEXT *pcontext) {
+    ptr_t sp;
+    int cnt = 0;
+#   define context (*pcontext)
+#   define PUSH1(reg) (regs[cnt++] = (word)pcontext->reg)
 #   define PUSH2(r1,r2) (PUSH1(r1), PUSH1(r2))
 #   define PUSH4(r1,r2,r3,r4) (PUSH2(r1,r2), PUSH2(r3,r4))
 #   if defined(I386)
+#     ifdef WOW64_THREAD_CONTEXT_WORKAROUND
+        PUSH2(ContextFlags, SegFs); /* cannot contain pointers */
+#     endif
       PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp);
-      /* WoW64 workaround. */
-      if (isWow64
-          && (context.ContextFlags & CONTEXT_EXCEPTION_REPORTING) != 0
-          && (context.ContextFlags & (CONTEXT_EXCEPTION_ACTIVE
-                                      /* | CONTEXT_SERVICE_ACTIVE */)) != 0) {
-        LDT_ENTRY selector;
-        PNT_TIB tib;
-
-        if (!GetThreadSelectorEntry(THREAD_HANDLE(thread), context.SegFs,
-                                    &selector))
-          ABORT("GetThreadSelectorEntry failed");
-        tib = (PNT_TIB)(selector.BaseLow
-                        | (selector.HighWord.Bits.BaseMid << 16)
-                        | (selector.HighWord.Bits.BaseHi << 24));
-        /* GetThreadContext() might return stale register values, so    */
-        /* we scan the entire stack region (down to the stack limit).   */
-        /* There is no 100% guarantee that all the registers are pushed */
-        /* but we do our best (the proper solution would be to fix it   */
-        /* inside Windows OS).                                          */
-        sp = (ptr_t)tib->StackLimit;
-#       ifdef DEBUG_THREADS
-          GC_log_printf("TIB stack limit/base: %p .. %p\n",
-                        (void *)tib->StackLimit, (void *)tib->StackBase);
-#       endif
-        GC_ASSERT(!((word)thread->stack_base
-                    COOLER_THAN (word)tib->StackBase));
-      } else {
-#       ifdef DEBUG_THREADS
-          {
-            static GC_bool logged;
-            if (isWow64 && !logged
-                && (context.ContextFlags & CONTEXT_EXCEPTION_REPORTING) == 0) {
-              GC_log_printf("CONTEXT_EXCEPTION_REQUEST not supported\n");
-              logged = TRUE;
-            }
-          }
-#       endif
-        sp = (ptr_t)context.Esp;
-      }
+      sp = (ptr_t)context.Esp;
 #   elif defined(X86_64)
       PUSH4(Rax,Rcx,Rdx,Rbx); PUSH2(Rbp, Rsi); PUSH1(Rdi);
       PUSH4(R8, R9, R10, R11); PUSH4(R12, R13, R14, R15);
@@ -1505,9 +1598,124 @@ STATIC word GC_push_stack_for(GC_thread thread, DWORD me)
       PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9);
       PUSH4(IntT10,IntT11,IntT12,IntAt);
       sp = (ptr_t)context.IntSp;
-#   elif !defined(CPPCHECK)
+#   elif defined(CPPCHECK)
+      sp = (ptr_t)(word)cnt; /* to workaround "cnt not used" false positive */
+#   else
 #     error Architecture is not supported
 #   endif
+#   undef context
+    GC_ASSERT(cnt == PUSHED_REGS_COUNT);
+    return sp;
+}
+
+STATIC word GC_push_stack_for(GC_thread thread, DWORD me)
+{
+  ptr_t sp, stack_min;
+
+  struct GC_traced_stack_sect_s *traced_stack_sect =
+                                      thread -> traced_stack_sect;
+  if (thread -> id == me) {
+    GC_ASSERT(thread -> thread_blocked_sp == NULL);
+    sp = GC_approx_sp();
+  } else if ((sp = thread -> thread_blocked_sp) == NULL) {
+              /* Use saved sp value for blocked threads. */
+#   ifdef RETRY_GET_THREAD_CONTEXT
+      /* We cache context when suspending the thread since it may       */
+      /* require looping.                                               */
+      word *regs = thread->context_regs;
+
+      if (thread->suspended) {
+        sp = thread->context_sp;
+      } else
+#   else
+      word regs[PUSHED_REGS_COUNT];
+#   endif
+
+      /* else */ {
+        CONTEXT context;
+
+        /* For unblocked threads call GetThreadContext().       */
+        context.ContextFlags = GET_THREAD_CONTEXT_FLAGS;
+        if (GetThreadContext(THREAD_HANDLE(thread), &context)) {
+          sp = copy_ptr_regs(regs, &context);
+        } else {
+#         ifdef RETRY_GET_THREAD_CONTEXT
+            /* At least, try to use the stale context if saved. */
+            sp = thread->context_sp;
+            if (NULL == sp) {
+              /* Skip the current thread, anyway its stack will */
+              /* be pushed when the world is stopped.           */
+              return 0;
+            }
+#         else
+            ABORT("GetThreadContext failed");
+#         endif
+        }
+      }
+#   ifdef THREAD_LOCAL_ALLOC
+      GC_ASSERT(thread->suspended || !GC_world_stopped);
+#   endif
+
+#   ifndef WOW64_THREAD_CONTEXT_WORKAROUND
+      GC_push_many_regs(regs, PUSHED_REGS_COUNT);
+#   else
+      GC_push_many_regs(regs + 2, PUSHED_REGS_COUNT - 2);
+                                        /* skip ContextFlags and SegFs */
+
+      /* WoW64 workaround. */
+      if (isWow64) {
+        DWORD ContextFlags = (DWORD)regs[0];
+        WORD SegFs = (WORD)regs[1];
+
+        if ((ContextFlags & CONTEXT_EXCEPTION_REPORTING) != 0
+            && (ContextFlags & (CONTEXT_EXCEPTION_ACTIVE
+                                /* | CONTEXT_SERVICE_ACTIVE */)) != 0) {
+          LDT_ENTRY selector;
+          PNT_TIB tib;
+
+          if (!GetThreadSelectorEntry(THREAD_HANDLE(thread), SegFs, &selector))
+            ABORT("GetThreadSelectorEntry failed");
+          tib = (PNT_TIB)(selector.BaseLow
+                          | (selector.HighWord.Bits.BaseMid << 16)
+                          | (selector.HighWord.Bits.BaseHi << 24));
+#         ifdef DEBUG_THREADS
+            GC_log_printf("TIB stack limit/base: %p .. %p\n",
+                          (void *)tib->StackLimit, (void *)tib->StackBase);
+#         endif
+          GC_ASSERT(!((word)thread->stack_base
+                      COOLER_THAN (word)tib->StackBase));
+          if (thread->stack_base != thread->initial_stack_base
+              /* We are in a coroutine. */
+              && ((word)thread->stack_base <= (word)tib->StackLimit
+                  || (word)tib->StackBase < (word)thread->stack_base)) {
+            /* The coroutine stack is not within TIB stack.   */
+            WARN("GetThreadContext might return stale register values"
+                 " including ESP=%p\n", sp);
+            /* TODO: Because of WoW64 bug, there is no guarantee that   */
+            /* sp really points to the stack top but, for now, we do    */
+            /* our best as the TIB stack limit/base cannot be used      */
+            /* while we are inside a coroutine.                         */
+          } else {
+            /* GetThreadContext() might return stale register values,   */
+            /* so we scan the entire stack region (down to the stack    */
+            /* limit).  There is no 100% guarantee that all the         */
+            /* registers are pushed but we do our best (the proper      */
+            /* solution would be to fix it inside Windows OS).          */
+            sp = (ptr_t)tib->StackLimit;
+          }
+        } /* else */
+#       ifdef DEBUG_THREADS
+          else {
+            static GC_bool logged;
+            if (!logged
+                && (ContextFlags & CONTEXT_EXCEPTION_REPORTING) == 0) {
+              GC_log_printf("CONTEXT_EXCEPTION_REQUEST not supported\n");
+              logged = TRUE;
+            }
+          }
+#       endif
+      }
+#   endif /* WOW64_THREAD_CONTEXT_WORKAROUND */
   } /* ! current thread */
 
   /* Set stack_min to the lowest address in the thread stack,   */
@@ -1592,6 +1800,8 @@ STATIC word GC_push_stack_for(GC_thread thread, DWORD me)
   return thread->stack_base - sp; /* stack grows down */
 }
 
+/* We hold allocation lock.  Should do exactly the right thing if the   */
+/* world is stopped.  Should not fail if it isn't.                      */
 GC_INNER void GC_push_all_stacks(void)
 {
   DWORD thread_id = GetCurrentThreadId();
@@ -1792,6 +2002,56 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
                         /* only a few entries).                         */
 # endif
 
+# if defined(GC_PTHREADS) && defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID)
+    static void set_marker_thread_name(unsigned id)
+    {
+      /* This code is the same as in pthread_support.c. */
+      char name_buf[16]; /* pthread_setname_np may fail for longer names */
+      int len = sizeof("GC-marker-") - 1;
+
+      /* Compose the name manually as snprintf may be unavailable or    */
+      /* "%u directive output may be truncated" warning may occur.      */
+      BCOPY("GC-marker-", name_buf, len);
+      if (id >= 10)
+        name_buf[len++] = (char)('0' + (id / 10) % 10);
+      name_buf[len] = (char)('0' + id % 10);
+      name_buf[len + 1] = '\0';
+
+      if (pthread_setname_np(pthread_self(), name_buf) != 0)
+        WARN("pthread_setname_np failed\n", 0);
+    }
+
+# elif !defined(MSWINCE)
+    /* A pointer to SetThreadDescription() which is available since     */
+    /* Windows 10.  The function prototype is in processthreadsapi.h.   */
+    static FARPROC setThreadDescription_fn;
+
+    static void set_marker_thread_name(unsigned id)
+    {
+      WCHAR name_buf[16];
+      int len = sizeof(L"GC-marker-") / sizeof(WCHAR) - 1;
+      HRESULT hr;
+
+      if (!setThreadDescription_fn) return; /* missing SetThreadDescription */
+
+      /* Compose the name manually as swprintf may be unavailable.      */
+      BCOPY(L"GC-marker-", name_buf, len * sizeof(WCHAR));
+      if (id >= 10)
+        name_buf[len++] = (WCHAR)('0' + (id / 10) % 10);
+      name_buf[len] = (WCHAR)('0' + id % 10);
+      name_buf[len + 1] = 0;
+
+      /* Invoke SetThreadDescription().  Cast the function pointer to word  */
+      /* first to avoid "incompatible function types" compiler warning.     */
+      hr = (*(HRESULT (WINAPI *)(HANDLE, const WCHAR *))
+            (word)setThreadDescription_fn)(GetCurrentThread(), name_buf);
+      if (FAILED(hr))
+        WARN("SetThreadDescription failed\n", 0);
+    }
+# else
+#   define set_marker_thread_name(id) (void)(id)
+# endif
+
   /* GC_mark_thread() is the same as in pthread_support.c */
 # ifdef GC_PTHREADS_PARAMARK
     STATIC void * GC_mark_thread(void * id)
@@ -1804,6 +2064,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
     word my_mark_no = 0;
 
     if ((word)id == GC_WORD_MAX) return 0; /* to prevent a compiler warning */
+    set_marker_thread_name((unsigned)(word)id);
     marker_sp[(word)id] = GC_approx_sp();
 #   ifdef IA64
       marker_bsp[(word)id] = GC_save_regs_in_stack();
@@ -2239,6 +2500,9 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
 
 # endif /* ! GC_PTHREADS_PARAMARK */
 
+  static unsigned required_markers_cnt = 0;
+                        /* The default value (0) means the number of    */
+                        /* markers should be selected automatically.    */
 #endif /* PARALLEL_MARK */
 
   /* We have no DllMain to take care of new threads.  Thus we   */
@@ -2267,14 +2531,14 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
     /* Clear the thread entry even if we exit with an exception.        */
     /* This is probably pointless, since an uncaught exception is       */
     /* supposed to result in the process being killed.                  */
-#   ifndef __GNUC__
+#   if !defined(__GNUC__) && !defined(NO_CRT)
       ret = NULL; /* to suppress "might be uninitialized" compiler warning */
       __try
 #   endif
     {
       ret = (void *)(word)(*start)(param);
     }
-#   ifndef __GNUC__
+#   if !defined(__GNUC__) && !defined(NO_CRT)
       __finally
 #   endif
     {
@@ -2343,7 +2607,8 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
     ExitThread(dwExitCode);
   }
 
-# if !defined(CYGWIN32) && !defined(MSWINCE) && !defined(MSWIN_XBOX1)
+# if !defined(CYGWIN32) && !defined(MSWINCE) && !defined(MSWIN_XBOX1) \
+     && !defined(NO_CRT)
     GC_API GC_uintptr_t GC_CALL GC_beginthreadex(
                                   void *security, unsigned stack_size,
                                   unsigned (__stdcall *start_address)(void *),
@@ -2397,7 +2662,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
       GC_unregister_my_thread();
       _endthreadex(retval);
     }
-# endif /* !CYGWIN32 && !MSWINCE && !MSWIN_XBOX1 */
+# endif /* !CYGWIN32 && !MSWINCE && !MSWIN_XBOX1 && !NO_CRT */
 
 #ifdef GC_WINMAIN_REDIRECT
   /* This might be useful on WinCE.  Shouldn't be used with GC_DLL.     */
@@ -2475,18 +2740,31 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
 
 #endif /* GC_WINMAIN_REDIRECT */
 
+GC_API void GC_CALL GC_set_markers_count(unsigned markers GC_ATTR_UNUSED)
+{
+  /* The same implementation as in pthread_support.c.   */
+# ifdef PARALLEL_MARK
+    required_markers_cnt = markers < MAX_MARKERS ? markers : MAX_MARKERS;
+# endif
+}
+
 GC_INNER void GC_thr_init(void)
 {
   struct GC_stack_base sb;
-# ifdef GC_ASSERTIONS
-    int sb_result;
+# if (!defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID) && !defined(MSWINCE) \
+      && defined(PARALLEL_MARK)) || defined(WOW64_THREAD_CONTEXT_WORKAROUND)
+    HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll"));
 # endif
 
   GC_ASSERT(I_HOLD_LOCK());
   if (GC_thr_initialized) return;
 
   GC_ASSERT((word)&GC_threads % sizeof(word) == 0);
-  GC_main_thread = GetCurrentThreadId();
+# ifdef GC_NO_THREADS_DISCOVERY
+#   define GC_main_thread GetCurrentThreadId()
+# else
+    GC_main_thread = GetCurrentThreadId();
+# endif
   GC_thr_initialized = TRUE;
 
 # ifdef CAN_HANDLE_FORK
@@ -2504,31 +2782,28 @@ GC_INNER void GC_thr_init(void)
     }
 # endif
 
-# if defined(I386)
+# ifdef WOW64_THREAD_CONTEXT_WORKAROUND
     /* Set isWow64 flag. */
-    {
-      HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll"));
       if (hK32) {
         FARPROC pfn = GetProcAddress(hK32, "IsWow64Process");
         if (pfn
-            && !(*(BOOL (WINAPI*)(HANDLE, BOOL*))pfn)(GetCurrentProcess(),
-                                                      &isWow64))
+            && !(*(BOOL (WINAPI*)(HANDLE, BOOL*))(word)pfn)(
+                                        GetCurrentProcess(), &isWow64))
           isWow64 = FALSE; /* IsWow64Process failed */
       }
-    }
 # endif
 
   /* Add the initial thread, so we can stop it. */
-# ifdef GC_ASSERTIONS
-    sb_result =
+  sb.mem_base = GC_stackbottom;
+  GC_ASSERT(sb.mem_base != NULL);
+# ifdef IA64
+    sb.reg_base = GC_register_stackbottom;
 # endif
-        GC_get_stack_base(&sb);
-  GC_ASSERT(sb_result == GC_SUCCESS);
 
 # if defined(PARALLEL_MARK)
     {
       char * markers_string = GETENV("GC_MARKERS");
-      int markers;
+      int markers = required_markers_cnt;
 
       if (markers_string != NULL) {
         markers = atoi(markers_string);
@@ -2537,7 +2812,10 @@ GC_INNER void GC_thr_init(void)
                "; using maximum threads\n", (signed_word)markers);
           markers = MAX_MARKERS;
         }
-      } else {
+      } else if (0 == markers) {
+        /* Unless the client sets the desired number of         */
+        /* parallel markers, it is determined based on the      */
+        /* number of CPU cores.                                 */
 #       ifdef MSWINCE
           /* There is no GetProcessAffinityMask() in WinCE.     */
           /* GC_sysinfo is already initialized.                 */
@@ -2578,7 +2856,6 @@ GC_INNER void GC_thr_init(void)
     }
 
     /* Check whether parallel mode could be enabled.    */
-    {
       if (GC_win32_dll_threads || available_markers_m1 <= 0) {
         /* Disable parallel marking. */
         GC_parallel = FALSE;
@@ -2599,14 +2876,17 @@ GC_INNER void GC_thr_init(void)
               || mark_cv == (HANDLE)0)
             ABORT("CreateEvent failed");
 #       endif
-        /* Disable true incremental collection, but generational is OK. */
-        GC_time_limit = GC_TIME_UNLIMITED;
+#       if !defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID) && !defined(MSWINCE)
+          if (hK32)
+            setThreadDescription_fn = GetProcAddress(hK32,
+                                                     "SetThreadDescription");
+#       endif
       }
-    }
 # endif /* PARALLEL_MARK */
 
   GC_ASSERT(0 == GC_lookup_thread_inner(GC_main_thread));
   GC_register_my_thread_inner(&sb, GC_main_thread);
+# undef GC_main_thread
 }
 
 #ifdef GC_PTHREADS
@@ -2854,7 +3134,7 @@ GC_INNER void GC_thr_init(void)
 
       /* Note that GC_use_threads_discovery should be called by the     */
       /* client application at start-up to activate automatic thread    */
-      /* registration (it is the default GC behavior since v7.0alpha7); */
+      /* registration (it is the default GC behavior);                  */
       /* to always have automatic thread registration turned on, the GC */
       /* should be compiled with -D GC_DISCOVER_TASK_THREADS.           */
       if (!GC_win32_dll_threads && parallel_initialized) return TRUE;

+ 3 - 1
blitz.mod/blitz.bmx

@@ -8,12 +8,14 @@ bbdoc: BASIC/BlitzMax runtime
 End Rem
 Module BRL.Blitz
 
-ModuleInfo "Version: 1.21"
+ModuleInfo "Version: 1.22"
 ModuleInfo "Author: Mark Sibly"
 ModuleInfo "License: zlib/libpng"
 ModuleInfo "Copyright: Blitz Research Ltd"
 ModuleInfo "Modserver: BRL"
 '
+ModuleInfo "History: 1.22"
+ModuleInfo "History: Update to bdwgc 8.1.0.fbcdf44"
 ModuleInfo "History: 1.21"
 ModuleInfo "History: Update to bdwgc 7.7.0.d76816e"
 ModuleInfo "History: 1.20"