aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/old/thirdparty/libgc/gc.c
diff options
context:
space:
mode:
authorIndrajith K L2022-12-03 17:00:20 +0530
committerIndrajith K L2022-12-03 17:00:20 +0530
commitf5c4671bfbad96bf346bd7e9a21fc4317b4959df (patch)
tree2764fc62da58f2ba8da7ed341643fc359873142f /v_windows/v/old/thirdparty/libgc/gc.c
downloadcli-tools-windows-master.tar.gz
cli-tools-windows-master.tar.bz2
cli-tools-windows-master.zip
Adds most of the toolsHEADmaster
Diffstat (limited to 'v_windows/v/old/thirdparty/libgc/gc.c')
-rw-r--r--v_windows/v/old/thirdparty/libgc/gc.c30266
1 files changed, 30266 insertions, 0 deletions
diff --git a/v_windows/v/old/thirdparty/libgc/gc.c b/v_windows/v/old/thirdparty/libgc/gc.c
new file mode 100644
index 0000000..2459097
--- /dev/null
+++ b/v_windows/v/old/thirdparty/libgc/gc.c
@@ -0,0 +1,30266 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ * Copyright (c) 2009-2018 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.
+ */
+
+#ifndef __cplusplus
+#define GC_INNER STATIC
+#define GC_EXTERN GC_INNER
+#endif
+#ifndef GC_DBG_MLC_H
+#define GC_DBG_MLC_H
+#ifndef GC_PRIVATE_H
+#define GC_PRIVATE_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if!defined(GC_BUILD)&&!defined(NOT_GCBUILD)
+#define GC_BUILD
+#endif
+#if (defined(__linux__)||defined(__GLIBC__)||defined(__GNU__)||(defined(__CYGWIN__)&&(defined(GC_THREADS)||!defined(USE_MMAP))))&&!defined(_GNU_SOURCE)
+#define _GNU_SOURCE 1
+#endif
+#if defined(__INTERIX)&&!defined(_ALL_SOURCE)
+#define _ALL_SOURCE 1
+#endif
+#if (defined(DGUX)&&defined(GC_THREADS)||defined(DGUX386_THREADS)||defined(GC_DGUX386_THREADS))&&!defined(_USING_POSIX4A_DRAFT10)
+#define _USING_POSIX4A_DRAFT10 1
+#endif
+#if defined(__MINGW32__)&&!defined(__MINGW_EXCPT_DEFINE_PSDK)&&defined(__i386__)&&defined(GC_EXTERN)
+#define __MINGW_EXCPT_DEFINE_PSDK 1
+#endif
+#if defined(NO_DEBUGGING)&&!defined(GC_ASSERTIONS)&&!defined(NDEBUG)
+#define NDEBUG 1
+#endif
+#ifndef GC_H
+#ifndef GC_H
+#define GC_H
+#if (defined(WIN64)&&!defined(_WIN64))&&defined(_MSC_VER)
+#pragma message("Warning:Expecting _WIN64 for x64 targets!Notice the leading underscore!")
+#endif
+#if defined(GC_H)
+#define GC_TMP_VERSION_MAJOR 8
+#define GC_TMP_VERSION_MINOR 1
+#define GC_TMP_VERSION_MICRO 0
+#ifdef GC_VERSION_MAJOR
+#if GC_TMP_VERSION_MAJOR!=GC_VERSION_MAJOR||GC_TMP_VERSION_MINOR!=GC_VERSION_MINOR||GC_TMP_VERSION_MICRO!=GC_VERSION_MICRO
+#error Inconsistent version info. Check README.md,include/gc_version.h and configure.ac.
+#endif
+#else
+#define GC_VERSION_MAJOR GC_TMP_VERSION_MAJOR
+#define GC_VERSION_MINOR GC_TMP_VERSION_MINOR
+#define GC_VERSION_MICRO GC_TMP_VERSION_MICRO
+#endif
+#endif
+#if defined(GC_H)
+#if defined(__GNUC__)&&defined(__GNUC_MINOR__)
+#define GC_GNUC_PREREQ(major,minor)((__GNUC__<<16)+__GNUC_MINOR__>=((major)<<16)+(minor))
+#else
+#define GC_GNUC_PREREQ(major,minor)0
+#endif
+#if defined(SOLARIS_THREADS)||defined(_SOLARIS_THREADS)||defined(_SOLARIS_PTHREADS)||defined(GC_SOLARIS_PTHREADS)
+#ifndef GC_SOLARIS_THREADS
+#define GC_SOLARIS_THREADS
+#endif
+#endif
+#if defined(IRIX_THREADS)
+#define GC_IRIX_THREADS
+#endif
+#if defined(DGUX_THREADS)&&!defined(GC_DGUX386_THREADS)
+#define GC_DGUX386_THREADS
+#endif
+#if defined(AIX_THREADS)
+#define GC_AIX_THREADS
+#endif
+#if defined(HPUX_THREADS)
+#define GC_HPUX_THREADS
+#endif
+#if defined(OSF1_THREADS)
+#define GC_OSF1_THREADS
+#endif
+#if defined(LINUX_THREADS)
+#define GC_LINUX_THREADS
+#endif
+#if defined(WIN32_THREADS)
+#define GC_WIN32_THREADS
+#endif
+#if defined(RTEMS_THREADS)
+#define GC_RTEMS_PTHREADS
+#endif
+#if defined(USE_LD_WRAP)
+#define GC_USE_LD_WRAP
+#endif
+#if defined(GC_WIN32_PTHREADS)&&!defined(GC_WIN32_THREADS)
+#define GC_WIN32_THREADS
+#endif
+#if defined(GC_AIX_THREADS)||defined(GC_DARWIN_THREADS)||defined(GC_DGUX386_THREADS)||defined(GC_FREEBSD_THREADS)||defined(GC_HPUX_THREADS)||defined(GC_IRIX_THREADS)||defined(GC_LINUX_THREADS)||defined(GC_NETBSD_THREADS)||defined(GC_OPENBSD_THREADS)||defined(GC_OSF1_THREADS)||defined(GC_SOLARIS_THREADS)||defined(GC_WIN32_THREADS)||defined(GC_RTEMS_PTHREADS)
+#ifndef GC_THREADS
+#define GC_THREADS
+#endif
+#elif defined(GC_THREADS)
+#if defined(__linux__)
+#define GC_LINUX_THREADS
+#elif defined(__OpenBSD__)
+#define GC_OPENBSD_THREADS
+#elif defined(_PA_RISC1_1)||defined(_PA_RISC2_0)||defined(hppa)||defined(__HPPA)||(defined(__ia64)&&defined(_HPUX_SOURCE))
+#define GC_HPUX_THREADS
+#elif defined(__HAIKU__)
+#define GC_HAIKU_THREADS
+#elif defined(__DragonFly__)||defined(__FreeBSD_kernel__)||(defined(__FreeBSD__)&&!defined(SN_TARGET_ORBIS))
+#define GC_FREEBSD_THREADS
+#elif defined(__NetBSD__)
+#define GC_NETBSD_THREADS
+#elif defined(__alpha)||defined(__alpha__)
+#define GC_OSF1_THREADS
+#elif (defined(mips)||defined(__mips)||defined(_mips))&&!(defined(nec_ews)||defined(_nec_ews)||defined(ultrix)||defined(__ultrix))
+#define GC_IRIX_THREADS
+#elif defined(__sparc)||((defined(sun)||defined(__sun))&&(defined(i386)||defined(__i386__)||defined(__amd64)||defined(__amd64__)))
+#define GC_SOLARIS_THREADS
+#elif defined(__APPLE__)&&defined(__MACH__)
+#define GC_DARWIN_THREADS
+#endif
+#if defined(DGUX)&&(defined(i386)||defined(__i386__))
+#define GC_DGUX386_THREADS
+#endif
+#if defined(_AIX)
+#define GC_AIX_THREADS
+#endif
+#if (defined(_WIN32)||defined(_MSC_VER)||defined(__BORLANDC__)||defined(__CYGWIN32__)||defined(__CYGWIN__)||defined(__CEGCC__)||defined(_WIN32_WCE)||defined(__MINGW32__))&&!defined(GC_WIN32_THREADS)
+#define GC_WIN32_THREADS
+#endif
+#if defined(__rtems__)&&(defined(i386)||defined(__i386__))
+#define GC_RTEMS_PTHREADS
+#endif
+#endif
+#undef GC_PTHREADS
+#if (!defined(GC_WIN32_THREADS)||defined(GC_WIN32_PTHREADS)||defined(__CYGWIN32__)||defined(__CYGWIN__))&&defined(GC_THREADS)&&!defined(NN_PLATFORM_CTR)&&!defined(NN_BUILD_TARGET_PLATFORM_NX)
+#define GC_PTHREADS
+#endif
+#if!defined(_PTHREADS)&&defined(GC_NETBSD_THREADS)
+#define _PTHREADS
+#endif
+#if defined(GC_DGUX386_THREADS)&&!defined(_POSIX4A_DRAFT10_SOURCE)
+#define _POSIX4A_DRAFT10_SOURCE 1
+#endif
+#if!defined(_REENTRANT)&&defined(GC_PTHREADS)&&!defined(GC_WIN32_THREADS)
+#define _REENTRANT 1
+#endif
+#define __GC
+#if!defined(_WIN32_WCE)||defined(__GNUC__)
+#include <stddef.h>
+#if defined(__MINGW32__)&&!defined(_WIN32_WCE)
+#include <stdint.h>
+#endif
+#else
+#include <stdlib.h>
+#ifndef _PTRDIFF_T_DEFINED
+#define _PTRDIFF_T_DEFINED
+typedef long ptrdiff_t;
+#endif
+#endif
+#if!defined(GC_NOT_DLL)&&!defined(GC_DLL)&&((defined(_DLL)&&!defined(__GNUC__))||(defined(DLL_EXPORT)&&defined(GC_BUILD)))
+#define GC_DLL
+#endif
+#if defined(GC_DLL)&&!defined(GC_API)
+#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
+#define GC_API extern __declspec(dllexport)
+#else
+#define GC_API __declspec(dllimport)
+#endif
+#elif defined(__WATCOMC__)
+#ifdef GC_BUILD
+#define GC_API extern __declspec(dllexport)
+#else
+#define GC_API extern __declspec(dllimport)
+#endif
+#elif defined(__SYMBIAN32__)
+#ifdef GC_BUILD
+#define GC_API extern EXPORT_C
+#else
+#define GC_API extern IMPORT_C
+#endif
+#elif defined(__GNUC__)
+#if defined(GC_BUILD)&&!defined(GC_NO_VISIBILITY)&&(GC_GNUC_PREREQ(4,0)||defined(GC_VISIBILITY_HIDDEN_SET))
+#define GC_API extern __attribute__((__visibility__("default")))
+#endif
+#endif
+#endif
+#ifndef GC_API
+#define GC_API extern
+#endif
+#ifndef GC_CALL
+#define GC_CALL
+#endif
+#ifndef GC_CALLBACK
+#define GC_CALLBACK GC_CALL
+#endif
+#ifndef GC_ATTR_MALLOC
+#ifdef GC_OOM_FUNC_RETURNS_ALIAS
+#define GC_ATTR_MALLOC
+#elif GC_GNUC_PREREQ(3,1)
+#define GC_ATTR_MALLOC __attribute__((__malloc__))
+#elif defined(_MSC_VER)&&(_MSC_VER>=1900)&&!defined(__EDG__)
+#define GC_ATTR_MALLOC __declspec(allocator)__declspec(noalias)__declspec(restrict)
+#elif defined(_MSC_VER)&&_MSC_VER>=1400
+#define GC_ATTR_MALLOC __declspec(noalias)__declspec(restrict)
+#else
+#define GC_ATTR_MALLOC
+#endif
+#endif
+#ifndef GC_ATTR_ALLOC_SIZE
+#undef GC_ATTR_CALLOC_SIZE
+#ifdef __clang__
+#if __has_attribute(__alloc_size__)
+#define GC_ATTR_ALLOC_SIZE(argnum)__attribute__((__alloc_size__(argnum)))
+#define GC_ATTR_CALLOC_SIZE(n,s)__attribute__((__alloc_size__(n,s)))
+#else
+#define GC_ATTR_ALLOC_SIZE(argnum)
+#endif
+#elif GC_GNUC_PREREQ(4,3)&&!defined(__ICC)
+#define GC_ATTR_ALLOC_SIZE(argnum)__attribute__((__alloc_size__(argnum)))
+#define GC_ATTR_CALLOC_SIZE(n,s)__attribute__((__alloc_size__(n,s)))
+#else
+#define GC_ATTR_ALLOC_SIZE(argnum)
+#endif
+#endif
+#ifndef GC_ATTR_CALLOC_SIZE
+#define GC_ATTR_CALLOC_SIZE(n,s)
+#endif
+#ifndef GC_ATTR_NONNULL
+#if GC_GNUC_PREREQ(4,0)
+#define GC_ATTR_NONNULL(argnum)__attribute__((__nonnull__(argnum)))
+#else
+#define GC_ATTR_NONNULL(argnum)
+#endif
+#endif
+#ifndef GC_ATTR_CONST
+#if GC_GNUC_PREREQ(4,0)
+#define GC_ATTR_CONST __attribute__((__const__))
+#else
+#define GC_ATTR_CONST
+#endif
+#endif
+#ifndef GC_ATTR_DEPRECATED
+#ifdef GC_BUILD
+#undef GC_ATTR_DEPRECATED
+#define GC_ATTR_DEPRECATED
+#elif GC_GNUC_PREREQ(4,0)
+#define GC_ATTR_DEPRECATED __attribute__((__deprecated__))
+#elif defined(_MSC_VER)&&_MSC_VER>=1200
+#define GC_ATTR_DEPRECATED __declspec(deprecated)
+#else
+#define GC_ATTR_DEPRECATED
+#endif
+#endif
+#if defined(__sgi)&&!defined(__GNUC__)&&_COMPILER_VERSION>=720
+#define GC_ADD_CALLER
+#define GC_RETURN_ADDR (GC_word)__return_address
+#endif
+#if defined(__linux__)||defined(__GLIBC__)
+#if!defined(__native_client__)
+#include <features.h>
+#endif
+#if (__GLIBC__==2&&__GLIBC_MINOR__>=1||__GLIBC__ > 2)&&!defined(__ia64__)&&!defined(GC_MISSING_EXECINFO_H)&&!defined(GC_HAVE_BUILTIN_BACKTRACE)
+#define GC_HAVE_BUILTIN_BACKTRACE
+#endif
+#if defined(__i386__)||defined(__amd64__)||defined(__x86_64__)
+#define GC_CAN_SAVE_CALL_STACKS
+#endif
+#endif
+#if defined(_MSC_VER)&&_MSC_VER>=1200&&!defined(_AMD64_)&&!defined(_M_X64)&&!defined(_WIN32_WCE)&&!defined(GC_HAVE_NO_BUILTIN_BACKTRACE)&&!defined(GC_HAVE_BUILTIN_BACKTRACE)
+#define GC_HAVE_BUILTIN_BACKTRACE
+#endif
+#if defined(GC_HAVE_BUILTIN_BACKTRACE)&&!defined(GC_CAN_SAVE_CALL_STACKS)
+#define GC_CAN_SAVE_CALL_STACKS
+#endif
+#if defined(__sparc__)
+#define GC_CAN_SAVE_CALL_STACKS
+#endif
+#if (defined(__linux__)||defined(__DragonFly__)||defined(__FreeBSD__)||defined(__FreeBSD_kernel__)||defined(__HAIKU__)||defined(__NetBSD__)||defined(__OpenBSD__)||defined(HOST_ANDROID)||defined(__ANDROID__))&&!defined(GC_CAN_SAVE_CALL_STACKS)
+#define GC_ADD_CALLER
+#if GC_GNUC_PREREQ(2,95)
+#define GC_RETURN_ADDR (GC_word)__builtin_return_address(0)
+#if GC_GNUC_PREREQ(4,0)&&(defined(__i386__)||defined(__amd64__)||defined(__x86_64__))
+#define GC_HAVE_RETURN_ADDR_PARENT
+#define GC_RETURN_ADDR_PARENT (GC_word)__builtin_extract_return_addr(__builtin_return_address(1))
+#endif
+#else
+#define GC_RETURN_ADDR 0
+#endif
+#endif
+#ifdef GC_PTHREADS
+#if (defined(GC_DARWIN_THREADS)||defined(GC_WIN32_PTHREADS)||defined(__native_client__)||defined(GC_RTEMS_PTHREADS))&&!defined(GC_NO_DLOPEN)
+#define GC_NO_DLOPEN
+#endif
+#if (defined(GC_DARWIN_THREADS)||defined(GC_WIN32_PTHREADS)||defined(GC_OPENBSD_THREADS)||defined(__native_client__))&&!defined(GC_NO_PTHREAD_SIGMASK)
+#define GC_NO_PTHREAD_SIGMASK
+#endif
+#if defined(__native_client__)
+#ifndef GC_PTHREAD_CREATE_CONST
+#define GC_PTHREAD_CREATE_CONST
+#endif
+#ifndef GC_HAVE_PTHREAD_EXIT
+#define GC_HAVE_PTHREAD_EXIT
+#define GC_PTHREAD_EXIT_ATTRIBUTE
+#endif
+#endif
+#if!defined(GC_HAVE_PTHREAD_EXIT)&&!defined(HOST_ANDROID)&&!defined(__ANDROID__)&&(defined(GC_LINUX_THREADS)||defined(GC_SOLARIS_THREADS))
+#define GC_HAVE_PTHREAD_EXIT
+#if GC_GNUC_PREREQ(2,7)
+#define GC_PTHREAD_EXIT_ATTRIBUTE __attribute__((__noreturn__))
+#elif defined(__NORETURN)
+#define GC_PTHREAD_EXIT_ATTRIBUTE __NORETURN
+#else
+#define GC_PTHREAD_EXIT_ATTRIBUTE
+#endif
+#endif
+#if (!defined(GC_HAVE_PTHREAD_EXIT)||defined(__native_client__))&&!defined(GC_NO_PTHREAD_CANCEL)
+#define GC_NO_PTHREAD_CANCEL
+#endif
+#endif
+#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
+#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
+#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
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef void*GC_PTR;
+#ifdef _WIN64
+#if defined(__int64)&&!defined(CPPCHECK)
+typedef unsigned __int64 GC_word;
+typedef __int64 GC_signed_word;
+#else
+typedef unsigned long long GC_word;
+typedef long long GC_signed_word;
+#endif
+#else
+typedef unsigned long GC_word;
+typedef long GC_signed_word;
+#endif
+GC_API unsigned GC_CALL GC_get_version(void);
+GC_API GC_ATTR_DEPRECATED GC_word GC_gc_no;
+GC_API GC_word GC_CALL GC_get_gc_no(void);
+#ifdef GC_THREADS
+GC_API GC_ATTR_DEPRECATED int GC_parallel;
+GC_API int GC_CALL GC_get_parallel(void);
+GC_API void GC_CALL GC_set_markers_count(unsigned);
+#endif
+typedef void*(GC_CALLBACK*GC_oom_func)(size_t);
+GC_API GC_ATTR_DEPRECATED GC_oom_func GC_oom_fn;
+GC_API void GC_CALL GC_set_oom_fn(GC_oom_func)GC_ATTR_NONNULL(1);
+GC_API GC_oom_func GC_CALL GC_get_oom_fn(void);
+typedef void (GC_CALLBACK*GC_on_heap_resize_proc)(GC_word);
+GC_API GC_ATTR_DEPRECATED GC_on_heap_resize_proc GC_on_heap_resize;
+GC_API void GC_CALL GC_set_on_heap_resize(GC_on_heap_resize_proc);
+GC_API GC_on_heap_resize_proc GC_CALL GC_get_on_heap_resize(void);
+typedef enum {
+GC_EVENT_START,
+GC_EVENT_MARK_START,
+GC_EVENT_MARK_END,
+GC_EVENT_RECLAIM_START,
+GC_EVENT_RECLAIM_END,
+GC_EVENT_END,
+GC_EVENT_PRE_STOP_WORLD,
+GC_EVENT_POST_STOP_WORLD,
+GC_EVENT_PRE_START_WORLD,
+GC_EVENT_POST_START_WORLD,
+GC_EVENT_THREAD_SUSPENDED,
+GC_EVENT_THREAD_UNSUSPENDED
+} GC_EventType;
+typedef void (GC_CALLBACK*GC_on_collection_event_proc)(GC_EventType);
+GC_API void GC_CALL GC_set_on_collection_event(GC_on_collection_event_proc);
+GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void);
+#if defined(GC_THREADS)||(defined(GC_BUILD)&&defined(NN_PLATFORM_CTR))
+typedef void (GC_CALLBACK*GC_on_thread_event_proc)(GC_EventType,
+void*);
+GC_API void GC_CALL GC_set_on_thread_event(GC_on_thread_event_proc);
+GC_API GC_on_thread_event_proc GC_CALL GC_get_on_thread_event(void);
+#endif
+GC_API GC_ATTR_DEPRECATED int GC_find_leak;
+GC_API void GC_CALL GC_set_find_leak(int);
+GC_API int GC_CALL GC_get_find_leak(void);
+GC_API GC_ATTR_DEPRECATED int GC_all_interior_pointers;
+GC_API void GC_CALL GC_set_all_interior_pointers(int);
+GC_API int GC_CALL GC_get_all_interior_pointers(void);
+GC_API GC_ATTR_DEPRECATED int GC_finalize_on_demand;
+GC_API void GC_CALL GC_set_finalize_on_demand(int);
+GC_API int GC_CALL GC_get_finalize_on_demand(void);
+GC_API GC_ATTR_DEPRECATED int GC_java_finalization;
+GC_API void GC_CALL GC_set_java_finalization(int);
+GC_API int GC_CALL GC_get_java_finalization(void);
+typedef void (GC_CALLBACK*GC_finalizer_notifier_proc)(void);
+GC_API GC_ATTR_DEPRECATED GC_finalizer_notifier_proc GC_finalizer_notifier;
+GC_API void GC_CALL GC_set_finalizer_notifier(GC_finalizer_notifier_proc);
+GC_API GC_finalizer_notifier_proc GC_CALL GC_get_finalizer_notifier(void);
+GC_API
+#ifndef GC_DONT_GC
+GC_ATTR_DEPRECATED
+#endif
+int GC_dont_gc;
+GC_API GC_ATTR_DEPRECATED int GC_dont_expand;
+GC_API void GC_CALL GC_set_dont_expand(int);
+GC_API int GC_CALL GC_get_dont_expand(void);
+GC_API GC_ATTR_DEPRECATED int GC_use_entire_heap;
+GC_API GC_ATTR_DEPRECATED int GC_full_freq;
+GC_API void GC_CALL GC_set_full_freq(int);
+GC_API int GC_CALL GC_get_full_freq(void);
+GC_API GC_ATTR_DEPRECATED GC_word GC_non_gc_bytes;
+GC_API void GC_CALL GC_set_non_gc_bytes(GC_word);
+GC_API GC_word GC_CALL GC_get_non_gc_bytes(void);
+GC_API GC_ATTR_DEPRECATED int GC_no_dls;
+GC_API void GC_CALL GC_set_no_dls(int);
+GC_API int GC_CALL GC_get_no_dls(void);
+GC_API GC_ATTR_DEPRECATED GC_word GC_free_space_divisor;
+GC_API void GC_CALL GC_set_free_space_divisor(GC_word);
+GC_API GC_word GC_CALL GC_get_free_space_divisor(void);
+GC_API GC_ATTR_DEPRECATED GC_word GC_max_retries;
+GC_API void GC_CALL GC_set_max_retries(GC_word);
+GC_API GC_word GC_CALL GC_get_max_retries(void);
+GC_API GC_ATTR_DEPRECATED char*GC_stackbottom;
+GC_API GC_ATTR_DEPRECATED int GC_dont_precollect;
+GC_API void GC_CALL GC_set_dont_precollect(int);
+GC_API int GC_CALL GC_get_dont_precollect(void);
+GC_API GC_ATTR_DEPRECATED unsigned long GC_time_limit;
+#define GC_TIME_UNLIMITED 999999
+GC_API void GC_CALL GC_set_time_limit(unsigned long);
+GC_API unsigned long GC_CALL GC_get_time_limit(void);
+struct GC_timeval_s {
+unsigned long tv_ms;
+unsigned long tv_nsec;
+};
+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);
+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);
+GC_API void GC_CALL GC_start_performance_measurement(void);
+GC_API unsigned long GC_CALL GC_get_full_gc_total_time(void);
+GC_API void GC_CALL GC_set_pages_executable(int);
+GC_API int GC_CALL GC_get_pages_executable(void);
+GC_API void GC_CALL GC_set_min_bytes_allocd(size_t);
+GC_API size_t GC_CALL GC_get_min_bytes_allocd(void);
+GC_API void GC_CALL GC_set_rate(int);
+GC_API int GC_CALL GC_get_rate(void);
+GC_API void GC_CALL GC_set_max_prior_attempts(int);
+GC_API int GC_CALL GC_get_max_prior_attempts(void);
+GC_API void GC_CALL GC_set_handle_fork(int);
+GC_API void GC_CALL GC_atfork_prepare(void);
+GC_API void GC_CALL GC_atfork_parent(void);
+GC_API void GC_CALL GC_atfork_child(void);
+GC_API void GC_CALL GC_init(void);
+GC_API int GC_CALL GC_is_init_called(void);
+GC_API void GC_CALL GC_deinit(void);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_malloc(size_t);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_malloc_atomic(size_t);
+GC_API GC_ATTR_MALLOC char*GC_CALL GC_strdup(const char*);
+GC_API GC_ATTR_MALLOC char*GC_CALL
+GC_strndup(const char*,size_t)GC_ATTR_NONNULL(1);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_malloc_uncollectable(size_t);
+GC_API GC_ATTR_DEPRECATED void*GC_CALL GC_malloc_stubborn(size_t);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(2)void*GC_CALL
+GC_memalign(size_t,size_t);
+GC_API int GC_CALL GC_posix_memalign(void**,size_t,
+size_t)GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_free(void*);
+#define GC_MALLOC_STUBBORN(sz)GC_MALLOC(sz)
+#define GC_NEW_STUBBORN(t)GC_NEW(t)
+#define GC_CHANGE_STUBBORN(p)GC_change_stubborn(p)
+GC_API GC_ATTR_DEPRECATED void GC_CALL GC_change_stubborn(const void*);
+GC_API void GC_CALL GC_end_stubborn_change(const void*)GC_ATTR_NONNULL(1);
+GC_API void*GC_CALL GC_base(void*);
+GC_API int GC_CALL GC_is_heap_ptr(const void*);
+GC_API size_t GC_CALL GC_size(const void*)GC_ATTR_NONNULL(1);
+GC_API void*GC_CALL GC_realloc(void*,
+size_t)
+GC_ATTR_ALLOC_SIZE(2);
+GC_API int GC_CALL GC_expand_hp(size_t);
+GC_API void GC_CALL GC_set_max_heap_size(GC_word);
+GC_API void GC_CALL GC_exclude_static_roots(void*,
+void*);
+GC_API void GC_CALL GC_clear_exclusion_table(void);
+GC_API void GC_CALL GC_clear_roots(void);
+GC_API void GC_CALL GC_add_roots(void*,
+void*);
+GC_API void GC_CALL GC_remove_roots(void*,
+void*);
+GC_API void GC_CALL GC_register_displacement(size_t);
+GC_API void GC_CALL GC_debug_register_displacement(size_t);
+GC_API void GC_CALL GC_gcollect(void);
+GC_API void GC_CALL GC_gcollect_and_unmap(void);
+typedef int (GC_CALLBACK*GC_stop_func)(void);
+GC_API int GC_CALL GC_try_to_collect(GC_stop_func)
+GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_set_stop_func(GC_stop_func)
+GC_ATTR_NONNULL(1);
+GC_API GC_stop_func GC_CALL GC_get_stop_func(void);
+GC_API size_t GC_CALL GC_get_heap_size(void);
+GC_API size_t GC_CALL GC_get_free_bytes(void);
+GC_API size_t GC_CALL GC_get_unmapped_bytes(void);
+GC_API size_t GC_CALL GC_get_bytes_since_gc(void);
+GC_API size_t GC_CALL GC_get_expl_freed_bytes_since_gc(void);
+GC_API size_t GC_CALL GC_get_total_bytes(void);
+GC_API void GC_CALL GC_get_heap_usage_safe(GC_word*,
+GC_word*,
+GC_word*,
+GC_word*,
+GC_word*);
+struct GC_prof_stats_s {
+GC_word heapsize_full;
+GC_word free_bytes_full;
+GC_word unmapped_bytes;
+GC_word bytes_allocd_since_gc;
+GC_word allocd_bytes_before_gc;
+GC_word non_gc_bytes;
+GC_word gc_no;
+GC_word markers_m1;
+GC_word bytes_reclaimed_since_gc;
+GC_word reclaimed_bytes_before_gc;
+GC_word expl_freed_bytes_since_gc;
+};
+GC_API size_t GC_CALL GC_get_prof_stats(struct GC_prof_stats_s*,
+size_t);
+#ifdef GC_THREADS
+GC_API size_t GC_CALL GC_get_prof_stats_unsafe(struct GC_prof_stats_s*,
+size_t);
+#endif
+GC_API size_t GC_CALL GC_get_size_map_at(int i);
+GC_API size_t GC_CALL GC_get_memory_use(void);
+GC_API void GC_CALL GC_disable(void);
+GC_API int GC_CALL GC_is_disabled(void);
+GC_API void GC_CALL GC_enable(void);
+GC_API void GC_CALL GC_set_manual_vdb_allowed(int);
+GC_API int GC_CALL GC_get_manual_vdb_allowed(void);
+GC_API void GC_CALL GC_enable_incremental(void);
+GC_API int GC_CALL GC_is_incremental_mode(void);
+#define GC_PROTECTS_POINTER_HEAP 1
+#define GC_PROTECTS_PTRFREE_HEAP 2
+#define GC_PROTECTS_STATIC_DATA 4
+#define GC_PROTECTS_STACK 8
+#define GC_PROTECTS_NONE 0
+GC_API int GC_CALL GC_incremental_protection_needs(void);
+GC_API int GC_CALL GC_collect_a_little(void);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_malloc_ignore_off_page(size_t);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_malloc_atomic_ignore_off_page(size_t);
+#ifdef GC_ADD_CALLER
+#define GC_EXTRAS GC_RETURN_ADDR,__FILE__,__LINE__
+#define GC_EXTRA_PARAMS GC_word ra,const char*s,int i
+#else
+#define GC_EXTRAS __FILE__,__LINE__
+#define GC_EXTRA_PARAMS const char*s,int i
+#endif
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_malloc_atomic_uncollectable(size_t);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_debug_malloc_atomic_uncollectable(size_t,GC_EXTRA_PARAMS);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_debug_malloc(size_t,GC_EXTRA_PARAMS);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_debug_malloc_atomic(size_t,GC_EXTRA_PARAMS);
+GC_API GC_ATTR_MALLOC char*GC_CALL
+GC_debug_strdup(const char*,GC_EXTRA_PARAMS);
+GC_API GC_ATTR_MALLOC char*GC_CALL
+GC_debug_strndup(const char*,size_t,GC_EXTRA_PARAMS)
+GC_ATTR_NONNULL(1);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_debug_malloc_uncollectable(size_t,
+GC_EXTRA_PARAMS);
+GC_API GC_ATTR_DEPRECATED void*GC_CALL
+GC_debug_malloc_stubborn(size_t,GC_EXTRA_PARAMS);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_debug_malloc_ignore_off_page(size_t,
+GC_EXTRA_PARAMS);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_debug_malloc_atomic_ignore_off_page(size_t,
+GC_EXTRA_PARAMS);
+GC_API void GC_CALL GC_debug_free(void*);
+GC_API void*GC_CALL GC_debug_realloc(void*,
+size_t,GC_EXTRA_PARAMS)
+GC_ATTR_ALLOC_SIZE(2);
+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);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_debug_malloc_replacement(size_t);
+GC_API GC_ATTR_ALLOC_SIZE(2)void*GC_CALL
+GC_debug_realloc_replacement(void*,
+size_t);
+#ifdef GC_DEBUG_REPLACEMENT
+#define GC_MALLOC(sz)GC_debug_malloc_replacement(sz)
+#define GC_REALLOC(old,sz)GC_debug_realloc_replacement(old,sz)
+#elif defined(GC_DEBUG)
+#define GC_MALLOC(sz)GC_debug_malloc(sz,GC_EXTRAS)
+#define GC_REALLOC(old,sz)GC_debug_realloc(old,sz,GC_EXTRAS)
+#else
+#define GC_MALLOC(sz)GC_malloc(sz)
+#define GC_REALLOC(old,sz)GC_realloc(old,sz)
+#endif
+#ifdef GC_DEBUG
+#define GC_MALLOC_ATOMIC(sz)GC_debug_malloc_atomic(sz,GC_EXTRAS)
+#define GC_STRDUP(s)GC_debug_strdup(s,GC_EXTRAS)
+#define GC_STRNDUP(s,sz)GC_debug_strndup(s,sz,GC_EXTRAS)
+#define GC_MALLOC_ATOMIC_UNCOLLECTABLE(sz)GC_debug_malloc_atomic_uncollectable(sz,GC_EXTRAS)
+#define GC_MALLOC_UNCOLLECTABLE(sz)GC_debug_malloc_uncollectable(sz,GC_EXTRAS)
+#define GC_MALLOC_IGNORE_OFF_PAGE(sz)GC_debug_malloc_ignore_off_page(sz,GC_EXTRAS)
+#define GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sz)GC_debug_malloc_atomic_ignore_off_page(sz,GC_EXTRAS)
+#define GC_FREE(p)GC_debug_free(p)
+#define GC_REGISTER_FINALIZER(p,f,d,of,od)GC_debug_register_finalizer(p,f,d,of,od)
+#define GC_REGISTER_FINALIZER_IGNORE_SELF(p,f,d,of,od)GC_debug_register_finalizer_ignore_self(p,f,d,of,od)
+#define GC_REGISTER_FINALIZER_NO_ORDER(p,f,d,of,od)GC_debug_register_finalizer_no_order(p,f,d,of,od)
+#define GC_REGISTER_FINALIZER_UNREACHABLE(p,f,d,of,od)GC_debug_register_finalizer_unreachable(p,f,d,of,od)
+#define GC_END_STUBBORN_CHANGE(p)GC_debug_end_stubborn_change(p)
+#define GC_PTR_STORE_AND_DIRTY(p,q)GC_debug_ptr_store_and_dirty(p,q)
+#define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link,obj)GC_general_register_disappearing_link(link,GC_base(( void*)(obj)))
+#define GC_REGISTER_LONG_LINK(link,obj)GC_register_long_link(link,GC_base(( void*)(obj)))
+#define GC_REGISTER_DISPLACEMENT(n)GC_debug_register_displacement(n)
+#else
+#define GC_MALLOC_ATOMIC(sz)GC_malloc_atomic(sz)
+#define GC_STRDUP(s)GC_strdup(s)
+#define GC_STRNDUP(s,sz)GC_strndup(s,sz)
+#define GC_MALLOC_ATOMIC_UNCOLLECTABLE(sz)GC_malloc_atomic_uncollectable(sz)
+#define GC_MALLOC_UNCOLLECTABLE(sz)GC_malloc_uncollectable(sz)
+#define GC_MALLOC_IGNORE_OFF_PAGE(sz)GC_malloc_ignore_off_page(sz)
+#define GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sz)GC_malloc_atomic_ignore_off_page(sz)
+#define GC_FREE(p)GC_free(p)
+#define GC_REGISTER_FINALIZER(p,f,d,of,od)GC_register_finalizer(p,f,d,of,od)
+#define GC_REGISTER_FINALIZER_IGNORE_SELF(p,f,d,of,od)GC_register_finalizer_ignore_self(p,f,d,of,od)
+#define GC_REGISTER_FINALIZER_NO_ORDER(p,f,d,of,od)GC_register_finalizer_no_order(p,f,d,of,od)
+#define GC_REGISTER_FINALIZER_UNREACHABLE(p,f,d,of,od)GC_register_finalizer_unreachable(p,f,d,of,od)
+#define GC_END_STUBBORN_CHANGE(p)GC_end_stubborn_change(p)
+#define GC_PTR_STORE_AND_DIRTY(p,q)GC_ptr_store_and_dirty(p,q)
+#define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link,obj)GC_general_register_disappearing_link(link,obj)
+#define GC_REGISTER_LONG_LINK(link,obj)GC_register_long_link(link,obj)
+#define GC_REGISTER_DISPLACEMENT(n)GC_register_displacement(n)
+#endif
+#define GC_NEW(t)((t*)GC_MALLOC(sizeof(t)))
+#define GC_NEW_ATOMIC(t)((t*)GC_MALLOC_ATOMIC(sizeof(t)))
+#define GC_NEW_UNCOLLECTABLE(t)((t*)GC_MALLOC_UNCOLLECTABLE(sizeof(t)))
+#ifdef GC_REQUIRE_WCSDUP
+GC_API GC_ATTR_MALLOC wchar_t*GC_CALL
+GC_wcsdup(const wchar_t*)GC_ATTR_NONNULL(1);
+GC_API GC_ATTR_MALLOC wchar_t*GC_CALL
+GC_debug_wcsdup(const wchar_t*,GC_EXTRA_PARAMS)GC_ATTR_NONNULL(1);
+#ifdef GC_DEBUG
+#define GC_WCSDUP(s)GC_debug_wcsdup(s,GC_EXTRAS)
+#else
+#define GC_WCSDUP(s)GC_wcsdup(s)
+#endif
+#endif
+typedef void (GC_CALLBACK*GC_finalization_proc)(void*,
+void*);
+GC_API void GC_CALL GC_register_finalizer(void*,
+GC_finalization_proc,void*,
+GC_finalization_proc*,void**)
+GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_debug_register_finalizer(void*,
+GC_finalization_proc,void*,
+GC_finalization_proc*,void**)
+GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_register_finalizer_ignore_self(void*,
+GC_finalization_proc,void*,
+GC_finalization_proc*,void**)
+GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_debug_register_finalizer_ignore_self(void*,
+GC_finalization_proc,void*,
+GC_finalization_proc*,void**)
+GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_register_finalizer_no_order(void*,
+GC_finalization_proc,void*,
+GC_finalization_proc*,void**)
+GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_debug_register_finalizer_no_order(void*,
+GC_finalization_proc,void*,
+GC_finalization_proc*,void**)
+GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_register_finalizer_unreachable(void*,
+GC_finalization_proc,void*,
+GC_finalization_proc*,void**)
+GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_debug_register_finalizer_unreachable(void*,
+GC_finalization_proc,void*,
+GC_finalization_proc*,void**)
+GC_ATTR_NONNULL(1);
+#define GC_NO_MEMORY 2
+GC_API int GC_CALL GC_register_disappearing_link(void**)
+GC_ATTR_NONNULL(1);
+GC_API int GC_CALL GC_general_register_disappearing_link(void**,
+const void*)
+GC_ATTR_NONNULL(1)GC_ATTR_NONNULL(2);
+GC_API int GC_CALL GC_move_disappearing_link(void**,
+void**)
+GC_ATTR_NONNULL(2);
+GC_API int GC_CALL GC_unregister_disappearing_link(void**);
+GC_API int GC_CALL GC_register_long_link(void**,
+const void*)
+GC_ATTR_NONNULL(1)GC_ATTR_NONNULL(2);
+GC_API int GC_CALL GC_move_long_link(void**,
+void**)
+GC_ATTR_NONNULL(2);
+GC_API int GC_CALL GC_unregister_long_link(void**);
+typedef enum {
+GC_TOGGLE_REF_DROP,
+GC_TOGGLE_REF_STRONG,
+GC_TOGGLE_REF_WEAK
+} GC_ToggleRefStatus;
+typedef GC_ToggleRefStatus (GC_CALLBACK*GC_toggleref_func)(void*);
+GC_API void GC_CALL GC_set_toggleref_func(GC_toggleref_func);
+GC_API GC_toggleref_func GC_CALL GC_get_toggleref_func(void);
+GC_API int GC_CALL GC_toggleref_add(void*,int)
+GC_ATTR_NONNULL(1);
+typedef void (GC_CALLBACK*GC_await_finalize_proc)(void*);
+GC_API void GC_CALL GC_set_await_finalize_proc(GC_await_finalize_proc);
+GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void);
+GC_API int GC_CALL GC_should_invoke_finalizers(void);
+GC_API int GC_CALL GC_invoke_finalizers(void);
+#if defined(__GNUC__)&&!defined(__INTEL_COMPILER)
+#define GC_reachable_here(ptr)__asm__ __volatile__(" "::"X"(ptr):"memory")
+#else
+GC_API void GC_CALL GC_noop1(GC_word);
+#ifdef LINT2
+#define GC_reachable_here(ptr)GC_noop1(~(GC_word)(ptr)^(~(GC_word)0))
+#else
+#define GC_reachable_here(ptr)GC_noop1((GC_word)(ptr))
+#endif
+#endif
+typedef void (GC_CALLBACK*GC_warn_proc)(char*,
+GC_word);
+GC_API void GC_CALL GC_set_warn_proc(GC_warn_proc)GC_ATTR_NONNULL(1);
+GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void);
+GC_API void GC_CALLBACK GC_ignore_warn_proc(char*,GC_word);
+GC_API void GC_CALL GC_set_log_fd(int);
+typedef void (GC_CALLBACK*GC_abort_func)(const char*);
+GC_API void GC_CALL GC_set_abort_func(GC_abort_func)GC_ATTR_NONNULL(1);
+GC_API GC_abort_func GC_CALL GC_get_abort_func(void);
+GC_API void GC_CALL GC_abort_on_oom(void);
+typedef GC_word GC_hidden_pointer;
+#define GC_HIDE_POINTER(p)(~(GC_hidden_pointer)(p))
+#define GC_REVEAL_POINTER(p)((void*)GC_HIDE_POINTER(p))
+#if defined(I_HIDE_POINTERS)||defined(GC_I_HIDE_POINTERS)
+#define HIDE_POINTER(p)GC_HIDE_POINTER(p)
+#define REVEAL_POINTER(p)GC_REVEAL_POINTER(p)
+#endif
+#ifdef GC_THREADS
+GC_API void GC_CALL GC_alloc_lock(void);
+GC_API void GC_CALL GC_alloc_unlock(void);
+#else
+#define GC_alloc_lock()(void)0
+#define GC_alloc_unlock()(void)0
+#endif
+typedef void*(GC_CALLBACK*GC_fn_type)(void*);
+GC_API void*GC_CALL GC_call_with_alloc_lock(GC_fn_type,
+void*)GC_ATTR_NONNULL(1);
+struct GC_stack_base {
+void*mem_base;
+#if defined(__ia64)||defined(__ia64__)||defined(_M_IA64)
+void*reg_base;
+#endif
+};
+typedef void*(GC_CALLBACK*GC_stack_base_func)(
+struct GC_stack_base*,void*);
+GC_API void*GC_CALL GC_call_with_stack_base(GC_stack_base_func,
+void*)GC_ATTR_NONNULL(1);
+#define GC_SUCCESS 0
+#define GC_DUPLICATE 1
+#define GC_NO_THREADS 2
+#define GC_UNIMPLEMENTED 3
+#define GC_NOT_FOUND 4
+#if defined(GC_DARWIN_THREADS)||defined(GC_WIN32_THREADS)
+GC_API void GC_CALL GC_use_threads_discovery(void);
+#endif
+#ifdef GC_THREADS
+GC_API void GC_CALL GC_set_suspend_signal(int);
+GC_API void GC_CALL GC_set_thr_restart_signal(int);
+GC_API int GC_CALL GC_get_suspend_signal(void);
+GC_API int GC_CALL GC_get_thr_restart_signal(void);
+GC_API void GC_CALL GC_start_mark_threads(void);
+GC_API void GC_CALL GC_allow_register_threads(void);
+GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base*)
+GC_ATTR_NONNULL(1);
+GC_API int GC_CALL GC_thread_is_registered(void);
+GC_API void GC_CALL GC_register_altstack(void*,
+GC_word,
+void*,
+GC_word);
+GC_API int GC_CALL GC_unregister_my_thread(void);
+GC_API void GC_CALL GC_stop_world_external(void);
+GC_API void GC_CALL GC_start_world_external(void);
+#endif
+GC_API void*GC_CALL GC_do_blocking(GC_fn_type,
+void*)GC_ATTR_NONNULL(1);
+GC_API void*GC_CALL GC_call_with_gc_active(GC_fn_type,
+void*)GC_ATTR_NONNULL(1);
+GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base*)
+GC_ATTR_NONNULL(1);
+GC_API void*GC_CALL GC_get_my_stackbottom(struct GC_stack_base*)
+GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_set_stackbottom(void*,
+const struct GC_stack_base*)
+GC_ATTR_NONNULL(2);
+GC_API void*GC_CALL GC_same_obj(void*,void*);
+GC_API void*GC_CALL GC_pre_incr(void**,ptrdiff_t)
+GC_ATTR_NONNULL(1);
+GC_API void*GC_CALL GC_post_incr(void**,ptrdiff_t)
+GC_ATTR_NONNULL(1);
+GC_API void*GC_CALL GC_is_visible(void*);
+GC_API void*GC_CALL GC_is_valid_displacement(void*);
+GC_API void GC_CALL GC_dump(void);
+GC_API void GC_CALL GC_dump_named(const char*);
+GC_API void GC_CALL GC_dump_regions(void);
+GC_API void GC_CALL GC_dump_finalization(void);
+#if defined(GC_DEBUG)&&defined(__GNUC__)
+#define GC_PTR_ADD3(x,n,type_of_result)((type_of_result)GC_same_obj((x)+(n),(x)))
+#define GC_PRE_INCR3(x,n,type_of_result)((type_of_result)GC_pre_incr((void**)(&(x)),(n)*sizeof(*x)))
+#define GC_POST_INCR3(x,n,type_of_result)((type_of_result)GC_post_incr((void**)(&(x)),(n)*sizeof(*x)))
+#define GC_PTR_ADD(x,n)GC_PTR_ADD3(x,n,__typeof__(x))
+#define GC_PRE_INCR(x,n)GC_PRE_INCR3(x,n,__typeof__(x))
+#define GC_POST_INCR(x)GC_POST_INCR3(x,1,__typeof__(x))
+#define GC_POST_DECR(x)GC_POST_INCR3(x,-1,__typeof__(x))
+#else
+#define GC_PTR_ADD(x,n)((x)+(n))
+#define GC_PRE_INCR(x,n)((x)+=(n))
+#define GC_POST_INCR(x)((x)++)
+#define GC_POST_DECR(x)((x)--)
+#endif
+#ifdef GC_DEBUG
+#define GC_PTR_STORE(p,q)(*(void**)GC_is_visible((void*)(p))=GC_is_valid_displacement((void*)(q)))
+#else
+#define GC_PTR_STORE(p,q)(*(void**)(p)=(void*)(q))
+#endif
+GC_API void GC_CALL GC_ptr_store_and_dirty(void*,
+const void*);
+GC_API void GC_CALL GC_debug_ptr_store_and_dirty(void*,
+const void*);
+GC_API void (GC_CALLBACK*GC_same_obj_print_proc)(void*,
+void*);
+GC_API void (GC_CALLBACK*GC_is_valid_displacement_print_proc)(void*);
+GC_API void (GC_CALLBACK*GC_is_visible_print_proc)(void*);
+#ifdef GC_PTHREADS
+#ifdef __cplusplus
+}
+#endif
+#ifndef GC_PTHREAD_REDIRECTS_H
+#define GC_PTHREAD_REDIRECTS_H
+#if defined(GC_H)&&defined(GC_PTHREADS)
+#ifndef GC_PTHREAD_REDIRECTS_ONLY
+#include <pthread.h>
+#ifndef GC_NO_DLOPEN
+#include <dlfcn.h>
+#endif
+#ifndef GC_NO_PTHREAD_SIGMASK
+#include <signal.h>
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifndef GC_SUSPEND_THREAD_ID
+#define GC_SUSPEND_THREAD_ID pthread_t
+#endif
+#ifndef GC_NO_DLOPEN
+GC_API void*GC_dlopen(const char*,int);
+#endif
+#ifndef GC_NO_PTHREAD_SIGMASK
+#if defined(GC_PTHREAD_SIGMASK_NEEDED)||defined(_BSD_SOURCE)||defined(_GNU_SOURCE)||(_POSIX_C_SOURCE>=199506L)||(_XOPEN_SOURCE>=500)
+GC_API int GC_pthread_sigmask(int,const sigset_t*,
+sigset_t*);
+#endif
+#endif
+#ifndef GC_PTHREAD_CREATE_CONST
+#define GC_PTHREAD_CREATE_CONST const
+#endif
+GC_API int GC_pthread_create(pthread_t*,
+GC_PTHREAD_CREATE_CONST pthread_attr_t*,
+void*(*)(void*),void*);
+GC_API int GC_pthread_join(pthread_t,void**);
+GC_API int GC_pthread_detach(pthread_t);
+#ifndef GC_NO_PTHREAD_CANCEL
+GC_API int GC_pthread_cancel(pthread_t);
+#endif
+#if defined(GC_HAVE_PTHREAD_EXIT)&&!defined(GC_PTHREAD_EXIT_DECLARED)
+#define GC_PTHREAD_EXIT_DECLARED
+GC_API void GC_pthread_exit(void*)GC_PTHREAD_EXIT_ATTRIBUTE;
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+#if!defined(GC_NO_THREAD_REDIRECTS)&&!defined(GC_USE_LD_WRAP)
+#undef pthread_create
+#undef pthread_join
+#undef pthread_detach
+#define pthread_create GC_pthread_create
+#define pthread_join GC_pthread_join
+#define pthread_detach GC_pthread_detach
+#ifndef GC_NO_PTHREAD_SIGMASK
+#undef pthread_sigmask
+#define pthread_sigmask GC_pthread_sigmask
+#endif
+#ifndef GC_NO_DLOPEN
+#undef dlopen
+#define dlopen GC_dlopen
+#endif
+#ifndef GC_NO_PTHREAD_CANCEL
+#undef pthread_cancel
+#define pthread_cancel GC_pthread_cancel
+#endif
+#ifdef GC_HAVE_PTHREAD_EXIT
+#undef pthread_exit
+#define pthread_exit GC_pthread_exit
+#endif
+#endif
+#endif
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+#endif
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_malloc_many(size_t);
+#define GC_NEXT(p)(*(void**)(p))
+typedef int (GC_CALLBACK*GC_has_static_roots_func)(
+const char*,
+void*,
+size_t);
+GC_API void GC_CALL GC_register_has_static_roots_callback(
+GC_has_static_roots_func);
+#if!defined(CPPCHECK)&&!defined(GC_WINDOWS_H_INCLUDED)&&defined(WINAPI)
+#define GC_WINDOWS_H_INCLUDED
+#endif
+#if defined(GC_WIN32_THREADS)&&(!defined(GC_PTHREADS)||defined(GC_BUILD)||defined(GC_WINDOWS_H_INCLUDED))
+#if (!defined(GC_NO_THREAD_DECLS)||defined(GC_BUILD))&&!defined(GC_DONT_INCL_WINDOWS_H)
+#ifdef __cplusplus
+}
+#endif
+#if!defined(_WIN32_WCE)&&!defined(__CEGCC__)
+#include <process.h>
+#endif
+#if defined(GC_BUILD)||!defined(GC_DONT_INCLUDE_WINDOWS_H)
+#include <windows.h>
+#define GC_WINDOWS_H_INCLUDED
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef GC_UNDERSCORE_STDCALL
+#define GC_CreateThread _GC_CreateThread
+#define GC_ExitThread _GC_ExitThread
+#endif
+#ifndef DECLSPEC_NORETURN
+#ifdef GC_WINDOWS_H_INCLUDED
+#define DECLSPEC_NORETURN
+#else
+#define DECLSPEC_NORETURN __declspec(noreturn)
+#endif
+#endif
+#if!defined(_UINTPTR_T)&&!defined(_UINTPTR_T_DEFINED)&&!defined(UINTPTR_MAX)
+typedef GC_word GC_uintptr_t;
+#else
+typedef uintptr_t GC_uintptr_t;
+#endif
+#ifdef _WIN64
+#define GC_WIN32_SIZE_T GC_uintptr_t
+#elif defined(GC_WINDOWS_H_INCLUDED)
+#define GC_WIN32_SIZE_T DWORD
+#else
+#define GC_WIN32_SIZE_T unsigned long
+#endif
+#ifdef GC_INSIDE_DLL
+#ifdef GC_UNDERSCORE_STDCALL
+#define GC_DllMain _GC_DllMain
+#endif
+#ifdef GC_WINDOWS_H_INCLUDED
+GC_API BOOL WINAPI GC_DllMain(HINSTANCE,
+ULONG,
+LPVOID);
+#else
+GC_API int __stdcall GC_DllMain(void*,unsigned long,void*);
+#endif
+#endif
+#ifdef GC_WINDOWS_H_INCLUDED
+GC_API HANDLE WINAPI GC_CreateThread(
+LPSECURITY_ATTRIBUTES,
+GC_WIN32_SIZE_T,
+LPTHREAD_START_ROUTINE,
+LPVOID,DWORD,
+LPDWORD);
+GC_API DECLSPEC_NORETURN void WINAPI GC_ExitThread(
+DWORD);
+#else
+struct _SECURITY_ATTRIBUTES;
+GC_API void*__stdcall GC_CreateThread(struct _SECURITY_ATTRIBUTES*,
+GC_WIN32_SIZE_T,
+unsigned long (__stdcall*)(void*),
+void*,unsigned long,unsigned long*);
+GC_API DECLSPEC_NORETURN void __stdcall GC_ExitThread(unsigned long);
+#endif
+#if!defined(_WIN32_WCE)&&!defined(__CEGCC__)
+GC_API GC_uintptr_t GC_CALL GC_beginthreadex(
+void*,unsigned,
+unsigned (__stdcall*)(void*),
+void*,unsigned,
+unsigned*);
+GC_API void GC_CALL GC_endthreadex(unsigned);
+#endif
+#endif
+#ifdef GC_WINMAIN_REDIRECT
+#define WinMain GC_WinMain
+#endif
+#define GC_use_DllMain GC_use_threads_discovery
+#ifndef GC_NO_THREAD_REDIRECTS
+#define CreateThread GC_CreateThread
+#define ExitThread GC_ExitThread
+#undef _beginthreadex
+#define _beginthreadex GC_beginthreadex
+#undef _endthreadex
+#define _endthreadex GC_endthreadex
+#endif
+#endif
+GC_API void GC_CALL GC_set_force_unmap_on_gcollect(int);
+GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
+#if defined(__CYGWIN32__)||defined(__CYGWIN__)
+#ifdef __x86_64__
+extern int __data_start__[],__data_end__[];
+extern int __bss_start__[],__bss_end__[];
+#define GC_DATASTART ((GC_word)__data_start__ < (GC_word)__bss_start__?(void*)__data_start__:(void*)__bss_start__)
+#define GC_DATAEND ((GC_word)__data_end__ > (GC_word)__bss_end__?(void*)__data_end__:(void*)__bss_end__)
+#else
+extern int _data_start__[],_data_end__[],_bss_start__[],_bss_end__[];
+#define GC_DATASTART ((GC_word)_data_start__ < (GC_word)_bss_start__?(void*)_data_start__:(void*)_bss_start__)
+#define GC_DATAEND ((GC_word)_data_end__ > (GC_word)_bss_end__?(void*)_data_end__:(void*)_bss_end__)
+#endif
+#define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART,GC_DATAEND);GC_gcollect()
+#elif defined(_AIX)
+extern int _data[],_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)
+#pragma weak __dso_handle
+extern int __dso_handle[];
+GC_API void*GC_CALL GC_find_limit(void*,int);
+#define GC_INIT_CONF_ROOTS (void)(__dso_handle!=0?(GC_add_roots(__dso_handle,GC_find_limit(__dso_handle,1)),0):0)
+#else
+#define GC_INIT_CONF_ROOTS
+#endif
+#ifdef GC_DONT_EXPAND
+#define GC_INIT_CONF_DONT_EXPAND GC_set_dont_expand(1)
+#else
+#define GC_INIT_CONF_DONT_EXPAND
+#endif
+#ifdef GC_FORCE_UNMAP_ON_GCOLLECT
+#define GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT GC_set_force_unmap_on_gcollect(1)
+#else
+#define GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT
+#endif
+#ifdef GC_DONT_GC
+#define GC_INIT_CONF_MAX_RETRIES (void)(GC_dont_gc=1)
+#elif defined(GC_MAX_RETRIES)&&!defined(CPPCHECK)
+#define GC_INIT_CONF_MAX_RETRIES GC_set_max_retries(GC_MAX_RETRIES)
+#else
+#define GC_INIT_CONF_MAX_RETRIES
+#endif
+#if defined(GC_ALLOCD_BYTES_PER_FINALIZER)&&!defined(CPPCHECK)
+#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
+#endif
+#if defined(GC_FREE_SPACE_DIVISOR)&&!defined(CPPCHECK)
+#define GC_INIT_CONF_FREE_SPACE_DIVISOR GC_set_free_space_divisor(GC_FREE_SPACE_DIVISOR)
+#else
+#define GC_INIT_CONF_FREE_SPACE_DIVISOR
+#endif
+#if defined(GC_FULL_FREQ)&&!defined(CPPCHECK)
+#define GC_INIT_CONF_FULL_FREQ GC_set_full_freq(GC_FULL_FREQ)
+#else
+#define GC_INIT_CONF_FULL_FREQ
+#endif
+#if defined(GC_TIME_LIMIT)&&!defined(CPPCHECK)
+#define GC_INIT_CONF_TIME_LIMIT GC_set_time_limit(GC_TIME_LIMIT)
+#else
+#define GC_INIT_CONF_TIME_LIMIT
+#endif
+#if defined(GC_MARKERS)&&defined(GC_THREADS)&&!defined(CPPCHECK)
+#define GC_INIT_CONF_MARKERS GC_set_markers_count(GC_MARKERS)
+#else
+#define GC_INIT_CONF_MARKERS
+#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
+#define GC_INIT_CONF_SUSPEND_SIGNAL
+#endif
+#if defined(GC_SIG_THR_RESTART)&&defined(GC_THREADS)&&!defined(CPPCHECK)
+#define GC_INIT_CONF_THR_RESTART_SIGNAL GC_set_thr_restart_signal(GC_SIG_THR_RESTART)
+#else
+#define GC_INIT_CONF_THR_RESTART_SIGNAL
+#endif
+#if defined(GC_MAXIMUM_HEAP_SIZE)&&!defined(CPPCHECK)
+#define GC_INIT_CONF_MAXIMUM_HEAP_SIZE GC_set_max_heap_size(GC_MAXIMUM_HEAP_SIZE)
+#else
+#define GC_INIT_CONF_MAXIMUM_HEAP_SIZE
+#endif
+#ifdef GC_IGNORE_WARN
+#define GC_INIT_CONF_IGNORE_WARN GC_set_warn_proc(GC_ignore_warn_proc)
+#else
+#define GC_INIT_CONF_IGNORE_WARN
+#endif
+#if defined(GC_INITIAL_HEAP_SIZE)&&!defined(CPPCHECK)
+#define GC_INIT_CONF_INITIAL_HEAP_SIZE { size_t heap_size=GC_get_heap_size();if (heap_size < (GC_INITIAL_HEAP_SIZE))(void)GC_expand_hp((GC_INITIAL_HEAP_SIZE)- heap_size);}
+#else
+#define GC_INIT_CONF_INITIAL_HEAP_SIZE
+#endif
+#define GC_INIT(){ GC_INIT_CONF_DONT_EXPAND;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;GC_init();GC_INIT_CONF_ROOTS;GC_INIT_CONF_IGNORE_WARN;GC_INIT_CONF_INITIAL_HEAP_SIZE;}
+GC_API void GC_CALL GC_win32_free_heap(void);
+#if defined(__SYMBIAN32__)
+void GC_init_global_static_roots(void);
+#endif
+#if defined(_AMIGA)&&!defined(GC_AMIGA_MAKINGLIB)
+void*GC_amiga_realloc(void*,size_t);
+#define GC_realloc(a,b)GC_amiga_realloc(a,b)
+void GC_amiga_set_toany(void (*)(void));
+extern int GC_amiga_free_space_divisor_inc;
+extern void*(*GC_amiga_allocwrapper_do)(size_t,void*(GC_CALL*)(size_t));
+#define GC_malloc(a)(*GC_amiga_allocwrapper_do)(a,GC_malloc)
+#define GC_malloc_atomic(a)(*GC_amiga_allocwrapper_do)(a,GC_malloc_atomic)
+#define GC_malloc_uncollectable(a)(*GC_amiga_allocwrapper_do)(a,GC_malloc_uncollectable)
+#define GC_malloc_atomic_uncollectable(a)(*GC_amiga_allocwrapper_do)(a,GC_malloc_atomic_uncollectable)
+#define GC_malloc_ignore_off_page(a)(*GC_amiga_allocwrapper_do)(a,GC_malloc_ignore_off_page)
+#define GC_malloc_atomic_ignore_off_page(a)(*GC_amiga_allocwrapper_do)(a,GC_malloc_atomic_ignore_off_page)
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+#endif
+#include <stdlib.h>
+#if!defined(sony_news)
+#include <stddef.h>
+#endif
+#ifdef DGUX
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#ifdef BSD_TIME
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#ifdef PARALLEL_MARK
+#define AO_REQUIRE_CAS
+#if!defined(__GNUC__)&&!defined(AO_ASSUME_WINDOWS98)
+#define AO_ASSUME_WINDOWS98
+#endif
+#endif
+#ifndef GC_TINY_FL_H
+#define GC_TINY_FL_H
+#ifndef GC_GRANULE_BYTES
+#if defined(__LP64__)||defined (_LP64)||defined(_WIN64)||defined(__s390x__)||(defined(__x86_64__)&&!defined(__ILP32__))||defined(__alpha__)||defined(__powerpc64__)||defined(__arch64__)
+#define GC_GRANULE_BYTES 16
+#define GC_GRANULE_WORDS 2
+#else
+#define GC_GRANULE_BYTES 8
+#define GC_GRANULE_WORDS 2
+#endif
+#endif
+#if GC_GRANULE_WORDS==2
+#define GC_WORDS_TO_GRANULES(n)((n)>>1)
+#else
+#define GC_WORDS_TO_GRANULES(n)((n)*sizeof(void*)/GC_GRANULE_BYTES)
+#endif
+#ifndef GC_TINY_FREELISTS
+#if GC_GRANULE_BYTES==16
+#define GC_TINY_FREELISTS 25
+#else
+#define GC_TINY_FREELISTS 33
+#endif
+#endif
+#define GC_RAW_BYTES_FROM_INDEX(i)((i)*GC_GRANULE_BYTES)
+#endif
+#ifndef GC_MARK_H
+#define GC_MARK_H
+#ifndef GC_H
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define GC_PROC_BYTES 100
+#if defined(GC_BUILD)||defined(NOT_GCBUILD)
+struct GC_ms_entry;
+#else
+struct GC_ms_entry { void*opaque;};
+#endif
+typedef struct GC_ms_entry*(*GC_mark_proc)(GC_word*,
+struct GC_ms_entry*,
+struct GC_ms_entry*,
+GC_word);
+#define GC_LOG_MAX_MARK_PROCS 6
+#define GC_MAX_MARK_PROCS (1<<GC_LOG_MAX_MARK_PROCS)
+#define GC_RESERVED_MARK_PROCS 8
+#define GC_GCJ_RESERVED_MARK_PROC_INDEX 0
+#define GC_DS_TAG_BITS 2
+#define GC_DS_TAGS ((1<<GC_DS_TAG_BITS)- 1)
+#define GC_DS_LENGTH 0
+#define GC_DS_BITMAP 1
+#define GC_DS_PROC 2
+#define GC_MAKE_PROC(proc_index,env)(((((env)<<GC_LOG_MAX_MARK_PROCS)|(proc_index))<<GC_DS_TAG_BITS)|GC_DS_PROC)
+#define GC_DS_PER_OBJECT 3
+#define GC_INDIR_PER_OBJ_BIAS 0x10
+GC_API void*GC_least_plausible_heap_addr;
+GC_API void*GC_greatest_plausible_heap_addr;
+GC_API struct GC_ms_entry*GC_CALL GC_mark_and_push(void*,
+struct GC_ms_entry*,
+struct GC_ms_entry*,
+void**);
+#define GC_MARK_AND_PUSH(obj,msp,lim,src)((GC_word)(obj)>=(GC_word)GC_least_plausible_heap_addr&&(GC_word)(obj)<=(GC_word)GC_greatest_plausible_heap_addr?GC_mark_and_push(obj,msp,lim,src):(msp))
+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()))
+GC_API GC_ATTR_DEPRECATED
+#ifdef GC_BUILD
+const
+#endif
+size_t GC_debug_header_size;
+GC_API void**GC_CALL GC_new_free_list(void);
+GC_API void**GC_CALL GC_new_free_list_inner(void);
+GC_API unsigned GC_CALL GC_new_kind(void**,
+GC_word,
+int,
+int)GC_ATTR_NONNULL(1);
+GC_API unsigned GC_CALL GC_new_kind_inner(void**,
+GC_word,
+int,
+int)GC_ATTR_NONNULL(1);
+GC_API unsigned GC_CALL GC_new_proc(GC_mark_proc);
+GC_API unsigned GC_CALL GC_new_proc_inner(GC_mark_proc);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL GC_generic_malloc(
+size_t,
+int);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_generic_malloc_ignore_off_page(
+size_t,int);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_generic_malloc_uncollectable(
+size_t,int);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_generic_or_special_malloc(
+size_t,int);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_debug_generic_or_special_malloc(
+size_t,int,
+GC_EXTRA_PARAMS);
+#ifdef GC_DEBUG
+#define GC_GENERIC_OR_SPECIAL_MALLOC(sz,knd)GC_debug_generic_or_special_malloc(sz,knd,GC_EXTRAS)
+#else
+#define GC_GENERIC_OR_SPECIAL_MALLOC(sz,knd)GC_generic_or_special_malloc(sz,knd)
+#endif
+GC_API int GC_CALL GC_get_kind_and_size(const void*,size_t*)
+GC_ATTR_NONNULL(1);
+typedef void (GC_CALLBACK*GC_describe_type_fn)(void*,
+char*);
+#define GC_TYPE_DESCR_LEN 40
+GC_API void GC_CALL GC_register_describe_type_fn(int,
+GC_describe_type_fn);
+GC_API void*GC_CALL GC_clear_stack(void*);
+typedef void (GC_CALLBACK*GC_start_callback_proc)(void);
+GC_API void GC_CALL GC_set_start_callback(GC_start_callback_proc);
+GC_API GC_start_callback_proc GC_CALL GC_get_start_callback(void);
+GC_API int GC_CALL GC_is_marked(const void*)GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_clear_mark_bit(const void*)GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_set_mark_bit(const void*)GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_push_all(void*,void*);
+GC_API void GC_CALL GC_push_all_eager(void*,void*);
+GC_API void GC_CALL GC_push_conditional(void*,void*,
+int);
+GC_API void GC_CALL GC_push_finalizer_structures(void);
+typedef void (GC_CALLBACK*GC_push_other_roots_proc)(void);
+GC_API void GC_CALL GC_set_push_other_roots(GC_push_other_roots_proc);
+GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void);
+typedef void (GC_CALLBACK*GC_reachable_object_proc)(void*,
+size_t,
+void*);
+GC_API void GC_CALL GC_enumerate_reachable_objects_inner(
+GC_reachable_object_proc,
+void*)GC_ATTR_NONNULL(1);
+GC_API int GC_CALL GC_is_tmp_root(void*);
+GC_API void GC_CALL GC_print_trace(GC_word);
+GC_API void GC_CALL GC_print_trace_inner(GC_word);
+#ifdef __cplusplus
+}
+#endif
+#endif
+typedef GC_word word;
+typedef GC_signed_word signed_word;
+typedef unsigned int unsigned32;
+typedef int GC_bool;
+#define TRUE 1
+#define FALSE 0
+#ifndef PTR_T_DEFINED
+typedef char*ptr_t;
+#define PTR_T_DEFINED
+#endif
+#ifndef SIZE_MAX
+#include <limits.h>
+#endif
+#if defined(SIZE_MAX)&&!defined(CPPCHECK)
+#define GC_SIZE_MAX ((size_t)SIZE_MAX)
+#else
+#define GC_SIZE_MAX (~(size_t)0)
+#endif
+#if GC_GNUC_PREREQ(3,0)&&!defined(LINT2)
+#define EXPECT(expr,outcome)__builtin_expect(expr,outcome)
+#else
+#define EXPECT(expr,outcome)(expr)
+#endif
+#define SIZET_SAT_ADD(a,b)(EXPECT((a)< GC_SIZE_MAX - (b),TRUE)?(a)+(b):GC_SIZE_MAX)
+#ifndef GCCONFIG_H
+#define GCCONFIG_H
+#ifdef CPPCHECK
+#undef CLOCKS_PER_SEC
+#undef FIXUP_POINTER
+#undef POINTER_MASK
+#undef POINTER_SHIFT
+#undef REDIRECT_REALLOC
+#undef _MAX_PATH
+#endif
+#ifndef PTR_T_DEFINED
+typedef char*ptr_t;
+#define PTR_T_DEFINED
+#endif
+#if!defined(sony_news)
+#include <stddef.h>
+#endif
+#ifdef __cplusplus
+#define EXTERN_C_BEGIN extern "C" {
+#define EXTERN_C_END }
+#else
+#define EXTERN_C_BEGIN
+#define EXTERN_C_END
+#endif
+EXTERN_C_BEGIN
+#if defined(__clang__)&&defined(__clang_major__)
+#define GC_CLANG_PREREQ(major,minor)((__clang_major__<<16)+__clang_minor__>=((major)<<16)+(minor))
+#define GC_CLANG_PREREQ_FULL(major,minor,patchlevel)(GC_CLANG_PREREQ(major,(minor)+1)||(__clang_major__==(major)&&__clang_minor__==(minor)&&__clang_patchlevel__>=(patchlevel)))
+#else
+#define GC_CLANG_PREREQ(major,minor)0
+#define GC_CLANG_PREREQ_FULL(major,minor,patchlevel)0
+#endif
+#ifdef LINT2
+#define COVERT_DATAFLOW(w)(~(GC_word)(w)^(~(GC_word)0))
+#else
+#define COVERT_DATAFLOW(w)((GC_word)(w))
+#endif
+#if defined(__ANDROID__)&&!defined(HOST_ANDROID)
+#define HOST_ANDROID 1
+#endif
+#if defined(TIZEN)&&!defined(HOST_TIZEN)
+#define HOST_TIZEN 1
+#endif
+#if defined(__SYMBIAN32__)&&!defined(SYMBIAN)
+#define SYMBIAN
+#ifdef __WINS__
+#pragma data_seg(".data2")
+#endif
+#endif
+#if (defined(linux)||defined(__linux__)||defined(HOST_ANDROID))&&!defined(LINUX)&&!defined(__native_client__)
+#define LINUX
+#endif
+#if defined(__NetBSD__)
+#define NETBSD
+#endif
+#if defined(__OpenBSD__)
+#define OPENBSD
+#endif
+#if (defined(__FreeBSD__)||defined(__DragonFly__)||defined(__FreeBSD_kernel__))&&!defined(FREEBSD)&&!defined(SN_TARGET_ORBIS)
+#define FREEBSD
+#endif
+#if defined(macosx)||(defined(__APPLE__)&&defined(__MACH__))
+#define DARWIN
+EXTERN_C_END
+#include <TargetConditionals.h>
+EXTERN_C_BEGIN
+#endif
+#if defined(__native_client__)
+#define NACL
+#if!defined(__portable_native_client__)&&!defined(__arm__)
+#define I386
+#define mach_type_known
+#else
+#endif
+#endif
+#if defined(__aarch64__)
+#define AARCH64
+#if!defined(LINUX)&&!defined(DARWIN)&&!defined(FREEBSD)&&!defined(NETBSD)&&!defined(NN_BUILD_TARGET_PLATFORM_NX)&&!defined(OPENBSD)
+#define NOSYS
+#define mach_type_known
+#endif
+#endif
+#if defined(__arm)||defined(__arm__)||defined(__thumb__)
+#define ARM32
+#if defined(NACL)
+#define mach_type_known
+#elif!defined(LINUX)&&!defined(NETBSD)&&!defined(FREEBSD)&&!defined(OPENBSD)&&!defined(DARWIN)&&!defined(_WIN32)&&!defined(__CEGCC__)&&!defined(NN_PLATFORM_CTR)&&!defined(SN_TARGET_ORBIS)&&!defined(SN_TARGET_PSP2)&&!defined(SYMBIAN)
+#define NOSYS
+#define mach_type_known
+#endif
+#endif
+#if defined(sun)&&defined(mc68000)&&!defined(CPPCHECK)
+#error SUNOS4 no longer supported
+#endif
+#if defined(hp9000s300)&&!defined(CPPCHECK)
+#error M68K based HP machines no longer supported
+#endif
+#if defined(OPENBSD)&&defined(m68k)
+#define M68K
+#define mach_type_known
+#endif
+#if defined(OPENBSD)&&defined(__sparc__)
+#define SPARC
+#define mach_type_known
+#endif
+#if defined(OPENBSD)&&defined(__arm__)
+#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
+#endif
+#if defined(NETBSD)&&(defined(m68k)||defined(__m68k__))
+#define M68K
+#define mach_type_known
+#endif
+#if defined(NETBSD)&&defined(__powerpc__)
+#define POWERPC
+#define mach_type_known
+#endif
+#if defined(NETBSD)&&(defined(__arm32__)||defined(__arm__))
+#define ARM32
+#define mach_type_known
+#endif
+#if defined(NETBSD)&&defined(__aarch64__)
+#define AARCH64
+#define mach_type_known
+#endif
+#if defined(NETBSD)&&defined(__sh__)
+#define SH
+#define mach_type_known
+#endif
+#if defined(vax)||defined(__vax__)
+#define VAX
+#ifdef ultrix
+#define ULTRIX
+#else
+#define BSD
+#endif
+#define mach_type_known
+#endif
+#if defined(NETBSD)&&defined(__vax__)
+#define VAX
+#define mach_type_known
+#endif
+#if defined(mips)||defined(__mips)||defined(_mips)
+#define MIPS
+#if defined(nec_ews)||defined(_nec_ews)
+#define EWS4800
+#endif
+#if!defined(LINUX)&&!defined(EWS4800)&&!defined(NETBSD)&&!defined(OPENBSD)
+#if defined(ultrix)||defined(__ultrix)
+#define ULTRIX
+#else
+#define IRIX5
+#endif
+#endif
+#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
+#define mach_type_known
+#endif
+#if defined(__or1k__)
+#define OR1K
+#define mach_type_known
+#endif
+#if defined(DGUX)&&(defined(i386)||defined(__i386__))
+#define I386
+#ifndef _USING_DGUX
+#define _USING_DGUX
+#endif
+#define mach_type_known
+#endif
+#if defined(sequent)&&(defined(i386)||defined(__i386__))
+#define I386
+#define SEQUENT
+#define mach_type_known
+#endif
+#if (defined(sun)||defined(__sun))&&(defined(i386)||defined(__i386__))
+#define I386
+#define SOLARIS
+#define mach_type_known
+#endif
+#if (defined(sun)||defined(__sun))&&defined(__amd64)
+#define X86_64
+#define SOLARIS
+#define mach_type_known
+#endif
+#if (defined(__OS2__)||defined(__EMX__))&&defined(__32BIT__)
+#define I386
+#define OS2
+#define mach_type_known
+#endif
+#if defined(ibm032)&&!defined(CPPCHECK)
+#error IBM PC/RT no longer supported
+#endif
+#if (defined(sun)||defined(__sun))&&(defined(sparc)||defined(__sparc))
+EXTERN_C_END
+#include <errno.h>
+EXTERN_C_BEGIN
+#define SPARC
+#define SOLARIS
+#define mach_type_known
+#elif defined(sparc)&&defined(unix)&&!defined(sun)&&!defined(linux)&&!defined(FREEBSD)&&!defined(NETBSD)&&!defined(OPENBSD)
+#define SPARC
+#define DRSNX
+#define mach_type_known
+#endif
+#if defined(_IBMR2)
+#define POWERPC
+#define AIX
+#define mach_type_known
+#endif
+#if defined(NETBSD)&&defined(__sparc__)
+#define SPARC
+#define mach_type_known
+#endif
+#if defined(_M_XENIX)&&defined(_M_SYSV)&&defined(_M_I386)
+#define I386
+#if defined(_SCO_ELF)
+#define SCO_ELF
+#else
+#define SCO
+#endif
+#define mach_type_known
+#endif
+#if defined(_AUX_SOURCE)&&!defined(CPPCHECK)
+#error A/UX no longer supported
+#endif
+#if defined(_PA_RISC1_0)||defined(_PA_RISC1_1)||defined(_PA_RISC2_0)||defined(hppa)||defined(__hppa__)
+#define HP_PA
+#if!defined(LINUX)&&!defined(HPUX)&&!defined(OPENBSD)
+#define HPUX
+#endif
+#define mach_type_known
+#endif
+#if defined(__ia64)&&(defined(_HPUX_SOURCE)||defined(__HP_aCC))
+#define IA64
+#ifndef HPUX
+#define HPUX
+#endif
+#define mach_type_known
+#endif
+#if (defined(__BEOS__)||defined(__HAIKU__))&&defined(_X86_)
+#define I386
+#define HAIKU
+#define mach_type_known
+#endif
+#if defined(__HAIKU__)&&(defined(__amd64__)||defined(__x86_64__))
+#define X86_64
+#define HAIKU
+#define mach_type_known
+#endif
+#if defined(OPENBSD)&&defined(__amd64__)
+#define X86_64
+#define mach_type_known
+#endif
+#if defined(LINUX)&&(defined(i386)||defined(__i386__))
+#define I386
+#define mach_type_known
+#endif
+#if defined(LINUX)&&defined(__x86_64__)
+#define X86_64
+#define mach_type_known
+#endif
+#if defined(LINUX)&&(defined(__ia64__)||defined(__ia64))
+#define IA64
+#define mach_type_known
+#endif
+#if defined(LINUX)&&defined(__aarch64__)
+#define AARCH64
+#define mach_type_known
+#endif
+#if defined(LINUX)&&(defined(__arm)||defined(__arm__))
+#define ARM32
+#define mach_type_known
+#endif
+#if defined(LINUX)&&defined(__cris__)
+#ifndef CRIS
+#define CRIS
+#endif
+#define mach_type_known
+#endif
+#if defined(LINUX)&&(defined(powerpc)||defined(__powerpc__)||defined(powerpc64)||defined(__powerpc64__))
+#define POWERPC
+#define mach_type_known
+#endif
+#if defined(LINUX)&&defined(__mc68000__)
+#define M68K
+#define mach_type_known
+#endif
+#if defined(LINUX)&&(defined(sparc)||defined(__sparc__))
+#define SPARC
+#define mach_type_known
+#endif
+#if defined(LINUX)&&defined(__sh__)
+#define SH
+#define mach_type_known
+#endif
+#if defined(LINUX)&&defined(__avr32__)
+#define AVR32
+#define mach_type_known
+#endif
+#if defined(LINUX)&&defined(__m32r__)
+#define M32R
+#define mach_type_known
+#endif
+#if defined(__alpha)||defined(__alpha__)
+#define ALPHA
+#if!defined(LINUX)&&!defined(NETBSD)&&!defined(OPENBSD)&&!defined(FREEBSD)
+#define OSF1
+#endif
+#define mach_type_known
+#endif
+#if defined(_AMIGA)&&!defined(AMIGA)
+#define AMIGA
+#endif
+#ifdef AMIGA
+#define M68K
+#define mach_type_known
+#endif
+#if defined(THINK_C)||(defined(__MWERKS__)&&!defined(__powerc)&&!defined(SYMBIAN))
+#define M68K
+#define MACOS
+#define mach_type_known
+#endif
+#if defined(__MWERKS__)&&defined(__powerc)&&!defined(__MACH__)&&!defined(SYMBIAN)
+#define POWERPC
+#define MACOS
+#define mach_type_known
+#endif
+#if defined(OPENBSD)&&defined(__powerpc__)
+#define POWERPC
+#define mach_type_known
+#endif
+#if defined(DARWIN)
+#if defined(__ppc__)||defined(__ppc64__)
+#define POWERPC
+#define mach_type_known
+#elif defined(__x86_64__)||defined(__x86_64)
+#define X86_64
+#define mach_type_known
+#elif defined(__i386__)
+#define I386
+#define mach_type_known
+#elif defined(__arm__)
+#define ARM32
+#define mach_type_known
+#elif defined(__aarch64__)
+#define AARCH64
+#define mach_type_known
+#endif
+#endif
+#if defined(__rtems__)&&(defined(i386)||defined(__i386__))
+#define I386
+#define RTEMS
+#define mach_type_known
+#endif
+#if defined(NeXT)&&defined(mc68000)
+#define M68K
+#define NEXT
+#define mach_type_known
+#endif
+#if defined(NeXT)&&(defined(i386)||defined(__i386__))
+#define I386
+#define NEXT
+#define mach_type_known
+#endif
+#if defined(OPENBSD)&&(defined(i386)||defined(__i386__))
+#define I386
+#define mach_type_known
+#endif
+#if defined(NETBSD)&&(defined(i386)||defined(__i386__))
+#define I386
+#define mach_type_known
+#endif
+#if defined(NETBSD)&&defined(__x86_64__)
+#define X86_64
+#define mach_type_known
+#endif
+#if defined(FREEBSD)&&(defined(i386)||defined(__i386__))
+#define I386
+#define mach_type_known
+#endif
+#if (defined(FREEBSD)||defined(SN_TARGET_ORBIS))&&(defined(__amd64__)||defined(__x86_64__))
+#define X86_64
+#define mach_type_known
+#endif
+#if defined(FREEBSD)&&defined(__sparc__)
+#define SPARC
+#define mach_type_known
+#endif
+#if defined(FREEBSD)&&(defined(powerpc)||defined(__powerpc__))
+#define POWERPC
+#define mach_type_known
+#endif
+#if defined(FREEBSD)&&defined(__arm__)
+#define ARM32
+#define mach_type_known
+#endif
+#if defined(FREEBSD)&&defined(__aarch64__)
+#define AARCH64
+#define mach_type_known
+#endif
+#if defined(FREEBSD)&&(defined(mips)||defined(__mips)||defined(_mips))
+#define MIPS
+#define mach_type_known
+#endif
+#if defined(bsdi)&&(defined(i386)||defined(__i386__))
+#define I386
+#define BSDI
+#define mach_type_known
+#endif
+#if!defined(mach_type_known)&&defined(__386BSD__)
+#define I386
+#define THREE86BSD
+#define mach_type_known
+#endif
+#if defined(_CX_UX)&&defined(_M88K)
+#define M88K
+#define CX_UX
+#define mach_type_known
+#endif
+#if defined(DGUX)&&defined(m88k)
+#define M88K
+#define mach_type_known
+#endif
+#if defined(_WIN32_WCE)||defined(__CEGCC__)||defined(__MINGW32CE__)
+#if defined(SH3)||defined(SH4)
+#define SH
+#endif
+#if defined(x86)||defined(__i386__)
+#define I386
+#endif
+#if defined(_M_ARM)||defined(ARM)||defined(_ARM_)
+#define ARM32
+#endif
+#define MSWINCE
+#define mach_type_known
+#else
+#if ((defined(_MSDOS)||defined(_MSC_VER))&&(_M_IX86>=300))||(defined(_WIN32)&&!defined(__CYGWIN32__)&&!defined(__CYGWIN__)&&!defined(__INTERIX)&&!defined(SYMBIAN))
+#if defined(__LP64__)||defined(_M_X64)
+#define X86_64
+#elif defined(_M_ARM)
+#define ARM32
+#elif defined(_M_ARM64)
+#define AARCH64
+#else
+#define I386
+#endif
+#ifdef _XBOX_ONE
+#define MSWIN_XBOX1
+#else
+#ifndef MSWIN32
+#define MSWIN32
+#endif
+#if defined(WINAPI_FAMILY)&&(WINAPI_FAMILY==WINAPI_FAMILY_APP)
+#define MSWINRT_FLAVOR
+#endif
+#endif
+#define mach_type_known
+#endif
+#if defined(_MSC_VER)&&defined(_M_IA64)
+#define IA64
+#define MSWIN32
+#endif
+#endif
+#if defined(__DJGPP__)
+#define I386
+#ifndef DJGPP
+#define DJGPP
+#endif
+#define mach_type_known
+#endif
+#if defined(__CYGWIN32__)||defined(__CYGWIN__)
+#if defined(__LP64__)
+#define X86_64
+#else
+#define I386
+#endif
+#define CYGWIN32
+#define mach_type_known
+#endif
+#if defined(__INTERIX)
+#define I386
+#define INTERIX
+#define mach_type_known
+#endif
+#if defined(__MINGW32__)&&!defined(mach_type_known)
+#define I386
+#define MSWIN32
+#define mach_type_known
+#endif
+#if defined(__BORLANDC__)
+#define I386
+#define MSWIN32
+#define mach_type_known
+#endif
+#if defined(_UTS)&&!defined(mach_type_known)
+#define S370
+#define UTS4
+#define mach_type_known
+#endif
+#if defined(__pj__)&&!defined(CPPCHECK)
+#error PicoJava no longer supported
+#endif
+#if defined(__embedded__)&&defined(PPC)
+#define POWERPC
+#define NOSYS
+#define mach_type_known
+#endif
+#if defined(__WATCOMC__)&&defined(__386__)
+#define I386
+#if!defined(OS2)&&!defined(MSWIN32)&&!defined(DOS4GW)
+#if defined(__OS2__)
+#define OS2
+#else
+#if defined(__WINDOWS_386__)||defined(__NT__)
+#define MSWIN32
+#else
+#define DOS4GW
+#endif
+#endif
+#endif
+#define mach_type_known
+#endif
+#if defined(__s390__)&&defined(LINUX)
+#define S390
+#define mach_type_known
+#endif
+#if defined(__GNU__)
+#if defined(__i386__)
+#define HURD
+#define I386
+#define mach_type_known
+#endif
+#endif
+#if defined(__TANDEM)
+#define MIPS
+#define NONSTOP
+#define mach_type_known
+#endif
+#if defined(__arc__)&&defined(LINUX)
+#define ARC
+#define mach_type_known
+#endif
+#if defined(__hexagon__)&&defined(LINUX)
+#define HEXAGON
+#define mach_type_known
+#endif
+#if defined(__tile__)&&defined(LINUX)
+#ifdef __tilegx__
+#define TILEGX
+#else
+#define TILEPRO
+#endif
+#define mach_type_known
+#endif
+#if defined(__riscv)&&(defined(FREEBSD)||defined(LINUX))
+#define RISCV
+#define mach_type_known
+#endif
+#if defined(SN_TARGET_PSP2)
+#define mach_type_known
+#endif
+#if defined(NN_PLATFORM_CTR)
+#define mach_type_known
+#endif
+#if defined(NN_BUILD_TARGET_PLATFORM_NX)
+#define NINTENDO_SWITCH
+#define mach_type_known
+#endif
+#if defined(SYMBIAN)
+#define mach_type_known
+#endif
+#if defined(__EMSCRIPTEN__)
+#define I386
+#define mach_type_known
+#endif
+#if!defined(mach_type_known)&&!defined(CPPCHECK)
+#error The collector has not been ported to this machine/OS combination
+#endif
+#if GC_GNUC_PREREQ(2,8)&&!defined(__INTEL_COMPILER)&&!defined(__PATHCC__)&&!defined(__FUJITSU)&&!(defined(POWERPC)&&defined(DARWIN))&&!defined(RTEMS)&&!defined(__ARMCC_VERSION)&&!defined(__clang__)
+#define HAVE_BUILTIN_UNWIND_INIT
+#endif
+#ifdef SYMBIAN
+#define MACH_TYPE "SYMBIAN"
+#define OS_TYPE "SYMBIAN"
+#define CPP_WORDSZ 32
+#define ALIGNMENT 4
+#define DATASTART (ptr_t)ALIGNMENT
+#define DATAEND (ptr_t)ALIGNMENT
+#endif
+#define STACK_GRAN 0x1000000
+#ifdef M68K
+#define MACH_TYPE "M68K"
+#define ALIGNMENT 2
+#ifdef OPENBSD
+#define OS_TYPE "OPENBSD"
+#define HEURISTIC2
+#ifdef __ELF__
+extern ptr_t GC_data_start;
+#define DATASTART GC_data_start
+#define DYNAMIC_LOADING
+#else
+extern char etext[];
+#define DATASTART ((ptr_t)(etext))
+#endif
+#endif
+#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
+extern char etext[];
+#define DATASTART ((ptr_t)(etext))
+#endif
+#endif
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define LINUX_STACKBOTTOM
+#define COUNT_UNMAPPED_REGIONS
+#if!defined(REDIRECT_MALLOC)
+#define MPROTECT_VDB
+#endif
+#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
+extern char**__environ;
+#define DATASTART ((ptr_t)(&__environ))
+#endif
+extern int _end[];
+#define DATAEND ((ptr_t)(_end))
+#else
+extern int etext[];
+#define DATASTART ((ptr_t)((((word)(etext))+0xfff)&~0xfff))
+#endif
+#endif
+#ifdef AMIGA
+#define OS_TYPE "AMIGA"
+#define DATAEND
+#define GETPAGESIZE()4096
+#endif
+#ifdef MACOS
+#ifndef __LOWMEM__
+EXTERN_C_END
+#include <LowMem.h>
+EXTERN_C_BEGIN
+#endif
+#define OS_TYPE "MACOS"
+#define STACKBOTTOM ((ptr_t)LMGetCurStackBase())
+#define DATAEND
+#define GETPAGESIZE()4096
+#endif
+#ifdef NEXT
+#define OS_TYPE "NEXT"
+#define DATASTART ((ptr_t)get_etext())
+#define DATASTART_IS_FUNC
+#define STACKBOTTOM ((ptr_t)0x4000000)
+#define DATAEND
+#endif
+#endif
+#ifdef POWERPC
+#define MACH_TYPE "POWERPC"
+#ifdef MACOS
+#define ALIGNMENT 2
+#ifndef __LOWMEM__
+EXTERN_C_END
+#include <LowMem.h>
+EXTERN_C_BEGIN
+#endif
+#define OS_TYPE "MACOS"
+#define STACKBOTTOM ((ptr_t)LMGetCurStackBase())
+#define DATAEND
+#endif
+#ifdef LINUX
+#if defined(__powerpc64__)
+#define ALIGNMENT 8
+#define CPP_WORDSZ 64
+#ifndef HBLKSIZE
+#define HBLKSIZE 4096
+#endif
+#else
+#define ALIGNMENT 4
+#endif
+#define OS_TYPE "LINUX"
+#if defined(__bg__)
+#define HEURISTIC2
+#define NO_PTHREAD_GETATTR_NP
+#else
+#define LINUX_STACKBOTTOM
+#endif
+#define COUNT_UNMAPPED_REGIONS
+#define DYNAMIC_LOADING
+#define SEARCH_FOR_DATA_START
+extern int _end[];
+#define DATAEND ((ptr_t)(_end))
+#endif
+#ifdef DARWIN
+#define OS_TYPE "DARWIN"
+#define DYNAMIC_LOADING
+#if defined(__ppc64__)
+#define ALIGNMENT 8
+#define CPP_WORDSZ 64
+#define STACKBOTTOM ((ptr_t)0x7fff5fc00000)
+#define CACHE_LINE_SIZE 64
+#ifndef HBLKSIZE
+#define HBLKSIZE 4096
+#endif
+#else
+#define ALIGNMENT 4
+#define STACKBOTTOM ((ptr_t)0xc0000000)
+#endif
+#define DATASTART ((ptr_t)get_etext())
+#define DATAEND ((ptr_t)get_end())
+#define USE_MMAP_ANON
+#define MPROTECT_VDB
+EXTERN_C_END
+#include <unistd.h>
+EXTERN_C_BEGIN
+#define GETPAGESIZE()(unsigned)getpagesize()
+#if defined(USE_PPC_PREFETCH)&&defined(__GNUC__)
+#define PREFETCH(x)__asm__ __volatile__ ("dcbt 0,%0"::"r" ((const void*)(x)))
+#define GC_PREFETCH_FOR_WRITE(x)__asm__ __volatile__ ("dcbtst 0,%0"::"r" ((const void*)(x)))
+#endif
+#define NO_PTHREAD_TRYLOCK
+#endif
+#ifdef OPENBSD
+#define OS_TYPE "OPENBSD"
+#if defined(__powerpc64__)
+#define ALIGNMENT 8
+#define CPP_WORDSZ 64
+#else
+#define ALIGNMENT 4
+#endif
+#ifndef GC_OPENBSD_THREADS
+#define HEURISTIC2
+#endif
+extern int __data_start[];
+#define DATASTART ((ptr_t)__data_start)
+extern int _end[];
+#define DATAEND ((ptr_t)(&_end))
+#define DYNAMIC_LOADING
+#endif
+#ifdef FREEBSD
+#if defined(__powerpc64__)
+#define ALIGNMENT 8
+#define CPP_WORDSZ 64
+#ifndef HBLKSIZE
+#define HBLKSIZE 4096
+#endif
+#else
+#define ALIGNMENT 4
+#endif
+#define OS_TYPE "FREEBSD"
+#ifndef GC_FREEBSD_THREADS
+#define MPROTECT_VDB
+#endif
+#define SIG_SUSPEND SIGUSR1
+#define SIG_THR_RESTART SIGUSR2
+#define FREEBSD_STACKBOTTOM
+#define DYNAMIC_LOADING
+extern char etext[];
+#define DATASTART GC_FreeBSDGetDataStart(0x1000,(ptr_t)etext)
+#define DATASTART_USES_BSDGETDATASTART
+#endif
+#ifdef NETBSD
+#define ALIGNMENT 4
+#define OS_TYPE "NETBSD"
+#define HEURISTIC2
+extern ptr_t GC_data_start;
+#define DATASTART GC_data_start
+#define DYNAMIC_LOADING
+#endif
+#ifdef SN_TARGET_PS3
+#define OS_TYPE "SN_TARGET_PS3"
+#define NO_GETENV
+#define CPP_WORDSZ 32
+#define ALIGNMENT 4
+extern int _end[];
+extern int __bss_start;
+#define DATASTART ((ptr_t)(__bss_start))
+#define DATAEND ((ptr_t)(_end))
+#define STACKBOTTOM ((ptr_t)ps3_get_stack_bottom())
+#define NO_PTHREAD_TRYLOCK
+#endif
+#ifdef AIX
+#define OS_TYPE "AIX"
+#undef ALIGNMENT
+#undef IA64
+#ifdef __64BIT__
+#define ALIGNMENT 8
+#define CPP_WORDSZ 64
+#define STACKBOTTOM ((ptr_t)0x1000000000000000)
+#else
+#define ALIGNMENT 4
+#define CPP_WORDSZ 32
+#define STACKBOTTOM ((ptr_t)((ulong)&errno))
+#endif
+#define USE_MMAP_ANON
+extern int _data[],_end[];
+#define DATASTART ((ptr_t)((ulong)_data))
+#define DATAEND ((ptr_t)((ulong)_end))
+extern int errno;
+#define DYNAMIC_LOADING
+#endif
+#ifdef NOSYS
+#define ALIGNMENT 4
+#define OS_TYPE "NOSYS"
+extern void __end[],__dso_handle[];
+#define DATASTART ((ptr_t)__dso_handle)
+#define DATAEND ((ptr_t)(__end))
+#undef STACK_GRAN
+#define STACK_GRAN 0x10000000
+#define HEURISTIC1
+#endif
+#endif
+#ifdef NACL
+#define OS_TYPE "NACL"
+#if defined(__GLIBC__)
+#define DYNAMIC_LOADING
+#endif
+#define DATASTART ((ptr_t)0x10020000)
+extern int _end[];
+#define DATAEND ((ptr_t)_end)
+#undef STACK_GRAN
+#define STACK_GRAN 0x10000
+#define HEURISTIC1
+#define NO_PTHREAD_GETATTR_NP
+#define USE_MMAP_ANON
+#define GETPAGESIZE()65536
+#define MAX_NACL_GC_THREADS 1024
+#endif
+#ifdef VAX
+#define MACH_TYPE "VAX"
+#define ALIGNMENT 4
+extern char etext[];
+#define DATASTART ((ptr_t)(etext))
+#ifdef BSD
+#define OS_TYPE "BSD"
+#define HEURISTIC1
+#endif
+#ifdef ULTRIX
+#define OS_TYPE "ULTRIX"
+#define STACKBOTTOM ((ptr_t)0x7fffc800)
+#endif
+#endif
+#ifdef SPARC
+#define MACH_TYPE "SPARC"
+#if defined(__arch64__)||defined(__sparcv9)
+#define ALIGNMENT 8
+#define CPP_WORDSZ 64
+#define ELF_CLASS ELFCLASS64
+#else
+#define ALIGNMENT 4
+#define CPP_WORDSZ 32
+#endif
+#ifdef SOLARIS
+#define OS_TYPE "SOLARIS"
+extern int _etext[];
+extern int _end[];
+ptr_t GC_SysVGetDataStart(size_t,ptr_t);
+#define DATASTART GC_SysVGetDataStart(0x10000,(ptr_t)_etext)
+#define DATASTART_IS_FUNC
+#define DATAEND ((ptr_t)(_end))
+#if!defined(USE_MMAP)&&defined(REDIRECT_MALLOC)
+#define USE_MMAP 1
+#endif
+#ifdef USE_MMAP
+#define HEAP_START (ptr_t)0x40000000
+#else
+#define HEAP_START DATAEND
+#endif
+#define PROC_VDB
+EXTERN_C_END
+#include <sys/vmparam.h>
+#include <unistd.h>
+EXTERN_C_BEGIN
+#ifdef USERLIMIT
+#define STACKBOTTOM ((ptr_t)USRSTACK)
+#else
+#define HEURISTIC2
+#endif
+#define GETPAGESIZE()(unsigned)sysconf(_SC_PAGESIZE)
+#define DYNAMIC_LOADING
+#endif
+#ifdef DRSNX
+#define OS_TYPE "DRSNX"
+extern int etext[];
+ptr_t GC_SysVGetDataStart(size_t,ptr_t);
+#define DATASTART GC_SysVGetDataStart(0x10000,(ptr_t)etext)
+#define DATASTART_IS_FUNC
+#define MPROTECT_VDB
+#define STACKBOTTOM ((ptr_t)0xdfff0000)
+#define DYNAMIC_LOADING
+#endif
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#ifdef __ELF__
+#define DYNAMIC_LOADING
+#elif!defined(CPPCHECK)
+#error Linux SPARC a.out not supported
+#endif
+#define COUNT_UNMAPPED_REGIONS
+extern int _end[];
+extern int _etext[];
+#define DATAEND ((ptr_t)(_end))
+#define SVR4
+ptr_t GC_SysVGetDataStart(size_t,ptr_t);
+#ifdef __arch64__
+#define DATASTART GC_SysVGetDataStart(0x100000,(ptr_t)_etext)
+#else
+#define DATASTART GC_SysVGetDataStart(0x10000,(ptr_t)_etext)
+#endif
+#define DATASTART_IS_FUNC
+#define LINUX_STACKBOTTOM
+#endif
+#ifdef OPENBSD
+#define OS_TYPE "OPENBSD"
+#ifndef GC_OPENBSD_THREADS
+#define HEURISTIC2
+#endif
+extern int __data_start[];
+#define DATASTART ((ptr_t)__data_start)
+extern int _end[];
+#define DATAEND ((ptr_t)(&_end))
+#define DYNAMIC_LOADING
+#endif
+#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
+extern char etext[];
+#define DATASTART ((ptr_t)(etext))
+#endif
+#endif
+#ifdef FREEBSD
+#define OS_TYPE "FREEBSD"
+#define SIG_SUSPEND SIGUSR1
+#define SIG_THR_RESTART SIGUSR2
+#define FREEBSD_STACKBOTTOM
+#define DYNAMIC_LOADING
+extern char etext[];
+extern char edata[];
+#if!defined(CPPCHECK)
+extern char end[];
+#endif
+#define NEED_FIND_LIMIT
+#define DATASTART ((ptr_t)(&etext))
+void*GC_find_limit(void*,int);
+#define DATAEND (ptr_t)GC_find_limit(DATASTART,TRUE)
+#define DATAEND_IS_FUNC
+#define GC_HAVE_DATAREGION2
+#define DATASTART2 ((ptr_t)(&edata))
+#define DATAEND2 ((ptr_t)(&end))
+#endif
+#endif
+#ifdef I386
+#define MACH_TYPE "I386"
+#if (defined(__LP64__)||defined(_WIN64))&&!defined(CPPCHECK)
+#error This should be handled as X86_64
+#else
+#define CPP_WORDSZ 32
+#define ALIGNMENT 4
+#endif
+#ifdef SEQUENT
+#define OS_TYPE "SEQUENT"
+extern int etext[];
+#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
+#define USE_MMAP_ANON
+#define STACK_GROWS_DOWN
+#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
+#include <OS.h>
+EXTERN_C_BEGIN
+#define GETPAGESIZE()(unsigned)B_PAGE_SIZE
+extern int etext[];
+#define DATASTART ((ptr_t)((((word)(etext))+0xfff)&~0xfff))
+#define DYNAMIC_LOADING
+#define MPROTECT_VDB
+#endif
+#ifdef SOLARIS
+#define OS_TYPE "SOLARIS"
+extern int _etext[],_end[];
+ptr_t GC_SysVGetDataStart(size_t,ptr_t);
+#define DATASTART GC_SysVGetDataStart(0x1000,(ptr_t)_etext)
+#define DATASTART_IS_FUNC
+#define DATAEND ((ptr_t)(_end))
+EXTERN_C_END
+#include <sys/vmparam.h>
+EXTERN_C_BEGIN
+#ifdef USERLIMIT
+#define STACKBOTTOM ((ptr_t)USRSTACK)
+#else
+#define HEURISTIC2
+#endif
+#ifdef SOLARIS25_PROC_VDB_BUG_FIXED
+#define PROC_VDB
+#endif
+#ifndef GC_THREADS
+#define MPROTECT_VDB
+#endif
+#define DYNAMIC_LOADING
+#if!defined(USE_MMAP)&&defined(REDIRECT_MALLOC)
+#define USE_MMAP 1
+#endif
+#ifdef USE_MMAP
+#define HEAP_START (ptr_t)0x40000000
+#else
+#define HEAP_START DATAEND
+#endif
+#endif
+#ifdef SCO
+#define OS_TYPE "SCO"
+extern int etext[];
+#define DATASTART ((ptr_t)((((word)(etext))+0x3fffff)&~0x3fffff)+((word)(etext)&0xfff))
+#define STACKBOTTOM ((ptr_t)0x7ffffffc)
+#endif
+#ifdef SCO_ELF
+#define OS_TYPE "SCO_ELF"
+extern int etext[];
+#define DATASTART ((ptr_t)(etext))
+#define STACKBOTTOM ((ptr_t)0x08048000)
+#define DYNAMIC_LOADING
+#define ELF_CLASS ELFCLASS32
+#endif
+#ifdef DGUX
+#define OS_TYPE "DGUX"
+extern int _etext,_end;
+ptr_t GC_SysVGetDataStart(size_t,ptr_t);
+#define DATASTART GC_SysVGetDataStart(0x1000,(ptr_t)(&_etext))
+#define DATASTART_IS_FUNC
+#define DATAEND ((ptr_t)(&_end))
+#define STACK_GROWS_DOWN
+#define HEURISTIC2
+EXTERN_C_END
+#include <unistd.h>
+EXTERN_C_BEGIN
+#define GETPAGESIZE()(unsigned)sysconf(_SC_PAGESIZE)
+#define DYNAMIC_LOADING
+#ifndef USE_MMAP
+#define USE_MMAP 1
+#endif
+#define MAP_FAILED (void*)((word)-1)
+#define HEAP_START (ptr_t)0x40000000
+#endif
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define LINUX_STACKBOTTOM
+#define COUNT_UNMAPPED_REGIONS
+#if!defined(REDIRECT_MALLOC)
+#define MPROTECT_VDB
+#else
+#endif
+#define HEAP_START (ptr_t)0x1000
+#ifdef __ELF__
+#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))
+#endif
+extern int _end[];
+#define DATAEND ((ptr_t)(_end))
+#if!defined(GC_NO_SIGSETJMP)&&(defined(HOST_TIZEN)||(defined(HOST_ANDROID)&&!(GC_GNUC_PREREQ(4,8)||GC_CLANG_PREREQ(3,2)||__ANDROID_API__>=18)))
+#define GC_NO_SIGSETJMP 1
+#endif
+#else
+extern int etext[];
+#define DATASTART ((ptr_t)((((word)(etext))+0xfff)&~0xfff))
+#endif
+#ifdef USE_I686_PREFETCH
+#define PREFETCH(x)__asm__ __volatile__ ("prefetchnta %0"::"m"(*(char*)(x)))
+#ifdef FORCE_WRITE_PREFETCH
+#define GC_PREFETCH_FOR_WRITE(x)__asm__ __volatile__ ("prefetcht0 %0"::"m"(*(char*)(x)))
+#else
+#define GC_NO_PREFETCH_FOR_WRITE
+#endif
+#elif defined(USE_3DNOW_PREFETCH)
+#define PREFETCH(x)__asm__ __volatile__ ("prefetch %0"::"m"(*(char*)(x)))
+#define GC_PREFETCH_FOR_WRITE(x)__asm__ __volatile__ ("prefetchw %0"::"m"(*(char*)(x)))
+#endif
+#if defined(__GLIBC__)&&!defined(__UCLIBC__)
+#define GLIBC_2_19_TSX_BUG
+EXTERN_C_END
+#include <gnu/libc-version.h>
+EXTERN_C_BEGIN
+#endif
+#endif
+#ifdef CYGWIN32
+#define OS_TYPE "CYGWIN32"
+#define WOW64_THREAD_CONTEXT_WORKAROUND
+#define RETRY_GET_THREAD_CONTEXT
+#define DATASTART ((ptr_t)GC_DATASTART)
+#define DATAEND ((ptr_t)GC_DATAEND)
+#ifdef USE_WINALLOC
+#define GWW_VDB
+#else
+#
+#ifdef USE_MMAP
+#define NEED_FIND_LIMIT
+#define USE_MMAP_ANON
+#endif
+#endif
+#endif
+#ifdef INTERIX
+#define OS_TYPE "INTERIX"
+extern int _data_start__[];
+extern int _bss_end__[];
+#define DATASTART ((ptr_t)_data_start__)
+#define DATAEND ((ptr_t)_bss_end__)
+#define STACKBOTTOM ({ ptr_t rv;__asm__ __volatile__ ("movl %%fs:4,%%eax":"=a" (rv));rv;})
+#define USE_MMAP_ANON
+#endif
+#ifdef OS2
+#define OS_TYPE "OS2"
+#define DATAEND
+#endif
+#ifdef MSWIN32
+#define OS_TYPE "MSWIN32"
+#define WOW64_THREAD_CONTEXT_WORKAROUND
+#define RETRY_GET_THREAD_CONTEXT
+#define MPROTECT_VDB
+#define GWW_VDB
+#define DATAEND
+#endif
+#ifdef MSWINCE
+#define OS_TYPE "MSWINCE"
+#define DATAEND
+#endif
+#ifdef DJGPP
+#define OS_TYPE "DJGPP"
+EXTERN_C_END
+#include "stubinfo.h"
+EXTERN_C_BEGIN
+extern int etext[];
+extern int _stklen;
+extern int __djgpp_stack_limit;
+#define DATASTART ((ptr_t)((((word)(etext))+0x1ff)&~0x1ff))
+#define STACKBOTTOM ((ptr_t)((word)__djgpp_stack_limit+_stklen))
+#endif
+#ifdef OPENBSD
+#define OS_TYPE "OPENBSD"
+#ifndef GC_OPENBSD_THREADS
+#define HEURISTIC2
+#endif
+extern int __data_start[];
+#define DATASTART ((ptr_t)__data_start)
+extern int _end[];
+#define DATAEND ((ptr_t)(&_end))
+#define DYNAMIC_LOADING
+#endif
+#ifdef FREEBSD
+#define OS_TYPE "FREEBSD"
+#ifndef GC_FREEBSD_THREADS
+#define MPROTECT_VDB
+#endif
+#ifdef __GLIBC__
+#define SIG_SUSPEND (32+6)
+#define SIG_THR_RESTART (32+5)
+extern int _end[];
+#define DATAEND ((ptr_t)(_end))
+#else
+#define SIG_SUSPEND SIGUSR1
+#define SIG_THR_RESTART SIGUSR2
+#endif
+#define FREEBSD_STACKBOTTOM
+#ifdef __ELF__
+#define DYNAMIC_LOADING
+#endif
+extern char etext[];
+#define DATASTART GC_FreeBSDGetDataStart(0x1000,(ptr_t)etext)
+#define DATASTART_USES_BSDGETDATASTART
+#endif
+#ifdef NETBSD
+#define OS_TYPE "NETBSD"
+#ifdef __ELF__
+#define DYNAMIC_LOADING
+#endif
+#endif
+#ifdef THREE86BSD
+#define OS_TYPE "THREE86BSD"
+#endif
+#ifdef BSDI
+#define OS_TYPE "BSDI"
+#endif
+#if defined(NETBSD)||defined(THREE86BSD)||defined(BSDI)
+#define HEURISTIC2
+extern char etext[];
+#define DATASTART ((ptr_t)(etext))
+#endif
+#ifdef NEXT
+#define OS_TYPE "NEXT"
+#define DATASTART ((ptr_t)get_etext())
+#define DATASTART_IS_FUNC
+#define STACKBOTTOM ((ptr_t)0xc0000000)
+#define DATAEND
+#endif
+#ifdef RTEMS
+#define OS_TYPE "RTEMS"
+EXTERN_C_END
+#include <sys/unistd.h>
+EXTERN_C_BEGIN
+extern int etext[];
+void*rtems_get_stack_bottom(void);
+#define InitStackBottom rtems_get_stack_bottom()
+#define DATASTART ((ptr_t)etext)
+#define STACKBOTTOM ((ptr_t)InitStackBottom)
+#define SIG_SUSPEND SIGUSR1
+#define SIG_THR_RESTART SIGUSR2
+#endif
+#ifdef DOS4GW
+#define OS_TYPE "DOS4GW"
+extern long __nullarea;
+extern char _end;
+extern char*_STACKTOP;
+#pragma aux __nullarea "*";
+#pragma aux _end "*";
+#define STACKBOTTOM ((ptr_t)_STACKTOP)
+#define DATASTART ((ptr_t)(&__nullarea))
+#define DATAEND ((ptr_t)(&_end))
+#endif
+#ifdef HURD
+#define OS_TYPE "HURD"
+#define STACK_GROWS_DOWN
+#define HEURISTIC2
+#define SIG_SUSPEND SIGUSR1
+#define SIG_THR_RESTART SIGUSR2
+#define SEARCH_FOR_DATA_START
+extern int _end[];
+#define DATAEND ((ptr_t)(_end))
+#define DYNAMIC_LOADING
+#define USE_MMAP_ANON
+#endif
+#ifdef DARWIN
+#define OS_TYPE "DARWIN"
+#define DARWIN_DONT_PARSE_STACK 1
+#define DYNAMIC_LOADING
+#define DATASTART ((ptr_t)get_etext())
+#define DATAEND ((ptr_t)get_end())
+#define STACKBOTTOM ((ptr_t)0xc0000000)
+#define USE_MMAP_ANON
+#define MPROTECT_VDB
+EXTERN_C_END
+#include <unistd.h>
+EXTERN_C_BEGIN
+#define GETPAGESIZE()(unsigned)getpagesize()
+#define NO_PTHREAD_TRYLOCK
+#if TARGET_OS_IPHONE&&!defined(NO_DYLD_BIND_FULLY_IMAGE)
+#define NO_DYLD_BIND_FULLY_IMAGE
+#endif
+#endif
+#endif
+#ifdef NS32K
+#define MACH_TYPE "NS32K"
+#define ALIGNMENT 4
+extern char**environ;
+#define DATASTART ((ptr_t)(&environ))
+#define STACKBOTTOM ((ptr_t)0xfffff000)
+#endif
+#ifdef MIPS
+#define MACH_TYPE "MIPS"
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define DYNAMIC_LOADING
+#define COUNT_UNMAPPED_REGIONS
+extern int _end[];
+#pragma weak __data_start
+extern int __data_start[];
+#define DATASTART ((ptr_t)(__data_start))
+#define DATAEND ((ptr_t)(_end))
+#ifdef _MIPS_SZPTR
+#define CPP_WORDSZ _MIPS_SZPTR
+#define ALIGNMENT (_MIPS_SZPTR/8)
+#else
+#define ALIGNMENT 4
+#endif
+#ifndef HBLKSIZE
+#define HBLKSIZE 4096
+#endif
+#if __GLIBC__==2&&__GLIBC_MINOR__>=2||__GLIBC__ > 2
+#define LINUX_STACKBOTTOM
+#else
+#define STACKBOTTOM ((ptr_t)0x7fff8000)
+#endif
+#endif
+#ifdef EWS4800
+#define HEURISTIC2
+#if defined(_MIPS_SZPTR)&&(_MIPS_SZPTR==64)
+extern int _fdata[],_end[];
+#define DATASTART ((ptr_t)_fdata)
+#define DATAEND ((ptr_t)_end)
+#define CPP_WORDSZ _MIPS_SZPTR
+#define ALIGNMENT (_MIPS_SZPTR/8)
+#else
+extern int etext[],edata[];
+#if!defined(CPPCHECK)
+extern int end[];
+#endif
+extern int _DYNAMIC_LINKING[],_gp[];
+#define DATASTART ((ptr_t)((((word)(etext)+0x3ffff)&~0x3ffff)+((word)(etext)&0xffff)))
+#define DATAEND ((ptr_t)(edata))
+#define GC_HAVE_DATAREGION2
+#define DATASTART2 (_DYNAMIC_LINKING?(ptr_t)(((word)_gp+0x8000+0x3ffff)&~0x3ffff):(ptr_t)edata)
+#define DATAEND2 ((ptr_t)(end))
+#define ALIGNMENT 4
+#endif
+#define OS_TYPE "EWS4800"
+#endif
+#ifdef ULTRIX
+#define HEURISTIC2
+#define DATASTART ((ptr_t)0x10000000)
+#define OS_TYPE "ULTRIX"
+#define ALIGNMENT 4
+#endif
+#ifdef IRIX5
+#define HEURISTIC2
+extern int _fdata[];
+#define DATASTART ((ptr_t)(_fdata))
+#ifdef USE_MMAP
+#define HEAP_START (ptr_t)0x30000000
+#else
+#define HEAP_START DATASTART
+#endif
+#define OS_TYPE "IRIX5"
+#ifdef _MIPS_SZPTR
+#define CPP_WORDSZ _MIPS_SZPTR
+#define ALIGNMENT (_MIPS_SZPTR/8)
+#else
+#define ALIGNMENT 4
+#endif
+#define DYNAMIC_LOADING
+#endif
+#ifdef MSWINCE
+#define OS_TYPE "MSWINCE"
+#define ALIGNMENT 4
+#define DATAEND
+#endif
+#ifdef NETBSD
+#define OS_TYPE "NETBSD"
+#define ALIGNMENT 4
+#define HEURISTIC2
+#ifdef __ELF__
+extern ptr_t GC_data_start;
+#define DATASTART GC_data_start
+#define NEED_FIND_LIMIT
+#define DYNAMIC_LOADING
+#else
+#define DATASTART ((ptr_t)0x10000000)
+#define STACKBOTTOM ((ptr_t)0x7ffff000)
+#endif
+#endif
+#ifdef OPENBSD
+#define OS_TYPE "OPENBSD"
+#define CPP_WORDSZ 64
+#define ALIGNMENT 8
+#ifndef GC_OPENBSD_THREADS
+#define HEURISTIC2
+#endif
+extern int __data_start[];
+#define DATASTART ((ptr_t)__data_start)
+extern int _end[];
+#define DATAEND ((ptr_t)(&_end))
+#define DYNAMIC_LOADING
+#endif
+#ifdef FREEBSD
+#define OS_TYPE "FREEBSD"
+#define ALIGNMENT 4
+#ifndef GC_FREEBSD_THREADS
+#define MPROTECT_VDB
+#endif
+#define SIG_SUSPEND SIGUSR1
+#define SIG_THR_RESTART SIGUSR2
+#define FREEBSD_STACKBOTTOM
+#define DYNAMIC_LOADING
+extern char etext[];
+#define DATASTART GC_FreeBSDGetDataStart(0x1000,(ptr_t)etext)
+#define DATASTART_USES_BSDGETDATASTART
+#endif
+#if defined(NONSTOP)
+#define CPP_WORDSZ 32
+#define OS_TYPE "NONSTOP"
+#define ALIGNMENT 4
+#define DATASTART ((ptr_t)0x08000000)
+extern char**environ;
+#define DATAEND ((ptr_t)(environ - 0x10))
+#define STACKBOTTOM ((ptr_t)0x4fffffff)
+#endif
+#endif
+#ifdef NIOS2
+#define CPP_WORDSZ 32
+#define MACH_TYPE "NIOS2"
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define DYNAMIC_LOADING
+#define COUNT_UNMAPPED_REGIONS
+extern int _end[];
+extern int __data_start[];
+#define DATASTART ((ptr_t)(__data_start))
+#define DATAEND ((ptr_t)(_end))
+#define ALIGNMENT 4
+#ifndef HBLKSIZE
+#define HBLKSIZE 4096
+#endif
+#define LINUX_STACKBOTTOM
+#endif
+#endif
+#ifdef OR1K
+#define CPP_WORDSZ 32
+#define MACH_TYPE "OR1K"
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define DYNAMIC_LOADING
+#define COUNT_UNMAPPED_REGIONS
+extern int _end[];
+extern int __data_start[];
+#define DATASTART ((ptr_t)(__data_start))
+#define DATAEND ((ptr_t)(_end))
+#define ALIGNMENT 4
+#ifndef HBLKSIZE
+#define HBLKSIZE 4096
+#endif
+#define LINUX_STACKBOTTOM
+#endif
+#endif
+#ifdef HP_PA
+#define MACH_TYPE "HP_PA"
+#ifdef __LP64__
+#define CPP_WORDSZ 64
+#define ALIGNMENT 8
+#else
+#define CPP_WORDSZ 32
+#define ALIGNMENT 4
+#endif
+#if!defined(GC_HPUX_THREADS)&&!defined(GC_LINUX_THREADS)&&!defined(OPENBSD)&&!defined(LINUX)
+#define MPROTECT_VDB
+#endif
+#define STACK_GROWS_UP
+#ifdef HPUX
+#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
+#define STACKBOTTOM ((ptr_t)0x7b033000)
+#elif defined(USE_ENVIRON_POINTER)
+extern char**environ;
+#define STACKBOTTOM ((ptr_t)environ)
+#elif!defined(HEURISTIC2)
+#define HPUX_MAIN_STACKBOTTOM
+#define NEED_FIND_LIMIT
+#endif
+#define DYNAMIC_LOADING
+EXTERN_C_END
+#include <unistd.h>
+EXTERN_C_BEGIN
+#define GETPAGESIZE()(unsigned)sysconf(_SC_PAGE_SIZE)
+#ifndef __GNUC__
+#define PREFETCH(x)do { register long addr=(long)(x);(void)_asm ("LDW",0,0,addr,0);} while (0)
+#endif
+#endif
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define LINUX_STACKBOTTOM
+#define COUNT_UNMAPPED_REGIONS
+#define DYNAMIC_LOADING
+#define SEARCH_FOR_DATA_START
+extern int _end[];
+#define DATAEND ((ptr_t)(&_end))
+#endif
+#ifdef OPENBSD
+#define OS_TYPE "OPENBSD"
+#ifndef GC_OPENBSD_THREADS
+#define HEURISTIC2
+#endif
+extern int __data_start[];
+#define DATASTART ((ptr_t)__data_start)
+extern int _end[];
+#define DATAEND ((ptr_t)(&_end))
+#define DYNAMIC_LOADING
+#endif
+#endif
+#ifdef ALPHA
+#define MACH_TYPE "ALPHA"
+#define ALIGNMENT 8
+#define CPP_WORDSZ 64
+#ifdef NETBSD
+#define OS_TYPE "NETBSD"
+#define HEURISTIC2
+extern ptr_t GC_data_start;
+#define DATASTART GC_data_start
+#define ELFCLASS32 32
+#define ELFCLASS64 64
+#define ELF_CLASS ELFCLASS64
+#define DYNAMIC_LOADING
+#endif
+#ifdef OPENBSD
+#define OS_TYPE "OPENBSD"
+#ifndef GC_OPENBSD_THREADS
+#define HEURISTIC2
+#endif
+extern int __data_start[];
+#define DATASTART ((ptr_t)__data_start)
+extern int _end[];
+#define DATAEND ((ptr_t)(&_end))
+#define DYNAMIC_LOADING
+#endif
+#ifdef FREEBSD
+#define OS_TYPE "FREEBSD"
+#define SIG_SUSPEND SIGUSR1
+#define SIG_THR_RESTART SIGUSR2
+#define FREEBSD_STACKBOTTOM
+#define DYNAMIC_LOADING
+extern char etext[];
+extern char edata[];
+#if!defined(CPPCHECK)
+extern char end[];
+#endif
+#define NEED_FIND_LIMIT
+#define DATASTART ((ptr_t)(&etext))
+void*GC_find_limit(void*,int);
+#define DATAEND (ptr_t)GC_find_limit(DATASTART,TRUE)
+#define DATAEND_IS_FUNC
+#define GC_HAVE_DATAREGION2
+#define DATASTART2 ((ptr_t)(&edata))
+#define DATAEND2 ((ptr_t)(&end))
+#endif
+#ifdef OSF1
+#define OS_TYPE "OSF1"
+#define DATASTART ((ptr_t)0x140000000)
+extern int _end[];
+#define DATAEND ((ptr_t)(&_end))
+extern char**environ;
+#define STACKBOTTOM ((ptr_t)(((word)(environ)|(getpagesize()-1))+1))
+extern int __start[];
+#define HEURISTIC2_LIMIT ((ptr_t)((word)(__start)&~(getpagesize()-1)))
+#ifndef GC_OSF1_THREADS
+#define MPROTECT_VDB
+#endif
+#define DYNAMIC_LOADING
+#endif
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define LINUX_STACKBOTTOM
+#define COUNT_UNMAPPED_REGIONS
+#ifdef __ELF__
+#define SEARCH_FOR_DATA_START
+#define DYNAMIC_LOADING
+#else
+#define DATASTART ((ptr_t)0x140000000)
+#endif
+extern int _end[];
+#define DATAEND ((ptr_t)(_end))
+#if!defined(REDIRECT_MALLOC)
+#define MPROTECT_VDB
+#endif
+#endif
+#endif
+#ifdef IA64
+#define MACH_TYPE "IA64"
+#ifdef HPUX
+#ifdef _ILP32
+#define CPP_WORDSZ 32
+#define ALIGNMENT 4
+#else
+#if!defined(_LP64)&&!defined(CPPCHECK)
+#error Unknown ABI
+#endif
+#define CPP_WORDSZ 64
+#define ALIGNMENT 8
+#endif
+#define OS_TYPE "HPUX"
+extern int __data_start[];
+#define DATASTART ((ptr_t)(__data_start))
+#ifdef USE_MMAP
+#define USE_MMAP_ANON
+#endif
+extern char**environ;
+#define STACKBOTTOM ((ptr_t)environ)
+#define HPUX_STACKBOTTOM
+#define DYNAMIC_LOADING
+EXTERN_C_END
+#include <unistd.h>
+EXTERN_C_BEGIN
+#define GETPAGESIZE()(unsigned)sysconf(_SC_PAGE_SIZE)
+#define BACKING_STORE_DISPLACEMENT 0x1000000
+#define BACKING_STORE_ALIGNMENT 0x1000
+extern ptr_t GC_register_stackbottom;
+#define BACKING_STORE_BASE GC_register_stackbottom
+#endif
+#ifdef LINUX
+#define CPP_WORDSZ 64
+#define ALIGNMENT 8
+#define OS_TYPE "LINUX"
+#define LINUX_STACKBOTTOM
+extern ptr_t GC_register_stackbottom;
+#define BACKING_STORE_BASE GC_register_stackbottom
+#define COUNT_UNMAPPED_REGIONS
+#define SEARCH_FOR_DATA_START
+#ifdef __GNUC__
+#define DYNAMIC_LOADING
+#else
+#endif
+#if!defined(REDIRECT_MALLOC)
+#define MPROTECT_VDB
+#endif
+extern int _end[];
+#define DATAEND ((ptr_t)(_end))
+#ifdef __GNUC__
+#ifndef __INTEL_COMPILER
+#define PREFETCH(x)__asm__ (" lfetch [%0]"::"r"(x))
+#define GC_PREFETCH_FOR_WRITE(x)__asm__ (" lfetch.excl [%0]"::"r"(x))
+#define CLEAR_DOUBLE(x)__asm__ (" stf.spill [%0]=f0"::"r"((void*)(x)))
+#else
+EXTERN_C_END
+#include <ia64intrin.h>
+EXTERN_C_BEGIN
+#define PREFETCH(x)__lfetch(__lfhint_none,(x))
+#define GC_PREFETCH_FOR_WRITE(x)__lfetch(__lfhint_nta,(x))
+#define CLEAR_DOUBLE(x)__stf_spill((void*)(x),0)
+#endif
+#endif
+#endif
+#ifdef MSWIN32
+#define OS_TYPE "MSWIN32"
+#define DATAEND
+#if defined(_WIN64)
+#define CPP_WORDSZ 64
+#else
+#define CPP_WORDSZ 32
+#endif
+#define ALIGNMENT 8
+#endif
+#endif
+#ifdef M88K
+#define MACH_TYPE "M88K"
+#define ALIGNMENT 4
+extern int etext[];
+#ifdef CX_UX
+#define OS_TYPE "CX_UX"
+#define DATASTART ((ptr_t)((((word)(etext)+0x3fffff)&~0x3fffff)+0x10000))
+#endif
+#ifdef DGUX
+#define OS_TYPE "DGUX"
+ptr_t GC_SysVGetDataStart(size_t,ptr_t);
+#define DATASTART GC_SysVGetDataStart(0x10000,(ptr_t)etext)
+#define DATASTART_IS_FUNC
+#endif
+#define STACKBOTTOM ((char*)0xf0000000)
+#endif
+#ifdef S370
+#define MACH_TYPE "S370"
+#define ALIGNMENT 4
+#ifdef UTS4
+#define OS_TYPE "UTS4"
+extern int etext[];
+extern int _etext[];
+extern int _end[];
+ptr_t GC_SysVGetDataStart(size_t,ptr_t);
+#define DATASTART GC_SysVGetDataStart(0x10000,(ptr_t)_etext)
+#define DATASTART_IS_FUNC
+#define DATAEND ((ptr_t)(_end))
+#define HEURISTIC2
+#endif
+#endif
+#ifdef S390
+#define MACH_TYPE "S390"
+#ifndef __s390x__
+#define ALIGNMENT 4
+#define CPP_WORDSZ 32
+#else
+#define ALIGNMENT 8
+#define CPP_WORDSZ 64
+#ifndef HBLKSIZE
+#define HBLKSIZE 4096
+#endif
+#endif
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define LINUX_STACKBOTTOM
+#define DYNAMIC_LOADING
+#define COUNT_UNMAPPED_REGIONS
+extern int __data_start[] __attribute__((__weak__));
+#define DATASTART ((ptr_t)(__data_start))
+extern int _end[] __attribute__((__weak__));
+#define DATAEND ((ptr_t)(_end))
+#define CACHE_LINE_SIZE 256
+#define GETPAGESIZE()4096
+#endif
+#endif
+#ifdef AARCH64
+#define MACH_TYPE "AARCH64"
+#ifdef __ILP32__
+#define CPP_WORDSZ 32
+#define ALIGNMENT 4
+#else
+#define CPP_WORDSZ 64
+#define ALIGNMENT 8
+#endif
+#ifndef HBLKSIZE
+#define HBLKSIZE 4096
+#endif
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define LINUX_STACKBOTTOM
+#define COUNT_UNMAPPED_REGIONS
+#if!defined(REDIRECT_MALLOC)
+#define MPROTECT_VDB
+#endif
+#define DYNAMIC_LOADING
+#if defined(HOST_ANDROID)
+#define SEARCH_FOR_DATA_START
+#else
+extern int __data_start[];
+#define DATASTART ((ptr_t)__data_start)
+#endif
+extern int _end[];
+#define DATAEND ((ptr_t)(&_end))
+#endif
+#ifdef DARWIN
+#define OS_TYPE "DARWIN"
+#define DARWIN_DONT_PARSE_STACK 1
+#define DYNAMIC_LOADING
+#define DATASTART ((ptr_t)get_etext())
+#define DATAEND ((ptr_t)get_end())
+#define STACKBOTTOM ((ptr_t)0x16fdfffff)
+#define USE_MMAP_ANON
+EXTERN_C_END
+#include <unistd.h>
+EXTERN_C_BEGIN
+#define GETPAGESIZE()(unsigned)getpagesize()
+#define NO_PTHREAD_TRYLOCK
+#if TARGET_OS_IPHONE&&!defined(NO_DYLD_BIND_FULLY_IMAGE)
+#define NO_DYLD_BIND_FULLY_IMAGE
+#endif
+#endif
+#ifdef FREEBSD
+#define OS_TYPE "FREEBSD"
+#ifndef GC_FREEBSD_THREADS
+#define MPROTECT_VDB
+#endif
+#define FREEBSD_STACKBOTTOM
+#define DYNAMIC_LOADING
+extern char etext[];
+#define DATASTART GC_FreeBSDGetDataStart(0x1000,(ptr_t)etext)
+#define DATASTART_USES_BSDGETDATASTART
+#endif
+#ifdef NETBSD
+#define OS_TYPE "NETBSD"
+#define HEURISTIC2
+extern ptr_t GC_data_start;
+#define DATASTART GC_data_start
+#define ELF_CLASS ELFCLASS64
+#define DYNAMIC_LOADING
+#endif
+#ifdef OPENBSD
+#define OS_TYPE "OPENBSD"
+#ifndef GC_OPENBSD_THREADS
+#define HEURISTIC2
+#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
+#define DATAEND (ptr_t)(&__bss_end)
+void*switch_get_stack_bottom(void);
+#define STACKBOTTOM ((ptr_t)switch_get_stack_bottom())
+#endif
+#ifdef MSWIN32
+#define OS_TYPE "MSWIN32"
+#ifndef DATAEND
+#define DATAEND
+#endif
+#endif
+#ifdef NOSYS
+extern int __data_start[];
+#define DATASTART ((ptr_t)__data_start)
+extern void*__stack_base__;
+#define STACKBOTTOM ((ptr_t)__stack_base__)
+#endif
+#endif
+#ifdef ARM32
+#if defined(NACL)
+#define MACH_TYPE "NACL"
+#else
+#define MACH_TYPE "ARM32"
+#endif
+#define CPP_WORDSZ 32
+#define ALIGNMENT 4
+#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
+extern char etext[];
+#define DATASTART ((ptr_t)(etext))
+#endif
+#endif
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define LINUX_STACKBOTTOM
+#define COUNT_UNMAPPED_REGIONS
+#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))
+#endif
+extern int _end[];
+#define DATAEND ((ptr_t)(_end))
+#endif
+#ifdef MSWINCE
+#define OS_TYPE "MSWINCE"
+#define DATAEND
+#endif
+#ifdef FREEBSD
+#define OS_TYPE "FREEBSD"
+#ifndef GC_FREEBSD_THREADS
+#define MPROTECT_VDB
+#endif
+#define SIG_SUSPEND SIGUSR1
+#define SIG_THR_RESTART SIGUSR2
+#define FREEBSD_STACKBOTTOM
+#define DYNAMIC_LOADING
+extern char etext[];
+#define DATASTART GC_FreeBSDGetDataStart(0x1000,(ptr_t)etext)
+#define DATASTART_USES_BSDGETDATASTART
+#endif
+#ifdef DARWIN
+#define OS_TYPE "DARWIN"
+#define DARWIN_DONT_PARSE_STACK 1
+#define DYNAMIC_LOADING
+#define DATASTART ((ptr_t)get_etext())
+#define DATAEND ((ptr_t)get_end())
+#define STACKBOTTOM ((ptr_t)0x30000000)
+#define USE_MMAP_ANON
+EXTERN_C_END
+#include <unistd.h>
+EXTERN_C_BEGIN
+#define GETPAGESIZE()(unsigned)getpagesize()
+#define NO_PTHREAD_TRYLOCK
+#if TARGET_OS_IPHONE&&!defined(NO_DYLD_BIND_FULLY_IMAGE)
+#define NO_DYLD_BIND_FULLY_IMAGE
+#endif
+#endif
+#ifdef OPENBSD
+#define OS_TYPE "OPENBSD"
+#ifndef GC_OPENBSD_THREADS
+#define HEURISTIC2
+#endif
+extern int __data_start[];
+#define DATASTART ((ptr_t)__data_start)
+extern int _end[];
+#define DATAEND ((ptr_t)(&_end))
+#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
+void*psp2_get_stack_bottom(void);
+#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[];
+#define DATAEND (ptr_t)(Image$$ZI$$ZI$$Limit)
+void*n3ds_get_stack_bottom(void);
+#define STACKBOTTOM ((ptr_t)n3ds_get_stack_bottom())
+#endif
+#ifdef MSWIN32
+#define OS_TYPE "MSWIN32"
+#ifndef DATAEND
+#define DATAEND
+#endif
+#endif
+#ifdef NOSYS
+extern int __data_start[];
+#define DATASTART ((ptr_t)(__data_start))
+extern void*__stack_base__;
+#define STACKBOTTOM ((ptr_t)(__stack_base__))
+#endif
+#endif
+#ifdef CRIS
+#define MACH_TYPE "CRIS"
+#define CPP_WORDSZ 32
+#define ALIGNMENT 1
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define DYNAMIC_LOADING
+#define LINUX_STACKBOTTOM
+#define COUNT_UNMAPPED_REGIONS
+#define SEARCH_FOR_DATA_START
+extern int _end[];
+#define DATAEND ((ptr_t)(_end))
+#endif
+#endif
+#if defined(SH)&&!defined(SH4)
+#define MACH_TYPE "SH"
+#define ALIGNMENT 4
+#ifdef MSWINCE
+#define OS_TYPE "MSWINCE"
+#define DATAEND
+#endif
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define LINUX_STACKBOTTOM
+#define COUNT_UNMAPPED_REGIONS
+#define DYNAMIC_LOADING
+#define SEARCH_FOR_DATA_START
+extern int _end[];
+#define DATAEND ((ptr_t)(_end))
+#endif
+#ifdef NETBSD
+#define OS_TYPE "NETBSD"
+#define HEURISTIC2
+extern ptr_t GC_data_start;
+#define DATASTART GC_data_start
+#define DYNAMIC_LOADING
+#endif
+#ifdef OPENBSD
+#define OS_TYPE "OPENBSD"
+#ifndef GC_OPENBSD_THREADS
+#define HEURISTIC2
+#endif
+extern int __data_start[];
+#define DATASTART ((ptr_t)__data_start)
+extern int _end[];
+#define DATAEND ((ptr_t)(&_end))
+#define DYNAMIC_LOADING
+#endif
+#endif
+#ifdef SH4
+#define MACH_TYPE "SH4"
+#define ALIGNMENT 4
+#ifdef MSWINCE
+#define OS_TYPE "MSWINCE"
+#define DATAEND
+#endif
+#endif
+#ifdef AVR32
+#define MACH_TYPE "AVR32"
+#define CPP_WORDSZ 32
+#define ALIGNMENT 4
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define DYNAMIC_LOADING
+#define LINUX_STACKBOTTOM
+#define COUNT_UNMAPPED_REGIONS
+#define SEARCH_FOR_DATA_START
+extern int _end[];
+#define DATAEND ((ptr_t)(_end))
+#endif
+#endif
+#ifdef M32R
+#define CPP_WORDSZ 32
+#define MACH_TYPE "M32R"
+#define ALIGNMENT 4
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define LINUX_STACKBOTTOM
+#define COUNT_UNMAPPED_REGIONS
+#define DYNAMIC_LOADING
+#define SEARCH_FOR_DATA_START
+extern int _end[];
+#define DATAEND ((ptr_t)(_end))
+#endif
+#endif
+#ifdef X86_64
+#define MACH_TYPE "X86_64"
+#ifdef __ILP32__
+#define ALIGNMENT 4
+#define CPP_WORDSZ 32
+#else
+#define ALIGNMENT 8
+#define CPP_WORDSZ 64
+#endif
+#ifndef HBLKSIZE
+#define HBLKSIZE 4096
+#endif
+#ifndef CACHE_LINE_SIZE
+#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);
+#define STACKBOTTOM ((ptr_t)ps4_get_stack_bottom())
+#endif
+#ifdef OPENBSD
+#define OS_TYPE "OPENBSD"
+#ifndef GC_OPENBSD_THREADS
+#define HEURISTIC2
+#endif
+extern int __data_start[];
+extern int _end[];
+#define DATASTART ((ptr_t)__data_start)
+#define DATAEND ((ptr_t)(&_end))
+#define DYNAMIC_LOADING
+#endif
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define LINUX_STACKBOTTOM
+#if!defined(REDIRECT_MALLOC)
+#define MPROTECT_VDB
+#else
+#endif
+#define COUNT_UNMAPPED_REGIONS
+#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__)
+#define USE_MMAP_ANON
+#define GETCONTEXT_FPU_EXCMASK_BUG
+#define GLIBC_2_19_TSX_BUG
+EXTERN_C_END
+#include <gnu/libc-version.h>
+EXTERN_C_BEGIN
+#endif
+#endif
+#ifdef DARWIN
+#define OS_TYPE "DARWIN"
+#define DARWIN_DONT_PARSE_STACK 1
+#define DYNAMIC_LOADING
+#define DATASTART ((ptr_t)get_etext())
+#define DATAEND ((ptr_t)get_end())
+#define STACKBOTTOM ((ptr_t)0x7fff5fc00000)
+#define USE_MMAP_ANON
+#define MPROTECT_VDB
+EXTERN_C_END
+#include <unistd.h>
+EXTERN_C_BEGIN
+#define GETPAGESIZE()(unsigned)getpagesize()
+#define NO_PTHREAD_TRYLOCK
+#if TARGET_OS_IPHONE&&!defined(NO_DYLD_BIND_FULLY_IMAGE)
+#define NO_DYLD_BIND_FULLY_IMAGE
+#endif
+#endif
+#ifdef FREEBSD
+#define OS_TYPE "FREEBSD"
+#ifndef GC_FREEBSD_THREADS
+#define MPROTECT_VDB
+#endif
+#ifdef __GLIBC__
+#define SIG_SUSPEND (32+6)
+#define SIG_THR_RESTART (32+5)
+extern int _end[];
+#define DATAEND ((ptr_t)(_end))
+#else
+#define SIG_SUSPEND SIGUSR1
+#define SIG_THR_RESTART SIGUSR2
+#endif
+#define FREEBSD_STACKBOTTOM
+#if defined(__DragonFly__)
+#define COUNT_UNMAPPED_REGIONS
+#endif
+#define DYNAMIC_LOADING
+extern char etext[];
+#define DATASTART GC_FreeBSDGetDataStart(0x1000,(ptr_t)etext)
+#define DATASTART_USES_BSDGETDATASTART
+#endif
+#ifdef NETBSD
+#define OS_TYPE "NETBSD"
+#define HEURISTIC2
+extern ptr_t GC_data_start;
+#define DATASTART GC_data_start
+#define DYNAMIC_LOADING
+#endif
+#ifdef HAIKU
+#define OS_TYPE "HAIKU"
+EXTERN_C_END
+#include <OS.h>
+EXTERN_C_BEGIN
+#define GETPAGESIZE()(unsigned)B_PAGE_SIZE
+#define HEURISTIC2
+#define SEARCH_FOR_DATA_START
+#define DYNAMIC_LOADING
+#define MPROTECT_VDB
+#endif
+#ifdef SOLARIS
+#define OS_TYPE "SOLARIS"
+#define ELF_CLASS ELFCLASS64
+extern int _etext[],_end[];
+ptr_t GC_SysVGetDataStart(size_t,ptr_t);
+#define DATASTART GC_SysVGetDataStart(0x1000,(ptr_t)_etext)
+#define DATASTART_IS_FUNC
+#define DATAEND ((ptr_t)(_end))
+EXTERN_C_END
+#include <sys/vmparam.h>
+EXTERN_C_BEGIN
+#ifdef USERLIMIT
+#define STACKBOTTOM ((ptr_t)USRSTACK)
+#else
+#define HEURISTIC2
+#endif
+#ifdef SOLARIS25_PROC_VDB_BUG_FIXED
+#define PROC_VDB
+#endif
+#ifndef GC_THREADS
+#define MPROTECT_VDB
+#endif
+#define DYNAMIC_LOADING
+#if!defined(USE_MMAP)&&defined(REDIRECT_MALLOC)
+#define USE_MMAP 1
+#endif
+#ifdef USE_MMAP
+#define HEAP_START (ptr_t)0x40000000
+#else
+#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)
+#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
+LONG64 durango_get_stack_bottom(void);
+#define STACKBOTTOM ((ptr_t)durango_get_stack_bottom())
+#define GETPAGESIZE()4096
+#ifndef USE_MMAP
+#define USE_MMAP 1
+#endif
+#define PROT_NONE 0
+#define PROT_READ 1
+#define PROT_WRITE 2
+#define PROT_EXEC 4
+#define MAP_PRIVATE 2
+#define MAP_FIXED 0x10
+#define MAP_FAILED ((void*)-1)
+#endif
+#ifdef MSWIN32
+#define OS_TYPE "MSWIN32"
+#define RETRY_GET_THREAD_CONTEXT
+#if!defined(__GNUC__)||defined(__INTEL_COMPILER)||GC_GNUC_PREREQ(4,7)
+#define MPROTECT_VDB
+#endif
+#define GWW_VDB
+#ifndef DATAEND
+#define DATAEND
+#endif
+#endif
+#endif
+#ifdef ARC
+#define CPP_WORDSZ 32
+#define MACH_TYPE "ARC"
+#define ALIGNMENT 4
+#define CACHE_LINE_SIZE 64
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define LINUX_STACKBOTTOM
+#define COUNT_UNMAPPED_REGIONS
+#define DYNAMIC_LOADING
+extern int __data_start[] __attribute__((__weak__));
+#define DATASTART ((ptr_t)__data_start)
+#endif
+#endif
+#ifdef HEXAGON
+#define CPP_WORDSZ 32
+#define MACH_TYPE "HEXAGON"
+#define ALIGNMENT 4
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+#define LINUX_STACKBOTTOM
+#if!defined(REDIRECT_MALLOC)
+#define MPROTECT_VDB
+#endif
+#define COUNT_UNMAPPED_REGIONS
+#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
+#ifdef TILEPRO
+#define CPP_WORDSZ 32
+#define MACH_TYPE "TILEPro"
+#define ALIGNMENT 4
+#define PREFETCH(x)__insn_prefetch(x)
+#define CACHE_LINE_SIZE 64
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+extern int __data_start[];
+#define DATASTART ((ptr_t)__data_start)
+#define LINUX_STACKBOTTOM
+#define COUNT_UNMAPPED_REGIONS
+#define DYNAMIC_LOADING
+#endif
+#endif
+#ifdef TILEGX
+#define CPP_WORDSZ (__SIZEOF_POINTER__*8)
+#define MACH_TYPE "TILE-Gx"
+#define ALIGNMENT __SIZEOF_POINTER__
+#if CPP_WORDSZ < 64
+#define CLEAR_DOUBLE(x)(*(long long*)(x)=0)
+#endif
+#define PREFETCH(x)__insn_prefetch_l1(x)
+#define CACHE_LINE_SIZE 64
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+extern int __data_start[];
+#define DATASTART ((ptr_t)__data_start)
+#define LINUX_STACKBOTTOM
+#define COUNT_UNMAPPED_REGIONS
+#define DYNAMIC_LOADING
+#endif
+#endif
+#ifdef RISCV
+#define MACH_TYPE "RISC-V"
+#define CPP_WORDSZ __riscv_xlen
+#define ALIGNMENT (CPP_WORDSZ/8)
+#ifdef FREEBSD
+#define OS_TYPE "FREEBSD"
+#ifndef GC_FREEBSD_THREADS
+#define MPROTECT_VDB
+#endif
+#define SIG_SUSPEND SIGUSR1
+#define SIG_THR_RESTART SIGUSR2
+#define FREEBSD_STACKBOTTOM
+#define DYNAMIC_LOADING
+extern char etext[];
+#define DATASTART GC_FreeBSDGetDataStart(0x1000,(ptr_t)etext)
+#define DATASTART_USES_BSDGETDATASTART
+#endif
+#ifdef LINUX
+#define OS_TYPE "LINUX"
+extern int __data_start[] __attribute__((__weak__));
+#define DATASTART ((ptr_t)__data_start)
+#define LINUX_STACKBOTTOM
+#define COUNT_UNMAPPED_REGIONS
+#define DYNAMIC_LOADING
+#endif
+#endif
+#if defined(__GLIBC__)&&!defined(DONT_USE_LIBC_PRIVATES)
+#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)
+#undef LINUX_STACKBOTTOM
+#define HEURISTIC2
+#endif
+#if defined(USE_MMAP_ANON)&&!defined(USE_MMAP)
+#define USE_MMAP 1
+#elif (defined(LINUX)||defined(OPENBSD))&&defined(USE_MMAP)
+#define USE_MMAP_ANON
+#endif
+#if defined(GC_LINUX_THREADS)&&defined(REDIRECT_MALLOC)&&!defined(USE_PROC_FOR_LIBRARIES)
+#define USE_PROC_FOR_LIBRARIES
+#endif
+#ifndef STACK_GROWS_UP
+#define STACK_GROWS_DOWN
+#endif
+#ifndef CPP_WORDSZ
+#define CPP_WORDSZ 32
+#endif
+#ifndef OS_TYPE
+#define OS_TYPE ""
+#endif
+#ifndef DATAEND
+#if!defined(CPPCHECK)
+extern int end[];
+#endif
+#define DATAEND ((ptr_t)(end))
+#endif
+#if defined(HOST_ANDROID)&&defined(__clang__)&&!defined(BROKEN_UUENDUU_SYM)
+#undef DATAEND
+#pragma weak __end__
+extern int __end__[];
+#define DATAEND (__end__!=0?(ptr_t)__end__:(ptr_t)_end)
+#endif
+#if (defined(SVR4)||defined(HOST_ANDROID)||defined(HOST_TIZEN))&&!defined(GETPAGESIZE)
+EXTERN_C_END
+#include <unistd.h>
+EXTERN_C_BEGIN
+#define GETPAGESIZE()(unsigned)sysconf(_SC_PAGESIZE)
+#endif
+#ifndef GETPAGESIZE
+#if defined(SOLARIS)||defined(IRIX5)||defined(LINUX)||defined(NETBSD)||defined(FREEBSD)||defined(HPUX)
+EXTERN_C_END
+#include <unistd.h>
+EXTERN_C_BEGIN
+#endif
+#define GETPAGESIZE()(unsigned)getpagesize()
+#endif
+#if defined(HOST_ANDROID)&&!(__ANDROID_API__>=23)&&((defined(MIPS)&&(CPP_WORDSZ==32))||defined(ARM32)||defined(I386))
+#define USE_TKILL_ON_ANDROID
+#endif
+#if defined(SOLARIS)||defined(DRSNX)||defined(UTS4)
+#define SVR4
+#endif
+#if defined(SOLARIS)||defined(DRSNX)
+#define SOLARISDL
+#define SUNOS5SIGS
+#endif
+#if defined(HPUX)
+#define SUNOS5SIGS
+#endif
+#if defined(FREEBSD)&&(defined(__DragonFly__)||__FreeBSD__>=4||(__FreeBSD_kernel__>=4))
+#define SUNOS5SIGS
+#endif
+#if!defined(GC_EXPLICIT_SIGNALS_UNBLOCK)&&defined(SUNOS5SIGS)&&!defined(GC_NO_PTHREAD_SIGMASK)
+#define GC_EXPLICIT_SIGNALS_UNBLOCK
+#endif
+#if!defined(NO_SIGNALS_UNBLOCK_IN_MAIN)&&defined(GC_NO_PTHREAD_SIGMASK)
+#define NO_SIGNALS_UNBLOCK_IN_MAIN
+#endif
+#if!defined(NO_MARKER_SPECIAL_SIGMASK)&&(defined(NACL)||defined(GC_WIN32_PTHREADS))
+#define NO_MARKER_SPECIAL_SIGMASK
+#endif
+#ifdef GC_NETBSD_THREADS
+#define SIGRTMIN 33
+#define SIGRTMAX 63
+#define GC_NETBSD_THREADS_WORKAROUND
+#endif
+#ifdef GC_OPENBSD_THREADS
+EXTERN_C_END
+#include <sys/param.h>
+EXTERN_C_BEGIN
+#if OpenBSD < 201211
+#define GC_OPENBSD_UTHREADS 1
+#endif
+#endif
+#if defined(SVR4)||defined(LINUX)||defined(IRIX5)||defined(HPUX)||defined(OPENBSD)||defined(NETBSD)||defined(FREEBSD)||defined(DGUX)||defined(BSD)||defined(HAIKU)||defined(HURD)||defined(AIX)||defined(DARWIN)||defined(OSF1)
+#define UNIX_LIKE
+#endif
+#if defined(CPPCHECK)
+#undef CPP_WORDSZ
+#define CPP_WORDSZ (__SIZEOF_POINTER__*8)
+#elif CPP_WORDSZ!=32&&CPP_WORDSZ!=64
+#error Bad word size
+#endif
+#if!defined(ALIGNMENT)&&!defined(CPPCHECK)
+#error Undefined ALIGNMENT
+#endif
+#ifdef PCR
+#undef DYNAMIC_LOADING
+#undef STACKBOTTOM
+#undef HEURISTIC1
+#undef HEURISTIC2
+#undef PROC_VDB
+#undef MPROTECT_VDB
+#define PCR_VDB
+#endif
+#if!defined(STACKBOTTOM)&&(defined(ECOS)||defined(NOSYS))&&!defined(CPPCHECK)
+#error Undefined STACKBOTTOM
+#endif
+#ifdef IGNORE_DYNAMIC_LOADING
+#undef DYNAMIC_LOADING
+#endif
+#if defined(SMALL_CONFIG)&&!defined(GC_DISABLE_INCREMENTAL)
+#define GC_DISABLE_INCREMENTAL
+#endif
+#if (defined(MSWIN32)||defined(MSWINCE))&&!defined(USE_WINALLOC)
+#define USE_WINALLOC 1
+#endif
+#ifdef USE_WINALLOC
+#undef USE_MMAP
+#endif
+#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))
+#define MMAP_SUPPORTED
+#endif
+#if defined(USE_MUNMAP)&&!defined(MUNMAP_THRESHOLD)&&(defined(SN_TARGET_ORBIS)||defined(SN_TARGET_PS3)||defined(SN_TARGET_PSP2)||defined(MSWIN_XBOX1))
+#define MUNMAP_THRESHOLD 2
+#endif
+#if defined(USE_MUNMAP)&&defined(COUNT_UNMAPPED_REGIONS)&&!defined(GC_UNMAPPED_REGIONS_SOFT_LIMIT)
+#if defined(__DragonFly__)
+#define GC_UNMAPPED_REGIONS_SOFT_LIMIT (1000000/4)
+#else
+#define GC_UNMAPPED_REGIONS_SOFT_LIMIT 16384
+#endif
+#endif
+#if defined(GC_DISABLE_INCREMENTAL)||defined(DEFAULT_VDB)
+#undef GWW_VDB
+#undef MPROTECT_VDB
+#undef PCR_VDB
+#undef PROC_VDB
+#endif
+#ifdef GC_DISABLE_INCREMENTAL
+#undef CHECKSUMS
+#endif
+#ifdef USE_GLOBAL_ALLOC
+#undef GWW_VDB
+#endif
+#if defined(BASE_ATOMIC_OPS_EMULATED)
+#undef MPROTECT_VDB
+#endif
+#if defined(USE_PROC_FOR_LIBRARIES)&&defined(GC_LINUX_THREADS)
+#undef MPROTECT_VDB
+#endif
+#if defined(MPROTECT_VDB)&&defined(GC_PREFER_MPROTECT_VDB)
+#undef PCR_VDB
+#undef PROC_VDB
+#endif
+#ifdef PROC_VDB
+#undef MPROTECT_VDB
+#endif
+#if defined(MPROTECT_VDB)&&!defined(MSWIN32)&&!defined(MSWINCE)
+#include <signal.h>
+#endif
+#if defined(SIGBUS)&&!defined(HAVE_SIGBUS)&&!defined(CPPCHECK)
+#define HAVE_SIGBUS
+#endif
+#ifndef SA_SIGINFO
+#define NO_SA_SIGACTION
+#endif
+#if (defined(NO_SA_SIGACTION)||defined(GC_NO_SIGSETJMP))&&defined(MPROTECT_VDB)&&!defined(DARWIN)&&!defined(MSWIN32)&&!defined(MSWINCE)
+#undef MPROTECT_VDB
+#endif
+#if!defined(PCR_VDB)&&!defined(PROC_VDB)&&!defined(MPROTECT_VDB)&&!defined(GWW_VDB)&&!defined(DEFAULT_VDB)&&!defined(GC_DISABLE_INCREMENTAL)
+#define DEFAULT_VDB
+#endif
+#if ((defined(UNIX_LIKE)&&(defined(DARWIN)||defined(HAIKU)||defined(HURD)||defined(OPENBSD)||defined(ARM32)||defined(AVR32)||defined(MIPS)||defined(NIOS2)||defined(OR1K)))||(defined(LINUX)&&!defined(__gnu_linux__))||(defined(RTEMS)&&defined(I386))||defined(HOST_ANDROID))&&!defined(NO_GETCONTEXT)
+#define NO_GETCONTEXT 1
+#endif
+#ifndef PREFETCH
+#if GC_GNUC_PREREQ(3,0)&&!defined(NO_PREFETCH)
+#define PREFETCH(x)__builtin_prefetch((x),0,0)
+#else
+#define PREFETCH(x)(void)0
+#endif
+#endif
+#ifndef GC_PREFETCH_FOR_WRITE
+#if GC_GNUC_PREREQ(3,0)&&!defined(GC_NO_PREFETCH_FOR_WRITE)
+#define GC_PREFETCH_FOR_WRITE(x)__builtin_prefetch((x),1)
+#else
+#define GC_PREFETCH_FOR_WRITE(x)(void)0
+#endif
+#endif
+#ifndef CACHE_LINE_SIZE
+#define CACHE_LINE_SIZE 32
+#endif
+#ifndef STATIC
+#ifdef GC_ASSERTIONS
+#define STATIC
+#else
+#define STATIC static
+#endif
+#endif
+#if defined(LINUX)&&(defined(USE_PROC_FOR_LIBRARIES)||defined(IA64)||!defined(SMALL_CONFIG))
+#define NEED_PROC_MAPS
+#endif
+#if defined(LINUX)||defined(HURD)||defined(__GLIBC__)
+#define REGISTER_LIBRARIES_EARLY
+#endif
+#if defined(SEARCH_FOR_DATA_START)
+extern ptr_t GC_data_start;
+#define DATASTART GC_data_start
+#endif
+#ifndef HEAP_START
+#define HEAP_START ((ptr_t)0)
+#endif
+#ifndef CLEAR_DOUBLE
+#define CLEAR_DOUBLE(x)(((word*)(x))[0]=0,((word*)(x))[1]=0)
+#endif
+#if defined(GC_LINUX_THREADS)&&defined(REDIRECT_MALLOC)&&!defined(INCLUDE_LINUX_THREAD_DESCR)
+#define INCLUDE_LINUX_THREAD_DESCR
+#endif
+#if!defined(CPPCHECK)
+#if defined(GC_IRIX_THREADS)&&!defined(IRIX5)
+#error Inconsistent configuration
+#endif
+#if defined(GC_LINUX_THREADS)&&!defined(LINUX)&&!defined(NACL)
+#error Inconsistent configuration
+#endif
+#if defined(GC_NETBSD_THREADS)&&!defined(NETBSD)
+#error Inconsistent configuration
+#endif
+#if defined(GC_FREEBSD_THREADS)&&!defined(FREEBSD)
+#error Inconsistent configuration
+#endif
+#if defined(GC_SOLARIS_THREADS)&&!defined(SOLARIS)
+#error Inconsistent configuration
+#endif
+#if defined(GC_HPUX_THREADS)&&!defined(HPUX)
+#error Inconsistent configuration
+#endif
+#if defined(GC_AIX_THREADS)&&!defined(_AIX)
+#error Inconsistent configuration
+#endif
+#if defined(GC_WIN32_THREADS)&&!defined(CYGWIN32)&&!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(MSWIN_XBOX1)
+#error Inconsistent configuration
+#endif
+#if defined(GC_WIN32_PTHREADS)&&defined(CYGWIN32)
+#error Inconsistent configuration
+#endif
+#endif
+#if defined(PCR)||defined(GC_WIN32_THREADS)||defined(GC_PTHREADS)||((defined(NN_PLATFORM_CTR)||defined(NINTENDO_SWITCH)||defined(SN_TARGET_ORBIS)||defined(SN_TARGET_PS3)||defined(SN_TARGET_PSP2))&&defined(GC_THREADS))
+#define THREADS
+#endif
+#if defined(PARALLEL_MARK)&&!defined(THREADS)&&!defined(CPPCHECK)
+#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))||(defined(USE_PROC_FOR_LIBRARIES)&&defined(THREADS)))&&!defined(NO_CRT)&&!defined(NO_WRAP_MARK_SOME)
+#define WRAP_MARK_SOME
+#endif
+#if defined(PARALLEL_MARK)&&!defined(DEFAULT_STACK_MAYBE_SMALL)&&(defined(HPUX)||defined(GC_DGUX386_THREADS)||defined(NO_GETCONTEXT))
+#define DEFAULT_STACK_MAYBE_SMALL
+#endif
+#ifdef PARALLEL_MARK
+#define MIN_STACK_SIZE (8*HBLKSIZE*sizeof(word))
+#endif
+#if defined(HOST_ANDROID)&&!defined(THREADS)&&!defined(USE_GET_STACKBASE_FOR_MAIN)
+#define USE_GET_STACKBASE_FOR_MAIN
+#endif
+#if ((defined(FREEBSD)&&defined(__GLIBC__))||defined(LINUX)||defined(NETBSD)||defined(HOST_ANDROID))&&!defined(NO_PTHREAD_GETATTR_NP)
+#define HAVE_PTHREAD_GETATTR_NP 1
+#elif defined(FREEBSD)&&!defined(__GLIBC__)&&!defined(NO_PTHREAD_ATTR_GET_NP)
+#define HAVE_PTHREAD_NP_H 1
+#define HAVE_PTHREAD_ATTR_GET_NP 1
+#endif
+#if defined(UNIX_LIKE)&&defined(THREADS)&&!defined(NO_CANCEL_SAFE)&&!defined(HOST_ANDROID)
+#define CANCEL_SAFE
+#endif
+#ifdef CANCEL_SAFE
+#define IF_CANCEL(x)x
+#else
+#define IF_CANCEL(x)
+#endif
+#if!defined(CAN_HANDLE_FORK)&&!defined(NO_HANDLE_FORK)&&!defined(HAVE_NO_FORK)&&((defined(GC_PTHREADS)&&!defined(NACL)&&!defined(GC_WIN32_PTHREADS)&&!defined(USE_WINALLOC))||(defined(DARWIN)&&defined(MPROTECT_VDB))||defined(HANDLE_FORK))
+#define CAN_HANDLE_FORK
+#endif
+#if defined(CAN_HANDLE_FORK)&&!defined(CAN_CALL_ATFORK)&&!defined(HURD)&&!defined(SN_TARGET_ORBIS)&&!defined(HOST_TIZEN)&&(!defined(HOST_ANDROID)||__ANDROID_API__>=21)
+#define CAN_CALL_ATFORK
+#endif
+#if!defined(CAN_HANDLE_FORK)&&!defined(HAVE_NO_FORK)&&(defined(MSWIN32)||defined(MSWINCE)||defined(DOS4GW)||defined(OS2)||defined(SYMBIAN))
+#define HAVE_NO_FORK
+#endif
+#if!defined(USE_MARK_BITS)&&!defined(USE_MARK_BYTES)&&defined(PARALLEL_MARK)
+#define USE_MARK_BYTES
+#endif
+#if (defined(MSWINCE)&&!defined(__CEGCC__)||defined(MSWINRT_FLAVOR))&&!defined(NO_GETENV)
+#define NO_GETENV
+#endif
+#if (defined(NO_GETENV)||defined(MSWINCE))&&!defined(NO_GETENV_WIN32)
+#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)
+#define MSGBOX_ON_ERROR
+#endif
+#ifndef STRTOULL
+#if defined(_WIN64)&&!defined(__GNUC__)
+#define STRTOULL _strtoui64
+#elif defined(_LLP64)||defined(__LLP64__)||defined(_WIN64)
+#define STRTOULL strtoull
+#else
+#define STRTOULL strtoul
+#endif
+#endif
+#ifndef GC_WORD_C
+#if defined(_WIN64)&&!defined(__GNUC__)
+#define GC_WORD_C(val)val##ui64
+#elif defined(_LLP64)||defined(__LLP64__)||defined(_WIN64)
+#define GC_WORD_C(val)val##ULL
+#else
+#define GC_WORD_C(val)((word)val##UL)
+#endif
+#endif
+#if defined(__has_feature)
+#if __has_feature(address_sanitizer)&&!defined(ADDRESS_SANITIZER)
+#define ADDRESS_SANITIZER
+#endif
+#if __has_feature(memory_sanitizer)&&!defined(MEMORY_SANITIZER)
+#define MEMORY_SANITIZER
+#endif
+#if __has_feature(thread_sanitizer)&&!defined(THREAD_SANITIZER)
+#define THREAD_SANITIZER
+#endif
+#else
+#ifdef __SANITIZE_ADDRESS__
+#define ADDRESS_SANITIZER
+#endif
+#endif
+#if defined(SPARC)
+#define ASM_CLEAR_CODE
+#endif
+#if defined(SPARC)
+#define CAN_SAVE_CALL_ARGS
+#endif
+#if (defined(I386)||defined(X86_64))&&(defined(LINUX)||defined(__GLIBC__))
+#define CAN_SAVE_CALL_ARGS
+#endif
+#if defined(SAVE_CALL_COUNT)&&!defined(GC_ADD_CALLER)&&defined(GC_CAN_SAVE_CALL_STACKS)
+#define SAVE_CALL_CHAIN
+#endif
+#ifdef SAVE_CALL_CHAIN
+#if defined(SAVE_CALL_NARGS)&&defined(CAN_SAVE_CALL_ARGS)
+#define NARGS SAVE_CALL_NARGS
+#else
+#define NARGS 0
+#endif
+#endif
+#ifdef SAVE_CALL_CHAIN
+#if!defined(SAVE_CALL_COUNT)||defined(CPPCHECK)
+#define NFRAMES 6
+#else
+#define NFRAMES ((SAVE_CALL_COUNT+1)&~1)
+#endif
+#define NEED_CALLINFO
+#endif
+#ifdef GC_ADD_CALLER
+#define NFRAMES 1
+#define NARGS 0
+#define NEED_CALLINFO
+#endif
+#if (defined(FREEBSD)||(defined(DARWIN)&&!defined(_POSIX_C_SOURCE))||(defined(SOLARIS)&&(!defined(_XOPEN_SOURCE)||defined(__EXTENSIONS__)))||defined(LINUX))&&!defined(HAVE_DLADDR)
+#define HAVE_DLADDR 1
+#endif
+#if defined(MAKE_BACK_GRAPH)&&!defined(DBG_HDRS_ALL)
+#define DBG_HDRS_ALL 1
+#endif
+#if defined(POINTER_MASK)&&!defined(POINTER_SHIFT)
+#define POINTER_SHIFT 0
+#endif
+#if defined(POINTER_SHIFT)&&!defined(POINTER_MASK)
+#define POINTER_MASK ((word)(-1))
+#endif
+#if!defined(FIXUP_POINTER)&&defined(POINTER_MASK)
+#define FIXUP_POINTER(p)(p=((p)&POINTER_MASK)<<POINTER_SHIFT)
+#endif
+#if defined(FIXUP_POINTER)
+#define NEED_FIXUP_POINTER
+#else
+#define FIXUP_POINTER(p)
+#endif
+#if!defined(MARK_BIT_PER_GRANULE)&&!defined(MARK_BIT_PER_OBJ)
+#define MARK_BIT_PER_GRANULE
+#endif
+#if!defined(CPPCHECK)
+#if defined(MARK_BIT_PER_GRANULE)&&defined(MARK_BIT_PER_OBJ)
+#error Define only one of MARK_BIT_PER_GRANULE and MARK_BIT_PER_OBJ
+#endif
+#if defined(STACK_GROWS_UP)&&defined(STACK_GROWS_DOWN)
+#error Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defined
+#endif
+#if!defined(STACK_GROWS_UP)&&!defined(STACK_GROWS_DOWN)
+#error One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defined
+#endif
+#if defined(REDIRECT_MALLOC)&&defined(THREADS)&&!defined(LINUX)&&!defined(REDIRECT_MALLOC_IN_HEADER)
+#error REDIRECT_MALLOC with THREADS works at most on Linux
+#endif
+#endif
+#ifdef GC_PRIVATE_H
+struct hblk;
+#if defined(PCR)
+char*real_malloc(size_t bytes);
+#define GET_MEM(bytes)HBLKPTR(real_malloc(SIZET_SAT_ADD(bytes,GC_page_size))+GC_page_size-1)
+#elif defined(OS2)
+void*os2_alloc(size_t bytes);
+#define GET_MEM(bytes)HBLKPTR((ptr_t)os2_alloc( SIZET_SAT_ADD(bytes,GC_page_size))+GC_page_size-1)
+#elif defined(NEXT)||defined(DOS4GW)||defined(NONSTOP)||(defined(AMIGA)&&!defined(GC_AMIGA_FASTALLOC))||(defined(SOLARIS)&&!defined(USE_MMAP))||defined(RTEMS)||defined(__CC_ARM)
+#define GET_MEM(bytes)HBLKPTR((size_t)calloc(1,SIZET_SAT_ADD(bytes,GC_page_size))+GC_page_size - 1)
+#elif defined(MSWIN_XBOX1)
+ptr_t GC_durango_get_mem(size_t bytes);
+#define GET_MEM(bytes)(struct hblk*)GC_durango_get_mem(bytes)
+#elif defined(MSWIN32)||defined(CYGWIN32)
+ptr_t GC_win32_get_mem(size_t bytes);
+#define GET_MEM(bytes)(struct hblk*)GC_win32_get_mem(bytes)
+#elif defined(MACOS)
+#if defined(USE_TEMPORARY_MEMORY)
+Ptr GC_MacTemporaryNewPtr(size_t size,Boolean clearMemory);
+#define GET_MEM(bytes)HBLKPTR(GC_MacTemporaryNewPtr( SIZET_SAT_ADD(bytes,GC_page_size),true)+GC_page_size-1)
+#else
+#define GET_MEM(bytes)HBLKPTR(NewPtrClear(SIZET_SAT_ADD(bytes,GC_page_size))+GC_page_size-1)
+#endif
+#elif defined(MSWINCE)
+ptr_t GC_wince_get_mem(size_t bytes);
+#define GET_MEM(bytes)(struct hblk*)GC_wince_get_mem(bytes)
+#elif defined(AMIGA)&&defined(GC_AMIGA_FASTALLOC)
+void*GC_amiga_get_mem(size_t bytes);
+#define GET_MEM(bytes)HBLKPTR((size_t)GC_amiga_get_mem( SIZET_SAT_ADD(bytes,GC_page_size))+GC_page_size-1)
+#elif defined(SN_TARGET_ORBIS)
+void*ps4_get_mem(size_t bytes);
+#define GET_MEM(bytes)(struct hblk*)ps4_get_mem(bytes)
+#elif defined(SN_TARGET_PS3)
+void*ps3_get_mem(size_t bytes);
+#define GET_MEM(bytes)(struct hblk*)ps3_get_mem(bytes)
+#elif defined(SN_TARGET_PSP2)
+void*psp2_get_mem(size_t bytes);
+#define GET_MEM(bytes)(struct hblk*)psp2_get_mem(bytes)
+#elif defined(NINTENDO_SWITCH)
+void*switch_get_mem(size_t bytes);
+#define GET_MEM(bytes)(struct hblk*)switch_get_mem(bytes)
+#elif defined(HAIKU)
+ptr_t GC_haiku_get_mem(size_t bytes);
+#define GET_MEM(bytes)(struct hblk*)GC_haiku_get_mem(bytes)
+#else
+ptr_t GC_unix_get_mem(size_t bytes);
+#define GET_MEM(bytes)(struct hblk*)GC_unix_get_mem(bytes)
+#endif
+#endif
+EXTERN_C_END
+#endif
+#if!defined(GC_ATOMIC_UNCOLLECTABLE)&&defined(ATOMIC_UNCOLLECTABLE)
+#define GC_ATOMIC_UNCOLLECTABLE
+#endif
+#ifndef GC_INNER
+#if defined(GC_DLL)&&defined(__GNUC__)&&!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(CYGWIN32)
+#if GC_GNUC_PREREQ(4,0)&&!defined(GC_NO_VISIBILITY)
+#define GC_INNER __attribute__((__visibility__("hidden")))
+#else
+#define GC_INNER
+#endif
+#else
+#define GC_INNER
+#endif
+#define GC_EXTERN extern GC_INNER
+#endif
+#ifdef __cplusplus
+#define REGISTER
+#else
+#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__)
+#define GC_ATTR_WORD_ALIGNED __attribute__((__aligned__(sizeof(word))))
+#else
+#define GC_ATTR_WORD_ALIGNED
+#endif
+#ifndef HEADERS_H
+#ifndef GC_HEADERS_H
+#define GC_HEADERS_H
+#if CPP_WORDSZ!=32&&CPP_WORDSZ < 36&&!defined(CPPCHECK)
+#error Get a real machine
+#endif
+EXTERN_C_BEGIN
+typedef struct hblkhdr hdr;
+#if CPP_WORDSZ > 32
+#define HASH_TL
+#endif
+#if defined(LARGE_CONFIG)||!defined(SMALL_CONFIG)
+#define LOG_BOTTOM_SZ 10
+#else
+#define LOG_BOTTOM_SZ 11
+#endif
+#define BOTTOM_SZ (1<<LOG_BOTTOM_SZ)
+#ifndef HASH_TL
+#define LOG_TOP_SZ (WORDSZ - LOG_BOTTOM_SZ - LOG_HBLKSIZE)
+#else
+#define LOG_TOP_SZ 11
+#endif
+#define TOP_SZ (1<<LOG_TOP_SZ)
+#ifdef COUNT_HDR_CACHE_HITS
+extern word GC_hdr_cache_hits;
+extern word GC_hdr_cache_misses;
+#define HC_HIT()(void)(++GC_hdr_cache_hits)
+#define HC_MISS()(void)(++GC_hdr_cache_misses)
+#else
+#define HC_HIT()
+#define HC_MISS()
+#endif
+typedef struct hce {
+word block_addr;
+hdr*hce_hdr;
+} hdr_cache_entry;
+#define HDR_CACHE_SIZE 8
+#define DECLARE_HDR_CACHE hdr_cache_entry hdr_cache[HDR_CACHE_SIZE]
+#define INIT_HDR_CACHE BZERO(hdr_cache,sizeof(hdr_cache))
+#define HCE(h)(hdr_cache+(((word)(h)>>LOG_HBLKSIZE)&(HDR_CACHE_SIZE-1)))
+#define HCE_VALID_FOR(hce,h)((hce)->block_addr==((word)(h)>>LOG_HBLKSIZE))
+#define HCE_HDR(h)((hce)->hce_hdr)
+#ifdef PRINT_BLACK_LIST
+GC_INNER hdr*GC_header_cache_miss(ptr_t p,hdr_cache_entry*hce,
+ptr_t source);
+#define HEADER_CACHE_MISS(p,hce,source)GC_header_cache_miss(p,hce,source)
+#else
+GC_INNER hdr*GC_header_cache_miss(ptr_t p,hdr_cache_entry*hce);
+#define HEADER_CACHE_MISS(p,hce,source)GC_header_cache_miss(p,hce)
+#endif
+#define HC_GET_HDR(p,hhdr,source){ hdr_cache_entry*hce=HCE(p);if (EXPECT(HCE_VALID_FOR(hce,p),TRUE)){ HC_HIT();hhdr=hce->hce_hdr;} else { hhdr=HEADER_CACHE_MISS(p,hce,source);if (NULL==hhdr)break;} }
+typedef struct bi {
+hdr*index[BOTTOM_SZ];
+struct bi*asc_link;
+struct bi*desc_link;
+word key;
+#ifdef HASH_TL
+struct bi*hash_link;
+#endif
+} bottom_index;
+#define MAX_JUMP (HBLKSIZE - 1)
+#define HDR_FROM_BI(bi,p)((bi)->index[((word)(p)>>LOG_HBLKSIZE)&(BOTTOM_SZ - 1)])
+#ifndef HASH_TL
+#define BI(p)(GC_top_index [(word)(p)>>(LOG_BOTTOM_SZ+LOG_HBLKSIZE)])
+#define HDR_INNER(p)HDR_FROM_BI(BI(p),p)
+#ifdef SMALL_CONFIG
+#define HDR(p)GC_find_header((ptr_t)(p))
+#else
+#define HDR(p)HDR_INNER(p)
+#endif
+#define GET_BI(p,bottom_indx)(void)((bottom_indx)=BI(p))
+#define GET_HDR(p,hhdr)(void)((hhdr)=HDR(p))
+#define SET_HDR(p,hhdr)(void)(HDR_INNER(p)=(hhdr))
+#define GET_HDR_ADDR(p,ha)(void)((ha)=&HDR_INNER(p))
+#else
+#define TL_HASH(hi)((hi)&(TOP_SZ - 1))
+#define GET_BI(p,bottom_indx)do { REGISTER word hi=(word)(p)>>(LOG_BOTTOM_SZ+LOG_HBLKSIZE);REGISTER bottom_index*_bi=GC_top_index[TL_HASH(hi)];while (_bi->key!=hi&&_bi!=GC_all_nils)_bi=_bi->hash_link;(bottom_indx)=_bi;} while (0)
+#define GET_HDR_ADDR(p,ha)do { REGISTER bottom_index*bi;GET_BI(p,bi);(ha)=&HDR_FROM_BI(bi,p);} while (0)
+#define GET_HDR(p,hhdr)do { REGISTER hdr**_ha;GET_HDR_ADDR(p,_ha);(hhdr)=*_ha;} while (0)
+#define SET_HDR(p,hhdr)do { REGISTER hdr**_ha;GET_HDR_ADDR(p,_ha);*_ha=(hhdr);} while (0)
+#define HDR(p)GC_find_header((ptr_t)(p))
+#endif
+#define IS_FORWARDING_ADDR_OR_NIL(hhdr)((size_t)(hhdr)<=MAX_JUMP)
+#define FORWARDED_ADDR(h,hhdr)((struct hblk*)(h)- (size_t)(hhdr))
+EXTERN_C_END
+#endif
+#endif
+#ifndef GC_ATTR_NO_SANITIZE_ADDR
+#ifndef ADDRESS_SANITIZER
+#define GC_ATTR_NO_SANITIZE_ADDR
+#elif GC_CLANG_PREREQ(3,8)
+#define GC_ATTR_NO_SANITIZE_ADDR __attribute__((no_sanitize("address")))
+#else
+#define GC_ATTR_NO_SANITIZE_ADDR __attribute__((no_sanitize_address))
+#endif
+#endif
+#ifndef GC_ATTR_NO_SANITIZE_MEMORY
+#ifndef MEMORY_SANITIZER
+#define GC_ATTR_NO_SANITIZE_MEMORY
+#elif GC_CLANG_PREREQ(3,8)
+#define GC_ATTR_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory")))
+#else
+#define GC_ATTR_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
+#endif
+#endif
+#ifndef GC_ATTR_NO_SANITIZE_THREAD
+#ifndef THREAD_SANITIZER
+#define GC_ATTR_NO_SANITIZE_THREAD
+#elif GC_CLANG_PREREQ(3,8)
+#define GC_ATTR_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
+#else
+#define GC_ATTR_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
+#endif
+#endif
+#ifndef GC_ATTR_UNUSED
+#if GC_GNUC_PREREQ(3,4)
+#define GC_ATTR_UNUSED __attribute__((__unused__))
+#else
+#define GC_ATTR_UNUSED
+#endif
+#endif
+#ifdef HAVE_CONFIG_H
+#define GC_INLINE static inline
+#elif defined(_MSC_VER)||defined(__INTEL_COMPILER)||defined(__DMC__)||(GC_GNUC_PREREQ(3,0)&&defined(__STRICT_ANSI__))||defined(__WATCOMC__)
+#define GC_INLINE static __inline
+#elif GC_GNUC_PREREQ(3,0)||defined(__sun)
+#define GC_INLINE static inline
+#else
+#define GC_INLINE static
+#endif
+#ifndef GC_ATTR_NOINLINE
+#if GC_GNUC_PREREQ(4,0)
+#define GC_ATTR_NOINLINE __attribute__((__noinline__))
+#elif _MSC_VER>=1400
+#define GC_ATTR_NOINLINE __declspec(noinline)
+#else
+#define GC_ATTR_NOINLINE
+#endif
+#endif
+#ifndef GC_API_OSCALL
+#if defined(__GNUC__)
+#if GC_GNUC_PREREQ(4,0)&&!defined(GC_NO_VISIBILITY)
+#define GC_API_OSCALL extern __attribute__((__visibility__("default")))
+#else
+#define GC_API_OSCALL extern
+#endif
+#else
+#define GC_API_OSCALL GC_API
+#endif
+#endif
+#ifndef GC_API_PRIV
+#define GC_API_PRIV GC_API
+#endif
+#if defined(THREADS)&&!defined(NN_PLATFORM_CTR)
+#ifndef GC_ATOMIC_OPS_H
+#define GC_ATOMIC_OPS_H
+#ifdef GC_BUILTIN_ATOMIC
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef GC_word AO_t;
+#ifdef GC_PRIVATE_H
+#define AO_INLINE GC_INLINE
+#else
+#define AO_INLINE static __inline
+#endif
+typedef unsigned char AO_TS_t;
+#define AO_TS_CLEAR 0
+#define AO_TS_INITIALIZER (AO_TS_t)AO_TS_CLEAR
+#if defined(__GCC_ATOMIC_TEST_AND_SET_TRUEVAL)&&!defined(CPPCHECK)
+#define AO_TS_SET __GCC_ATOMIC_TEST_AND_SET_TRUEVAL
+#else
+#define AO_TS_SET (AO_TS_t)1
+#endif
+#define AO_CLEAR(p)__atomic_clear(p,__ATOMIC_RELEASE)
+#define AO_test_and_set_acquire(p)__atomic_test_and_set(p,__ATOMIC_ACQUIRE)
+#define AO_HAVE_test_and_set_acquire
+#define AO_compiler_barrier()__atomic_signal_fence(__ATOMIC_SEQ_CST)
+#define AO_nop_full()__atomic_thread_fence(__ATOMIC_SEQ_CST)
+#define AO_HAVE_nop_full
+#define AO_fetch_and_add(p,v)__atomic_fetch_add(p,v,__ATOMIC_RELAXED)
+#define AO_HAVE_fetch_and_add
+#define AO_fetch_and_add1(p)AO_fetch_and_add(p,1)
+#define AO_HAVE_fetch_and_add1
+#define AO_or(p,v)(void)__atomic_or_fetch(p,v,__ATOMIC_RELAXED)
+#define AO_HAVE_or
+#define AO_load(p)__atomic_load_n(p,__ATOMIC_RELAXED)
+#define AO_HAVE_load
+#define AO_load_acquire(p)__atomic_load_n(p,__ATOMIC_ACQUIRE)
+#define AO_HAVE_load_acquire
+#define AO_load_acquire_read(p)AO_load_acquire(p)
+#define AO_HAVE_load_acquire_read
+#define AO_store(p,v)__atomic_store_n(p,v,__ATOMIC_RELAXED)
+#define AO_HAVE_store
+#define AO_store_release(p,v)__atomic_store_n(p,v,__ATOMIC_RELEASE)
+#define AO_HAVE_store_release
+#define AO_store_release_write(p,v)AO_store_release(p,v)
+#define AO_HAVE_store_release_write
+#define AO_char_load(p)__atomic_load_n(p,__ATOMIC_RELAXED)
+#define AO_HAVE_char_load
+#define AO_char_store(p,v)__atomic_store_n(p,v,__ATOMIC_RELAXED)
+#define AO_HAVE_char_store
+#ifdef AO_REQUIRE_CAS
+AO_INLINE int
+AO_compare_and_swap(volatile AO_t*p,AO_t ov,AO_t nv)
+{
+return (int)__atomic_compare_exchange_n(p,&ov,nv,0,
+__ATOMIC_RELAXED,__ATOMIC_RELAXED);
+}
+AO_INLINE int
+AO_compare_and_swap_release(volatile AO_t*p,AO_t ov,AO_t nv)
+{
+return (int)__atomic_compare_exchange_n(p,&ov,nv,0,
+__ATOMIC_RELEASE,__ATOMIC_RELAXED);
+}
+#define AO_HAVE_compare_and_swap_release
+#endif
+#ifdef __cplusplus
+}
+#endif
+#ifndef NO_LOCKFREE_AO_OR
+#define HAVE_LOCKFREE_AO_OR 1
+#endif
+#else
+#include "atomic_ops.h"
+#if (!defined(AO_HAVE_load)||!defined(AO_HAVE_store))&&!defined(CPPCHECK)
+#error AO_load or AO_store is missing;probably old version of atomic_ops
+#endif
+#endif
+#endif
+#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
+#ifndef GC_LOCKS_H
+#define GC_LOCKS_H
+#ifdef THREADS
+#ifdef PCR
+#include <base/PCR_Base.h>
+#include <th/PCR_Th.h>
+#endif
+EXTERN_C_BEGIN
+#ifdef PCR
+GC_EXTERN PCR_Th_ML GC_allocate_ml;
+#if defined(CPPCHECK)
+#define DCL_LOCK_STATE
+#else
+#define DCL_LOCK_STATE PCR_ERes GC_fastLockRes;PCR_sigset_t GC_old_sig_mask
+#endif
+#define UNCOND_LOCK()PCR_Th_ML_Acquire(&GC_allocate_ml)
+#define UNCOND_UNLOCK()PCR_Th_ML_Release(&GC_allocate_ml)
+#elif defined(NN_PLATFORM_CTR)||defined(NINTENDO_SWITCH)
+extern void GC_lock(void);
+extern void GC_unlock(void);
+#define UNCOND_LOCK()GC_lock()
+#define UNCOND_UNLOCK()GC_unlock()
+#endif
+#if (!defined(AO_HAVE_test_and_set_acquire)||defined(GC_RTEMS_PTHREADS)||defined(SN_TARGET_ORBIS)||defined(SN_TARGET_PS3)||defined(GC_WIN32_THREADS)||defined(BASE_ATOMIC_OPS_EMULATED)||defined(LINT2))&&defined(GC_PTHREADS)
+#define USE_PTHREAD_LOCKS
+#undef USE_SPIN_LOCK
+#endif
+#if defined(GC_WIN32_THREADS)&&!defined(USE_PTHREAD_LOCKS)
+#define NO_THREAD (DWORD)(-1)
+GC_EXTERN CRITICAL_SECTION GC_allocate_ml;
+#ifdef GC_ASSERTIONS
+GC_EXTERN DWORD GC_lock_holder;
+#define SET_LOCK_HOLDER()GC_lock_holder=GetCurrentThreadId()
+#define UNSET_LOCK_HOLDER()GC_lock_holder=NO_THREAD
+#define I_HOLD_LOCK()(!GC_need_to_lock||GC_lock_holder==GetCurrentThreadId())
+#ifdef THREAD_SANITIZER
+#define I_DONT_HOLD_LOCK()TRUE
+#else
+#define I_DONT_HOLD_LOCK()(!GC_need_to_lock||GC_lock_holder!=GetCurrentThreadId())
+#endif
+#define UNCOND_LOCK(){ GC_ASSERT(I_DONT_HOLD_LOCK());EnterCriticalSection(&GC_allocate_ml);SET_LOCK_HOLDER();}
+#define UNCOND_UNLOCK(){ GC_ASSERT(I_HOLD_LOCK());UNSET_LOCK_HOLDER();LeaveCriticalSection(&GC_allocate_ml);}
+#else
+#define UNCOND_LOCK()EnterCriticalSection(&GC_allocate_ml)
+#define UNCOND_UNLOCK()LeaveCriticalSection(&GC_allocate_ml)
+#endif
+#elif defined(GC_PTHREADS)
+EXTERN_C_END
+#include <pthread.h>
+EXTERN_C_BEGIN
+#if!defined(GC_WIN32_PTHREADS)
+#define NUMERIC_THREAD_ID(id)((unsigned long)(id))
+#define THREAD_EQUAL(id1,id2)((id1)==(id2))
+#define NUMERIC_THREAD_ID_UNIQUE
+#elif defined(__WINPTHREADS_VERSION_MAJOR)
+#define NUMERIC_THREAD_ID(id)((unsigned long)(id))
+#define THREAD_EQUAL(id1,id2)((id1)==(id2))
+#ifndef _WIN64
+#define NUMERIC_THREAD_ID_UNIQUE
+#endif
+#else
+#define NUMERIC_THREAD_ID(id)((unsigned long)(word)(id.p))
+#define THREAD_EQUAL(id1,id2)((id1.p==id2.p)&&(id1.x==id2.x))
+#undef NUMERIC_THREAD_ID_UNIQUE
+#endif
+#define NO_THREAD ((unsigned long)(-1l))
+#ifdef SN_TARGET_PSP2
+EXTERN_C_END
+#include "psp2-support.h"
+EXTERN_C_BEGIN
+GC_EXTERN WapiMutex GC_allocate_ml_PSP2;
+#define UNCOND_LOCK(){ int res;GC_ASSERT(I_DONT_HOLD_LOCK());res=PSP2_MutexLock(&GC_allocate_ml_PSP2);GC_ASSERT(0==res);(void)res;SET_LOCK_HOLDER();}
+#define UNCOND_UNLOCK(){ int res;GC_ASSERT(I_HOLD_LOCK());UNSET_LOCK_HOLDER();res=PSP2_MutexUnlock(&GC_allocate_ml_PSP2);GC_ASSERT(0==res);(void)res;}
+#elif (!defined(THREAD_LOCAL_ALLOC)||defined(USE_SPIN_LOCK))&&!defined(USE_PTHREAD_LOCKS)
+#undef USE_SPIN_LOCK
+#define USE_SPIN_LOCK
+GC_EXTERN volatile AO_TS_t GC_allocate_lock;
+GC_INNER void GC_lock(void);
+#ifdef GC_ASSERTIONS
+#define UNCOND_LOCK(){ GC_ASSERT(I_DONT_HOLD_LOCK());if (AO_test_and_set_acquire(&GC_allocate_lock)==AO_TS_SET)GC_lock();SET_LOCK_HOLDER();}
+#define UNCOND_UNLOCK(){ GC_ASSERT(I_HOLD_LOCK());UNSET_LOCK_HOLDER();AO_CLEAR(&GC_allocate_lock);}
+#else
+#define UNCOND_LOCK(){ if (AO_test_and_set_acquire(&GC_allocate_lock)==AO_TS_SET)GC_lock();}
+#define UNCOND_UNLOCK()AO_CLEAR(&GC_allocate_lock)
+#endif
+#else
+#ifndef USE_PTHREAD_LOCKS
+#define USE_PTHREAD_LOCKS
+#endif
+#endif
+#ifdef USE_PTHREAD_LOCKS
+EXTERN_C_END
+#include <pthread.h>
+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(){ GC_ASSERT(I_HOLD_LOCK());UNSET_LOCK_HOLDER();pthread_mutex_unlock(&GC_allocate_ml);}
+#else
+#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();}
+#endif
+#define UNCOND_UNLOCK()pthread_mutex_unlock(&GC_allocate_ml)
+#endif
+#endif
+#ifdef GC_ASSERTIONS
+GC_EXTERN unsigned long GC_lock_holder;
+#define SET_LOCK_HOLDER()GC_lock_holder=NUMERIC_THREAD_ID(pthread_self())
+#define UNSET_LOCK_HOLDER()GC_lock_holder=NO_THREAD
+#define I_HOLD_LOCK()(!GC_need_to_lock||GC_lock_holder==NUMERIC_THREAD_ID(pthread_self()))
+#if!defined(NUMERIC_THREAD_ID_UNIQUE)||defined(THREAD_SANITIZER)
+#define I_DONT_HOLD_LOCK()TRUE
+#else
+#define I_DONT_HOLD_LOCK()(!GC_need_to_lock||GC_lock_holder!=NUMERIC_THREAD_ID(pthread_self()))
+#endif
+#endif
+#ifndef GC_WIN32_THREADS
+GC_EXTERN volatile GC_bool GC_collecting;
+#ifdef AO_HAVE_char_store
+#define ENTER_GC()AO_char_store((unsigned char*)&GC_collecting,TRUE)
+#define EXIT_GC()AO_char_store((unsigned char*)&GC_collecting,FALSE)
+#else
+#define ENTER_GC()(void)(GC_collecting=TRUE)
+#define EXIT_GC()(void)(GC_collecting=FALSE)
+#endif
+#endif
+#endif
+#if defined(GC_ALWAYS_MULTITHREADED)&&(defined(USE_PTHREAD_LOCKS)||defined(USE_SPIN_LOCK))
+#define GC_need_to_lock TRUE
+#define set_need_to_lock()(void)0
+#else
+#if defined(GC_ALWAYS_MULTITHREADED)&&!defined(CPPCHECK)
+#error Runtime initialization of GC lock is needed!
+#endif
+#undef GC_ALWAYS_MULTITHREADED
+GC_EXTERN GC_bool GC_need_to_lock;
+#ifdef THREAD_SANITIZER
+#define set_need_to_lock()(void)(*(GC_bool volatile*)&GC_need_to_lock?FALSE:(GC_need_to_lock=TRUE))
+#else
+#define set_need_to_lock()(void)(GC_need_to_lock=TRUE)
+#endif
+#endif
+EXTERN_C_END
+#else
+#define LOCK()(void)0
+#define UNLOCK()(void)0
+#ifdef GC_ASSERTIONS
+#define I_HOLD_LOCK()TRUE
+#define I_DONT_HOLD_LOCK()TRUE
+#endif
+#endif
+#if defined(UNCOND_LOCK)&&!defined(LOCK)
+#if (defined(LINT2)&&defined(USE_PTHREAD_LOCKS))||defined(GC_ALWAYS_MULTITHREADED)
+#define LOCK()UNCOND_LOCK()
+#define UNLOCK()UNCOND_UNLOCK()
+#else
+#define LOCK()do { if (GC_need_to_lock)UNCOND_LOCK();} while (0)
+#define UNLOCK()do { if (GC_need_to_lock)UNCOND_UNLOCK();} while (0)
+#endif
+#endif
+#ifndef ENTER_GC
+#define ENTER_GC()
+#define EXIT_GC()
+#endif
+#ifndef DCL_LOCK_STATE
+#define DCL_LOCK_STATE
+#endif
+#endif
+#define GC_WORD_MAX (~(word)0)
+#ifdef STACK_GROWS_DOWN
+#define COOLER_THAN >
+#define HOTTER_THAN <
+#define MAKE_COOLER(x,y)if ((word)((x)+(y))> (word)(x)){(x)+=(y);} else (x)=(ptr_t)GC_WORD_MAX
+#define MAKE_HOTTER(x,y)(x)-=(y)
+#else
+#define COOLER_THAN <
+#define HOTTER_THAN >
+#define MAKE_COOLER(x,y)if ((word)((x)- (y))< (word)(x)){(x)-=(y);} else (x)=0
+#define MAKE_HOTTER(x,y)(x)+=(y)
+#endif
+#if defined(AMIGA)&&defined(__SASC)
+#define GC_FAR __far
+#else
+#define GC_FAR
+#endif
+EXTERN_C_BEGIN
+#ifndef GC_NO_FINALIZATION
+#define GC_INVOKE_FINALIZERS()GC_notify_or_invoke_finalizers()
+GC_INNER void GC_notify_or_invoke_finalizers(void);
+GC_INNER void GC_finalize(void);
+#ifndef GC_TOGGLE_REFS_NOT_NEEDED
+GC_INNER void GC_process_togglerefs(void);
+#endif
+#ifndef SMALL_CONFIG
+GC_INNER void GC_print_finalization_stats(void);
+#endif
+#else
+#define GC_INVOKE_FINALIZERS()(void)0
+#endif
+#if!defined(DONT_ADD_BYTE_AT_END)
+#ifdef LINT2
+#define EXTRA_BYTES ((size_t)(GC_all_interior_pointers?1:0))
+#else
+#define EXTRA_BYTES (size_t)GC_all_interior_pointers
+#endif
+#define MAX_EXTRA_BYTES 1
+#else
+#define EXTRA_BYTES 0
+#define MAX_EXTRA_BYTES 0
+#endif
+#ifndef LARGE_CONFIG
+#define MINHINCR 16
+#define MAXHINCR 2048
+#else
+#define MINHINCR 64
+#define MAXHINCR 4096
+#endif
+#define BL_LIMIT GC_black_list_spacing
+#ifdef NEED_CALLINFO
+struct callinfo {
+word ci_pc;
+#if NARGS > 0
+word ci_arg[NARGS];
+#endif
+#if (NFRAMES*(NARGS+1))% 2==1
+word ci_dummy;
+#endif
+};
+#endif
+#ifdef SAVE_CALL_CHAIN
+GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]);
+GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
+#endif
+EXTERN_C_END
+#ifndef NO_CLOCK
+#ifdef BSD_TIME
+#undef CLOCK_TYPE
+#undef GET_TIME
+#undef MS_TIME_DIFF
+#define CLOCK_TYPE struct timeval
+#define CLOCK_TYPE_INITIALIZER { 0,0 }
+#define GET_TIME(x)do { struct rusage rusage;getrusage(RUSAGE_SELF,&rusage);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 - (a.tv_usec < b.tv_usec&&(long)(a.tv_usec - b.tv_usec)% 1000!=0?1:0)))
+#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)
+#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)
+#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())
+#define MS_TIME_DIFF(a,b)((unsigned long)((a)- (b)))
+#define NS_FRAC_TIME_DIFF(a,b)0UL
+#endif
+#elif defined(NN_PLATFORM_CTR)
+#define CLOCK_TYPE long long
+EXTERN_C_BEGIN
+CLOCK_TYPE n3ds_get_system_tick(void);
+CLOCK_TYPE n3ds_convert_tick_to_ms(CLOCK_TYPE tick);
+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)))
+#define NS_FRAC_TIME_DIFF(a,b)0UL
+#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)((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
+#include <time.h>
+#if defined(FREEBSD)&&!defined(CLOCKS_PER_SEC)
+#include <machine/limits.h>
+#define CLOCKS_PER_SEC CLK_TCK
+#endif
+#if!defined(CLOCKS_PER_SEC)
+#define CLOCKS_PER_SEC 1000000
+#endif
+#define CLOCK_TYPE clock_t
+#define GET_TIME(x)(void)(x=clock())
+#define MS_TIME_DIFF(a,b)(CLOCKS_PER_SEC % 1000==0?(unsigned long)((a)- (b))/(unsigned long)(CLOCKS_PER_SEC/1000):((unsigned long)((a)- (b))*1000)/(unsigned long)CLOCKS_PER_SEC)
+#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
+#ifndef CLOCK_TYPE_INITIALIZER
+#define CLOCK_TYPE_INITIALIZER 0
+#endif
+#endif
+#if defined(SPARC)&&defined(SUNOS4)||(defined(M68K)&&defined(NEXT))||defined(VAX)
+#define BCOPY_EXISTS
+#elif defined(AMIGA)||defined(DARWIN)
+#include <string.h>
+#define BCOPY_EXISTS
+#elif defined(MACOS)&&defined(POWERPC)
+#include <MacMemory.h>
+#define bcopy(x,y,n)BlockMoveData(x,y,n)
+#define bzero(x,n)BlockZero(x,n)
+#define BCOPY_EXISTS
+#endif
+#if!defined(BCOPY_EXISTS)||defined(CPPCHECK)
+#include <string.h>
+#define BCOPY(x,y,n)memcpy(y,x,(size_t)(n))
+#define BZERO(x,n)memset(x,0,(size_t)(n))
+#else
+#define BCOPY(x,y,n)bcopy((void*)(x),(void*)(y),(size_t)(n))
+#define BZERO(x,n)bzero((void*)(x),(size_t)(n))
+#endif
+#ifdef PCR
+#include "th/PCR_ThCtl.h"
+#endif
+EXTERN_C_BEGIN
+#ifdef PCR
+#define STOP_WORLD()PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_stopNormal,PCR_allSigsBlocked,PCR_waitForever)
+#define START_WORLD()PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_null,PCR_allSigsBlocked,PCR_waitForever)
+#else
+#if defined(NN_PLATFORM_CTR)||defined(NINTENDO_SWITCH)||defined(GC_WIN32_THREADS)||defined(GC_PTHREADS)
+GC_INNER void GC_stop_world(void);
+GC_INNER void GC_start_world(void);
+#define STOP_WORLD()GC_stop_world()
+#define START_WORLD()GC_start_world()
+#else
+#define STOP_WORLD()GC_ASSERT(GC_blocked_sp==NULL)
+#define START_WORLD()
+#endif
+#endif
+#ifdef THREADS
+GC_EXTERN GC_on_thread_event_proc GC_on_thread_event;
+#endif
+#if defined(SMALL_CONFIG)||defined(PCR)
+#define GC_on_abort(msg)(void)0
+#else
+GC_API_PRIV GC_abort_func GC_on_abort;
+#endif
+#if defined(CPPCHECK)
+#define ABORT(msg){ GC_on_abort(msg);abort();}
+#elif defined(PCR)
+#define ABORT(s)PCR_Base_Panic(s)
+#else
+#if defined(MSWIN_XBOX1)&&!defined(DebugBreak)
+#define DebugBreak()__debugbreak()
+#elif defined(MSWINCE)&&!defined(DebugBreak)&&(!defined(UNDER_CE)||(defined(__MINGW32CE__)&&!defined(ARM32)))
+#define DebugBreak()_exit(-1)
+#endif
+#if defined(MSWIN32)&&(defined(NO_DEBUGGING)||defined(LINT2))
+#define ABORT(msg)(GC_on_abort(msg),_exit(-1))
+#elif defined(MSWINCE)&&defined(NO_DEBUGGING)
+#define ABORT(msg)(GC_on_abort(msg),ExitProcess(-1))
+#elif defined(MSWIN32)||defined(MSWINCE)
+#if defined(_CrtDbgBreak)&&defined(_DEBUG)&&defined(_MSC_VER)
+#define ABORT(msg){ GC_on_abort(msg);_CrtDbgBreak();}
+#else
+#define ABORT(msg){ GC_on_abort(msg);DebugBreak();}
+#endif
+#else
+#define ABORT(msg)(GC_on_abort(msg),abort())
+#endif
+#endif
+#define ABORT_ARG1(C_msg,C_fmt,arg1)MACRO_BLKSTMT_BEGIN GC_INFOLOG_PRINTF(C_msg C_fmt "\n",arg1);ABORT(C_msg);MACRO_BLKSTMT_END
+#define ABORT_ARG2(C_msg,C_fmt,arg1,arg2)MACRO_BLKSTMT_BEGIN GC_INFOLOG_PRINTF(C_msg C_fmt "\n",arg1,arg2);ABORT(C_msg);MACRO_BLKSTMT_END
+#define ABORT_ARG3(C_msg,C_fmt,arg1,arg2,arg3)MACRO_BLKSTMT_BEGIN GC_INFOLOG_PRINTF(C_msg C_fmt "\n",arg1,arg2,arg3);ABORT(C_msg);MACRO_BLKSTMT_END
+#define ABORT_RET(msg)if ((signed_word)GC_current_warn_proc==-1){} else ABORT(msg)
+#ifdef PCR
+#define EXIT()PCR_Base_Exit(1,PCR_waitForever)
+#else
+#define EXIT()(GC_on_abort(NULL),exit(1))
+#endif
+#define WARN(msg,arg)(*GC_current_warn_proc)(( char*)("GC Warning:" msg),(word)(arg))
+GC_EXTERN GC_warn_proc GC_current_warn_proc;
+#ifndef WARN_PRIdPTR
+#define WARN_PRIdPTR "ld"
+#endif
+#define TRUSTED_STRING(s)(char*)COVERT_DATAFLOW(s)
+#ifdef GC_READ_ENV_FILE
+GC_INNER char*GC_envfile_getenv(const char*name);
+#define GETENV(name)GC_envfile_getenv(name)
+#elif defined(NO_GETENV)&&!defined(CPPCHECK)
+#define GETENV(name)NULL
+#elif defined(EMPTY_GETENV_RESULTS)
+GC_INLINE char*fixed_getenv(const char*name)
+{
+char*value=getenv(name);
+return value!=NULL&&*value!='\0'?value:NULL;
+}
+#define GETENV(name)fixed_getenv(name)
+#else
+#define GETENV(name)getenv(name)
+#endif
+EXTERN_C_END
+#if defined(DARWIN)
+#include <mach/thread_status.h>
+#ifndef MAC_OS_X_VERSION_MAX_ALLOWED
+#include <AvailabilityMacros.h>
+#endif
+#if defined(POWERPC)
+#if CPP_WORDSZ==32
+#define GC_THREAD_STATE_T ppc_thread_state_t
+#else
+#define GC_THREAD_STATE_T ppc_thread_state64_t
+#define GC_MACH_THREAD_STATE PPC_THREAD_STATE64
+#define GC_MACH_THREAD_STATE_COUNT PPC_THREAD_STATE64_COUNT
+#endif
+#elif defined(I386)||defined(X86_64)
+#if CPP_WORDSZ==32
+#if defined(i386_THREAD_STATE_COUNT)&&!defined(x86_THREAD_STATE32_COUNT)
+#define GC_THREAD_STATE_T i386_thread_state_t
+#define GC_MACH_THREAD_STATE i386_THREAD_STATE
+#define GC_MACH_THREAD_STATE_COUNT i386_THREAD_STATE_COUNT
+#else
+#define GC_THREAD_STATE_T x86_thread_state32_t
+#define GC_MACH_THREAD_STATE x86_THREAD_STATE32
+#define GC_MACH_THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT
+#endif
+#else
+#define GC_THREAD_STATE_T x86_thread_state64_t
+#define GC_MACH_THREAD_STATE x86_THREAD_STATE64
+#define GC_MACH_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
+#endif
+#elif defined(ARM32)&&defined(ARM_UNIFIED_THREAD_STATE)&&!defined(CPPCHECK)
+#define GC_THREAD_STATE_T arm_unified_thread_state_t
+#define GC_MACH_THREAD_STATE ARM_UNIFIED_THREAD_STATE
+#define GC_MACH_THREAD_STATE_COUNT ARM_UNIFIED_THREAD_STATE_COUNT
+#elif defined(ARM32)
+#define GC_THREAD_STATE_T arm_thread_state_t
+#ifdef ARM_MACHINE_THREAD_STATE_COUNT
+#define GC_MACH_THREAD_STATE ARM_MACHINE_THREAD_STATE
+#define GC_MACH_THREAD_STATE_COUNT ARM_MACHINE_THREAD_STATE_COUNT
+#endif
+#elif defined(AARCH64)
+#define GC_THREAD_STATE_T arm_thread_state64_t
+#define GC_MACH_THREAD_STATE ARM_THREAD_STATE64
+#define GC_MACH_THREAD_STATE_COUNT ARM_THREAD_STATE64_COUNT
+#elif!defined(CPPCHECK)
+#error define GC_THREAD_STATE_T
+#endif
+#ifndef GC_MACH_THREAD_STATE
+#define GC_MACH_THREAD_STATE MACHINE_THREAD_STATE
+#define GC_MACH_THREAD_STATE_COUNT MACHINE_THREAD_STATE_COUNT
+#endif
+#if CPP_WORDSZ==32
+#define GC_MACH_HEADER mach_header
+#define GC_MACH_SECTION section
+#define GC_GETSECTBYNAME getsectbynamefromheader
+#else
+#define GC_MACH_HEADER mach_header_64
+#define GC_MACH_SECTION section_64
+#define GC_GETSECTBYNAME getsectbynamefromheader_64
+#endif
+#if __DARWIN_UNIX03
+#define THREAD_FLD_NAME(x)__ ## x
+#else
+#define THREAD_FLD_NAME(x)x
+#endif
+#if defined(ARM32)&&defined(ARM_UNIFIED_THREAD_STATE)
+#define THREAD_FLD(x)ts_32.THREAD_FLD_NAME(x)
+#else
+#define THREAD_FLD(x)THREAD_FLD_NAME(x)
+#endif
+#endif
+#include <setjmp.h>
+#if __STDC_VERSION__>=201112L
+#include <assert.h>
+#endif
+EXTERN_C_BEGIN
+#if CPP_WORDSZ==32
+#define WORDS_TO_BYTES(x)((x)<<2)
+#define BYTES_TO_WORDS(x)((x)>>2)
+#define LOGWL ((word)5)
+#define modWORDSZ(n)((n)&0x1f)
+#if ALIGNMENT!=4
+#define UNALIGNED_PTRS
+#endif
+#endif
+#if CPP_WORDSZ==64
+#define WORDS_TO_BYTES(x)((x)<<3)
+#define BYTES_TO_WORDS(x)((x)>>3)
+#define LOGWL ((word)6)
+#define modWORDSZ(n)((n)&0x3f)
+#if ALIGNMENT!=8
+#define UNALIGNED_PTRS
+#endif
+#endif
+#define GRANULE_BYTES GC_GRANULE_BYTES
+#define TINY_FREELISTS GC_TINY_FREELISTS
+#define WORDSZ ((word)CPP_WORDSZ)
+#define SIGNB ((word)1<<(WORDSZ-1))
+#define BYTES_PER_WORD ((word)(sizeof (word)))
+#define divWORDSZ(n)((n)>>LOGWL)
+#if GRANULE_BYTES==8
+#define BYTES_TO_GRANULES(n)((n)>>3)
+#define GRANULES_TO_BYTES(n)((n)<<3)
+#if CPP_WORDSZ==64
+#define GRANULES_TO_WORDS(n)(n)
+#elif CPP_WORDSZ==32
+#define GRANULES_TO_WORDS(n)((n)<<1)
+#else
+#define GRANULES_TO_WORDS(n)BYTES_TO_WORDS(GRANULES_TO_BYTES(n))
+#endif
+#elif GRANULE_BYTES==16
+#define BYTES_TO_GRANULES(n)((n)>>4)
+#define GRANULES_TO_BYTES(n)((n)<<4)
+#if CPP_WORDSZ==64
+#define GRANULES_TO_WORDS(n)((n)<<1)
+#elif CPP_WORDSZ==32
+#define GRANULES_TO_WORDS(n)((n)<<2)
+#else
+#define GRANULES_TO_WORDS(n)BYTES_TO_WORDS(GRANULES_TO_BYTES(n))
+#endif
+#else
+#error Bad GRANULE_BYTES value
+#endif
+#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
+#else
+#define CPP_LOG_HBLKSIZE 12
+#endif
+#else
+#define CPP_LOG_HBLKSIZE 10
+#endif
+#else
+#if HBLKSIZE==512
+#define CPP_LOG_HBLKSIZE 9
+#elif HBLKSIZE==1024
+#define CPP_LOG_HBLKSIZE 10
+#elif HBLKSIZE==2048
+#define CPP_LOG_HBLKSIZE 11
+#elif HBLKSIZE==4096
+#define CPP_LOG_HBLKSIZE 12
+#elif HBLKSIZE==8192
+#define CPP_LOG_HBLKSIZE 13
+#elif HBLKSIZE==16384
+#define CPP_LOG_HBLKSIZE 14
+#elif!defined(CPPCHECK)
+#error Bad HBLKSIZE value
+#endif
+#undef HBLKSIZE
+#endif
+#define CPP_HBLKSIZE (1<<CPP_LOG_HBLKSIZE)
+#define LOG_HBLKSIZE ((size_t)CPP_LOG_HBLKSIZE)
+#define HBLKSIZE ((size_t)CPP_HBLKSIZE)
+#define GC_SQRT_SIZE_MAX ((((size_t)1)<<(WORDSZ/2))- 1)
+#define CPP_MAXOBJBYTES (CPP_HBLKSIZE/2)
+#define MAXOBJBYTES ((size_t)CPP_MAXOBJBYTES)
+#define CPP_MAXOBJWORDS BYTES_TO_WORDS(CPP_MAXOBJBYTES)
+#define MAXOBJWORDS ((size_t)CPP_MAXOBJWORDS)
+#define CPP_MAXOBJGRANULES BYTES_TO_GRANULES(CPP_MAXOBJBYTES)
+#define MAXOBJGRANULES ((size_t)CPP_MAXOBJGRANULES)
+#define divHBLKSZ(n)((n)>>LOG_HBLKSIZE)
+#define HBLK_PTR_DIFF(p,q)divHBLKSZ((ptr_t)p - (ptr_t)q)
+#define modHBLKSZ(n)((n)&(HBLKSIZE-1))
+#define HBLKPTR(objptr)((struct hblk*)(((word)(objptr))&~(word)(HBLKSIZE-1)))
+#define HBLKDISPL(objptr)(((size_t)(objptr))&(HBLKSIZE-1))
+#define ROUNDUP_GRANULE_SIZE(lb)(SIZET_SAT_ADD(lb,GRANULE_BYTES - 1)&~(GRANULE_BYTES - 1))
+#define ROUNDED_UP_GRANULES(lb)BYTES_TO_GRANULES(SIZET_SAT_ADD(lb,GRANULE_BYTES - 1+EXTRA_BYTES))
+#if MAX_EXTRA_BYTES==0
+#define SMALL_OBJ(bytes)EXPECT((bytes)<=(MAXOBJBYTES),TRUE)
+#else
+#define SMALL_OBJ(bytes)(EXPECT((bytes)<=(MAXOBJBYTES - MAX_EXTRA_BYTES),TRUE)||(bytes)<=MAXOBJBYTES - EXTRA_BYTES)
+#endif
+#define ADD_SLOP(lb)SIZET_SAT_ADD(lb,EXTRA_BYTES)
+#ifdef LARGE_CONFIG
+#if CPP_WORDSZ==32
+#define LOG_PHT_ENTRIES 20
+#else
+#define LOG_PHT_ENTRIES 21
+#endif
+#elif!defined(SMALL_CONFIG)
+#define LOG_PHT_ENTRIES 18
+#else
+#define LOG_PHT_ENTRIES 15
+#endif
+#define PHT_ENTRIES ((word)1<<LOG_PHT_ENTRIES)
+#define PHT_SIZE (PHT_ENTRIES>>LOGWL)
+typedef word page_hash_table[PHT_SIZE];
+#define PHT_HASH(addr)((((word)(addr))>>LOG_HBLKSIZE)&(PHT_ENTRIES - 1))
+#define get_pht_entry_from_index(bl,index)(((bl)[divWORDSZ(index)]>>modWORDSZ(index))&1)
+#define set_pht_entry_from_index(bl,index)(void)((bl)[divWORDSZ(index)]|=(word)1<<modWORDSZ(index))
+#if defined(THREADS)&&defined(AO_HAVE_or)
+#define set_pht_entry_from_index_concurrent(bl,index)AO_or((volatile AO_t*)&(bl)[divWORDSZ(index)],(AO_t)((word)1<<modWORDSZ(index)))
+#else
+#define set_pht_entry_from_index_concurrent(bl,index)set_pht_entry_from_index(bl,index)
+#endif
+#define HBLKMASK (HBLKSIZE-1)
+#define MARK_BITS_PER_HBLK (HBLKSIZE/GRANULE_BYTES)
+union word_ptr_ao_u {
+word w;
+signed_word sw;
+void*vp;
+#ifdef PARALLEL_MARK
+volatile AO_t ao;
+#endif
+};
+struct hblkhdr {
+struct hblk*hb_next;
+struct hblk*hb_prev;
+struct hblk*hb_block;
+unsigned char hb_obj_kind;
+unsigned char hb_flags;
+#define IGNORE_OFF_PAGE 1
+#define WAS_UNMAPPED 2
+#define FREE_BLK 4
+#ifdef ENABLE_DISCLAIM
+#define HAS_DISCLAIM 8
+#define MARK_UNCONDITIONALLY 0x10
+#endif
+#ifdef MARK_BIT_PER_GRANULE
+#define LARGE_BLOCK 0x20
+#endif
+unsigned short hb_last_reclaimed;
+#ifdef MARK_BIT_PER_OBJ
+unsigned32 hb_inv_sz;
+#define LARGE_INV_SZ (1<<16)
+#endif
+word hb_sz;
+word hb_descr;
+#ifdef MARK_BIT_PER_GRANULE
+unsigned short*hb_map;
+#endif
+#ifdef PARALLEL_MARK
+volatile AO_t hb_n_marks;
+#else
+size_t hb_n_marks;
+#endif
+#ifdef USE_MARK_BYTES
+#define MARK_BITS_SZ (MARK_BITS_PER_HBLK+1)
+union {
+char _hb_marks[MARK_BITS_SZ];
+word dummy;
+} _mark_byte_union;
+#define hb_marks _mark_byte_union._hb_marks
+#else
+#define MARK_BITS_SZ (MARK_BITS_PER_HBLK/CPP_WORDSZ+1)
+word hb_marks[MARK_BITS_SZ];
+#endif
+};
+#define ANY_INDEX 23
+#define HBLK_WORDS (HBLKSIZE/sizeof(word))
+#define HBLK_GRANULES (HBLKSIZE/GRANULE_BYTES)
+#define HBLK_OBJS(sz_in_bytes)(HBLKSIZE/(sz_in_bytes))
+struct hblk {
+char hb_body[HBLKSIZE];
+};
+#define HBLK_IS_FREE(hdr)(((hdr)->hb_flags&FREE_BLK)!=0)
+#define OBJ_SZ_TO_BLOCKS(lb)divHBLKSZ((lb)+HBLKSIZE-1)
+#define OBJ_SZ_TO_BLOCKS_CHECKED(lb)divHBLKSZ(SIZET_SAT_ADD(lb,HBLKSIZE - 1))
+#define obj_link(p)(*(void**)(p))
+#define LOG_MAX_MARK_PROCS 6
+#define MAX_MARK_PROCS (1<<LOG_MAX_MARK_PROCS)
+#ifdef LARGE_CONFIG
+#define MAX_ROOT_SETS 8192
+#elif!defined(SMALL_CONFIG)
+#define MAX_ROOT_SETS 2048
+#else
+#define MAX_ROOT_SETS 512
+#endif
+#define MAX_EXCLUSIONS (MAX_ROOT_SETS/4)
+struct exclusion {
+ptr_t e_start;
+ptr_t e_end;
+};
+struct roots {
+ptr_t r_start;
+ptr_t r_end;
+#if!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(CYGWIN32)
+struct roots*r_next;
+#endif
+GC_bool r_tmp;
+};
+#if!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(CYGWIN32)
+#define LOG_RT_SIZE 6
+#define RT_SIZE (1<<LOG_RT_SIZE)
+#endif
+#ifndef MAX_HEAP_SECTS
+#ifdef LARGE_CONFIG
+#if CPP_WORDSZ > 32
+#define MAX_HEAP_SECTS 81920
+#else
+#define MAX_HEAP_SECTS 7680
+#endif
+#elif defined(SMALL_CONFIG)&&!defined(USE_PROC_FOR_LIBRARIES)
+#if defined(PARALLEL_MARK)&&(defined(MSWIN32)||defined(CYGWIN32))
+#define MAX_HEAP_SECTS 384
+#else
+#define MAX_HEAP_SECTS 128
+#endif
+#elif CPP_WORDSZ > 32
+#define MAX_HEAP_SECTS 1024
+#else
+#define MAX_HEAP_SECTS 512
+#endif
+#endif
+typedef struct GC_ms_entry {
+ptr_t mse_start;
+union word_ptr_ao_u mse_descr;
+} mse;
+typedef int mark_state_t;
+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;
+struct finalizable_object*finalize_now;
+};
+union toggle_ref_u {
+void*strong_ref;
+GC_hidden_pointer weak_ref;
+};
+typedef struct {
+word ed_bitmap;
+GC_bool ed_continued;
+} typed_ext_descr_t;
+struct _GC_arrays {
+word _heapsize;
+word _requested_heapsize;
+ptr_t _last_heap_addr;
+ptr_t _prev_heap_addr;
+word _large_free_bytes;
+word _large_allocd_bytes;
+word _max_large_allocd_bytes;
+word _bytes_allocd_before_gc;
+#ifndef SEPARATE_GLOBALS
+#define GC_bytes_allocd GC_arrays._bytes_allocd
+word _bytes_allocd;
+#endif
+word _bytes_dropped;
+word _bytes_finalized;
+word _bytes_freed;
+word _finalizer_bytes_freed;
+bottom_index*_all_bottom_indices;
+bottom_index*_all_bottom_indices_end;
+ptr_t _scratch_free_ptr;
+hdr*_hdr_free_list;
+ptr_t _scratch_end_ptr;
+ptr_t _scratch_last_end_ptr;
+mse*_mark_stack;
+mse*_mark_stack_limit;
+#ifdef PARALLEL_MARK
+mse*volatile _mark_stack_top;
+#else
+mse*_mark_stack_top;
+#endif
+word _composite_in_use;
+word _atomic_in_use;
+#ifdef USE_MUNMAP
+#define GC_unmapped_bytes GC_arrays._unmapped_bytes
+word _unmapped_bytes;
+#ifdef COUNT_UNMAPPED_REGIONS
+#define GC_num_unmapped_regions GC_arrays._num_unmapped_regions
+signed_word _num_unmapped_regions;
+#endif
+#else
+#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;
+#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;
+#define GC_mark_stack_too_small GC_arrays._mark_stack_too_small
+GC_bool _mark_stack_too_small;
+#define GC_objects_are_marked GC_arrays._objects_are_marked
+GC_bool _objects_are_marked;
+#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;
+#if defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32)
+#define GC_n_heap_bases GC_arrays._n_heap_bases
+word _n_heap_bases;
+#endif
+#ifdef USE_PROC_FOR_LIBRARIES
+#define GC_n_memory GC_arrays._n_memory
+word _n_memory;
+#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;
+size_t _excl_table_entries;
+#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;
+size_t _avail_descr;
+typed_ext_descr_t*_ext_descriptors;
+GC_mark_proc _mark_procs[MAX_MARK_PROCS];
+char _modws_valid_offsets[sizeof(word)];
+#if!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(CYGWIN32)
+#define GC_root_index GC_arrays._root_index
+struct roots*_root_index[RT_SIZE];
+#endif
+#ifdef SAVE_CALL_CHAIN
+#define GC_last_stack GC_arrays._last_stack
+struct callinfo _last_stack[NFRAMES];
+#endif
+#ifndef SEPARATE_GLOBALS
+#define GC_objfreelist GC_arrays._objfreelist
+void*_objfreelist[MAXOBJGRANULES+1];
+#define GC_aobjfreelist GC_arrays._aobjfreelist
+void*_aobjfreelist[MAXOBJGRANULES+1];
+#endif
+void*_uobjfreelist[MAXOBJGRANULES+1];
+#ifdef GC_ATOMIC_UNCOLLECTABLE
+#define GC_auobjfreelist GC_arrays._auobjfreelist
+void*_auobjfreelist[MAXOBJGRANULES+1];
+#endif
+size_t _size_map[MAXOBJBYTES+1];
+#ifdef MARK_BIT_PER_GRANULE
+#define GC_obj_map GC_arrays._obj_map
+unsigned short*_obj_map[MAXOBJGRANULES+1];
+#define MAP_LEN BYTES_TO_GRANULES(HBLKSIZE)
+#endif
+#define VALID_OFFSET_SZ HBLKSIZE
+char _valid_offsets[VALID_OFFSET_SZ];
+#ifndef GC_DISABLE_INCREMENTAL
+#define GC_grungy_pages GC_arrays._grungy_pages
+page_hash_table _grungy_pages;
+#define GC_dirty_pages GC_arrays._dirty_pages
+volatile page_hash_table _dirty_pages;
+#endif
+#if (defined(CHECKSUMS)&&defined(GWW_VDB))||defined(PROC_VDB)
+#define GC_written_pages GC_arrays._written_pages
+page_hash_table _written_pages;
+#endif
+#define GC_heap_sects GC_arrays._heap_sects
+struct HeapSect {
+ptr_t hs_start;
+size_t hs_bytes;
+} _heap_sects[MAX_HEAP_SECTS];
+#if defined(USE_PROC_FOR_LIBRARIES)
+#define GC_our_memory GC_arrays._our_memory
+struct HeapSect _our_memory[MAX_HEAP_SECTS];
+#endif
+#if defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32)
+#define GC_heap_bases GC_arrays._heap_bases
+ptr_t _heap_bases[MAX_HEAP_SECTS];
+#endif
+#ifdef MSWINCE
+#define GC_heap_lengths GC_arrays._heap_lengths
+word _heap_lengths[MAX_HEAP_SECTS];
+#endif
+struct roots _static_roots[MAX_ROOT_SETS];
+struct exclusion _excl_table[MAX_EXCLUSIONS];
+bottom_index*_top_index[TOP_SZ];
+};
+GC_API_PRIV GC_FAR struct _GC_arrays GC_arrays;
+#define GC_all_nils GC_arrays._all_nils
+#define GC_atomic_in_use GC_arrays._atomic_in_use
+#define GC_bytes_allocd_before_gc GC_arrays._bytes_allocd_before_gc
+#define GC_bytes_dropped GC_arrays._bytes_dropped
+#define GC_bytes_finalized GC_arrays._bytes_finalized
+#define GC_bytes_freed GC_arrays._bytes_freed
+#define GC_composite_in_use GC_arrays._composite_in_use
+#define GC_excl_table GC_arrays._excl_table
+#define GC_finalizer_bytes_freed GC_arrays._finalizer_bytes_freed
+#define GC_heapsize GC_arrays._heapsize
+#define GC_large_allocd_bytes GC_arrays._large_allocd_bytes
+#define GC_large_free_bytes GC_arrays._large_free_bytes
+#define GC_last_heap_addr GC_arrays._last_heap_addr
+#define GC_mark_stack GC_arrays._mark_stack
+#define GC_mark_stack_limit GC_arrays._mark_stack_limit
+#define GC_mark_stack_top GC_arrays._mark_stack_top
+#define GC_mark_procs GC_arrays._mark_procs
+#define GC_max_large_allocd_bytes GC_arrays._max_large_allocd_bytes
+#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
+#define GC_static_roots GC_arrays._static_roots
+#define GC_top_index GC_arrays._top_index
+#define GC_uobjfreelist GC_arrays._uobjfreelist
+#define GC_valid_offsets GC_arrays._valid_offsets
+#define beginGC_arrays ((ptr_t)(&GC_arrays))
+#define endGC_arrays (((ptr_t)(&GC_arrays))+(sizeof GC_arrays))
+#define USED_HEAP_SIZE (GC_heapsize - GC_large_free_bytes)
+#ifndef MAXOBJKINDS
+#define MAXOBJKINDS 16
+#endif
+GC_EXTERN struct obj_kind {
+void**ok_freelist;
+struct hblk**ok_reclaim_list;
+word ok_descriptor;
+GC_bool ok_relocate_descr;
+GC_bool ok_init;
+#ifdef ENABLE_DISCLAIM
+GC_bool ok_mark_unconditionally;
+int (GC_CALLBACK*ok_disclaim_proc)(void*);
+#define OK_DISCLAIM_INITZ,FALSE,0
+#else
+#define OK_DISCLAIM_INITZ
+#endif
+} GC_obj_kinds[MAXOBJKINDS];
+#define beginGC_obj_kinds ((ptr_t)(&GC_obj_kinds))
+#define endGC_obj_kinds (beginGC_obj_kinds+(sizeof GC_obj_kinds))
+#ifdef SEPARATE_GLOBALS
+extern word GC_bytes_allocd;
+extern ptr_t GC_objfreelist[MAXOBJGRANULES+1];
+#define beginGC_objfreelist ((ptr_t)(&GC_objfreelist))
+#define endGC_objfreelist (beginGC_objfreelist+sizeof(GC_objfreelist))
+extern ptr_t GC_aobjfreelist[MAXOBJGRANULES+1];
+#define beginGC_aobjfreelist ((ptr_t)(&GC_aobjfreelist))
+#define endGC_aobjfreelist (beginGC_aobjfreelist+sizeof(GC_aobjfreelist))
+#endif
+#define PTRFREE 0
+#define NORMAL 1
+#define UNCOLLECTABLE 2
+#ifdef GC_ATOMIC_UNCOLLECTABLE
+#define AUNCOLLECTABLE 3
+#define IS_UNCOLLECTABLE(k)(((k)&~1)==UNCOLLECTABLE)
+#define GC_N_KINDS_INITIAL_VALUE 4
+#else
+#define IS_UNCOLLECTABLE(k)((k)==UNCOLLECTABLE)
+#define GC_N_KINDS_INITIAL_VALUE 3
+#endif
+GC_EXTERN unsigned GC_n_kinds;
+GC_EXTERN size_t GC_page_size;
+#define ROUNDUP_PAGESIZE(lb)(SIZET_SAT_ADD(lb,GC_page_size - 1)&~(GC_page_size - 1))
+#ifdef MMAP_SUPPORTED
+#define ROUNDUP_PAGESIZE_IF_MMAP(lb)ROUNDUP_PAGESIZE(lb)
+#else
+#define ROUNDUP_PAGESIZE_IF_MMAP(lb)(lb)
+#endif
+#if defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32)
+GC_EXTERN SYSTEM_INFO GC_sysinfo;
+GC_INNER GC_bool GC_is_heap_base(void*p);
+#endif
+GC_EXTERN word GC_black_list_spacing;
+#ifdef GC_GCJ_SUPPORT
+extern struct hblk*GC_hblkfreelist[];
+extern word GC_free_bytes[];
+#endif
+GC_EXTERN word GC_root_size;
+GC_EXTERN GC_bool GC_debugging_started;
+struct blocking_data {
+GC_fn_type fn;
+void*client_data;
+};
+struct GC_traced_stack_sect_s {
+ptr_t saved_stack_ptr;
+#ifdef IA64
+ptr_t saved_backing_store_ptr;
+ptr_t backing_store_end;
+#endif
+struct GC_traced_stack_sect_s*prev;
+};
+#ifdef THREADS
+GC_INNER void GC_push_all_stack_sections(ptr_t lo,ptr_t hi,
+struct GC_traced_stack_sect_s*traced_stack_sect);
+GC_EXTERN word GC_total_stacksize;
+#else
+GC_EXTERN ptr_t GC_blocked_sp;
+GC_EXTERN struct GC_traced_stack_sect_s*GC_traced_stack_sect;
+#endif
+#ifdef IA64
+GC_INNER void GC_push_all_register_sections(ptr_t bs_lo,ptr_t bs_hi,
+int eager,struct GC_traced_stack_sect_s*traced_stack_sect);
+#endif
+#ifdef USE_MARK_BYTES
+#define mark_bit_from_hdr(hhdr,n)((hhdr)->hb_marks[n])
+#define set_mark_bit_from_hdr(hhdr,n)((hhdr)->hb_marks[n]=1)
+#define clear_mark_bit_from_hdr(hhdr,n)((hhdr)->hb_marks[n]=0)
+#else
+#if defined(PARALLEL_MARK)||(defined(THREAD_SANITIZER)&&defined(THREADS))
+#define OR_WORD(addr,bits)AO_or((volatile AO_t*)(addr),(AO_t)(bits))
+#else
+#define OR_WORD(addr,bits)(void)(*(addr)|=(bits))
+#endif
+#define mark_bit_from_hdr(hhdr,n)(((hhdr)->hb_marks[divWORDSZ(n)]>>modWORDSZ(n))&(word)1)
+#define set_mark_bit_from_hdr(hhdr,n)OR_WORD((hhdr)->hb_marks+divWORDSZ(n),(word)1<<modWORDSZ(n))
+#define clear_mark_bit_from_hdr(hhdr,n)((hhdr)->hb_marks[divWORDSZ(n)]&=~((word)1<<modWORDSZ(n)))
+#endif
+#ifdef MARK_BIT_PER_OBJ
+#define MARK_BIT_NO(offset,sz)(((word)(offset))/(sz))
+#define MARK_BIT_OFFSET(sz)1
+#define IF_PER_OBJ(x)x
+#define FINAL_MARK_BIT(sz)((sz)> MAXOBJBYTES?1:HBLK_OBJS(sz))
+#else
+#define MARK_BIT_NO(offset,sz)BYTES_TO_GRANULES((word)(offset))
+#define MARK_BIT_OFFSET(sz)BYTES_TO_GRANULES(sz)
+#define IF_PER_OBJ(x)
+#define FINAL_MARK_BIT(sz)((sz)> MAXOBJBYTES?MARK_BITS_PER_HBLK:BYTES_TO_GRANULES((sz)*HBLK_OBJS(sz)))
+#endif
+GC_INNER ptr_t GC_approx_sp(void);
+GC_INNER GC_bool GC_should_collect(void);
+void GC_apply_to_all_blocks(void (*fn)(struct hblk*h,word client_data),
+word client_data);
+GC_INNER struct hblk*GC_next_block(struct hblk*h,GC_bool allow_free);
+GC_INNER struct hblk*GC_prev_block(struct hblk*h);
+GC_INNER void GC_mark_init(void);
+GC_INNER void GC_clear_marks(void);
+GC_INNER void GC_invalidate_mark_state(void);
+GC_INNER GC_bool GC_mark_some(ptr_t cold_gc_frame);
+GC_INNER void GC_initiate_gc(void);
+GC_INNER GC_bool GC_collection_in_progress(void);
+#define GC_PUSH_ALL_SYM(sym)GC_push_all(( void*)&(sym),( void*)(&(sym)+1))
+GC_INNER void GC_push_all_stack(ptr_t b,ptr_t t);
+#if defined(WRAP_MARK_SOME)&&defined(PARALLEL_MARK)
+GC_INNER void GC_push_conditional_eager(void*bottom,void*top,
+GC_bool all);
+#endif
+GC_INNER void GC_push_roots(GC_bool all,ptr_t cold_gc_frame);
+GC_API_PRIV GC_push_other_roots_proc GC_push_other_roots;
+#ifdef THREADS
+void GC_push_thread_structures(void);
+#endif
+GC_EXTERN void (*GC_push_typed_structures)(void);
+GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t,void*),
+volatile ptr_t arg);
+#if defined(SPARC)||defined(IA64)
+ptr_t GC_save_regs_in_stack(void);
+#endif
+#if defined(AMIGA)||defined(MACOS)||defined(GC_DARWIN_THREADS)
+void GC_push_one(word p);
+#endif
+#ifdef GC_WIN32_THREADS
+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);
+#else
+GC_INNER void GC_mark_and_push_stack(ptr_t p);
+#endif
+GC_INNER void GC_clear_hdr_marks(hdr*hhdr);
+GC_INNER void GC_set_hdr_marks(hdr*hhdr);
+GC_INNER void GC_set_fl_marks(ptr_t p);
+#if defined(GC_ASSERTIONS)&&defined(THREAD_LOCAL_ALLOC)
+void GC_check_fl_marks(void**);
+#endif
+void GC_add_roots_inner(ptr_t b,ptr_t e,GC_bool tmp);
+#ifdef USE_PROC_FOR_LIBRARIES
+GC_INNER void GC_remove_roots_subregion(ptr_t b,ptr_t e);
+#endif
+GC_INNER void GC_exclude_static_roots_inner(void*start,void*finish);
+#if defined(DYNAMIC_LOADING)||defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32)||defined(PCR)
+GC_INNER void GC_register_dynamic_libraries(void);
+#endif
+GC_INNER void GC_cond_register_dynamic_libraries(void);
+ptr_t GC_get_main_stack_base(void);
+#ifdef IA64
+GC_INNER ptr_t GC_get_register_stack_base(void);
+#endif
+void GC_register_data_segments(void);
+#ifdef THREADS
+GC_INNER void GC_thr_init(void);
+GC_INNER void GC_init_parallel(void);
+#else
+GC_INNER GC_bool GC_is_static_root(void*p);
+#ifdef TRACE_BUF
+void GC_add_trace_entry(char*kind,word arg1,word arg2);
+#endif
+#endif
+#ifdef PRINT_BLACK_LIST
+GC_INNER void GC_add_to_black_list_normal(word p,ptr_t source);
+#define GC_ADD_TO_BLACK_LIST_NORMAL(bits,source)if (GC_all_interior_pointers){ GC_add_to_black_list_stack((word)(bits),(source));} else GC_add_to_black_list_normal((word)(bits),(source))
+GC_INNER void GC_add_to_black_list_stack(word p,ptr_t source);
+#define GC_ADD_TO_BLACK_LIST_STACK(bits,source)GC_add_to_black_list_stack((word)(bits),(source))
+#else
+GC_INNER void GC_add_to_black_list_normal(word p);
+#define GC_ADD_TO_BLACK_LIST_NORMAL(bits,source)if (GC_all_interior_pointers){ GC_add_to_black_list_stack((word)(bits));} else GC_add_to_black_list_normal((word)(bits))
+GC_INNER void GC_add_to_black_list_stack(word p);
+#define GC_ADD_TO_BLACK_LIST_STACK(bits,source)GC_add_to_black_list_stack((word)(bits))
+#endif
+struct hblk*GC_is_black_listed(struct hblk*h,word len);
+GC_INNER void GC_promote_black_lists(void);
+GC_INNER void GC_unpromote_black_lists(void);
+GC_INNER ptr_t GC_scratch_alloc(size_t bytes);
+#ifdef GWW_VDB
+#else
+#define GC_scratch_recycle_no_gww GC_scratch_recycle_inner
+#endif
+GC_INNER void GC_scratch_recycle_inner(void*ptr,size_t bytes);
+#ifdef MARK_BIT_PER_GRANULE
+GC_INNER GC_bool GC_add_map_entry(size_t sz);
+#endif
+GC_INNER void GC_register_displacement_inner(size_t offset);
+GC_INNER void GC_new_hblk(size_t size_in_granules,int kind);
+GC_INNER ptr_t GC_build_fl(struct hblk*h,size_t words,GC_bool clear,
+ptr_t list);
+GC_INNER struct hblk*GC_allochblk(size_t size_in_bytes,int kind,
+unsigned flags);
+GC_INNER ptr_t GC_alloc_large(size_t lb,int k,unsigned flags);
+GC_INNER void GC_freehblk(struct hblk*p);
+GC_INNER GC_bool GC_expand_hp_inner(word n);
+GC_INNER void GC_start_reclaim(GC_bool abort_if_found);
+GC_INNER void GC_continue_reclaim(word sz,int kind);
+GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func,GC_bool ignore_old);
+GC_INNER ptr_t GC_reclaim_generic(struct hblk*hbp,hdr*hhdr,size_t sz,
+GC_bool init,ptr_t list,
+signed_word*count);
+GC_INNER GC_bool GC_block_empty(hdr*hhdr);
+GC_INNER int GC_CALLBACK GC_never_stop_func(void);
+GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func f);
+#define GC_gcollect_inner()(void)GC_try_to_collect_inner(GC_never_stop_func)
+#ifdef THREADS
+GC_EXTERN GC_bool GC_in_thread_creation;
+#endif
+GC_EXTERN GC_bool GC_is_initialized;
+GC_INNER void GC_collect_a_little_inner(int n);
+GC_INNER void*GC_generic_malloc_inner(size_t lb,int k);
+#if defined(DBG_HDRS_ALL)||defined(GC_GCJ_SUPPORT)||!defined(GC_NO_FINALIZATION)
+GC_INNER void*GC_generic_malloc_inner_ignore_off_page(size_t lb,int k);
+#endif
+GC_INNER GC_bool GC_collect_or_expand(word needed_blocks,
+GC_bool ignore_off_page,GC_bool retry);
+GC_INNER ptr_t GC_allocobj(size_t sz,int kind);
+#ifdef GC_ADD_CALLER
+#ifdef GC_HAVE_RETURN_ADDR_PARENT
+#define GC_DBG_EXTRAS GC_RETURN_ADDR_PARENT,NULL,0
+#else
+#define GC_DBG_EXTRAS GC_RETURN_ADDR,NULL,0
+#endif
+#else
+#define GC_DBG_EXTRAS "unknown",0
+#endif
+#ifdef GC_COLLECT_AT_MALLOC
+extern size_t GC_dbg_collect_at_malloc_min_lb;
+#define GC_DBG_COLLECT_AT_MALLOC(lb)(void)((lb)>=GC_dbg_collect_at_malloc_min_lb?(GC_gcollect(),0):0)
+#else
+#define GC_DBG_COLLECT_AT_MALLOC(lb)(void)0
+#endif
+#if defined(THREAD_LOCAL_ALLOC)&&defined(GC_GCJ_SUPPORT)
+GC_INNER void*GC_core_gcj_malloc(size_t,void*);
+#endif
+GC_INNER void GC_init_headers(void);
+GC_INNER struct hblkhdr*GC_install_header(struct hblk*h);
+GC_INNER GC_bool GC_install_counts(struct hblk*h,size_t sz);
+GC_INNER void GC_remove_header(struct hblk*h);
+GC_INNER void GC_remove_counts(struct hblk*h,size_t sz);
+GC_INNER hdr*GC_find_header(ptr_t h);
+GC_INNER void GC_add_to_heap(struct hblk*p,size_t bytes);
+#ifdef USE_PROC_FOR_LIBRARIES
+GC_INNER void GC_add_to_our_memory(ptr_t p,size_t bytes);
+#else
+#define GC_add_to_our_memory(p,bytes)
+#endif
+GC_INNER void GC_print_all_errors(void);
+GC_EXTERN void (*GC_check_heap)(void);
+GC_EXTERN void (*GC_print_all_smashed)(void);
+GC_EXTERN void (*GC_print_heap_obj)(ptr_t p);
+#if defined(LINUX)&&defined(__ELF__)&&!defined(SMALL_CONFIG)
+void GC_print_address_map(void);
+#endif
+#ifndef SHORT_DBG_HDRS
+GC_EXTERN GC_bool GC_findleak_delay_free;
+GC_INNER GC_bool GC_check_leaked(ptr_t base);
+#endif
+GC_EXTERN GC_bool GC_have_errors;
+#define VERBOSE 2
+#if!defined(NO_CLOCK)||!defined(SMALL_CONFIG)
+extern int GC_print_stats;
+#else
+#define GC_print_stats 0
+#endif
+#ifdef KEEP_BACK_PTRS
+GC_EXTERN long GC_backtraces;
+GC_INNER void GC_generate_random_backtrace_no_gc(void);
+#endif
+#ifdef LINT2
+#define GC_RAND_MAX (~0U>>1)
+GC_API_PRIV long GC_random(void);
+#endif
+GC_EXTERN GC_bool GC_print_back_height;
+#ifdef MAKE_BACK_GRAPH
+void GC_print_back_graph_stats(void);
+#endif
+#ifdef THREADS
+GC_INNER void GC_free_inner(void*p);
+#endif
+#ifdef DBG_HDRS_ALL
+GC_INNER void*GC_debug_generic_malloc_inner(size_t lb,int k);
+GC_INNER void*GC_debug_generic_malloc_inner_ignore_off_page(size_t lb,
+int k);
+#define GC_INTERNAL_MALLOC GC_debug_generic_malloc_inner
+#define GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE GC_debug_generic_malloc_inner_ignore_off_page
+#ifdef THREADS
+GC_INNER void GC_debug_free_inner(void*p);
+#define GC_INTERNAL_FREE GC_debug_free_inner
+#else
+#define GC_INTERNAL_FREE GC_debug_free
+#endif
+#else
+#define GC_INTERNAL_MALLOC GC_generic_malloc_inner
+#define GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE GC_generic_malloc_inner_ignore_off_page
+#ifdef THREADS
+#define GC_INTERNAL_FREE GC_free_inner
+#else
+#define GC_INTERNAL_FREE GC_free
+#endif
+#endif
+#ifdef USE_MUNMAP
+GC_INNER void GC_unmap_old(void);
+GC_INNER void GC_merge_unmapped(void);
+GC_INNER void GC_unmap(ptr_t start,size_t bytes);
+GC_INNER void GC_remap(ptr_t start,size_t bytes);
+GC_INNER void GC_unmap_gap(ptr_t start1,size_t bytes1,ptr_t start2,
+size_t bytes2);
+GC_INLINE ptr_t GC_unmap_end(ptr_t start,size_t bytes)
+{
+return (ptr_t)((word)(start+bytes)&~(GC_page_size - 1));
+}
+#endif
+#ifdef CAN_HANDLE_FORK
+GC_EXTERN int GC_handle_fork;
+#endif
+#ifdef GC_DISABLE_INCREMENTAL
+#define GC_incremental FALSE
+#define GC_auto_incremental FALSE
+#define GC_manual_vdb FALSE
+#define GC_dirty(p)(void)(p)
+#define REACHABLE_AFTER_DIRTY(p)(void)(p)
+#else
+GC_EXTERN GC_bool GC_incremental;
+GC_INNER void GC_read_dirty(GC_bool output_unneeded);
+GC_INNER GC_bool GC_page_was_dirty(struct hblk*h);
+GC_INNER void GC_remove_protection(struct hblk*h,word nblocks,
+GC_bool pointerfree);
+GC_INNER GC_bool GC_dirty_init(void);
+GC_EXTERN GC_bool GC_manual_vdb;
+#define GC_auto_incremental (GC_incremental&&!GC_manual_vdb)
+GC_INNER void GC_dirty_inner(const void*p);
+#define GC_dirty(p)(GC_manual_vdb?GC_dirty_inner(p):(void)0)
+#define REACHABLE_AFTER_DIRTY(p)GC_reachable_here(p)
+#endif
+#define GC_base_C(p)((const void*)GC_base(( void*)(p)))
+void GC_print_block_list(void);
+void GC_print_hblkfreelist(void);
+void GC_print_heap_sects(void);
+void GC_print_static_roots(void);
+#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);
+#define GC_STORE_BACK_PTR(source,dest)GC_store_back_pointer(source,dest)
+#define GC_MARKED_FOR_FINALIZATION(dest)GC_marked_for_finalization(dest)
+#else
+#define GC_STORE_BACK_PTR(source,dest)(void)(source)
+#define GC_MARKED_FOR_FINALIZATION(dest)
+#endif
+void GC_noop6(word,word,word,word,word,word);
+GC_API void GC_CALL GC_noop1(word);
+#ifndef GC_ATTR_FORMAT_PRINTF
+#if GC_GNUC_PREREQ(3,0)
+#define GC_ATTR_FORMAT_PRINTF(spec_argnum,first_checked)__attribute__((__format__(__printf__,spec_argnum,first_checked)))
+#else
+#define GC_ATTR_FORMAT_PRINTF(spec_argnum,first_checked)
+#endif
+#endif
+GC_API_PRIV void GC_printf(const char*format,...)
+GC_ATTR_FORMAT_PRINTF(1,2);
+GC_API_PRIV void GC_err_printf(const char*format,...)
+GC_ATTR_FORMAT_PRINTF(1,2);
+GC_API_PRIV void GC_log_printf(const char*format,...)
+GC_ATTR_FORMAT_PRINTF(1,2);
+#ifndef GC_ANDROID_LOG
+#define GC_PRINT_STATS_FLAG (GC_print_stats!=0)
+#define GC_INFOLOG_PRINTF GC_COND_LOG_PRINTF
+#define GC_verbose_log_printf GC_log_printf
+#else
+extern GC_bool GC_quiet;
+#define GC_PRINT_STATS_FLAG (!GC_quiet)
+#ifndef GC_INFOLOG_PRINTF
+#define GC_INFOLOG_PRINTF if (GC_quiet){} else GC_info_log_printf
+#endif
+GC_INNER void GC_info_log_printf(const char*format,...)
+GC_ATTR_FORMAT_PRINTF(1,2);
+GC_INNER void GC_verbose_log_printf(const char*format,...)
+GC_ATTR_FORMAT_PRINTF(1,2);
+#endif
+#define GC_COND_LOG_PRINTF if (EXPECT(!GC_print_stats,TRUE)){} else GC_log_printf
+#define GC_VERBOSE_LOG_PRINTF if (EXPECT(GC_print_stats!=VERBOSE,TRUE)){} else GC_verbose_log_printf
+#ifndef GC_DBGLOG_PRINTF
+#define GC_DBGLOG_PRINTF if (!GC_PRINT_STATS_FLAG){} else GC_log_printf
+#endif
+void GC_err_puts(const char*s);
+#define TO_KiB_UL(v)((unsigned long)(((v)+((1<<9)- 1))>>10))
+GC_EXTERN unsigned GC_fail_count;
+GC_EXTERN long GC_large_alloc_warn_interval;
+GC_EXTERN signed_word GC_bytes_found;
+#ifndef GC_GET_HEAP_USAGE_NOT_NEEDED
+GC_EXTERN word GC_reclaimed_bytes_before_gc;
+#endif
+#ifdef USE_MUNMAP
+GC_EXTERN int GC_unmap_threshold;
+GC_EXTERN GC_bool GC_force_unmap_on_gcollect;
+#endif
+#ifdef MSWIN32
+GC_EXTERN GC_bool GC_no_win32_dlls;
+GC_EXTERN GC_bool GC_wnt;
+#endif
+#ifdef THREADS
+#if (defined(MSWIN32)&&!defined(CONSOLE_LOG))||defined(MSWINCE)
+GC_EXTERN CRITICAL_SECTION GC_write_cs;
+#ifdef GC_ASSERTIONS
+GC_EXTERN GC_bool GC_write_disabled;
+#endif
+#endif
+#if defined(GC_DISABLE_INCREMENTAL)||defined(HAVE_LOCKFREE_AO_OR)
+#define GC_acquire_dirty_lock()(void)0
+#define GC_release_dirty_lock()(void)0
+#else
+#define GC_acquire_dirty_lock()do { } while (AO_test_and_set_acquire(&GC_fault_handler_lock)==AO_TS_SET)
+#define GC_release_dirty_lock()AO_CLEAR(&GC_fault_handler_lock)
+GC_EXTERN volatile AO_TS_t GC_fault_handler_lock;
+#endif
+#ifdef MSWINCE
+GC_EXTERN GC_bool GC_dont_query_stack_min;
+#endif
+#elif defined(IA64)
+GC_EXTERN ptr_t GC_save_regs_ret_val;
+#endif
+#ifdef THREAD_LOCAL_ALLOC
+GC_EXTERN GC_bool GC_world_stopped;
+GC_INNER void GC_mark_thread_local_free_lists(void);
+#endif
+#if defined(MPROTECT_VDB)&&defined(GWW_VDB)
+GC_INNER GC_bool GC_gww_dirty_init(void);
+#endif
+#if defined(CHECKSUMS)||defined(PROC_VDB)
+GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk*h);
+#endif
+#ifdef CHECKSUMS
+#if defined(MPROTECT_VDB)&&!defined(DARWIN)
+void GC_record_fault(struct hblk*h);
+#endif
+void GC_check_dirty(void);
+#endif
+GC_INNER void GC_default_print_heap_obj_proc(ptr_t p);
+GC_INNER void GC_setpagesize(void);
+GC_INNER void GC_initialize_offsets(void);
+GC_INNER void GC_bl_init(void);
+GC_INNER void GC_bl_init_no_interiors(void);
+GC_INNER void GC_start_debugging_inner(void);
+GC_INNER void*GC_store_debug_info_inner(void*p,word sz,const char*str,
+int linenum);
+#ifdef REDIRECT_MALLOC
+#ifdef GC_LINUX_THREADS
+GC_INNER GC_bool GC_text_mapping(char*nm,ptr_t*startp,ptr_t*endp);
+#endif
+#elif defined(USE_WINALLOC)
+GC_INNER void GC_add_current_malloc_heap(void);
+#endif
+#ifdef MAKE_BACK_GRAPH
+GC_INNER void GC_build_back_graph(void);
+GC_INNER void GC_traverse_back_graph(void);
+#endif
+#ifdef MSWIN32
+GC_INNER void GC_init_win32(void);
+#endif
+#if!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(CYGWIN32)
+GC_INNER void*GC_roots_present(ptr_t);
+#endif
+#ifdef GC_WIN32_THREADS
+GC_INNER void GC_get_next_stack(char*start,char*limit,char**lo,
+char**hi);
+#if defined(MPROTECT_VDB)&&!defined(CYGWIN32)
+GC_INNER void GC_set_write_fault_handler(void);
+#endif
+#if defined(WRAP_MARK_SOME)&&!defined(GC_PTHREADS)
+GC_INNER GC_bool GC_started_thread_while_stopped(void);
+#endif
+#endif
+#ifdef THREADS
+GC_INNER void GC_reset_finalizer_nested(void);
+GC_INNER unsigned char*GC_check_finalizer_nested(void);
+GC_INNER void GC_do_blocking_inner(ptr_t data,void*context);
+GC_INNER void GC_push_all_stacks(void);
+#ifdef USE_PROC_FOR_LIBRARIES
+GC_INNER GC_bool GC_segment_is_thread_stack(ptr_t lo,ptr_t hi);
+#endif
+#ifdef IA64
+GC_INNER ptr_t GC_greatest_stack_base_below(ptr_t bound);
+#endif
+#endif
+#ifdef DYNAMIC_LOADING
+GC_INNER GC_bool GC_register_main_static_data(void);
+#ifdef DARWIN
+GC_INNER void GC_init_dyld(void);
+#endif
+#endif
+#ifdef SEARCH_FOR_DATA_START
+GC_INNER void GC_init_linux_data_start(void);
+void*GC_find_limit(void*,int);
+#endif
+#if defined(NETBSD)&&defined(__ELF__)
+GC_INNER void GC_init_netbsd_elf(void);
+void*GC_find_limit(void*,int);
+#endif
+#ifdef UNIX_LIKE
+GC_INNER void GC_set_and_save_fault_handler(void (*handler)(int));
+#endif
+#ifdef NEED_PROC_MAPS
+#if defined(DYNAMIC_LOADING)&&defined(USE_PROC_FOR_LIBRARIES)
+GC_INNER char*GC_parse_map_entry(char*buf_ptr,ptr_t*start,ptr_t*end,
+char**prot,unsigned int*maj_dev,
+char**mapping_name);
+#endif
+#if defined(IA64)||defined(INCLUDE_LINUX_THREAD_DESCR)
+GC_INNER GC_bool GC_enclosing_mapping(ptr_t addr,
+ptr_t*startp,ptr_t*endp);
+#endif
+GC_INNER char*GC_get_maps(void);
+#endif
+#ifdef GC_ASSERTIONS
+#define GC_ASSERT(expr)do { if (!(expr)){ GC_err_printf("Assertion failure:%s:%d\n",__FILE__,__LINE__);ABORT("assertion failure");} } while (0)
+GC_INNER word GC_compute_large_free_bytes(void);
+GC_INNER word GC_compute_root_size(void);
+#else
+#define GC_ASSERT(expr)
+#endif
+#if _MSC_VER>=1700
+#define GC_STATIC_ASSERT(expr)static_assert(expr,"static assertion failed:" #expr)
+#elif defined(static_assert)&&__STDC_VERSION__>=201112L
+#define GC_STATIC_ASSERT(expr)static_assert(expr,#expr)
+#elif defined(mips)&&!defined(__GNUC__)
+#define GC_STATIC_ASSERT(expr)do { if (0){ char j[(expr)?1:-1];j[0]='\0';j[0]=j[0];} } while(0)
+#else
+#define GC_STATIC_ASSERT(expr)(void)sizeof(char[(expr)?1:-1])
+#endif
+#if GC_GNUC_PREREQ(4,0)
+#define NONNULL_ARG_NOT_NULL(arg)(*(volatile void**)&(arg)!=NULL)
+#else
+#define NONNULL_ARG_NOT_NULL(arg)(NULL!=(arg))
+#endif
+#define COND_DUMP_CHECKS do { GC_ASSERT(GC_compute_large_free_bytes()==GC_large_free_bytes);GC_ASSERT(GC_compute_root_size()==GC_root_size);} while (0)
+#ifndef NO_DEBUGGING
+GC_EXTERN GC_bool GC_dump_regularly;
+#define COND_DUMP if (EXPECT(GC_dump_regularly,FALSE)){ GC_dump_named(NULL);} else COND_DUMP_CHECKS
+#else
+#define COND_DUMP COND_DUMP_CHECKS
+#endif
+#if defined(PARALLEL_MARK)
+#define GC_markers_m1 GC_parallel
+GC_EXTERN GC_bool GC_parallel_mark_disabled;
+GC_INNER void GC_wait_for_markers_init(void);
+GC_INNER void GC_acquire_mark_lock(void);
+GC_INNER void GC_release_mark_lock(void);
+GC_INNER void GC_notify_all_builder(void);
+GC_INNER void GC_wait_for_reclaim(void);
+GC_EXTERN signed_word GC_fl_builder_count;
+GC_INNER void GC_notify_all_marker(void);
+GC_INNER void GC_wait_marker(void);
+GC_EXTERN word GC_mark_no;
+GC_INNER void GC_help_marker(word my_mark_no);
+GC_INNER void GC_start_mark_threads_inner(void);
+#endif
+#if defined(GC_PTHREADS)&&!defined(GC_WIN32_THREADS)&&!defined(NACL)&&!defined(GC_DARWIN_THREADS)&&!defined(SIG_SUSPEND)
+#if (defined(GC_LINUX_THREADS)||defined(GC_DGUX386_THREADS))&&!defined(GC_USESIGRT_SIGNALS)
+#if defined(SPARC)&&!defined(SIGPWR)
+#define SIG_SUSPEND SIGLOST
+#else
+#define SIG_SUSPEND SIGPWR
+#endif
+#elif defined(GC_OPENBSD_THREADS)
+#ifndef GC_OPENBSD_UTHREADS
+#define SIG_SUSPEND SIGXFSZ
+#endif
+#elif defined(_SIGRTMIN)&&!defined(CPPCHECK)
+#define SIG_SUSPEND _SIGRTMIN+6
+#else
+#define SIG_SUSPEND SIGRTMIN+6
+#endif
+#endif
+#if defined(GC_PTHREADS)&&!defined(GC_SEM_INIT_PSHARED)
+#define GC_SEM_INIT_PSHARED 0
+#endif
+#if (defined(UNIX_LIKE)||(defined(NEED_FIND_LIMIT)&&defined(CYGWIN32)))&&!defined(GC_NO_SIGSETJMP)
+#if defined(SUNOS5SIGS)&&!defined(FREEBSD)&&!defined(LINUX)
+EXTERN_C_END
+#include <sys/siginfo.h>
+EXTERN_C_BEGIN
+#endif
+#define SETJMP(env)sigsetjmp(env,1)
+#define LONGJMP(env,val)siglongjmp(env,val)
+#define JMP_BUF sigjmp_buf
+#else
+#ifdef ECOS
+#define SETJMP(env)hal_setjmp(env)
+#else
+#define SETJMP(env)setjmp(env)
+#endif
+#define LONGJMP(env,val)longjmp(env,val)
+#define JMP_BUF jmp_buf
+#endif
+#if defined(HEURISTIC2)||defined(SEARCH_FOR_DATA_START)||((defined(SVR4)||defined(AIX)||defined(DGUX)||(defined(LINUX)&&defined(SPARC)))&&!defined(PCR))
+#define NEED_FIND_LIMIT
+#endif
+#if defined(DATASTART_USES_BSDGETDATASTART)
+EXTERN_C_END
+#include <machine/trap.h>
+EXTERN_C_BEGIN
+#if!defined(PCR)
+#define NEED_FIND_LIMIT
+#endif
+GC_INNER ptr_t GC_FreeBSDGetDataStart(size_t,ptr_t);
+#define DATASTART_IS_FUNC
+#endif
+#if (defined(NETBSD)||defined(OPENBSD))&&defined(__ELF__)&&!defined(NEED_FIND_LIMIT)
+#define NEED_FIND_LIMIT
+#endif
+#if defined(IA64)&&!defined(NEED_FIND_LIMIT)
+#define NEED_FIND_LIMIT
+#endif
+#if defined(NEED_FIND_LIMIT)||(defined(USE_PROC_FOR_LIBRARIES)&&defined(THREADS))
+GC_EXTERN JMP_BUF GC_jmp_buf;
+GC_INNER void GC_setup_temporary_fault_handler(void);
+GC_INNER void GC_reset_fault_handler(void);
+#endif
+#if defined(CANCEL_SAFE)
+#if defined(GC_ASSERTIONS)&&(defined(USE_COMPILER_TLS)||(defined(LINUX)&&!defined(ARM32)&&GC_GNUC_PREREQ(3,3)||defined(HPUX)))
+extern __thread unsigned char GC_cancel_disable_count;
+#define NEED_CANCEL_DISABLE_COUNT
+#define INCR_CANCEL_DISABLE()++GC_cancel_disable_count
+#define DECR_CANCEL_DISABLE()--GC_cancel_disable_count
+#define ASSERT_CANCEL_DISABLED()GC_ASSERT(GC_cancel_disable_count > 0)
+#else
+#define INCR_CANCEL_DISABLE()
+#define DECR_CANCEL_DISABLE()
+#define ASSERT_CANCEL_DISABLED()(void)0
+#endif
+#define DISABLE_CANCEL(state)do { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,&state);INCR_CANCEL_DISABLE();} while (0)
+#define RESTORE_CANCEL(state)do { ASSERT_CANCEL_DISABLED();pthread_setcancelstate(state,NULL);DECR_CANCEL_DISABLE();} while (0)
+#else
+#define DISABLE_CANCEL(state)(void)0
+#define RESTORE_CANCEL(state)(void)0
+#define ASSERT_CANCEL_DISABLED()(void)0
+#endif
+EXTERN_C_END
+#endif
+#ifdef KEEP_BACK_PTRS
+#ifndef GC_BACKPTR_H
+#define GC_BACKPTR_H
+#ifndef GC_H
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef enum {
+GC_UNREFERENCED,
+GC_NO_SPACE,
+GC_REFD_FROM_ROOT,
+GC_REFD_FROM_REG,
+GC_REFD_FROM_HEAP,
+GC_FINALIZER_REFD
+} GC_ref_kind;
+GC_API GC_ref_kind GC_CALL GC_get_back_ptr_info(void*,
+void**,size_t*)
+GC_ATTR_NONNULL(1);
+GC_API void*GC_CALL GC_generate_random_heap_address(void);
+GC_API void*GC_CALL GC_generate_random_valid_address(void);
+GC_API void GC_CALL GC_generate_random_backtrace(void);
+GC_API void GC_CALL GC_print_backtrace(void*)GC_ATTR_NONNULL(1);
+#ifdef __cplusplus
+}
+#endif
+#endif
+#endif
+EXTERN_C_BEGIN
+#if CPP_WORDSZ==32
+#define START_FLAG (word)0xfedcedcb
+#define END_FLAG (word)0xbcdecdef
+#else
+#define START_FLAG GC_WORD_C(0xFEDCEDCBfedcedcb)
+#define END_FLAG GC_WORD_C(0xBCDECDEFbcdecdef)
+#endif
+#if defined(KEEP_BACK_PTRS)||defined(PRINT_BLACK_LIST)||defined(MAKE_BACK_GRAPH)
+#define NOT_MARKED (ptr_t)0
+#define MARKED_FOR_FINALIZATION ((ptr_t)(word)2)
+#define MARKED_FROM_REGISTER ((ptr_t)(word)4)
+#endif
+typedef struct {
+#if defined(KEEP_BACK_PTRS)||defined(MAKE_BACK_GRAPH)
+#if ALIGNMENT==1
+#define HIDE_BACK_PTR(p)GC_HIDE_POINTER(~1&(word)(p))
+#else
+#define HIDE_BACK_PTR(p)GC_HIDE_POINTER(p)
+#endif
+#ifdef KEEP_BACK_PTRS
+GC_hidden_pointer oh_back_ptr;
+#endif
+#ifdef MAKE_BACK_GRAPH
+GC_hidden_pointer oh_bg_ptr;
+#endif
+#if defined(KEEP_BACK_PTRS)!=defined(MAKE_BACK_GRAPH)
+word oh_dummy;
+#endif
+#endif
+const char*oh_string;
+signed_word oh_int;
+#ifdef NEED_CALLINFO
+struct callinfo oh_ci[NFRAMES];
+#endif
+#ifndef SHORT_DBG_HDRS
+word oh_sz;
+word oh_sf;
+#endif
+} oh;
+#ifdef SHORT_DBG_HDRS
+#define DEBUG_BYTES (sizeof (oh))
+#define UNCOLLECTABLE_DEBUG_BYTES DEBUG_BYTES
+#else
+#define UNCOLLECTABLE_DEBUG_BYTES (sizeof (oh)+sizeof (word))
+#define DEBUG_BYTES (UNCOLLECTABLE_DEBUG_BYTES - EXTRA_BYTES)
+#endif
+#define SIMPLE_ROUNDED_UP_WORDS(n)BYTES_TO_WORDS((n)+WORDS_TO_BYTES(1)- 1)
+#if defined(SAVE_CALL_CHAIN)
+struct callinfo;
+GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]);
+GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
+#define ADD_CALL_CHAIN(base,ra)GC_save_callers(((oh*)(base))->oh_ci)
+#define PRINT_CALL_CHAIN(base)GC_print_callers(((oh*)(base))->oh_ci)
+#elif defined(GC_ADD_CALLER)
+struct callinfo;
+GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
+#define ADD_CALL_CHAIN(base,ra)((oh*)(base))->oh_ci[0].ci_pc=(ra)
+#define PRINT_CALL_CHAIN(base)GC_print_callers(((oh*)(base))->oh_ci)
+#else
+#define ADD_CALL_CHAIN(base,ra)
+#define PRINT_CALL_CHAIN(base)
+#endif
+#ifdef GC_ADD_CALLER
+#define OPT_RA ra,
+#else
+#define OPT_RA
+#endif
+#ifdef SHORT_DBG_HDRS
+#define GC_has_other_debug_info(p)1
+#else
+GC_INNER int GC_has_other_debug_info(ptr_t p);
+#endif
+#if defined(KEEP_BACK_PTRS)||defined(MAKE_BACK_GRAPH)
+#if defined(SHORT_DBG_HDRS)&&!defined(CPPCHECK)
+#error Non-ptr stored in object results in GC_HAS_DEBUG_INFO malfunction
+#endif
+#if defined(PARALLEL_MARK)&&defined(KEEP_BACK_PTRS)
+#define GC_HAS_DEBUG_INFO(p)((AO_load((volatile AO_t*)(p))&1)!=0&&GC_has_other_debug_info(p)> 0)
+#else
+#define GC_HAS_DEBUG_INFO(p)((*(word*)(p)&1)&&GC_has_other_debug_info(p)> 0)
+#endif
+#else
+#define GC_HAS_DEBUG_INFO(p)(GC_has_other_debug_info(p)> 0)
+#endif
+EXTERN_C_END
+#endif
+#ifdef MAKE_BACK_GRAPH
+#define MAX_IN 10
+#if (!defined(DBG_HDRS_ALL)||(ALIGNMENT!=CPP_WORDSZ/8))&&!defined(CPPCHECK)
+#error The configuration does not support MAKE_BACK_GRAPH
+#endif
+#define FLAG_MANY 2
+typedef struct back_edges_struct {
+word n_edges;
+unsigned short flags;
+#define RETAIN 1
+unsigned short height_gc_no;
+signed_word height;
+#define HEIGHT_UNKNOWN (-2)
+#define HEIGHT_IN_PROGRESS (-1)
+ptr_t edges[MAX_IN];
+struct back_edges_struct*cont;
+} back_edges;
+#define MAX_BACK_EDGE_STRUCTS 100000
+static back_edges*back_edge_space=0;
+STATIC int GC_n_back_edge_structs=0;
+static back_edges*avail_back_edges=0;
+static back_edges*new_back_edges(void)
+{
+if (0==back_edge_space){
+size_t bytes_to_get=ROUNDUP_PAGESIZE_IF_MMAP(MAX_BACK_EDGE_STRUCTS
+*sizeof(back_edges));
+GC_ASSERT(GC_page_size!=0);
+back_edge_space=(back_edges*)GET_MEM(bytes_to_get);
+if (NULL==back_edge_space)
+ABORT("Insufficient memory for back edges");
+GC_add_to_our_memory((ptr_t)back_edge_space,bytes_to_get);
+}
+if (0!=avail_back_edges){
+back_edges*result=avail_back_edges;
+avail_back_edges=result->cont;
+result->cont=0;
+return result;
+}
+if (GC_n_back_edge_structs>=MAX_BACK_EDGE_STRUCTS - 1){
+ABORT("Needed too much space for back edges:adjust "
+"MAX_BACK_EDGE_STRUCTS");
+}
+return back_edge_space+(GC_n_back_edge_structs++);
+}
+static void deallocate_back_edges(back_edges*p)
+{
+back_edges*last=p;
+while (0!=last->cont)last=last->cont;
+last->cont=avail_back_edges;
+avail_back_edges=p;
+}
+#define INITIAL_IN_PROGRESS 10000
+static ptr_t*in_progress_space=0;
+static size_t in_progress_size=0;
+static size_t n_in_progress=0;
+static void push_in_progress(ptr_t p)
+{
+if (n_in_progress>=in_progress_size){
+ptr_t*new_in_progress_space;
+GC_ASSERT(GC_page_size!=0);
+if (NULL==in_progress_space){
+in_progress_size=ROUNDUP_PAGESIZE_IF_MMAP(INITIAL_IN_PROGRESS
+*sizeof(ptr_t))
+/sizeof(ptr_t);
+new_in_progress_space=
+(ptr_t*)GET_MEM(in_progress_size*sizeof(ptr_t));
+} else {
+in_progress_size*=2;
+new_in_progress_space=(ptr_t*)
+GET_MEM(in_progress_size*sizeof(ptr_t));
+if (new_in_progress_space!=NULL)
+BCOPY(in_progress_space,new_in_progress_space,
+n_in_progress*sizeof(ptr_t));
+}
+GC_add_to_our_memory((ptr_t)new_in_progress_space,
+in_progress_size*sizeof(ptr_t));
+#ifndef GWW_VDB
+GC_scratch_recycle_no_gww(in_progress_space,
+n_in_progress*sizeof(ptr_t));
+#elif defined(LINT2)
+GC_noop1((word)in_progress_space);
+#endif
+in_progress_space=new_in_progress_space;
+}
+if (in_progress_space==0)
+ABORT("MAKE_BACK_GRAPH:Out of in-progress space:"
+"Huge linear data structure?");
+in_progress_space[n_in_progress++]=p;
+}
+static GC_bool is_in_progress(ptr_t p)
+{
+size_t i;
+for (i=0;i < n_in_progress;++i){
+if (in_progress_space[i]==p)return TRUE;
+}
+return FALSE;
+}
+GC_INLINE void pop_in_progress(ptr_t p GC_ATTR_UNUSED)
+{
+--n_in_progress;
+GC_ASSERT(in_progress_space[n_in_progress]==p);
+}
+#define GET_OH_BG_PTR(p)(ptr_t)GC_REVEAL_POINTER(((oh*)(p))->oh_bg_ptr)
+#define SET_OH_BG_PTR(p,q)(((oh*)(p))->oh_bg_ptr=GC_HIDE_POINTER(q))
+static void ensure_struct(ptr_t p)
+{
+ptr_t old_back_ptr=GET_OH_BG_PTR(p);
+if (!((word)old_back_ptr&FLAG_MANY)){
+back_edges*be=new_back_edges();
+be->flags=0;
+if (0==old_back_ptr){
+be->n_edges=0;
+} else {
+be->n_edges=1;
+be->edges[0]=old_back_ptr;
+}
+be->height=HEIGHT_UNKNOWN;
+be->height_gc_no=(unsigned short)(GC_gc_no - 1);
+GC_ASSERT((word)be>=(word)back_edge_space);
+SET_OH_BG_PTR(p,(word)be|FLAG_MANY);
+}
+}
+static void add_edge(ptr_t p,ptr_t q)
+{
+ptr_t pred=GET_OH_BG_PTR(q);
+back_edges*be,*be_cont;
+word i;
+GC_ASSERT(p==GC_base(p)&&q==GC_base(q));
+if (!GC_HAS_DEBUG_INFO(q)||!GC_HAS_DEBUG_INFO(p)){
+return;
+}
+if (NULL==pred){
+static unsigned random_number=13;
+#define GOT_LUCKY_NUMBER (((++random_number)&0x7f)==0)
+SET_OH_BG_PTR(q,p);
+if (GOT_LUCKY_NUMBER)ensure_struct(q);
+return;
+}
+{
+back_edges*e=(back_edges*)((word)pred&~FLAG_MANY);
+word n_edges;
+word total;
+int local=0;
+if (((word)pred&FLAG_MANY)!=0){
+n_edges=e->n_edges;
+} else if (((word)COVERT_DATAFLOW(pred)&1)==0){
+n_edges=1;
+local=-1;
+} else {
+n_edges=0;
+}
+for (total=0;total < n_edges;++total){
+if (local==MAX_IN){
+e=e->cont;
+local=0;
+}
+if (local>=0)
+pred=e->edges[local++];
+if (pred==p)
+return;
+}
+}
+ensure_struct(q);
+be=(back_edges*)((word)GET_OH_BG_PTR(q)&~FLAG_MANY);
+for (i=be->n_edges,be_cont=be;i > MAX_IN;i-=MAX_IN)
+be_cont=be_cont->cont;
+if (i==MAX_IN){
+be_cont->cont=new_back_edges();
+be_cont=be_cont->cont;
+i=0;
+}
+be_cont->edges[i]=p;
+be->n_edges++;
+#ifdef DEBUG_PRINT_BIG_N_EDGES
+if (GC_print_stats==VERBOSE&&be->n_edges==100){
+GC_err_printf("The following object has big in-degree:\n");
+GC_print_heap_obj(q);
+}
+#endif
+}
+typedef void (*per_object_func)(ptr_t p,size_t n_bytes,word gc_descr);
+static void per_object_helper(struct hblk*h,word fn)
+{
+hdr*hhdr=HDR(h);
+size_t sz=(size_t)hhdr->hb_sz;
+word descr=hhdr->hb_descr;
+per_object_func f=(per_object_func)fn;
+size_t i=0;
+do {
+f((ptr_t)(h->hb_body+i),sz,descr);
+i+=sz;
+} while (i+sz<=BYTES_TO_WORDS(HBLKSIZE));
+}
+GC_INLINE void GC_apply_to_each_object(per_object_func f)
+{
+GC_apply_to_all_blocks(per_object_helper,(word)f);
+}
+static void reset_back_edge(ptr_t p,size_t n_bytes GC_ATTR_UNUSED,
+word gc_descr GC_ATTR_UNUSED)
+{
+if (GC_HAS_DEBUG_INFO(p)){
+ptr_t old_back_ptr=GET_OH_BG_PTR(p);
+if ((word)old_back_ptr&FLAG_MANY){
+back_edges*be=(back_edges*)((word)old_back_ptr&~FLAG_MANY);
+if (!(be->flags&RETAIN)){
+deallocate_back_edges(be);
+SET_OH_BG_PTR(p,0);
+} else {
+GC_ASSERT(GC_is_marked(p));
+be->n_edges=0;
+if (0!=be->cont){
+deallocate_back_edges(be->cont);
+be->cont=0;
+}
+GC_ASSERT(GC_is_marked(p));
+be->flags&=~RETAIN;
+}
+} else {
+SET_OH_BG_PTR(p,0);
+}
+}
+}
+static void add_back_edges(ptr_t p,size_t n_bytes,word gc_descr)
+{
+word*currentp=(word*)(p+sizeof(oh));
+if((gc_descr&GC_DS_TAGS)!=GC_DS_LENGTH){
+gc_descr=n_bytes;
+}
+while ((word)currentp < (word)(p+gc_descr)){
+word current=*currentp++;
+FIXUP_POINTER(current);
+if (current>=(word)GC_least_plausible_heap_addr&&
+current<=(word)GC_greatest_plausible_heap_addr){
+ptr_t target=(ptr_t)GC_base((void*)current);
+if (0!=target){
+add_edge(p,target);
+}
+}
+}
+}
+GC_INNER void GC_build_back_graph(void)
+{
+GC_ASSERT(I_HOLD_LOCK());
+GC_apply_to_each_object(add_back_edges);
+}
+static word backwards_height(ptr_t p)
+{
+word result;
+ptr_t pred=GET_OH_BG_PTR(p);
+back_edges*be;
+if (NULL==pred)
+return 1;
+if (((word)pred&FLAG_MANY)==0){
+if (is_in_progress(p))return 0;
+push_in_progress(p);
+result=backwards_height(pred)+1;
+pop_in_progress(p);
+return result;
+}
+be=(back_edges*)((word)pred&~FLAG_MANY);
+if (be->height>=0&&be->height_gc_no==(unsigned short)GC_gc_no)
+return be->height;
+if (be->height==HEIGHT_IN_PROGRESS)return 0;
+result=(be->height > 0?be->height:1);
+be->height=HEIGHT_IN_PROGRESS;
+{
+back_edges*e=be;
+word n_edges;
+word total;
+int local=0;
+if (((word)pred&FLAG_MANY)!=0){
+n_edges=e->n_edges;
+} else if (((word)pred&1)==0){
+n_edges=1;
+local=-1;
+} else {
+n_edges=0;
+}
+for (total=0;total < n_edges;++total){
+word this_height;
+if (local==MAX_IN){
+e=e->cont;
+local=0;
+}
+if (local>=0)
+pred=e->edges[local++];
+if (GC_is_marked(pred)&&((word)GET_OH_BG_PTR(p)&FLAG_MANY)==0){
+GC_COND_LOG_PRINTF("Found bogus pointer from %p to %p\n",
+(void*)pred,(void*)p);
+this_height=1;
+} else {
+this_height=backwards_height(pred);
+}
+if (this_height>=result)
+result=this_height+1;
+}
+}
+be->height=result;
+be->height_gc_no=(unsigned short)GC_gc_no;
+return result;
+}
+STATIC word GC_max_height=0;
+STATIC ptr_t GC_deepest_obj=NULL;
+static void update_max_height(ptr_t p,size_t n_bytes GC_ATTR_UNUSED,
+word gc_descr GC_ATTR_UNUSED)
+{
+if (GC_is_marked(p)&&GC_HAS_DEBUG_INFO(p)){
+word p_height=0;
+ptr_t p_deepest_obj=0;
+ptr_t back_ptr;
+back_edges*be=0;
+back_ptr=GET_OH_BG_PTR(p);
+if (0!=back_ptr&&((word)back_ptr&FLAG_MANY)){
+be=(back_edges*)((word)back_ptr&~FLAG_MANY);
+if (be->height!=HEIGHT_UNKNOWN)p_height=be->height;
+}
+{
+ptr_t pred=GET_OH_BG_PTR(p);
+back_edges*e=(back_edges*)((word)pred&~FLAG_MANY);
+word n_edges;
+word total;
+int local=0;
+if (((word)pred&FLAG_MANY)!=0){
+n_edges=e->n_edges;
+} else if (pred!=NULL&&((word)pred&1)==0){
+n_edges=1;
+local=-1;
+} else {
+n_edges=0;
+}
+for (total=0;total < n_edges;++total){
+if (local==MAX_IN){
+e=e->cont;
+local=0;
+}
+if (local>=0)
+pred=e->edges[local++];
+if (!GC_is_marked(pred)&&GC_HAS_DEBUG_INFO(pred)){
+word this_height=backwards_height(pred);
+if (this_height > p_height){
+p_height=this_height;
+p_deepest_obj=pred;
+}
+}
+}
+}
+if (p_height > 0){
+if (be==0){
+ensure_struct(p);
+back_ptr=GET_OH_BG_PTR(p);
+be=(back_edges*)((word)back_ptr&~FLAG_MANY);
+}
+be->flags|=RETAIN;
+be->height=p_height;
+be->height_gc_no=(unsigned short)GC_gc_no;
+}
+if (p_height > GC_max_height){
+GC_max_height=p_height;
+GC_deepest_obj=p_deepest_obj;
+}
+}
+}
+STATIC word GC_max_max_height=0;
+GC_INNER void GC_traverse_back_graph(void)
+{
+GC_ASSERT(I_HOLD_LOCK());
+GC_max_height=0;
+GC_apply_to_each_object(update_max_height);
+if (0!=GC_deepest_obj)
+GC_set_mark_bit(GC_deepest_obj);
+}
+void GC_print_back_graph_stats(void)
+{
+GC_ASSERT(I_HOLD_LOCK());
+GC_printf("Maximum backwards height of reachable objects at GC %lu is %lu\n",
+(unsigned long)GC_gc_no,(unsigned long)GC_max_height);
+if (GC_max_height > GC_max_max_height){
+ptr_t obj=GC_deepest_obj;
+GC_max_max_height=GC_max_height;
+UNLOCK();
+GC_err_printf(
+"The following unreachable object is last in a longest chain "
+"of unreachable objects:\n");
+GC_print_heap_obj(obj);
+LOCK();
+}
+GC_COND_LOG_PRINTF("Needed max total of %d back-edge structs\n",
+GC_n_back_edge_structs);
+GC_apply_to_each_object(reset_back_edge);
+GC_deepest_obj=0;
+}
+#endif
+STATIC word*GC_old_normal_bl=NULL;
+STATIC word*GC_incomplete_normal_bl=NULL;
+STATIC word*GC_old_stack_bl=NULL;
+STATIC word*GC_incomplete_stack_bl=NULL;
+STATIC word GC_total_stack_black_listed=0;
+GC_INNER word GC_black_list_spacing=MINHINCR*HBLKSIZE;
+STATIC void GC_clear_bl(word*);
+GC_INNER void GC_default_print_heap_obj_proc(ptr_t p)
+{
+ptr_t base=(ptr_t)GC_base(p);
+int kind=HDR(base)->hb_obj_kind;
+GC_err_printf("object at %p of appr. %lu bytes (%s)\n",
+(void*)base,(unsigned long)GC_size(base),
+kind==PTRFREE?"atomic":
+IS_UNCOLLECTABLE(kind)?"uncollectable":"composite");
+}
+GC_INNER void (*GC_print_heap_obj)(ptr_t p)=GC_default_print_heap_obj_proc;
+#ifdef PRINT_BLACK_LIST
+STATIC void GC_print_blacklisted_ptr(word p,ptr_t source,
+const char*kind_str)
+{
+ptr_t base=(ptr_t)GC_base(source);
+if (0==base){
+GC_err_printf("Black listing (%s)%p referenced from %p in %s\n",
+kind_str,(void*)p,(void*)source,
+NULL!=source?"root set":"register");
+} else {
+GC_err_printf("Black listing (%s)%p referenced from %p in"
+" object at %p of appr. %lu bytes\n",
+kind_str,(void*)p,(void*)source,
+(void*)base,(unsigned long)GC_size(base));
+}
+}
+#endif
+GC_INNER void GC_bl_init_no_interiors(void)
+{
+if (GC_incomplete_normal_bl==0){
+GC_old_normal_bl=(word*)GC_scratch_alloc(sizeof(page_hash_table));
+GC_incomplete_normal_bl=(word*)GC_scratch_alloc(
+sizeof(page_hash_table));
+if (GC_old_normal_bl==0||GC_incomplete_normal_bl==0){
+GC_err_printf("Insufficient memory for black list\n");
+EXIT();
+}
+GC_clear_bl(GC_old_normal_bl);
+GC_clear_bl(GC_incomplete_normal_bl);
+}
+}
+GC_INNER void GC_bl_init(void)
+{
+if (!GC_all_interior_pointers){
+GC_bl_init_no_interiors();
+}
+GC_ASSERT(NULL==GC_old_stack_bl&&NULL==GC_incomplete_stack_bl);
+GC_old_stack_bl=(word*)GC_scratch_alloc(sizeof(page_hash_table));
+GC_incomplete_stack_bl=(word*)GC_scratch_alloc(sizeof(page_hash_table));
+if (GC_old_stack_bl==0||GC_incomplete_stack_bl==0){
+GC_err_printf("Insufficient memory for black list\n");
+EXIT();
+}
+GC_clear_bl(GC_old_stack_bl);
+GC_clear_bl(GC_incomplete_stack_bl);
+}
+STATIC void GC_clear_bl(word*doomed)
+{
+BZERO(doomed,sizeof(page_hash_table));
+}
+STATIC void GC_copy_bl(word*old,word*dest)
+{
+BCOPY(old,dest,sizeof(page_hash_table));
+}
+static word total_stack_black_listed(void);
+GC_INNER void GC_promote_black_lists(void)
+{
+word*very_old_normal_bl=GC_old_normal_bl;
+word*very_old_stack_bl=GC_old_stack_bl;
+GC_old_normal_bl=GC_incomplete_normal_bl;
+GC_old_stack_bl=GC_incomplete_stack_bl;
+if (!GC_all_interior_pointers){
+GC_clear_bl(very_old_normal_bl);
+}
+GC_clear_bl(very_old_stack_bl);
+GC_incomplete_normal_bl=very_old_normal_bl;
+GC_incomplete_stack_bl=very_old_stack_bl;
+GC_total_stack_black_listed=total_stack_black_listed();
+GC_VERBOSE_LOG_PRINTF(
+"%lu bytes in heap blacklisted for interior pointers\n",
+(unsigned long)GC_total_stack_black_listed);
+if (GC_total_stack_black_listed!=0){
+GC_black_list_spacing=
+HBLKSIZE*(GC_heapsize/GC_total_stack_black_listed);
+}
+if (GC_black_list_spacing < 3*HBLKSIZE){
+GC_black_list_spacing=3*HBLKSIZE;
+}
+if (GC_black_list_spacing > MAXHINCR*HBLKSIZE){
+GC_black_list_spacing=MAXHINCR*HBLKSIZE;
+}
+}
+GC_INNER void GC_unpromote_black_lists(void)
+{
+if (!GC_all_interior_pointers){
+GC_copy_bl(GC_old_normal_bl,GC_incomplete_normal_bl);
+}
+GC_copy_bl(GC_old_stack_bl,GC_incomplete_stack_bl);
+}
+#if defined(PARALLEL_MARK)&&defined(THREAD_SANITIZER)
+#define backlist_set_pht_entry_from_index(db,index)set_pht_entry_from_index_concurrent(db,index)
+#else
+#define backlist_set_pht_entry_from_index(bl,index)set_pht_entry_from_index(bl,index)
+#endif
+#ifdef PRINT_BLACK_LIST
+GC_INNER void GC_add_to_black_list_normal(word p,ptr_t source)
+#else
+GC_INNER void GC_add_to_black_list_normal(word p)
+#endif
+{
+if (GC_modws_valid_offsets[p&(sizeof(word)-1)]){
+word index=PHT_HASH((word)p);
+if (HDR(p)==0||get_pht_entry_from_index(GC_old_normal_bl,index)){
+#ifdef PRINT_BLACK_LIST
+if (!get_pht_entry_from_index(GC_incomplete_normal_bl,index)){
+GC_print_blacklisted_ptr(p,source,"normal");
+}
+#endif
+backlist_set_pht_entry_from_index(GC_incomplete_normal_bl,index);
+}
+}
+}
+#ifdef PRINT_BLACK_LIST
+GC_INNER void GC_add_to_black_list_stack(word p,ptr_t source)
+#else
+GC_INNER void GC_add_to_black_list_stack(word p)
+#endif
+{
+word index=PHT_HASH((word)p);
+if (HDR(p)==0||get_pht_entry_from_index(GC_old_stack_bl,index)){
+#ifdef PRINT_BLACK_LIST
+if (!get_pht_entry_from_index(GC_incomplete_stack_bl,index)){
+GC_print_blacklisted_ptr(p,source,"stack");
+}
+#endif
+backlist_set_pht_entry_from_index(GC_incomplete_stack_bl,index);
+}
+}
+struct hblk*GC_is_black_listed(struct hblk*h,word len)
+{
+word index=PHT_HASH((word)h);
+word i;
+word nblocks;
+if (!GC_all_interior_pointers
+&&(get_pht_entry_from_index(GC_old_normal_bl,index)
+||get_pht_entry_from_index(GC_incomplete_normal_bl,index))){
+return (h+1);
+}
+nblocks=divHBLKSZ(len);
+for (i=0;;){
+if (GC_old_stack_bl[divWORDSZ(index)]==0
+&&GC_incomplete_stack_bl[divWORDSZ(index)]==0){
+i+=WORDSZ - modWORDSZ(index);
+} else {
+if (get_pht_entry_from_index(GC_old_stack_bl,index)
+||get_pht_entry_from_index(GC_incomplete_stack_bl,index)){
+return(h+i+1);
+}
+i++;
+}
+if (i>=nblocks)break;
+index=PHT_HASH((word)(h+i));
+}
+return(0);
+}
+STATIC word GC_number_stack_black_listed(struct hblk*start,
+struct hblk*endp1)
+{
+struct hblk*h;
+word result=0;
+for (h=start;(word)h < (word)endp1;h++){
+word index=PHT_HASH((word)h);
+if (get_pht_entry_from_index(GC_old_stack_bl,index))result++;
+}
+return(result);
+}
+static word total_stack_black_listed(void)
+{
+unsigned i;
+word total=0;
+for (i=0;i < GC_n_heap_sects;i++){
+struct hblk*start=(struct hblk*)GC_heap_sects[i].hs_start;
+struct hblk*endp1=start+divHBLKSZ(GC_heap_sects[i].hs_bytes);
+total+=GC_number_stack_black_listed(start,endp1);
+}
+return(total*HBLKSIZE);
+}
+#ifdef CHECKSUMS
+#define NSUMS 10000
+#define OFFSET 0x10000
+typedef struct {
+GC_bool new_valid;
+word old_sum;
+word new_sum;
+struct hblk*block;
+} page_entry;
+page_entry GC_sums[NSUMS];
+STATIC word GC_faulted[NSUMS]={ 0 };
+STATIC size_t GC_n_faulted=0;
+#if defined(MPROTECT_VDB)&&!defined(DARWIN)
+void GC_record_fault(struct hblk*h)
+{
+word page=(word)h&~(GC_page_size - 1);
+GC_ASSERT(GC_page_size!=0);
+if (GC_n_faulted>=NSUMS)ABORT("write fault log overflowed");
+GC_faulted[GC_n_faulted++]=page;
+}
+#endif
+STATIC GC_bool GC_was_faulted(struct hblk*h)
+{
+size_t i;
+word page=(word)h&~(GC_page_size - 1);
+for (i=0;i < GC_n_faulted;++i){
+if (GC_faulted[i]==page)return TRUE;
+}
+return FALSE;
+}
+STATIC word GC_checksum(struct hblk*h)
+{
+word*p=(word*)h;
+word*lim=(word*)(h+1);
+word result=0;
+while ((word)p < (word)lim){
+result+=*p++;
+}
+return(result|0x80000000);
+}
+int GC_n_dirty_errors=0;
+int GC_n_faulted_dirty_errors=0;
+unsigned long GC_n_clean=0;
+unsigned long GC_n_dirty=0;
+STATIC void GC_update_check_page(struct hblk*h,int index)
+{
+page_entry*pe=GC_sums+index;
+hdr*hhdr=HDR(h);
+struct hblk*b;
+if (pe->block!=0&&pe->block!=h+OFFSET)ABORT("goofed");
+pe->old_sum=pe->new_sum;
+pe->new_sum=GC_checksum(h);
+#if!defined(MSWIN32)&&!defined(MSWINCE)
+if (pe->new_sum!=0x80000000&&!GC_page_was_ever_dirty(h)){
+GC_err_printf("GC_page_was_ever_dirty(%p)is wrong\n",(void*)h);
+}
+#endif
+if (GC_page_was_dirty(h)){
+GC_n_dirty++;
+} else {
+GC_n_clean++;
+}
+b=h;
+while (IS_FORWARDING_ADDR_OR_NIL(hhdr)&&hhdr!=0){
+b-=(word)hhdr;
+hhdr=HDR(b);
+}
+if (pe->new_valid
+&&hhdr!=0&&hhdr->hb_descr!=0
+&&pe->old_sum!=pe->new_sum){
+if (!GC_page_was_dirty(h)||!GC_page_was_ever_dirty(h)){
+GC_bool was_faulted=GC_was_faulted(h);
+GC_n_dirty_errors++;
+if (was_faulted)GC_n_faulted_dirty_errors++;
+}
+}
+pe->new_valid=TRUE;
+pe->block=h+OFFSET;
+}
+word GC_bytes_in_used_blocks=0;
+STATIC void GC_add_block(struct hblk*h,word dummy GC_ATTR_UNUSED)
+{
+hdr*hhdr=HDR(h);
+GC_bytes_in_used_blocks+=(hhdr->hb_sz+HBLKSIZE-1)&~(HBLKSIZE-1);
+}
+STATIC void GC_check_blocks(void)
+{
+word bytes_in_free_blocks=GC_large_free_bytes;
+GC_bytes_in_used_blocks=0;
+GC_apply_to_all_blocks(GC_add_block,(word)0);
+GC_COND_LOG_PRINTF("GC_bytes_in_used_blocks=%lu,"
+" bytes_in_free_blocks=%lu,heapsize=%lu\n",
+(unsigned long)GC_bytes_in_used_blocks,
+(unsigned long)bytes_in_free_blocks,
+(unsigned long)GC_heapsize);
+if (GC_bytes_in_used_blocks+bytes_in_free_blocks!=GC_heapsize){
+GC_err_printf("LOST SOME BLOCKS!!\n");
+}
+}
+void GC_check_dirty(void)
+{
+int index;
+unsigned i;
+struct hblk*h;
+ptr_t start;
+GC_check_blocks();
+GC_n_dirty_errors=0;
+GC_n_faulted_dirty_errors=0;
+GC_n_clean=0;
+GC_n_dirty=0;
+index=0;
+for (i=0;i < GC_n_heap_sects;i++){
+start=GC_heap_sects[i].hs_start;
+for (h=(struct hblk*)start;
+(word)h < (word)(start+GC_heap_sects[i].hs_bytes);h++){
+GC_update_check_page(h,index);
+index++;
+if (index>=NSUMS)goto out;
+}
+}
+out:
+GC_COND_LOG_PRINTF("Checked %lu clean and %lu dirty pages\n",
+GC_n_clean,GC_n_dirty);
+if (GC_n_dirty_errors > 0){
+GC_err_printf("Found %d dirty bit errors (%d were faulted)\n",
+GC_n_dirty_errors,GC_n_faulted_dirty_errors);
+}
+for (i=0;i < GC_n_faulted;++i){
+GC_faulted[i]=0;
+}
+GC_n_faulted=0;
+}
+#endif
+#ifndef GC_PMARK_H
+#define GC_PMARK_H
+#if defined(HAVE_CONFIG_H)&&!defined(GC_PRIVATE_H)
+#endif
+#ifndef GC_BUILD
+#define GC_BUILD
+#endif
+#if (defined(__linux__)||defined(__GLIBC__)||defined(__GNU__))&&!defined(_GNU_SOURCE)&&defined(GC_PTHREADS)&&!defined(GC_NO_PTHREAD_SIGMASK)
+#define _GNU_SOURCE 1
+#endif
+#if defined(KEEP_BACK_PTRS)||defined(PRINT_BLACK_LIST)
+#endif
+EXTERN_C_BEGIN
+#ifndef MARK_DESCR_OFFSET
+#define MARK_DESCR_OFFSET sizeof(word)
+#endif
+#define BITMAP_BITS (WORDSZ - GC_DS_TAG_BITS)
+#define PROC(descr)(GC_mark_procs[((descr)>>GC_DS_TAG_BITS)&(GC_MAX_MARK_PROCS-1)])
+#define ENV(descr)((descr)>>(GC_DS_TAG_BITS+GC_LOG_MAX_MARK_PROCS))
+#define MAX_ENV (((word)1<<(WORDSZ - GC_DS_TAG_BITS - GC_LOG_MAX_MARK_PROCS))- 1)
+GC_EXTERN unsigned GC_n_mark_procs;
+#define GC_MARK_STACK_DISCARDS (INITIAL_MARK_STACK_SIZE/8)
+#ifdef PARALLEL_MARK
+#endif
+GC_INNER mse*GC_signal_mark_stack_overflow(mse*msp);
+GC_INLINE mse*GC_push_obj(ptr_t obj,hdr*hhdr,mse*mark_stack_top,
+mse*mark_stack_limit)
+{
+word descr=hhdr->hb_descr;
+GC_ASSERT(!HBLK_IS_FREE(hhdr));
+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=obj;
+mark_stack_top->mse_descr.w=descr;
+}
+return mark_stack_top;
+}
+#define PUSH_CONTENTS(current,mark_stack_top,mark_stack_limit,source)do { hdr*my_hhdr;HC_GET_HDR(current,my_hhdr,source);mark_stack_top=GC_push_contents_hdr(current,mark_stack_top,mark_stack_limit,source,my_hhdr,TRUE);} while (0)
+#ifdef USE_MARK_BYTES
+#if defined(PARALLEL_MARK)&&defined(AO_HAVE_char_store)&&!defined(BASE_ATOMIC_OPS_EMULATED)
+#define SET_MARK_BIT_EXIT_IF_SET(hhdr,bit_no){ volatile unsigned char*mark_byte_addr=(unsigned char*)(hhdr)->hb_marks+(bit_no);if (AO_char_load(mark_byte_addr)!=0)break;AO_char_store(mark_byte_addr,1);}
+#else
+#define SET_MARK_BIT_EXIT_IF_SET(hhdr,bit_no){ char*mark_byte_addr=(char*)(hhdr)->hb_marks+(bit_no);if (*mark_byte_addr!=0)break;*mark_byte_addr=1;}
+#endif
+#else
+#ifdef PARALLEL_MARK
+#ifdef THREAD_SANITIZER
+#define OR_WORD_EXIT_IF_SET(addr,bits){ if (!((word)AO_load((volatile AO_t*)(addr))&(bits))){ AO_or((volatile AO_t*)(addr),(AO_t)(bits));} else { break;} }
+#else
+#define OR_WORD_EXIT_IF_SET(addr,bits){ if (!(*(addr)&(bits))){ AO_or((volatile AO_t*)(addr),(AO_t)(bits));} else { break;} }
+#endif
+#else
+#define OR_WORD_EXIT_IF_SET(addr,bits){ word old=*(addr);word my_bits=(bits);if ((old&my_bits)!=0)break;*(addr)=old|my_bits;}
+#endif
+#define SET_MARK_BIT_EXIT_IF_SET(hhdr,bit_no){ word*mark_word_addr=(hhdr)->hb_marks+divWORDSZ(bit_no);OR_WORD_EXIT_IF_SET(mark_word_addr,(word)1<<modWORDSZ(bit_no));}
+#endif
+#ifdef PARALLEL_MARK
+#define INCR_MARKS(hhdr)AO_store(&hhdr->hb_n_marks,AO_load(&hhdr->hb_n_marks)+1)
+#else
+#define INCR_MARKS(hhdr)(void)(++hhdr->hb_n_marks)
+#endif
+#ifdef ENABLE_TRACE
+#define TRACE(source,cmd)if (GC_trace_addr!=0&&(ptr_t)(source)==GC_trace_addr)cmd
+#define TRACE_TARGET(target,cmd)if (GC_trace_addr!=0&&(target)==*(ptr_t*)GC_trace_addr)cmd
+#else
+#define TRACE(source,cmd)
+#define TRACE_TARGET(source,cmd)
+#endif
+#if defined(I386)&&defined(__GNUC__)&&!defined(NACL)
+#define LONG_MULT(hprod,lprod,x,y)do { __asm__ __volatile__("mull %2":"=a"(lprod),"=d"(hprod):"g"(y),"0"(x));} while (0)
+#else
+#if defined(__int64)&&!defined(__GNUC__)&&!defined(CPPCHECK)
+#define ULONG_MULT_T unsigned __int64
+#else
+#define ULONG_MULT_T unsigned long long
+#endif
+#define LONG_MULT(hprod,lprod,x,y)do { ULONG_MULT_T prod=(ULONG_MULT_T)(x)*(ULONG_MULT_T)(y);GC_STATIC_ASSERT(sizeof(x)+sizeof(y)<=sizeof(prod));hprod=prod>>32;lprod=(unsigned32)prod;} while (0)
+#endif
+GC_INLINE mse*GC_push_contents_hdr(ptr_t current,mse*mark_stack_top,
+mse*mark_stack_limit,ptr_t source,
+hdr*hhdr,GC_bool do_offset_check)
+{
+do {
+size_t displ=HBLKDISPL(current);
+ptr_t base=current;
+#ifdef MARK_BIT_PER_GRANULE
+size_t gran_displ=BYTES_TO_GRANULES(displ);
+size_t gran_offset=hhdr->hb_map[gran_displ];
+size_t byte_offset=displ&(GRANULE_BYTES - 1);
+if (EXPECT((gran_offset|byte_offset)!=0,FALSE))
+#else
+unsigned32 gran_displ;
+unsigned32 inv_sz=hhdr->hb_inv_sz;
+#endif
+{
+#ifdef MARK_BIT_PER_GRANULE
+if ((hhdr->hb_flags&LARGE_BLOCK)!=0)
+#else
+if (EXPECT(inv_sz==LARGE_INV_SZ,FALSE))
+#endif
+{
+size_t obj_displ;
+base=(ptr_t)hhdr->hb_block;
+obj_displ=current - base;
+if (obj_displ!=displ){
+GC_ASSERT(obj_displ < hhdr->hb_sz);
+} else if (do_offset_check&&!GC_valid_offsets[obj_displ]){
+GC_ADD_TO_BLACK_LIST_NORMAL(current,source);
+break;
+}
+GC_ASSERT(hhdr->hb_sz > HBLKSIZE
+||hhdr->hb_block==HBLKPTR(current));
+GC_ASSERT((word)hhdr->hb_block<=(word)current);
+gran_displ=0;
+} else {
+#ifdef MARK_BIT_PER_GRANULE
+size_t obj_displ=GRANULES_TO_BYTES(gran_offset)+byte_offset;
+#else
+unsigned32 low_prod;
+LONG_MULT(gran_displ,low_prod,(unsigned32)displ,inv_sz);
+if ((low_prod>>16)!=0)
+#endif
+{
+#if defined(MARK_BIT_PER_OBJ)&&!defined(MARK_BIT_PER_GRANULE)
+size_t obj_displ;
+GC_STATIC_ASSERT(HBLKSIZE<=(1<<15));
+obj_displ=(((low_prod>>16)+1)*(size_t)hhdr->hb_sz)>>16;
+#endif
+if (do_offset_check&&!GC_valid_offsets[obj_displ]){
+GC_ADD_TO_BLACK_LIST_NORMAL(current,source);
+break;
+}
+#ifdef MARK_BIT_PER_GRANULE
+gran_displ-=gran_offset;
+#endif
+base-=obj_displ;
+}
+}
+}
+#ifdef MARK_BIT_PER_GRANULE
+GC_ASSERT(hhdr==GC_find_header(base));
+GC_ASSERT(gran_displ % BYTES_TO_GRANULES(hhdr->hb_sz)==0);
+#else
+GC_ASSERT(gran_displ<=HBLK_OBJS(hhdr->hb_sz));
+#endif
+TRACE(source,GC_log_printf("GC #%u:passed validity tests\n",
+(unsigned)GC_gc_no));
+SET_MARK_BIT_EXIT_IF_SET(hhdr,gran_displ);
+TRACE(source,GC_log_printf("GC #%u:previously unmarked\n",
+(unsigned)GC_gc_no));
+TRACE_TARGET(base,GC_log_printf("GC #%u:marking %p from %p instead\n",
+(unsigned)GC_gc_no,(void*)base,
+(void*)source));
+INCR_MARKS(hhdr);
+GC_STORE_BACK_PTR(source,base);
+mark_stack_top=GC_push_obj(base,hhdr,mark_stack_top,
+mark_stack_limit);
+} while (0);
+return mark_stack_top;
+}
+#if defined(PRINT_BLACK_LIST)||defined(KEEP_BACK_PTRS)
+#define PUSH_ONE_CHECKED_STACK(p,source)GC_mark_and_push_stack((ptr_t)(p),(ptr_t)(source))
+#else
+#define PUSH_ONE_CHECKED_STACK(p,source)GC_mark_and_push_stack((ptr_t)(p))
+#endif
+#ifdef NEED_FIXUP_POINTER
+#define GC_PUSH_ONE_STACK(p,source)do { if ((word)(p)>=(word)GC_least_plausible_heap_addr&&(word)(p)< (word)GC_greatest_plausible_heap_addr){ PUSH_ONE_CHECKED_STACK(p,source);} FIXUP_POINTER(p);if ((word)(p)>=(word)GC_least_plausible_heap_addr&&(word)(p)< (word)GC_greatest_plausible_heap_addr){ PUSH_ONE_CHECKED_STACK(p,source);} } while (0)
+#else
+#define GC_PUSH_ONE_STACK(p,source)do { if ((word)(p)>=(word)GC_least_plausible_heap_addr&&(word)(p)< (word)GC_greatest_plausible_heap_addr){ PUSH_ONE_CHECKED_STACK(p,source);} } while (0)
+#endif
+#define GC_PUSH_ONE_HEAP(p,source,mark_stack_top)do { FIXUP_POINTER(p);if ((word)(p)>=(word)GC_least_plausible_heap_addr&&(word)(p)< (word)GC_greatest_plausible_heap_addr)mark_stack_top=GC_mark_and_push((void*)(p),mark_stack_top,GC_mark_stack_limit,(void**)(source));} while (0)
+GC_INNER mse*GC_mark_from(mse*top,mse*bottom,mse*limit);
+#define MARK_FROM_MARK_STACK()GC_mark_stack_top=GC_mark_from(GC_mark_stack_top,GC_mark_stack,GC_mark_stack+GC_mark_stack_size);
+#define GC_mark_stack_empty()((word)GC_mark_stack_top < (word)GC_mark_stack)
+#define GC_MARK_FO(real_ptr,mark_proc)do { (*(mark_proc))(real_ptr);while (!GC_mark_stack_empty())MARK_FROM_MARK_STACK();if (GC_mark_state!=MS_NONE){ GC_set_mark_bit(real_ptr);while (!GC_mark_some((ptr_t)0)){ } } } while (0)
+#define MS_NONE 0
+#define MS_PUSH_RESCUERS 1
+#define MS_PUSH_UNCOLLECTABLE 2
+#define MS_ROOTS_PUSHED 3
+#define MS_PARTIALLY_INVALID 4
+#define MS_INVALID 5
+EXTERN_C_END
+#endif
+#ifdef GC_GCJ_SUPPORT
+#ifndef GC_GCJ_H
+#define GC_GCJ_H
+#ifndef GC_H
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+GC_API void GC_CALL GC_init_gcj_malloc(int,
+void*);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_gcj_malloc(size_t,
+void*);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_debug_gcj_malloc(size_t,
+void*,
+GC_EXTRA_PARAMS);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_gcj_malloc_ignore_off_page(size_t,
+void*);
+GC_API int GC_gcj_kind;
+GC_API int GC_gcj_debug_kind;
+#ifdef GC_DEBUG
+#define GC_GCJ_MALLOC(s,d)GC_debug_gcj_malloc(s,d,GC_EXTRAS)
+#define GC_GCJ_MALLOC_IGNORE_OFF_PAGE(s,d)GC_debug_gcj_malloc(s,d,GC_EXTRAS)
+#else
+#define GC_GCJ_MALLOC(s,d)GC_gcj_malloc(s,d)
+#define GC_GCJ_MALLOC_IGNORE_OFF_PAGE(s,d)GC_gcj_malloc_ignore_off_page(s,d)
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+int GC_gcj_kind=0;
+int GC_gcj_debug_kind=0;
+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,
+word env GC_ATTR_UNUSED)
+{
+ABORT_RET("No client gcj mark proc is specified");
+return mark_stack_ptr;
+}
+GC_API void GC_CALL GC_init_gcj_malloc(int mp_index,
+void*mp)
+{
+#ifndef GC_IGNORE_GCJ_INFO
+GC_bool ignore_gcj_info;
+#endif
+DCL_LOCK_STATE;
+if (mp==0)
+mp=(void*)(word)GC_gcj_fake_mark_proc;
+GC_init();
+LOCK();
+if (GC_gcjobjfreelist!=NULL){
+UNLOCK();
+return;
+}
+#ifdef GC_IGNORE_GCJ_INFO
+#define ignore_gcj_info TRUE
+#else
+ignore_gcj_info=(0!=GETENV("GC_IGNORE_GCJ_INFO"));
+#endif
+if (ignore_gcj_info){
+GC_COND_LOG_PRINTF("Gcj-style type information is disabled!\n");
+}
+GC_ASSERT(GC_mark_procs[mp_index]==(GC_mark_proc)0);
+GC_mark_procs[mp_index]=(GC_mark_proc)(word)mp;
+if ((unsigned)mp_index>=GC_n_mark_procs)
+ABORT("GC_init_gcj_malloc:bad index");
+GC_gcjobjfreelist=(ptr_t*)GC_new_free_list_inner();
+if (ignore_gcj_info){
+GC_gcj_kind=GC_new_kind_inner((void**)GC_gcjobjfreelist,
+GC_DS_LENGTH,
+TRUE,TRUE);
+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);
+GC_gcj_debug_kind=GC_new_kind_inner(GC_new_free_list_inner(),
+GC_MAKE_PROC(mp_index,
+1),
+FALSE,TRUE);
+}
+UNLOCK();
+#undef ignore_gcj_info
+}
+#define GENERAL_MALLOC_INNER(lb,k)GC_clear_stack(GC_generic_malloc_inner(lb,k))
+#define GENERAL_MALLOC_INNER_IOP(lb,k)GC_clear_stack(GC_generic_malloc_inner_ignore_off_page(lb,k))
+static void maybe_finalize(void)
+{
+static word last_finalized_no=0;
+DCL_LOCK_STATE;
+if (GC_gc_no==last_finalized_no||
+!EXPECT(GC_is_initialized,TRUE))return;
+UNLOCK();
+GC_INVOKE_FINALIZERS();
+LOCK();
+last_finalized_no=GC_gc_no;
+}
+#ifdef THREAD_LOCAL_ALLOC
+GC_INNER void*GC_core_gcj_malloc(size_t lb,
+void*ptr_to_struct_containing_descr)
+#else
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_gcj_malloc(size_t lb,
+void*ptr_to_struct_containing_descr)
+#endif
+{
+ptr_t op;
+DCL_LOCK_STATE;
+GC_DBG_COLLECT_AT_MALLOC(lb);
+if(SMALL_OBJ(lb)){
+word lg;
+LOCK();
+lg=GC_size_map[lb];
+op=GC_gcjobjfreelist[lg];
+if(EXPECT(0==op,FALSE)){
+maybe_finalize();
+op=(ptr_t)GENERAL_MALLOC_INNER((word)lb,GC_gcj_kind);
+if (0==op){
+GC_oom_func oom_fn=GC_oom_fn;
+UNLOCK();
+return((*oom_fn)(lb));
+}
+} else {
+GC_gcjobjfreelist[lg]=(ptr_t)obj_link(op);
+GC_bytes_allocd+=GRANULES_TO_BYTES((word)lg);
+}
+GC_ASSERT(((void**)op)[1]==0);
+} else {
+LOCK();
+maybe_finalize();
+op=(ptr_t)GENERAL_MALLOC_INNER((word)lb,GC_gcj_kind);
+if (0==op){
+GC_oom_func oom_fn=GC_oom_fn;
+UNLOCK();
+return((*oom_fn)(lb));
+}
+}
+*(void**)op=ptr_to_struct_containing_descr;
+UNLOCK();
+GC_dirty(op);
+REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr);
+return (void*)op;
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_debug_gcj_malloc(size_t lb,
+void*ptr_to_struct_containing_descr,GC_EXTRA_PARAMS)
+{
+void*result;
+DCL_LOCK_STATE;
+LOCK();
+maybe_finalize();
+result=GC_generic_malloc_inner(SIZET_SAT_ADD(lb,DEBUG_BYTES),
+GC_gcj_debug_kind);
+if (result==0){
+GC_oom_func oom_fn=GC_oom_fn;
+UNLOCK();
+GC_err_printf("GC_debug_gcj_malloc(%lu,%p)returning NULL (%s:%d)\n",
+(unsigned long)lb,ptr_to_struct_containing_descr,s,i);
+return((*oom_fn)(lb));
+}
+*((void**)((ptr_t)result+sizeof(oh)))=ptr_to_struct_containing_descr;
+if (!GC_debugging_started){
+GC_start_debugging_inner();
+}
+ADD_CALL_CHAIN(result,ra);
+result=GC_store_debug_info_inner(result,(word)lb,s,i);
+UNLOCK();
+GC_dirty(result);
+REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr);
+return result;
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_gcj_malloc_ignore_off_page(size_t lb,
+void*ptr_to_struct_containing_descr)
+{
+ptr_t op;
+DCL_LOCK_STATE;
+GC_DBG_COLLECT_AT_MALLOC(lb);
+if(SMALL_OBJ(lb)){
+word lg;
+LOCK();
+lg=GC_size_map[lb];
+op=GC_gcjobjfreelist[lg];
+if (EXPECT(0==op,FALSE)){
+maybe_finalize();
+op=(ptr_t)GENERAL_MALLOC_INNER_IOP(lb,GC_gcj_kind);
+if (0==op){
+GC_oom_func oom_fn=GC_oom_fn;
+UNLOCK();
+return((*oom_fn)(lb));
+}
+} else {
+GC_gcjobjfreelist[lg]=(ptr_t)obj_link(op);
+GC_bytes_allocd+=GRANULES_TO_BYTES((word)lg);
+}
+} else {
+LOCK();
+maybe_finalize();
+op=(ptr_t)GENERAL_MALLOC_INNER_IOP(lb,GC_gcj_kind);
+if (0==op){
+GC_oom_func oom_fn=GC_oom_fn;
+UNLOCK();
+return((*oom_fn)(lb));
+}
+}
+*(void**)op=ptr_to_struct_containing_descr;
+UNLOCK();
+GC_dirty(op);
+REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr);
+return (void*)op;
+}
+#endif
+GC_INNER hdr*GC_find_header(ptr_t h)
+{
+#ifdef HASH_TL
+hdr*result;
+GET_HDR(h,result);
+return(result);
+#else
+return(HDR_INNER(h));
+#endif
+}
+GC_INNER hdr*
+#ifdef PRINT_BLACK_LIST
+GC_header_cache_miss(ptr_t p,hdr_cache_entry*hce,ptr_t source)
+#else
+GC_header_cache_miss(ptr_t p,hdr_cache_entry*hce)
+#endif
+{
+hdr*hhdr;
+HC_MISS();
+GET_HDR(p,hhdr);
+if (IS_FORWARDING_ADDR_OR_NIL(hhdr)){
+if (GC_all_interior_pointers){
+if (hhdr!=0){
+ptr_t current=p;
+current=(ptr_t)HBLKPTR(current);
+do {
+current=current - HBLKSIZE*(word)hhdr;
+hhdr=HDR(current);
+} while(IS_FORWARDING_ADDR_OR_NIL(hhdr));
+if (hhdr->hb_flags&IGNORE_OFF_PAGE)
+return 0;
+if (HBLK_IS_FREE(hhdr)
+||p - current>=(ptrdiff_t)(hhdr->hb_sz)){
+GC_ADD_TO_BLACK_LIST_NORMAL(p,source);
+return 0;
+}
+} else {
+GC_ADD_TO_BLACK_LIST_NORMAL(p,source);
+}
+GC_ASSERT(hhdr==0||!HBLK_IS_FREE(hhdr));
+return hhdr;
+} else {
+if (hhdr==0){
+GC_ADD_TO_BLACK_LIST_NORMAL(p,source);
+}
+return 0;
+}
+} else {
+if (HBLK_IS_FREE(hhdr)){
+GC_ADD_TO_BLACK_LIST_NORMAL(p,source);
+return 0;
+} else {
+hce->block_addr=(word)(p)>>LOG_HBLKSIZE;
+hce->hce_hdr=hhdr;
+return hhdr;
+}
+}
+}
+GC_INNER ptr_t GC_scratch_alloc(size_t bytes)
+{
+ptr_t result=GC_scratch_free_ptr;
+size_t bytes_to_get;
+bytes=ROUNDUP_GRANULE_SIZE(bytes);
+for (;;){
+GC_scratch_free_ptr+=bytes;
+if ((word)GC_scratch_free_ptr<=(word)GC_scratch_end_ptr){
+return result;
+}
+GC_ASSERT(GC_page_size!=0);
+if (bytes>=MINHINCR*HBLKSIZE){
+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);
+GC_scratch_free_ptr-=bytes;
+if (result!=NULL){
+GC_scratch_last_end_ptr=result+bytes;
+}
+return result;
+}
+bytes_to_get=ROUNDUP_PAGESIZE_IF_MMAP(MINHINCR*HBLKSIZE);
+result=(ptr_t)GET_MEM(bytes_to_get);
+GC_add_to_our_memory(result,bytes_to_get);
+if (NULL==result){
+WARN("Out of memory - trying to allocate requested amount"
+" (%" WARN_PRIdPTR " bytes)...\n",(word)bytes);
+GC_scratch_free_ptr-=bytes;
+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;
+}
+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*alloc_hdr(void)
+{
+hdr*result;
+if (NULL==GC_hdr_free_list){
+result=(hdr*)GC_scratch_alloc(sizeof(hdr));
+} else {
+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*)GC_hdr_free_list;
+GC_hdr_free_list=hhdr;
+}
+#ifdef COUNT_HDR_CACHE_HITS
+word GC_hdr_cache_hits=0;
+word GC_hdr_cache_misses=0;
+#endif
+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");
+EXIT();
+}
+BZERO(GC_all_nils,sizeof(bottom_index));
+for (i=0;i < TOP_SZ;i++){
+GC_top_index[i]=GC_all_nils;
+}
+}
+static GC_bool get_index(word addr)
+{
+word hi=(word)(addr)>>(LOG_BOTTOM_SZ+LOG_HBLKSIZE);
+bottom_index*r;
+bottom_index*p;
+bottom_index**prev;
+bottom_index*pi;
+word i;
+GC_ASSERT(I_HOLD_LOCK());
+#ifdef HASH_TL
+i=TL_HASH(hi);
+pi=p=GC_top_index[i];
+while(p!=GC_all_nils){
+if (p->key==hi)return(TRUE);
+p=p->hash_link;
+}
+#else
+if (GC_top_index[hi]!=GC_all_nils)
+return TRUE;
+i=hi;
+#endif
+r=(bottom_index*)GC_scratch_alloc(sizeof(bottom_index));
+if (EXPECT(NULL==r,FALSE))
+return FALSE;
+BZERO(r,sizeof(bottom_index));
+r->key=hi;
+#ifdef HASH_TL
+r->hash_link=pi;
+#endif
+prev=&GC_all_bottom_indices;
+pi=0;
+while ((p=*prev)!=0&&p->key < hi){
+pi=p;
+prev=&(p->asc_link);
+}
+r->desc_link=pi;
+if (0==p){
+GC_all_bottom_indices_end=r;
+} else {
+p->desc_link=r;
+}
+r->asc_link=p;
+*prev=r;
+GC_top_index[i]=r;
+return(TRUE);
+}
+GC_INNER struct hblkhdr*GC_install_header(struct hblk*h)
+{
+hdr*result;
+if (!get_index((word)h))return(0);
+result=alloc_hdr();
+if (result){
+SET_HDR(h,result);
+#ifdef USE_MUNMAP
+result->hb_last_reclaimed=(unsigned short)GC_gc_no;
+#endif
+}
+return(result);
+}
+GC_INNER GC_bool GC_install_counts(struct hblk*h,size_t sz)
+{
+struct hblk*hbp;
+for (hbp=h;(word)hbp < (word)h+sz;hbp+=BOTTOM_SZ){
+if (!get_index((word)hbp))
+return FALSE;
+if ((word)hbp > GC_WORD_MAX - (word)BOTTOM_SZ*HBLKSIZE)
+break;
+}
+if (!get_index((word)h+sz - 1))
+return FALSE;
+for (hbp=h+1;(word)hbp < (word)h+sz;hbp+=1){
+word i=HBLK_PTR_DIFF(hbp,h);
+SET_HDR(hbp,(hdr*)(i > MAX_JUMP?MAX_JUMP:i));
+}
+return TRUE;
+}
+GC_INNER void GC_remove_header(struct hblk*h)
+{
+hdr**ha;
+GET_HDR_ADDR(h,ha);
+free_hdr(*ha);
+*ha=0;
+}
+GC_INNER void GC_remove_counts(struct hblk*h,size_t sz)
+{
+struct hblk*hbp;
+for (hbp=h+1;(word)hbp < (word)h+sz;hbp+=1){
+SET_HDR(hbp,0);
+}
+}
+void GC_apply_to_all_blocks(void (*fn)(struct hblk*h,word client_data),
+word client_data)
+{
+signed_word j;
+bottom_index*index_p;
+for (index_p=GC_all_bottom_indices;index_p!=0;
+index_p=index_p->asc_link){
+for (j=BOTTOM_SZ-1;j>=0;){
+if (!IS_FORWARDING_ADDR_OR_NIL(index_p->index[j])){
+if (!HBLK_IS_FREE(index_p->index[j])){
+(*fn)(((struct hblk*)
+(((index_p->key<<LOG_BOTTOM_SZ)+(word)j)
+<<LOG_HBLKSIZE)),
+client_data);
+}
+j--;
+} else if (index_p->index[j]==0){
+j--;
+} else {
+j-=(signed_word)(index_p->index[j]);
+}
+}
+}
+}
+GC_INNER struct hblk*GC_next_block(struct hblk*h,GC_bool allow_free)
+{
+REGISTER bottom_index*bi;
+REGISTER word j=((word)h>>LOG_HBLKSIZE)&(BOTTOM_SZ-1);
+GC_ASSERT(I_HOLD_LOCK());
+GET_BI(h,bi);
+if (bi==GC_all_nils){
+REGISTER word hi=(word)h>>(LOG_BOTTOM_SZ+LOG_HBLKSIZE);
+bi=GC_all_bottom_indices;
+while (bi!=0&&bi->key < hi)bi=bi->asc_link;
+j=0;
+}
+while (bi!=0){
+while (j < BOTTOM_SZ){
+hdr*hhdr=bi->index[j];
+if (IS_FORWARDING_ADDR_OR_NIL(hhdr)){
+j++;
+} else {
+if (allow_free||!HBLK_IS_FREE(hhdr)){
+return ((struct hblk*)
+(((bi->key<<LOG_BOTTOM_SZ)+j)
+<<LOG_HBLKSIZE));
+} else {
+j+=divHBLKSZ(hhdr->hb_sz);
+}
+}
+}
+j=0;
+bi=bi->asc_link;
+}
+return(0);
+}
+GC_INNER struct hblk*GC_prev_block(struct hblk*h)
+{
+bottom_index*bi;
+signed_word j=((word)h>>LOG_HBLKSIZE)&(BOTTOM_SZ-1);
+GC_ASSERT(I_HOLD_LOCK());
+GET_BI(h,bi);
+if (bi==GC_all_nils){
+word hi=(word)h>>(LOG_BOTTOM_SZ+LOG_HBLKSIZE);
+bi=GC_all_bottom_indices_end;
+while (bi!=0&&bi->key > hi)bi=bi->desc_link;
+j=BOTTOM_SZ - 1;
+}
+while(bi!=0){
+while (j>=0){
+hdr*hhdr=bi->index[j];
+if (0==hhdr){
+--j;
+} else if (IS_FORWARDING_ADDR_OR_NIL(hhdr)){
+j-=(signed_word)hhdr;
+} else {
+return((struct hblk*)
+(((bi->key<<LOG_BOTTOM_SZ)+j)
+<<LOG_HBLKSIZE));
+}
+}
+j=BOTTOM_SZ - 1;
+bi=bi->desc_link;
+}
+return(0);
+}
+#include <stdio.h>
+#ifndef SMALL_CONFIG
+STATIC ptr_t GC_build_fl_clear2(struct hblk*h,ptr_t ofl)
+{
+word*p=(word*)(h->hb_body);
+word*lim=(word*)(h+1);
+p[0]=(word)ofl;
+p[1]=0;
+p[2]=(word)p;
+p[3]=0;
+p+=4;
+for (;(word)p < (word)lim;p+=4){
+p[0]=(word)(p-2);
+p[1]=0;
+p[2]=(word)p;
+p[3]=0;
+};
+return((ptr_t)(p-2));
+}
+STATIC ptr_t GC_build_fl_clear4(struct hblk*h,ptr_t ofl)
+{
+word*p=(word*)(h->hb_body);
+word*lim=(word*)(h+1);
+p[0]=(word)ofl;
+p[1]=0;
+p[2]=0;
+p[3]=0;
+p+=4;
+for (;(word)p < (word)lim;p+=4){
+GC_PREFETCH_FOR_WRITE((ptr_t)(p+64));
+p[0]=(word)(p-4);
+p[1]=0;
+CLEAR_DOUBLE(p+2);
+};
+return((ptr_t)(p-4));
+}
+STATIC ptr_t GC_build_fl2(struct hblk*h,ptr_t ofl)
+{
+word*p=(word*)(h->hb_body);
+word*lim=(word*)(h+1);
+p[0]=(word)ofl;
+p[2]=(word)p;
+p+=4;
+for (;(word)p < (word)lim;p+=4){
+p[0]=(word)(p-2);
+p[2]=(word)p;
+};
+return((ptr_t)(p-2));
+}
+STATIC ptr_t GC_build_fl4(struct hblk*h,ptr_t ofl)
+{
+word*p=(word*)(h->hb_body);
+word*lim=(word*)(h+1);
+p[0]=(word)ofl;
+p[4]=(word)p;
+p+=8;
+for (;(word)p < (word)lim;p+=8){
+GC_PREFETCH_FOR_WRITE((ptr_t)(p+64));
+p[0]=(word)(p-4);
+p[4]=(word)p;
+};
+return((ptr_t)(p-4));
+}
+#endif
+GC_INNER ptr_t GC_build_fl(struct hblk*h,size_t sz,GC_bool clear,
+ptr_t list)
+{
+word*p,*prev;
+word*last_object;
+GC_PREFETCH_FOR_WRITE((ptr_t)h);
+GC_PREFETCH_FOR_WRITE((ptr_t)h+128);
+GC_PREFETCH_FOR_WRITE((ptr_t)h+256);
+GC_PREFETCH_FOR_WRITE((ptr_t)h+378);
+#ifndef SMALL_CONFIG
+switch (sz){
+case 2:if (clear){
+return GC_build_fl_clear2(h,list);
+} else {
+return GC_build_fl2(h,list);
+}
+case 4:if (clear){
+return GC_build_fl_clear4(h,list);
+} else {
+return GC_build_fl4(h,list);
+}
+default:
+break;
+}
+#endif
+if (clear)BZERO(h,HBLKSIZE);
+p=(word*)(h->hb_body)+sz;
+prev=(word*)(h->hb_body);
+last_object=(word*)((char*)h+HBLKSIZE);
+last_object-=sz;
+while ((word)p<=(word)last_object){
+obj_link(p)=(ptr_t)prev;
+prev=p;
+p+=sz;
+}
+p-=sz;
+*(ptr_t*)h=list;
+return ((ptr_t)p);
+}
+GC_INNER void GC_new_hblk(size_t gran,int kind)
+{
+struct hblk*h;
+GC_bool clear=GC_obj_kinds[kind].ok_init;
+GC_STATIC_ASSERT((sizeof (struct hblk))==HBLKSIZE);
+if (GC_debugging_started)clear=TRUE;
+h=GC_allochblk(GRANULES_TO_BYTES(gran),kind,0);
+if (h==0)return;
+if (IS_UNCOLLECTABLE(kind))GC_set_hdr_marks(HDR(h));
+GC_obj_kinds[kind].ok_freelist[gran]=
+GC_build_fl(h,GRANULES_TO_WORDS(gran),clear,
+(ptr_t)GC_obj_kinds[kind].ok_freelist[gran]);
+}
+GC_API void GC_CALL GC_register_displacement(size_t offset)
+{
+DCL_LOCK_STATE;
+LOCK();
+GC_register_displacement_inner(offset);
+UNLOCK();
+}
+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");
+}
+if (!GC_valid_offsets[offset]){
+GC_valid_offsets[offset]=TRUE;
+GC_modws_valid_offsets[offset % sizeof(word)]=TRUE;
+}
+}
+#ifdef MARK_BIT_PER_GRANULE
+GC_INNER GC_bool GC_add_map_entry(size_t granules)
+{
+unsigned displ;
+unsigned short*new_map;
+if (granules > BYTES_TO_GRANULES(MAXOBJBYTES))granules=0;
+if (GC_obj_map[granules]!=0){
+return(TRUE);
+}
+new_map=(unsigned short*)GC_scratch_alloc(MAP_LEN*sizeof(short));
+if (new_map==0)return(FALSE);
+GC_COND_LOG_PRINTF(
+"Adding block map for size of %u granules (%u bytes)\n",
+(unsigned)granules,(unsigned)GRANULES_TO_BYTES(granules));
+if (granules==0){
+for (displ=0;displ < BYTES_TO_GRANULES(HBLKSIZE);displ++){
+new_map[displ]=1;
+}
+} else {
+for (displ=0;displ < BYTES_TO_GRANULES(HBLKSIZE);displ++){
+new_map[displ]=(unsigned short)(displ % granules);
+}
+}
+GC_obj_map[granules]=new_map;
+return(TRUE);
+}
+#endif
+GC_INNER void GC_initialize_offsets(void)
+{
+unsigned i;
+if (GC_all_interior_pointers){
+for (i=0;i < VALID_OFFSET_SZ;++i)
+GC_valid_offsets[i]=TRUE;
+} else {
+BZERO(GC_valid_offsets,sizeof(GC_valid_offsets));
+for (i=0;i < sizeof(word);++i)
+GC_modws_valid_offsets[i]=FALSE;
+}
+}
+STATIC void GC_CALLBACK GC_default_same_obj_print_proc(void*p,void*q)
+{
+ABORT_ARG2("GC_same_obj test failed",
+":%p and %p are not in the same object",p,q);
+}
+void (GC_CALLBACK*GC_same_obj_print_proc)(void*,void*)
+=GC_default_same_obj_print_proc;
+GC_API void*GC_CALL GC_same_obj(void*p,void*q)
+{
+struct hblk*h;
+hdr*hhdr;
+ptr_t base,limit;
+word sz;
+if (!EXPECT(GC_is_initialized,TRUE))GC_init();
+hhdr=HDR((word)p);
+if (hhdr==0){
+if (divHBLKSZ((word)p)!=divHBLKSZ((word)q)
+&&HDR((word)q)!=0){
+goto fail;
+}
+return(p);
+}
+if (IS_FORWARDING_ADDR_OR_NIL(hhdr)){
+h=HBLKPTR(p)- (word)hhdr;
+hhdr=HDR(h);
+while (IS_FORWARDING_ADDR_OR_NIL(hhdr)){
+h=FORWARDED_ADDR(h,hhdr);
+hhdr=HDR(h);
+}
+limit=(ptr_t)h+hhdr->hb_sz;
+if ((word)p>=(word)limit||(word)q>=(word)limit
+||(word)q < (word)h){
+goto fail;
+}
+return(p);
+}
+sz=hhdr->hb_sz;
+if (sz > MAXOBJBYTES){
+base=(ptr_t)HBLKPTR(p);
+limit=base+sz;
+if ((word)p>=(word)limit){
+goto fail;
+}
+} else {
+size_t offset;
+size_t pdispl=HBLKDISPL(p);
+offset=pdispl % sz;
+if (HBLKPTR(p)!=HBLKPTR(q))goto fail;
+base=(ptr_t)p - offset;
+limit=base+sz;
+}
+if ((word)q>=(word)limit||(word)q < (word)base){
+goto fail;
+}
+return(p);
+fail:
+(*GC_same_obj_print_proc)((ptr_t)p,(ptr_t)q);
+return(p);
+}
+STATIC void GC_CALLBACK GC_default_is_valid_displacement_print_proc (void*p)
+{
+ABORT_ARG1("GC_is_valid_displacement test failed",":%p not valid",p);
+}
+void (GC_CALLBACK*GC_is_valid_displacement_print_proc)(void*)=
+GC_default_is_valid_displacement_print_proc;
+GC_API void*GC_CALL GC_is_valid_displacement(void*p)
+{
+hdr*hhdr;
+word pdispl;
+word offset;
+struct hblk*h;
+word sz;
+if (!EXPECT(GC_is_initialized,TRUE))GC_init();
+hhdr=HDR((word)p);
+if (hhdr==0)return(p);
+h=HBLKPTR(p);
+if (GC_all_interior_pointers){
+while (IS_FORWARDING_ADDR_OR_NIL(hhdr)){
+h=FORWARDED_ADDR(h,hhdr);
+hhdr=HDR(h);
+}
+} else if (IS_FORWARDING_ADDR_OR_NIL(hhdr)){
+goto fail;
+}
+sz=hhdr->hb_sz;
+pdispl=HBLKDISPL(p);
+offset=pdispl % sz;
+if ((sz > MAXOBJBYTES&&(word)p>=(word)h+sz)
+||!GC_valid_offsets[offset]
+||((word)p+(sz - offset)> (word)(h+1)
+&&!IS_FORWARDING_ADDR_OR_NIL(HDR(h+1)))){
+goto fail;
+}
+return(p);
+fail:
+(*GC_is_valid_displacement_print_proc)((ptr_t)p);
+return(p);
+}
+STATIC void GC_CALLBACK GC_default_is_visible_print_proc(void*p)
+{
+ABORT_ARG1("GC_is_visible test failed",":%p not GC-visible",p);
+}
+void (GC_CALLBACK*GC_is_visible_print_proc)(void*p)=
+GC_default_is_visible_print_proc;
+#ifndef THREADS
+STATIC GC_bool GC_on_stack(void*p)
+{
+#ifdef STACK_GROWS_DOWN
+if ((word)p>=(word)GC_approx_sp()
+&&(word)p < (word)GC_stackbottom){
+return(TRUE);
+}
+#else
+if ((word)p<=(word)GC_approx_sp()
+&&(word)p > (word)GC_stackbottom){
+return(TRUE);
+}
+#endif
+return(FALSE);
+}
+#endif
+GC_API void*GC_CALL GC_is_visible(void*p)
+{
+hdr*hhdr;
+if ((word)p&(ALIGNMENT - 1))goto fail;
+if (!EXPECT(GC_is_initialized,TRUE))GC_init();
+#ifdef THREADS
+hhdr=HDR((word)p);
+if (hhdr!=0&&GC_base(p)==0){
+goto fail;
+} else {
+return(p);
+}
+#else
+if (GC_on_stack(p))return(p);
+hhdr=HDR((word)p);
+if (hhdr==0){
+if (GC_is_static_root(p))return(p);
+#if defined(DYNAMIC_LOADING)||defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32)||defined(PCR)
+GC_register_dynamic_libraries();
+if (GC_is_static_root(p))
+return(p);
+#endif
+goto fail;
+} else {
+word descr;
+ptr_t base=(ptr_t)GC_base(p);
+if (NULL==base)goto fail;
+if (HBLKPTR(base)!=HBLKPTR(p))
+hhdr=HDR(base);
+descr=hhdr->hb_descr;
+retry:
+switch(descr&GC_DS_TAGS){
+case GC_DS_LENGTH:
+if ((word)p - (word)base > descr)goto fail;
+break;
+case GC_DS_BITMAP:
+if ((word)p - (word)base>=WORDS_TO_BYTES(BITMAP_BITS)
+||((word)p&(sizeof(word)- 1)))goto fail;
+if (!(((word)1<<(WORDSZ - ((ptr_t)p - (ptr_t)base)- 1))
+&descr))goto fail;
+break;
+case GC_DS_PROC:
+break;
+case GC_DS_PER_OBJECT:
+if ((signed_word)descr>=0){
+descr=*(word*)((ptr_t)base+(descr&~GC_DS_TAGS));
+} else {
+ptr_t type_descr=*(ptr_t*)base;
+descr=*(word*)(type_descr
+- (descr - (word)(GC_DS_PER_OBJECT
+- GC_INDIR_PER_OBJ_BIAS)));
+}
+goto retry;
+}
+return(p);
+}
+#endif
+fail:
+(*GC_is_visible_print_proc)((ptr_t)p);
+return(p);
+}
+GC_API void*GC_CALL GC_pre_incr (void**p,ptrdiff_t how_much)
+{
+void*initial=*p;
+void*result=GC_same_obj((void*)((ptr_t)initial+how_much),initial);
+if (!GC_all_interior_pointers){
+(void)GC_is_valid_displacement(result);
+}
+return (*p=result);
+}
+GC_API void*GC_CALL GC_post_incr (void**p,ptrdiff_t how_much)
+{
+void*initial=*p;
+void*result=GC_same_obj((void*)((ptr_t)initial+how_much),initial);
+if (!GC_all_interior_pointers){
+(void)GC_is_valid_displacement(result);
+}
+*p=result;
+return(initial);
+}
+#ifndef GC_INLINE_H
+#define GC_INLINE_H
+#if GC_GNUC_PREREQ(3,0)
+#define GC_EXPECT(expr,outcome)__builtin_expect(expr,outcome)
+#else
+#define GC_EXPECT(expr,outcome)(expr)
+#endif
+#ifndef GC_ASSERT
+#ifdef NDEBUG
+#define GC_ASSERT(expr)
+#else
+#include <assert.h>
+#define GC_ASSERT(expr)assert(expr)
+#endif
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifndef GC_PREFETCH_FOR_WRITE
+#if GC_GNUC_PREREQ(3,0)&&!defined(GC_NO_PREFETCH_FOR_WRITE)
+#define GC_PREFETCH_FOR_WRITE(x)__builtin_prefetch((x),1)
+#else
+#define GC_PREFETCH_FOR_WRITE(x)(void)0
+#endif
+#endif
+#define GC_I_PTRFREE 0
+#define GC_I_NORMAL 1
+GC_API void GC_CALL GC_generic_malloc_many(size_t,int,
+void**);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_malloc_kind(size_t,int);
+#ifdef GC_THREADS
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_malloc_kind_global(size_t,int);
+#else
+#define GC_malloc_kind_global GC_malloc_kind
+#endif
+#if defined(GC_THREADS)&&defined(AO_HAVE_store)
+#define GC_FAST_M_AO_STORE(my_fl,next)AO_store((volatile AO_t*)(my_fl),(AO_t)(next))
+#else
+#define GC_FAST_M_AO_STORE(my_fl,next)(void)(*(my_fl)=(next))
+#endif
+#define GC_FAST_MALLOC_GRANS(result,granules,tiny_fl,num_direct,kind,default_expr,init)do { if (GC_EXPECT((granules)>=GC_TINY_FREELISTS,0)){ result=(default_expr);} else { void**my_fl=(tiny_fl)+(granules);void*my_entry=*my_fl;void*next;for (;;){ if (GC_EXPECT((GC_word)my_entry > (num_direct)+GC_TINY_FREELISTS+1,1)){ next=*(void**)(my_entry);result=(void*)my_entry;GC_FAST_M_AO_STORE(my_fl,next);init;GC_PREFETCH_FOR_WRITE(next);if ((kind)!=GC_I_PTRFREE){ GC_end_stubborn_change(my_fl);GC_reachable_here(next);} GC_ASSERT(GC_size(result)>=(granules)*GC_GRANULE_BYTES);GC_ASSERT((kind)==GC_I_PTRFREE||((GC_word*)result)[1]==0);break;} if ((GC_signed_word)my_entry - (GC_signed_word)(num_direct)<=0&&my_entry!=0){ GC_FAST_M_AO_STORE(my_fl,(char*)my_entry+(granules)+1);result=(default_expr);break;} else { GC_generic_malloc_many(((granules)==0?GC_GRANULE_BYTES:GC_RAW_BYTES_FROM_INDEX(granules)),kind,my_fl);my_entry=*my_fl;if (my_entry==0){ result=(*GC_get_oom_fn())((granules)*GC_GRANULE_BYTES);break;} } } } } while (0)
+#define GC_WORDS_TO_WHOLE_GRANULES(n)GC_WORDS_TO_GRANULES((n)+GC_GRANULE_WORDS - 1)
+#define GC_MALLOC_WORDS_KIND(result,n,tiny_fl,kind,init)do { size_t granules=GC_WORDS_TO_WHOLE_GRANULES(n);GC_FAST_MALLOC_GRANS(result,granules,tiny_fl,0,kind,GC_malloc_kind(granules*GC_GRANULE_BYTES,kind),init);} while (0)
+#define GC_MALLOC_WORDS(result,n,tiny_fl)GC_MALLOC_WORDS_KIND(result,n,tiny_fl,GC_I_NORMAL,*(void**)(result)=0)
+#define GC_MALLOC_ATOMIC_WORDS(result,n,tiny_fl)GC_MALLOC_WORDS_KIND(result,n,tiny_fl,GC_I_PTRFREE,(void)0)
+#define GC_CONS(result,first,second,tiny_fl)do { void*l=(void*)(first);void*r=(void*)(second);GC_MALLOC_WORDS_KIND(result,2,tiny_fl,GC_I_NORMAL,(void)0);if ((result)!=0){*(void**)(result)=l;GC_PTR_STORE_AND_DIRTY((void**)(result)+1,r);GC_reachable_here(l);} } while (0)
+GC_API void GC_CALL GC_print_free_list(int,
+size_t);
+#ifdef __cplusplus
+}
+#endif
+#endif
+#include <stdio.h>
+#ifdef GC_USE_ENTIRE_HEAP
+int GC_use_entire_heap=TRUE;
+#else
+int GC_use_entire_heap=FALSE;
+#endif
+#define MAX_BLACK_LIST_ALLOC (2*HBLKSIZE)
+#define UNIQUE_THRESHOLD 32
+#define HUGE_THRESHOLD 256
+#define FL_COMPRESSION 8
+#define N_HBLK_FLS ((HUGE_THRESHOLD - UNIQUE_THRESHOLD)/FL_COMPRESSION+UNIQUE_THRESHOLD)
+#ifndef GC_GCJ_SUPPORT
+STATIC
+#endif
+struct hblk*GC_hblkfreelist[N_HBLK_FLS+1]={ 0 };
+#ifndef GC_GCJ_SUPPORT
+STATIC
+#endif
+word GC_free_bytes[N_HBLK_FLS+1]={ 0 };
+GC_INLINE int GC_enough_large_bytes_left(void)
+{
+int n;
+word bytes=GC_large_allocd_bytes;
+GC_ASSERT(GC_max_large_allocd_bytes<=GC_heapsize);
+for (n=N_HBLK_FLS;n>=0;--n){
+bytes+=GC_free_bytes[n];
+if (bytes>=GC_max_large_allocd_bytes)return n;
+}
+return 0;
+}
+STATIC int GC_hblk_fl_from_blocks(word blocks_needed)
+{
+if (blocks_needed<=UNIQUE_THRESHOLD)return (int)blocks_needed;
+if (blocks_needed>=HUGE_THRESHOLD)return N_HBLK_FLS;
+return (int)(blocks_needed - UNIQUE_THRESHOLD)/FL_COMPRESSION
++UNIQUE_THRESHOLD;
+}
+#define PHDR(hhdr)HDR((hhdr)->hb_prev)
+#define NHDR(hhdr)HDR((hhdr)->hb_next)
+#ifdef USE_MUNMAP
+#define IS_MAPPED(hhdr)(((hhdr)->hb_flags&WAS_UNMAPPED)==0)
+#else
+#define IS_MAPPED(hhdr)TRUE
+#endif
+#if!defined(NO_DEBUGGING)||defined(GC_ASSERTIONS)
+GC_INNER word GC_compute_large_free_bytes(void)
+{
+word total_free=0;
+unsigned i;
+for (i=0;i<=N_HBLK_FLS;++i){
+struct hblk*h;
+hdr*hhdr;
+for (h=GC_hblkfreelist[i];h!=0;h=hhdr->hb_next){
+hhdr=HDR(h);
+total_free+=hhdr->hb_sz;
+}
+}
+return total_free;
+}
+#endif
+#if!defined(NO_DEBUGGING)
+void GC_print_hblkfreelist(void)
+{
+unsigned i;
+word total;
+for (i=0;i<=N_HBLK_FLS;++i){
+struct hblk*h=GC_hblkfreelist[i];
+if (0!=h)GC_printf("Free list %u (total size %lu):\n",
+i,(unsigned long)GC_free_bytes[i]);
+while (h){
+hdr*hhdr=HDR(h);
+GC_printf("\t%p size %lu %s black listed\n",
+(void*)h,(unsigned long)hhdr->hb_sz,
+GC_is_black_listed(h,HBLKSIZE)!=0?"start":
+GC_is_black_listed(h,hhdr->hb_sz)!=0?"partially":
+"not");
+h=hhdr->hb_next;
+}
+}
+GC_printf("GC_large_free_bytes:%lu\n",
+(unsigned long)GC_large_free_bytes);
+if ((total=GC_compute_large_free_bytes())!=GC_large_free_bytes)
+GC_err_printf("GC_large_free_bytes INCONSISTENT!!Should be:%lu\n",
+(unsigned long)total);
+}
+static int free_list_index_of(hdr*wanted)
+{
+int i;
+for (i=0;i<=N_HBLK_FLS;++i){
+struct hblk*h;
+hdr*hhdr;
+for (h=GC_hblkfreelist[i];h!=0;h=hhdr->hb_next){
+hhdr=HDR(h);
+if (hhdr==wanted)return i;
+}
+}
+return -1;
+}
+GC_API void GC_CALL GC_dump_regions(void)
+{
+unsigned i;
+for (i=0;i < GC_n_heap_sects;++i){
+ptr_t start=GC_heap_sects[i].hs_start;
+size_t bytes=GC_heap_sects[i].hs_bytes;
+ptr_t end=start+bytes;
+ptr_t p;
+while (i+1 < GC_n_heap_sects&&GC_heap_sects[i+1].hs_start==end){
+++i;
+end=GC_heap_sects[i].hs_start+GC_heap_sects[i].hs_bytes;
+}
+GC_printf("***Section from %p to %p\n",(void*)start,(void*)end);
+for (p=start;(word)p < (word)end;){
+hdr*hhdr=HDR(p);
+if (IS_FORWARDING_ADDR_OR_NIL(hhdr)){
+GC_printf("\t%p Missing header!!(%p)\n",
+(void*)p,(void*)hhdr);
+p+=HBLKSIZE;
+continue;
+}
+if (HBLK_IS_FREE(hhdr)){
+int correct_index=GC_hblk_fl_from_blocks(
+divHBLKSZ(hhdr->hb_sz));
+int actual_index;
+GC_printf("\t%p\tfree block of size 0x%lx bytes%s\n",
+(void*)p,(unsigned long)(hhdr->hb_sz),
+IS_MAPPED(hhdr)?"":" (unmapped)");
+actual_index=free_list_index_of(hhdr);
+if (-1==actual_index){
+GC_printf("\t\tBlock not on free list %d!!\n",
+correct_index);
+} else if (correct_index!=actual_index){
+GC_printf("\t\tBlock on list %d,should be on %d!!\n",
+actual_index,correct_index);
+}
+p+=hhdr->hb_sz;
+} else {
+GC_printf("\t%p\tused for blocks of size 0x%lx bytes\n",
+(void*)p,(unsigned long)(hhdr->hb_sz));
+p+=HBLKSIZE*OBJ_SZ_TO_BLOCKS(hhdr->hb_sz);
+}
+}
+}
+}
+#endif
+static GC_bool setup_header(hdr*hhdr,struct hblk*block,size_t byte_sz,
+int kind,unsigned flags)
+{
+word descr;
+#ifdef MARK_BIT_PER_GRANULE
+if (byte_sz > MAXOBJBYTES)
+flags|=LARGE_BLOCK;
+#endif
+#ifdef ENABLE_DISCLAIM
+if (GC_obj_kinds[kind].ok_disclaim_proc)
+flags|=HAS_DISCLAIM;
+if (GC_obj_kinds[kind].ok_mark_unconditionally)
+flags|=MARK_UNCONDITIONALLY;
+#endif
+hhdr->hb_sz=byte_sz;
+hhdr->hb_obj_kind=(unsigned char)kind;
+hhdr->hb_flags=(unsigned char)flags;
+hhdr->hb_block=block;
+descr=GC_obj_kinds[kind].ok_descriptor;
+if (GC_obj_kinds[kind].ok_relocate_descr)descr+=byte_sz;
+hhdr->hb_descr=descr;
+#ifdef MARK_BIT_PER_OBJ
+if (byte_sz > MAXOBJBYTES){
+hhdr->hb_inv_sz=LARGE_INV_SZ;
+} else {
+word inv_sz;
+#if CPP_WORDSZ==64
+inv_sz=((word)1<<32)/byte_sz;
+if (((inv_sz*byte_sz)>>32)==0)++inv_sz;
+#else
+GC_ASSERT(byte_sz>=4);
+inv_sz=((unsigned)1<<31)/byte_sz;
+inv_sz*=2;
+while (inv_sz*byte_sz > byte_sz)++inv_sz;
+#endif
+#ifdef INV_SZ_COMPUTATION_CHECK
+GC_ASSERT(((1ULL<<32)+byte_sz - 1)/byte_sz==inv_sz);
+#endif
+hhdr->hb_inv_sz=inv_sz;
+}
+#endif
+#ifdef MARK_BIT_PER_GRANULE
+{
+size_t granules=BYTES_TO_GRANULES(byte_sz);
+if (EXPECT(!GC_add_map_entry(granules),FALSE)){
+hhdr->hb_sz=HBLKSIZE;
+hhdr->hb_descr=0;
+hhdr->hb_flags|=LARGE_BLOCK;
+hhdr->hb_map=0;
+return FALSE;
+}
+hhdr->hb_map=GC_obj_map[(hhdr->hb_flags&LARGE_BLOCK)!=0?
+0:granules];
+}
+#endif
+GC_clear_hdr_marks(hhdr);
+hhdr->hb_last_reclaimed=(unsigned short)GC_gc_no;
+return(TRUE);
+}
+STATIC void GC_remove_from_fl_at(hdr*hhdr,int index)
+{
+GC_ASSERT(((hhdr->hb_sz)&(HBLKSIZE-1))==0);
+if (hhdr->hb_prev==0){
+GC_ASSERT(HDR(GC_hblkfreelist[index])==hhdr);
+GC_hblkfreelist[index]=hhdr->hb_next;
+} else {
+hdr*phdr;
+GET_HDR(hhdr->hb_prev,phdr);
+phdr->hb_next=hhdr->hb_next;
+}
+GC_ASSERT(GC_free_bytes[index]>=hhdr->hb_sz);
+GC_free_bytes[index]-=hhdr->hb_sz;
+if (0!=hhdr->hb_next){
+hdr*nhdr;
+GC_ASSERT(!IS_FORWARDING_ADDR_OR_NIL(NHDR(hhdr)));
+GET_HDR(hhdr->hb_next,nhdr);
+nhdr->hb_prev=hhdr->hb_prev;
+}
+}
+GC_INLINE void GC_remove_from_fl(hdr*hhdr)
+{
+GC_remove_from_fl_at(hhdr,GC_hblk_fl_from_blocks(divHBLKSZ(hhdr->hb_sz)));
+}
+static struct hblk*get_block_ending_at(struct hblk*h)
+{
+struct hblk*p=h - 1;
+hdr*phdr;
+GET_HDR(p,phdr);
+while (0!=phdr&&IS_FORWARDING_ADDR_OR_NIL(phdr)){
+p=FORWARDED_ADDR(p,phdr);
+phdr=HDR(p);
+}
+if (0!=phdr){
+return p;
+}
+p=GC_prev_block(h - 1);
+if (p){
+phdr=HDR(p);
+if ((ptr_t)p+phdr->hb_sz==(ptr_t)h){
+return p;
+}
+}
+return NULL;
+}
+STATIC struct hblk*GC_free_block_ending_at(struct hblk*h)
+{
+struct hblk*p=get_block_ending_at(h);
+if (p){
+hdr*phdr=HDR(p);
+if (HBLK_IS_FREE(phdr)){
+return p;
+}
+}
+return 0;
+}
+STATIC void GC_add_to_fl(struct hblk*h,hdr*hhdr)
+{
+int index=GC_hblk_fl_from_blocks(divHBLKSZ(hhdr->hb_sz));
+struct hblk*second=GC_hblkfreelist[index];
+#if defined(GC_ASSERTIONS)&&!defined(USE_MUNMAP)
+struct hblk*next=(struct hblk*)((word)h+hhdr->hb_sz);
+hdr*nexthdr=HDR(next);
+struct hblk*prev=GC_free_block_ending_at(h);
+hdr*prevhdr=HDR(prev);
+GC_ASSERT(nexthdr==0||!HBLK_IS_FREE(nexthdr)
+||(GC_heapsize&SIGNB)!=0);
+GC_ASSERT(prev==0||!HBLK_IS_FREE(prevhdr)
+||(GC_heapsize&SIGNB)!=0);
+#endif
+GC_ASSERT(((hhdr->hb_sz)&(HBLKSIZE-1))==0);
+GC_hblkfreelist[index]=h;
+GC_free_bytes[index]+=hhdr->hb_sz;
+GC_ASSERT(GC_free_bytes[index]<=GC_large_free_bytes);
+hhdr->hb_next=second;
+hhdr->hb_prev=0;
+if (second){
+hdr*second_hdr;
+GET_HDR(second,second_hdr);
+second_hdr->hb_prev=h;
+}
+hhdr->hb_flags|=FREE_BLK;
+}
+#ifdef USE_MUNMAP
+#ifndef MUNMAP_THRESHOLD
+#define MUNMAP_THRESHOLD 6
+#endif
+GC_INNER int GC_unmap_threshold=MUNMAP_THRESHOLD;
+#ifdef COUNT_UNMAPPED_REGIONS
+static int calc_num_unmapped_regions_delta(struct hblk*h,hdr*hhdr)
+{
+struct hblk*prev=get_block_ending_at(h);
+struct hblk*next;
+GC_bool prev_unmapped=FALSE;
+GC_bool next_unmapped=FALSE;
+next=GC_next_block((struct hblk*)((ptr_t)h+hhdr->hb_sz),TRUE);
+if ((ptr_t)next!=GC_unmap_end((ptr_t)h,(size_t)hhdr->hb_sz)){
+next=NULL;
+}
+if (prev!=NULL){
+hdr*prevhdr=HDR(prev);
+prev_unmapped=!IS_MAPPED(prevhdr);
+}
+if (next!=NULL){
+hdr*nexthdr=HDR(next);
+next_unmapped=!IS_MAPPED(nexthdr);
+}
+if (prev_unmapped&&next_unmapped){
+return IS_MAPPED(hhdr)?-1:1;
+}
+if (!prev_unmapped&&!next_unmapped){
+return IS_MAPPED(hhdr)?1:-1;
+}
+return 0;
+}
+#endif
+GC_INLINE void GC_adjust_num_unmapped(struct hblk*h GC_ATTR_UNUSED,
+hdr*hhdr GC_ATTR_UNUSED)
+{
+#ifdef COUNT_UNMAPPED_REGIONS
+GC_num_unmapped_regions+=calc_num_unmapped_regions_delta(h,hhdr);
+#endif
+}
+GC_INNER void GC_unmap_old(void)
+{
+int i;
+if (GC_unmap_threshold==0)
+return;
+#ifdef COUNT_UNMAPPED_REGIONS
+if (GC_num_unmapped_regions>=GC_UNMAPPED_REGIONS_SOFT_LIMIT)
+return;
+#endif
+for (i=0;i<=N_HBLK_FLS;++i){
+struct hblk*h;
+hdr*hhdr;
+for (h=GC_hblkfreelist[i];0!=h;h=hhdr->hb_next){
+hhdr=HDR(h);
+if (!IS_MAPPED(hhdr))continue;
+if ((unsigned short)(GC_gc_no - hhdr->hb_last_reclaimed)>
+(unsigned short)GC_unmap_threshold){
+#ifdef COUNT_UNMAPPED_REGIONS
+int delta=calc_num_unmapped_regions_delta(h,hhdr);
+signed_word regions=GC_num_unmapped_regions+delta;
+if (delta>=0&&regions>=GC_UNMAPPED_REGIONS_SOFT_LIMIT){
+GC_COND_LOG_PRINTF("Unmapped regions limit reached!\n");
+return;
+}
+GC_num_unmapped_regions=regions;
+#endif
+GC_unmap((ptr_t)h,(size_t)hhdr->hb_sz);
+hhdr->hb_flags|=WAS_UNMAPPED;
+}
+}
+}
+}
+GC_INNER void GC_merge_unmapped(void)
+{
+int i;
+for (i=0;i<=N_HBLK_FLS;++i){
+struct hblk*h=GC_hblkfreelist[i];
+while (h!=0){
+struct hblk*next;
+hdr*hhdr,*nexthdr;
+word size,nextsize;
+GET_HDR(h,hhdr);
+size=hhdr->hb_sz;
+next=(struct hblk*)((word)h+size);
+GET_HDR(next,nexthdr);
+if (0!=nexthdr&&HBLK_IS_FREE(nexthdr)
+&&(signed_word)(size+(nextsize=nexthdr->hb_sz))> 0
+){
+if (IS_MAPPED(hhdr)&&!IS_MAPPED(nexthdr)){
+if (size > nextsize){
+GC_adjust_num_unmapped(next,nexthdr);
+GC_remap((ptr_t)next,nextsize);
+} else {
+GC_adjust_num_unmapped(h,hhdr);
+GC_unmap((ptr_t)h,size);
+GC_unmap_gap((ptr_t)h,size,(ptr_t)next,nextsize);
+hhdr->hb_flags|=WAS_UNMAPPED;
+}
+} else if (IS_MAPPED(nexthdr)&&!IS_MAPPED(hhdr)){
+if (size > nextsize){
+GC_adjust_num_unmapped(next,nexthdr);
+GC_unmap((ptr_t)next,nextsize);
+GC_unmap_gap((ptr_t)h,size,(ptr_t)next,nextsize);
+} else {
+GC_adjust_num_unmapped(h,hhdr);
+GC_remap((ptr_t)h,size);
+hhdr->hb_flags&=~WAS_UNMAPPED;
+hhdr->hb_last_reclaimed=nexthdr->hb_last_reclaimed;
+}
+} else if (!IS_MAPPED(hhdr)&&!IS_MAPPED(nexthdr)){
+GC_unmap_gap((ptr_t)h,size,(ptr_t)next,nextsize);
+}
+GC_remove_from_fl_at(hhdr,i);
+GC_remove_from_fl(nexthdr);
+hhdr->hb_sz+=nexthdr->hb_sz;
+GC_remove_header(next);
+GC_add_to_fl(h,hhdr);
+h=GC_hblkfreelist[i];
+} else {
+h=hhdr->hb_next;
+}
+}
+}
+}
+#endif
+STATIC struct hblk*GC_get_first_part(struct hblk*h,hdr*hhdr,
+size_t bytes,int index)
+{
+word total_size=hhdr->hb_sz;
+struct hblk*rest;
+hdr*rest_hdr;
+GC_ASSERT((total_size&(HBLKSIZE-1))==0);
+GC_remove_from_fl_at(hhdr,index);
+if (total_size==bytes)return h;
+rest=(struct hblk*)((word)h+bytes);
+rest_hdr=GC_install_header(rest);
+if (0==rest_hdr){
+WARN("Header allocation failed:dropping block\n",0);
+return(0);
+}
+rest_hdr->hb_sz=total_size - bytes;
+rest_hdr->hb_flags=0;
+#ifdef GC_ASSERTIONS
+hhdr->hb_flags&=~FREE_BLK;
+#endif
+GC_add_to_fl(rest,rest_hdr);
+return h;
+}
+STATIC void GC_split_block(struct hblk*h,hdr*hhdr,struct hblk*n,
+hdr*nhdr,int index)
+{
+word total_size=hhdr->hb_sz;
+word h_size=(word)n - (word)h;
+struct hblk*prev=hhdr->hb_prev;
+struct hblk*next=hhdr->hb_next;
+nhdr->hb_prev=prev;
+nhdr->hb_next=next;
+nhdr->hb_sz=total_size - h_size;
+nhdr->hb_flags=0;
+if (prev){
+HDR(prev)->hb_next=n;
+} else {
+GC_hblkfreelist[index]=n;
+}
+if (next){
+HDR(next)->hb_prev=n;
+}
+GC_ASSERT(GC_free_bytes[index] > h_size);
+GC_free_bytes[index]-=h_size;
+#ifdef USE_MUNMAP
+hhdr->hb_last_reclaimed=(unsigned short)GC_gc_no;
+#endif
+hhdr->hb_sz=h_size;
+GC_add_to_fl(h,hhdr);
+nhdr->hb_flags|=FREE_BLK;
+}
+STATIC struct hblk*
+GC_allochblk_nth(size_t sz,int kind,unsigned flags,int n,
+int may_split);
+#define AVOID_SPLIT_REMAPPED 2
+GC_INNER struct hblk*
+GC_allochblk(size_t sz,int kind,unsigned flags)
+{
+word blocks;
+int start_list;
+struct hblk*result;
+int may_split;
+int split_limit;
+GC_ASSERT((sz&(GRANULE_BYTES - 1))==0);
+blocks=OBJ_SZ_TO_BLOCKS_CHECKED(sz);
+if ((signed_word)(blocks*HBLKSIZE)< 0){
+return 0;
+}
+start_list=GC_hblk_fl_from_blocks(blocks);
+result=GC_allochblk_nth(sz,kind,flags,start_list,FALSE);
+if (0!=result)return result;
+may_split=TRUE;
+if (GC_use_entire_heap||GC_dont_gc
+||USED_HEAP_SIZE < GC_requested_heapsize
+||GC_incremental||!GC_should_collect()){
+split_limit=N_HBLK_FLS;
+} else if (GC_finalizer_bytes_freed > (GC_heapsize>>4)){
+split_limit=0;
+} else {
+split_limit=GC_enough_large_bytes_left();
+#ifdef USE_MUNMAP
+if (split_limit > 0)
+may_split=AVOID_SPLIT_REMAPPED;
+#endif
+}
+if (start_list < UNIQUE_THRESHOLD){
+++start_list;
+}
+for (;start_list<=split_limit;++start_list){
+result=GC_allochblk_nth(sz,kind,flags,start_list,may_split);
+if (0!=result)
+break;
+}
+return result;
+}
+STATIC long GC_large_alloc_warn_suppressed=0;
+STATIC struct hblk*
+GC_allochblk_nth(size_t sz,int kind,unsigned flags,int n,int may_split)
+{
+struct hblk*hbp;
+hdr*hhdr;
+struct hblk*thishbp;
+hdr*thishdr;
+signed_word size_needed=HBLKSIZE*OBJ_SZ_TO_BLOCKS_CHECKED(sz);
+for (hbp=GC_hblkfreelist[n];;hbp=hhdr->hb_next){
+signed_word size_avail;
+if (hbp){
+} else {
+return NULL;
+}
+GET_HDR(hbp,hhdr);
+size_avail=(signed_word)hhdr->hb_sz;
+if (size_avail < size_needed)continue;
+if (size_avail!=size_needed){
+if (!may_split)continue;
+thishbp=hhdr->hb_next;
+if (thishbp){
+signed_word next_size;
+GET_HDR(thishbp,thishdr);
+next_size=(signed_word)(thishdr->hb_sz);
+if (next_size < size_avail
+&&next_size>=size_needed
+&&!GC_is_black_listed(thishbp,(word)size_needed)){
+continue;
+}
+}
+}
+if (!IS_UNCOLLECTABLE(kind)&&(kind!=PTRFREE
+||size_needed > (signed_word)MAX_BLACK_LIST_ALLOC)){
+struct hblk*lasthbp=hbp;
+ptr_t search_end=(ptr_t)hbp+size_avail - size_needed;
+signed_word orig_avail=size_avail;
+signed_word eff_size_needed=(flags&IGNORE_OFF_PAGE)!=0?
+(signed_word)HBLKSIZE
+:size_needed;
+while ((word)lasthbp<=(word)search_end
+&&(thishbp=GC_is_black_listed(lasthbp,
+(word)eff_size_needed))!=0){
+lasthbp=thishbp;
+}
+size_avail-=(ptr_t)lasthbp - (ptr_t)hbp;
+thishbp=lasthbp;
+if (size_avail>=size_needed){
+if (thishbp!=hbp){
+#ifdef USE_MUNMAP
+if (may_split==AVOID_SPLIT_REMAPPED&&!IS_MAPPED(hhdr))
+continue;
+#endif
+thishdr=GC_install_header(thishbp);
+if (0!=thishdr){
+#ifdef USE_MUNMAP
+if (!IS_MAPPED(hhdr)){
+GC_adjust_num_unmapped(hbp,hhdr);
+GC_remap((ptr_t)hbp,(size_t)hhdr->hb_sz);
+hhdr->hb_flags&=~WAS_UNMAPPED;
+}
+#endif
+GC_split_block(hbp,hhdr,thishbp,thishdr,n);
+hbp=thishbp;
+hhdr=thishdr;
+}
+}
+} else if (size_needed > (signed_word)BL_LIMIT
+&&orig_avail - size_needed
+> (signed_word)BL_LIMIT){
+if (++GC_large_alloc_warn_suppressed
+>=GC_large_alloc_warn_interval){
+WARN("Repeated allocation of very large block "
+"(appr. size %" WARN_PRIdPTR "):\n"
+"\tMay lead to memory leak and poor performance\n",
+size_needed);
+GC_large_alloc_warn_suppressed=0;
+}
+size_avail=orig_avail;
+} else if (size_avail==0
+&&size_needed==(signed_word)HBLKSIZE
+&&IS_MAPPED(hhdr)){
+if (!GC_find_leak){
+static unsigned count=0;
+if ((++count&3)==0){
+word total_size=hhdr->hb_sz;
+struct hblk*limit=hbp+divHBLKSZ(total_size);
+struct hblk*h;
+struct hblk*prev=hhdr->hb_prev;
+GC_large_free_bytes-=total_size;
+GC_bytes_dropped+=total_size;
+GC_remove_from_fl_at(hhdr,n);
+for (h=hbp;(word)h < (word)limit;h++){
+if (h!=hbp){
+hhdr=GC_install_header(h);
+}
+if (NULL!=hhdr){
+(void)setup_header(hhdr,h,HBLKSIZE,PTRFREE,0);
+if (GC_debugging_started){
+BZERO(h,HBLKSIZE);
+}
+}
+}
+hbp=prev;
+if (0==hbp){
+return GC_allochblk_nth(sz,kind,flags,n,may_split);
+}
+hhdr=HDR(hbp);
+}
+}
+}
+}
+if( size_avail>=size_needed){
+#ifdef USE_MUNMAP
+if (!IS_MAPPED(hhdr)){
+GC_adjust_num_unmapped(hbp,hhdr);
+GC_remap((ptr_t)hbp,(size_t)hhdr->hb_sz);
+hhdr->hb_flags&=~WAS_UNMAPPED;
+}
+#endif
+hbp=GC_get_first_part(hbp,hhdr,size_needed,n);
+break;
+}
+}
+if (0==hbp)return 0;
+if (!GC_install_counts(hbp,(word)size_needed))return(0);
+if (!setup_header(hhdr,hbp,sz,kind,flags)){
+GC_remove_counts(hbp,(word)size_needed);
+return(0);
+}
+#ifndef GC_DISABLE_INCREMENTAL
+GC_ASSERT((size_needed&(HBLKSIZE-1))==0);
+GC_remove_protection(hbp,divHBLKSZ(size_needed),
+(hhdr->hb_descr==0));
+#endif
+GC_fail_count=0;
+GC_large_free_bytes-=size_needed;
+GC_ASSERT(IS_MAPPED(hhdr));
+return( hbp);
+}
+GC_INNER void GC_freehblk(struct hblk*hbp)
+{
+struct hblk*next,*prev;
+hdr*hhdr,*prevhdr,*nexthdr;
+word size;
+GET_HDR(hbp,hhdr);
+size=HBLKSIZE*OBJ_SZ_TO_BLOCKS(hhdr->hb_sz);
+if ((size&SIGNB)!=0)
+ABORT("Deallocating excessively large block. Too large an allocation?");
+GC_remove_counts(hbp,size);
+hhdr->hb_sz=size;
+#ifdef USE_MUNMAP
+hhdr->hb_last_reclaimed=(unsigned short)GC_gc_no;
+#endif
+if (HBLK_IS_FREE(hhdr)){
+ABORT_ARG1("Duplicate large block deallocation",
+" of %p",(void*)hbp);
+}
+GC_ASSERT(IS_MAPPED(hhdr));
+hhdr->hb_flags|=FREE_BLK;
+next=(struct hblk*)((ptr_t)hbp+size);
+GET_HDR(next,nexthdr);
+prev=GC_free_block_ending_at(hbp);
+if(0!=nexthdr&&HBLK_IS_FREE(nexthdr)&&IS_MAPPED(nexthdr)
+&&(signed_word)(hhdr->hb_sz+nexthdr->hb_sz)> 0
+){
+GC_remove_from_fl(nexthdr);
+hhdr->hb_sz+=nexthdr->hb_sz;
+GC_remove_header(next);
+}
+if (prev){
+prevhdr=HDR(prev);
+if (IS_MAPPED(prevhdr)
+&&(signed_word)(hhdr->hb_sz+prevhdr->hb_sz)> 0){
+GC_remove_from_fl(prevhdr);
+prevhdr->hb_sz+=hhdr->hb_sz;
+#ifdef USE_MUNMAP
+prevhdr->hb_last_reclaimed=(unsigned short)GC_gc_no;
+#endif
+GC_remove_header(hbp);
+hbp=prev;
+hhdr=prevhdr;
+}
+}
+GC_large_free_bytes+=size;
+GC_add_to_fl(hbp,hhdr);
+}
+#include <stdio.h>
+#if!defined(MACOS)&&!defined(MSWINCE)
+#include <signal.h>
+#if!defined(SN_TARGET_ORBIS)&&!defined(SN_TARGET_PSP2)&&!defined(__CC_ARM)
+#include <sys/types.h>
+#endif
+#endif
+word GC_non_gc_bytes=0;
+word GC_gc_no=0;
+#ifndef NO_CLOCK
+static unsigned long full_gc_total_time=0;
+static unsigned full_gc_total_ns_frac=0;
+static GC_bool measure_performance=FALSE;
+GC_API void GC_CALL GC_start_performance_measurement(void)
+{
+measure_performance=TRUE;
+}
+GC_API unsigned long GC_CALL GC_get_full_gc_total_time(void)
+{
+return full_gc_total_time;
+}
+#endif
+#ifndef GC_DISABLE_INCREMENTAL
+GC_INNER GC_bool GC_incremental=FALSE;
+#endif
+GC_API int GC_CALL GC_is_incremental_mode(void)
+{
+return (int)GC_incremental;
+}
+#ifdef THREADS
+int GC_parallel=FALSE;
+#endif
+#if defined(GC_FULL_FREQ)&&!defined(CPPCHECK)
+int GC_full_freq=GC_FULL_FREQ;
+#else
+int GC_full_freq=19;
+#endif
+STATIC GC_bool GC_need_full_gc=FALSE;
+#ifdef THREAD_LOCAL_ALLOC
+GC_INNER GC_bool GC_world_stopped=FALSE;
+#endif
+STATIC word GC_used_heap_size_after_full=0;
+EXTERN_C_BEGIN
+extern const char*const GC_copyright[];
+EXTERN_C_END
+const char*const GC_copyright[]=
+{"Copyright 1988,1989 Hans-J. Boehm and Alan J. Demers ",
+"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-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." };
+#ifndef GC_NO_VERSION_VAR
+EXTERN_C_BEGIN
+extern const unsigned GC_version;
+EXTERN_C_END
+const unsigned GC_version=((GC_VERSION_MAJOR<<16)|
+(GC_VERSION_MINOR<<8)|GC_VERSION_MICRO);
+#endif
+GC_API unsigned GC_CALL GC_get_version(void)
+{
+return (GC_VERSION_MAJOR<<16)|(GC_VERSION_MINOR<<8)|
+GC_VERSION_MICRO;
+}
+#ifdef GC_DONT_EXPAND
+int GC_dont_expand=TRUE;
+#else
+int GC_dont_expand=FALSE;
+#endif
+#if defined(GC_FREE_SPACE_DIVISOR)&&!defined(CPPCHECK)
+word GC_free_space_divisor=GC_FREE_SPACE_DIVISOR;
+#else
+word GC_free_space_divisor=3;
+#endif
+GC_INNER int GC_CALLBACK GC_never_stop_func(void)
+{
+return(0);
+}
+#if defined(GC_TIME_LIMIT)&&!defined(CPPCHECK)
+unsigned long GC_time_limit=GC_TIME_LIMIT;
+#elif defined(PARALLEL_MARK)
+unsigned long GC_time_limit=GC_TIME_UNLIMITED;
+#else
+unsigned long GC_time_limit=50;
+#endif
+#ifndef NO_CLOCK
+STATIC unsigned long GC_time_lim_nsec=0;
+#define TV_NSEC_LIMIT (1000UL*1000)
+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;
+#endif
+STATIC int GC_n_attempts=0;
+STATIC GC_stop_func GC_default_stop_func=GC_never_stop_func;
+GC_API void GC_CALL GC_set_stop_func(GC_stop_func stop_func)
+{
+DCL_LOCK_STATE;
+GC_ASSERT(NONNULL_ARG_NOT_NULL(stop_func));
+LOCK();
+GC_default_stop_func=stop_func;
+UNLOCK();
+}
+GC_API GC_stop_func GC_CALL GC_get_stop_func(void)
+{
+GC_stop_func stop_func;
+DCL_LOCK_STATE;
+LOCK();
+stop_func=GC_default_stop_func;
+UNLOCK();
+return stop_func;
+}
+#if defined(GC_DISABLE_INCREMENTAL)||defined(NO_CLOCK)
+#define GC_timeout_stop_func GC_default_stop_func
+#else
+STATIC int GC_CALLBACK GC_timeout_stop_func (void)
+{
+CLOCK_TYPE current_time;
+static unsigned count=0;
+unsigned long time_diff,nsec_diff;
+if ((*GC_default_stop_func)())
+return(1);
+if ((count++&3)!=0)return(0);
+GET_TIME(current_time);
+time_diff=MS_TIME_DIFF(current_time,GC_start_time);
+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);
+}
+#endif
+#ifdef THREADS
+GC_INNER word GC_total_stacksize=0;
+#endif
+static size_t min_bytes_allocd_minimum=1;
+GC_API void GC_CALL GC_set_min_bytes_allocd(size_t value)
+{
+GC_ASSERT(value > 0);
+min_bytes_allocd_minimum=value;
+}
+GC_API size_t GC_CALL GC_get_min_bytes_allocd(void)
+{
+return min_bytes_allocd_minimum;
+}
+static word min_bytes_allocd(void)
+{
+word result;
+word stack_size;
+word total_root_size;
+word scan_size;
+#ifdef THREADS
+if (GC_need_to_lock){
+stack_size=GC_total_stacksize;
+#ifdef DEBUG_THREADS
+GC_log_printf("Total stacks size:%lu\n",
+(unsigned long)stack_size);
+#endif
+} else
+#endif
+{
+#ifdef STACK_NOT_SCANNED
+stack_size=0;
+#elif defined(STACK_GROWS_UP)
+stack_size=GC_approx_sp()- GC_stackbottom;
+#else
+stack_size=GC_stackbottom - GC_approx_sp();
+#endif
+}
+total_root_size=2*stack_size+GC_root_size;
+scan_size=2*GC_composite_in_use+GC_atomic_in_use/4
++total_root_size;
+result=scan_size/GC_free_space_divisor;
+if (GC_incremental){
+result/=2;
+}
+return result > min_bytes_allocd_minimum
+?result:min_bytes_allocd_minimum;
+}
+STATIC word GC_non_gc_bytes_at_gc=0;
+STATIC word GC_adj_bytes_allocd(void)
+{
+signed_word result;
+signed_word expl_managed=(signed_word)GC_non_gc_bytes
+- (signed_word)GC_non_gc_bytes_at_gc;
+result=(signed_word)GC_bytes_allocd
++(signed_word)GC_bytes_dropped
+- (signed_word)GC_bytes_freed
++(signed_word)GC_finalizer_bytes_freed
+- expl_managed;
+if (result > (signed_word)GC_bytes_allocd){
+result=GC_bytes_allocd;
+}
+result+=GC_bytes_finalized;
+if (result < (signed_word)(GC_bytes_allocd>>3)){
+return(GC_bytes_allocd>>3);
+} else {
+return(result);
+}
+}
+STATIC void GC_clear_a_few_frames(void)
+{
+#ifndef CLEAR_NWORDS
+#define CLEAR_NWORDS 64
+#endif
+volatile word frames[CLEAR_NWORDS];
+BZERO((word*)frames,CLEAR_NWORDS*sizeof(word));
+}
+STATIC word GC_collect_at_heapsize=GC_WORD_MAX;
+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_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);
+}
+GC_start_callback_proc GC_start_call_back=0;
+GC_API void GC_CALL GC_set_start_callback(GC_start_callback_proc fn)
+{
+DCL_LOCK_STATE;
+LOCK();
+GC_start_call_back=fn;
+UNLOCK();
+}
+GC_API GC_start_callback_proc GC_CALL GC_get_start_callback(void)
+{
+GC_start_callback_proc fn;
+DCL_LOCK_STATE;
+LOCK();
+fn=GC_start_call_back;
+UNLOCK();
+return fn;
+}
+GC_INLINE void GC_notify_full_gc(void)
+{
+if (GC_start_call_back!=0){
+(*GC_start_call_back)();
+}
+}
+STATIC GC_bool GC_is_full_gc=FALSE;
+STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func);
+STATIC void GC_finish_collection(void);
+STATIC void GC_maybe_gc(void)
+{
+GC_ASSERT(I_HOLD_LOCK());
+ASSERT_CANCEL_DISABLED();
+if (GC_should_collect()){
+static int n_partial_gcs=0;
+if (!GC_incremental){
+GC_try_to_collect_inner(GC_never_stop_func);
+n_partial_gcs=0;
+return;
+} else {
+#ifdef PARALLEL_MARK
+if (GC_parallel)
+GC_wait_for_reclaim();
+#endif
+if (GC_need_full_gc||n_partial_gcs>=GC_full_freq){
+GC_COND_LOG_PRINTF(
+"***>Full mark for collection #%lu after %lu allocd bytes\n",
+(unsigned long)GC_gc_no+1,(unsigned long)GC_bytes_allocd);
+GC_promote_black_lists();
+(void)GC_reclaim_all((GC_stop_func)0,TRUE);
+GC_notify_full_gc();
+GC_clear_marks();
+n_partial_gcs=0;
+GC_is_full_gc=TRUE;
+} else {
+n_partial_gcs++;
+}
+}
+#ifndef NO_CLOCK
+if (GC_time_limit!=GC_TIME_UNLIMITED){ GET_TIME(GC_start_time);}
+#endif
+if (GC_stopped_mark(GC_time_limit==GC_TIME_UNLIMITED?
+GC_never_stop_func:GC_timeout_stop_func)){
+#ifdef SAVE_CALL_CHAIN
+GC_save_callers(GC_last_stack);
+#endif
+GC_finish_collection();
+} else {
+if (!GC_is_full_gc){
+GC_n_attempts++;
+}
+}
+}
+}
+STATIC GC_on_collection_event_proc GC_on_collection_event=0;
+GC_API void GC_CALL GC_set_on_collection_event(GC_on_collection_event_proc fn)
+{
+DCL_LOCK_STATE;
+LOCK();
+GC_on_collection_event=fn;
+UNLOCK();
+}
+GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void)
+{
+GC_on_collection_event_proc fn;
+DCL_LOCK_STATE;
+LOCK();
+fn=GC_on_collection_event;
+UNLOCK();
+return fn;
+}
+GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func)
+{
+#ifndef NO_CLOCK
+CLOCK_TYPE start_time=CLOCK_TYPE_INITIALIZER;
+GC_bool start_time_valid;
+#endif
+ASSERT_CANCEL_DISABLED();
+GC_ASSERT(I_HOLD_LOCK());
+if (GC_dont_gc||(*stop_func)())return FALSE;
+if (GC_on_collection_event)
+GC_on_collection_event(GC_EVENT_START);
+if (GC_incremental&&GC_collection_in_progress()){
+GC_COND_LOG_PRINTF(
+"GC_try_to_collect_inner:finishing collection in progress\n");
+while(GC_collection_in_progress()){
+if ((*stop_func)()){
+return(FALSE);
+}
+ENTER_GC();
+GC_collect_a_little_inner(1);
+EXIT_GC();
+}
+}
+GC_notify_full_gc();
+#ifndef NO_CLOCK
+start_time_valid=FALSE;
+if ((GC_print_stats|(int)measure_performance)!=0){
+if (GC_print_stats)
+GC_log_printf("Initiating full world-stop collection!\n");
+start_time_valid=TRUE;
+GET_TIME(start_time);
+}
+#endif
+GC_promote_black_lists();
+#ifdef PARALLEL_MARK
+if (GC_parallel)
+GC_wait_for_reclaim();
+#endif
+if ((GC_find_leak||stop_func!=GC_never_stop_func)
+&&!GC_reclaim_all(stop_func,FALSE)){
+return(FALSE);
+}
+GC_invalidate_mark_state();
+GC_clear_marks();
+#ifdef SAVE_CALL_CHAIN
+GC_save_callers(GC_last_stack);
+#endif
+GC_is_full_gc=TRUE;
+if (!GC_stopped_mark(stop_func)){
+if (!GC_incremental){
+GC_invalidate_mark_state();
+GC_unpromote_black_lists();
+}
+return(FALSE);
+}
+GC_finish_collection();
+#ifndef NO_CLOCK
+if (start_time_valid){
+CLOCK_TYPE current_time;
+unsigned long time_diff,ns_frac_diff;
+GET_TIME(current_time);
+time_diff=MS_TIME_DIFF(current_time,start_time);
+ns_frac_diff=NS_FRAC_TIME_DIFF(current_time,start_time);
+if (measure_performance){
+full_gc_total_time+=time_diff;
+full_gc_total_ns_frac+=(unsigned)ns_frac_diff;
+if (full_gc_total_ns_frac>=1000000U){
+full_gc_total_ns_frac-=1000000U;
+full_gc_total_time++;
+}
+}
+if (GC_print_stats)
+GC_log_printf("Complete collection took %lu ms %lu ns\n",
+time_diff,ns_frac_diff);
+}
+#endif
+if (GC_on_collection_event)
+GC_on_collection_event(GC_EVENT_END);
+return(TRUE);
+}
+#ifndef GC_RATE
+#define GC_RATE 10
+#endif
+#ifndef MAX_PRIOR_ATTEMPTS
+#define MAX_PRIOR_ATTEMPTS 1
+#endif
+STATIC int GC_deficit=0;
+STATIC int GC_rate=GC_RATE;
+GC_API void GC_CALL GC_set_rate(int value)
+{
+GC_ASSERT(value > 0);
+GC_rate=value;
+}
+GC_API int GC_CALL GC_get_rate(void)
+{
+return GC_rate;
+}
+static int max_prior_attempts=MAX_PRIOR_ATTEMPTS;
+GC_API void GC_CALL GC_set_max_prior_attempts(int value)
+{
+GC_ASSERT(value>=0);
+max_prior_attempts=value;
+}
+GC_API int GC_CALL GC_get_max_prior_attempts(void)
+{
+return max_prior_attempts;
+}
+GC_INNER void GC_collect_a_little_inner(int n)
+{
+IF_CANCEL(int cancel_state;)
+GC_ASSERT(I_HOLD_LOCK());
+if (GC_dont_gc)return;
+DISABLE_CANCEL(cancel_state);
+if (GC_incremental&&GC_collection_in_progress()){
+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(NULL))
+break;
+}
+#ifdef PARALLEL_MARK
+GC_parallel_mark_disabled=FALSE;
+#endif
+if (i < max_deficit){
+#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_finish_collection();
+} else {
+GC_n_attempts++;
+}
+} else {
+(void)GC_stopped_mark(GC_never_stop_func);
+GC_finish_collection();
+}
+}
+if (GC_deficit > 0){
+GC_deficit-=max_deficit;
+if (GC_deficit < 0)
+GC_deficit=0;
+}
+} else {
+GC_maybe_gc();
+}
+RESTORE_CANCEL(cancel_state);
+}
+GC_INNER void (*GC_check_heap)(void)=0;
+GC_INNER void (*GC_print_all_smashed)(void)=0;
+GC_API int GC_CALL GC_collect_a_little(void)
+{
+int result;
+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();
+return(result);
+}
+#ifndef NO_CLOCK
+static unsigned world_stopped_total_time=0;
+static unsigned world_stopped_total_divisor=0;
+#ifndef MAX_TOTAL_TIME_DIVISOR
+#define MAX_TOTAL_TIME_DIVISOR 1000
+#endif
+#endif
+#ifdef USE_MUNMAP
+#define IF_USE_MUNMAP(x)x
+#define COMMA_IF_USE_MUNMAP(x),x
+#else
+#define IF_USE_MUNMAP(x)
+#define COMMA_IF_USE_MUNMAP(x)
+#endif
+STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
+{
+int i;
+#ifndef NO_CLOCK
+CLOCK_TYPE start_time=CLOCK_TYPE_INITIALIZER;
+#endif
+GC_ASSERT(I_HOLD_LOCK());
+#if!defined(REDIRECT_MALLOC)&&defined(USE_WINALLOC)
+GC_add_current_malloc_heap();
+#endif
+#if defined(REGISTER_LIBRARIES_EARLY)
+GC_cond_register_dynamic_libraries();
+#endif
+#ifndef NO_CLOCK
+if (GC_PRINT_STATS_FLAG)
+GET_TIME(start_time);
+#endif
+#if!defined(GC_NO_FINALIZATION)&&!defined(GC_TOGGLE_REFS_NOT_NEEDED)
+GC_process_togglerefs();
+#endif
+#ifdef THREADS
+if (GC_on_collection_event)
+GC_on_collection_event(GC_EVENT_PRE_STOP_WORLD);
+#endif
+STOP_WORLD();
+#ifdef THREADS
+if (GC_on_collection_event)
+GC_on_collection_event(GC_EVENT_POST_STOP_WORLD);
+#endif
+#ifdef THREAD_LOCAL_ALLOC
+GC_world_stopped=TRUE;
+#endif
+GC_COND_LOG_PRINTF(
+"\n--> Marking for collection #%lu after %lu allocated bytes\n",
+(unsigned long)GC_gc_no+1,(unsigned long)GC_bytes_allocd);
+#ifdef MAKE_BACK_GRAPH
+if (GC_print_back_height){
+GC_build_back_graph();
+}
+#endif
+if (GC_on_collection_event)
+GC_on_collection_event(GC_EVENT_MARK_START);
+GC_clear_a_few_frames();
+GC_noop6(0,0,0,0,0,0);
+GC_initiate_gc();
+#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
+if (i>=0){
+GC_COND_LOG_PRINTF("Abandoned stopped marking after"
+" %d iterations\n",i);
+GC_deficit=i;
+#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
+if (GC_on_collection_event)
+GC_on_collection_event(GC_EVENT_POST_START_WORLD);
+#endif
+return FALSE;
+}
+GC_gc_no++;
+GC_DBGLOG_PRINTF("GC #%lu freed %ld bytes,heap %lu KiB"
+IF_USE_MUNMAP(" (+%lu KiB unmapped)")"\n",
+(unsigned long)GC_gc_no,(long)GC_bytes_found,
+TO_KiB_UL(GC_heapsize - GC_unmapped_bytes)
+COMMA_IF_USE_MUNMAP(TO_KiB_UL(GC_unmapped_bytes)));
+if (GC_debugging_started){
+(*GC_check_heap)();
+}
+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
+START_WORLD();
+#ifdef THREADS
+if (GC_on_collection_event)
+GC_on_collection_event(GC_EVENT_POST_START_WORLD);
+#endif
+#ifndef NO_CLOCK
+if (GC_PRINT_STATS_FLAG){
+unsigned long time_diff;
+unsigned total_time,divisor;
+CLOCK_TYPE current_time;
+GET_TIME(current_time);
+time_diff=MS_TIME_DIFF(current_time,start_time);
+total_time=world_stopped_total_time;
+divisor=world_stopped_total_divisor;
+if ((int)total_time < 0||divisor>=MAX_TOTAL_TIME_DIVISOR){
+total_time>>=1;
+divisor>>=1;
+}
+total_time+=time_diff < (((unsigned)-1)>>1)?
+(unsigned)time_diff:((unsigned)-1)>>1;
+world_stopped_total_time=total_time;
+world_stopped_total_divisor=++divisor;
+GC_ASSERT(divisor!=0);
+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);
+}
+GC_INNER void GC_set_fl_marks(ptr_t q)
+{
+if (q){
+struct hblk*h=HBLKPTR(q);
+struct hblk*last_h=h;
+hdr*hhdr=HDR(h);
+IF_PER_OBJ(word sz=hhdr->hb_sz;)
+for (;;){
+word bit_no=MARK_BIT_NO((ptr_t)q - (ptr_t)h,sz);
+if (!mark_bit_from_hdr(hhdr,bit_no)){
+set_mark_bit_from_hdr(hhdr,bit_no);
+++hhdr->hb_n_marks;
+}
+q=(ptr_t)obj_link(q);
+if (q==NULL)
+break;
+h=HBLKPTR(q);
+if (h!=last_h){
+last_h=h;
+hhdr=HDR(h);
+IF_PER_OBJ(sz=hhdr->hb_sz;)
+}
+}
+}
+}
+#if defined(GC_ASSERTIONS)&&defined(THREAD_LOCAL_ALLOC)
+void GC_check_fl_marks(void**pfreelist)
+{
+#if defined(AO_HAVE_load_acquire_read)&&!defined(THREAD_SANITIZER)
+AO_t*list=(AO_t*)AO_load_acquire_read((AO_t*)pfreelist);
+AO_t*prev;
+AO_t*p;
+if ((word)list<=HBLKSIZE)return;
+prev=(AO_t*)pfreelist;
+for (p=list;p!=NULL;){
+AO_t*next;
+if (!GC_is_marked(p)){
+ABORT_ARG2("Unmarked local free list entry",
+":object %p on list %p",(void*)p,(void*)list);
+}
+next=(AO_t*)AO_load_acquire_read(p);
+if (AO_load(prev)!=(AO_t)p)
+break;
+prev=p;
+p=next;
+}
+#else
+(void)pfreelist;
+#endif
+}
+#endif
+STATIC void GC_clear_fl_marks(ptr_t q)
+{
+struct hblk*h=HBLKPTR(q);
+struct hblk*last_h=h;
+hdr*hhdr=HDR(h);
+word sz=hhdr->hb_sz;
+for (;;){
+word bit_no=MARK_BIT_NO((ptr_t)q - (ptr_t)h,sz);
+if (mark_bit_from_hdr(hhdr,bit_no)){
+size_t n_marks=hhdr->hb_n_marks;
+GC_ASSERT(n_marks!=0);
+clear_mark_bit_from_hdr(hhdr,bit_no);
+n_marks--;
+#ifdef PARALLEL_MARK
+if (0!=n_marks||!GC_parallel){
+hhdr->hb_n_marks=n_marks;
+}
+#else
+hhdr->hb_n_marks=n_marks;
+#endif
+}
+GC_bytes_found-=sz;
+q=(ptr_t)obj_link(q);
+if (q==NULL)
+break;
+h=HBLKPTR(q);
+if (h!=last_h){
+last_h=h;
+hhdr=HDR(h);
+sz=hhdr->hb_sz;
+}
+}
+}
+#if defined(GC_ASSERTIONS)&&defined(THREAD_LOCAL_ALLOC)
+void GC_check_tls(void);
+#endif
+GC_on_heap_resize_proc GC_on_heap_resize=0;
+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;
+#if defined(CPPCHECK)
+word limit=(GC_WORD_MAX>>1)/50;
+#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));
+}
+STATIC void GC_finish_collection(void)
+{
+#ifndef NO_CLOCK
+CLOCK_TYPE start_time=CLOCK_TYPE_INITIALIZER;
+CLOCK_TYPE finalize_time=CLOCK_TYPE_INITIALIZER;
+#endif
+GC_ASSERT(I_HOLD_LOCK());
+#if defined(GC_ASSERTIONS)&&defined(THREAD_LOCAL_ALLOC)&&!defined(DBG_HDRS_ALL)
+GC_check_tls();
+#endif
+#ifndef NO_CLOCK
+if (GC_print_stats)
+GET_TIME(start_time);
+#endif
+if (GC_on_collection_event)
+GC_on_collection_event(GC_EVENT_RECLAIM_START);
+#ifndef GC_GET_HEAP_USAGE_NOT_NEEDED
+if (GC_bytes_found > 0)
+GC_reclaimed_bytes_before_gc+=(word)GC_bytes_found;
+#endif
+GC_bytes_found=0;
+#if defined(LINUX)&&defined(__ELF__)&&!defined(SMALL_CONFIG)
+if (GETENV("GC_PRINT_ADDRESS_MAP")!=0){
+GC_print_address_map();
+}
+#endif
+COND_DUMP;
+if (GC_find_leak){
+word size;
+unsigned kind;
+ptr_t q;
+for (kind=0;kind < GC_n_kinds;kind++){
+for (size=1;size<=MAXOBJGRANULES;size++){
+q=(ptr_t)GC_obj_kinds[kind].ok_freelist[size];
+if (q!=NULL)
+GC_set_fl_marks(q);
+}
+}
+GC_start_reclaim(TRUE);
+}
+#ifndef GC_NO_FINALIZATION
+GC_finalize();
+#endif
+#ifndef NO_CLOCK
+if (GC_print_stats)
+GET_TIME(finalize_time);
+#endif
+if (GC_print_back_height){
+#ifdef MAKE_BACK_GRAPH
+GC_traverse_back_graph();
+#elif!defined(SMALL_CONFIG)
+GC_err_printf("Back height not available:"
+"Rebuild collector with -DMAKE_BACK_GRAPH\n");
+#endif
+}
+{
+word size;
+ptr_t q;
+unsigned kind;
+for (kind=0;kind < GC_n_kinds;kind++){
+for (size=1;size<=MAXOBJGRANULES;size++){
+q=(ptr_t)GC_obj_kinds[kind].ok_freelist[size];
+if (q!=NULL)
+GC_clear_fl_marks(q);
+}
+}
+}
+GC_VERBOSE_LOG_PRINTF("Bytes recovered before sweep - f.l. count=%ld\n",
+(long)GC_bytes_found);
+GC_start_reclaim(FALSE);
+GC_DBGLOG_PRINTF("In-use heap:%d%% (%lu KiB pointers+%lu KiB other)\n",
+GC_compute_heap_usage_percent(),
+TO_KiB_UL(GC_composite_in_use),
+TO_KiB_UL(GC_atomic_in_use));
+if (GC_is_full_gc){
+GC_used_heap_size_after_full=USED_HEAP_SIZE;
+GC_need_full_gc=FALSE;
+} else {
+GC_need_full_gc=USED_HEAP_SIZE - GC_used_heap_size_after_full
+> min_bytes_allocd();
+}
+GC_VERBOSE_LOG_PRINTF("Immediately reclaimed %ld bytes,heapsize:"
+" %lu bytes" IF_USE_MUNMAP(" (%lu unmapped)")"\n",
+(long)GC_bytes_found,
+(unsigned long)GC_heapsize
+COMMA_IF_USE_MUNMAP((unsigned long)
+GC_unmapped_bytes));
+GC_n_attempts=0;
+GC_is_full_gc=FALSE;
+GC_bytes_allocd_before_gc+=GC_bytes_allocd;
+GC_non_gc_bytes_at_gc=GC_non_gc_bytes;
+GC_bytes_allocd=0;
+GC_bytes_dropped=0;
+GC_bytes_freed=0;
+GC_finalizer_bytes_freed=0;
+IF_USE_MUNMAP(GC_unmap_old());
+if (GC_on_collection_event)
+GC_on_collection_event(GC_EVENT_RECLAIM_END);
+#ifndef NO_CLOCK
+if (GC_print_stats){
+CLOCK_TYPE done_time;
+GET_TIME(done_time);
+#if!defined(SMALL_CONFIG)&&!defined(GC_NO_FINALIZATION)
+GC_print_finalization_stats();
+#endif
+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)
+GC_print_finalization_stats();
+#endif
+}
+STATIC GC_bool GC_try_to_collect_general(GC_stop_func stop_func,
+GC_bool force_unmap GC_ATTR_UNUSED)
+{
+GC_bool result;
+IF_USE_MUNMAP(int old_unmap_threshold;)
+IF_CANCEL(int cancel_state;)
+DCL_LOCK_STATE;
+if (!EXPECT(GC_is_initialized,TRUE))GC_init();
+if (GC_debugging_started)GC_print_all_smashed();
+GC_INVOKE_FINALIZERS();
+LOCK();
+DISABLE_CANCEL(cancel_state);
+#ifdef USE_MUNMAP
+old_unmap_threshold=GC_unmap_threshold;
+if (force_unmap||
+(GC_force_unmap_on_gcollect&&old_unmap_threshold > 0))
+GC_unmap_threshold=1;
+#endif
+ENTER_GC();
+GC_noop6(0,0,0,0,0,0);
+result=GC_try_to_collect_inner(stop_func!=0?stop_func:
+GC_default_stop_func);
+EXIT_GC();
+IF_USE_MUNMAP(GC_unmap_threshold=old_unmap_threshold);
+RESTORE_CANCEL(cancel_state);
+UNLOCK();
+if (result){
+if (GC_debugging_started)GC_print_all_smashed();
+GC_INVOKE_FINALIZERS();
+}
+return(result);
+}
+GC_API int GC_CALL GC_try_to_collect(GC_stop_func stop_func)
+{
+GC_ASSERT(NONNULL_ARG_NOT_NULL(stop_func));
+return (int)GC_try_to_collect_general(stop_func,FALSE);
+}
+GC_API void GC_CALL GC_gcollect(void)
+{
+(void)GC_try_to_collect_general(0,FALSE);
+if (GC_have_errors)GC_print_all_errors();
+}
+STATIC word GC_heapsize_at_forced_unmap=0;
+GC_API void GC_CALL GC_gcollect_and_unmap(void)
+{
+GC_heapsize_at_forced_unmap=GC_heapsize;
+(void)GC_try_to_collect_general(GC_never_stop_func,TRUE);
+}
+#ifdef USE_PROC_FOR_LIBRARIES
+GC_INNER void GC_add_to_our_memory(ptr_t p,size_t bytes)
+{
+if (0==p)return;
+if (GC_n_memory>=MAX_HEAP_SECTS)
+ABORT("Too many GC-allocated memory sections:Increase MAX_HEAP_SECTS");
+GC_our_memory[GC_n_memory].hs_start=p;
+GC_our_memory[GC_n_memory].hs_bytes=bytes;
+GC_n_memory++;
+}
+#endif
+GC_INNER void GC_add_to_heap(struct hblk*p,size_t bytes)
+{
+hdr*phdr;
+word endp;
+if (GC_n_heap_sects>=MAX_HEAP_SECTS){
+ABORT("Too many heap sections:Increase MAXHINCR or MAX_HEAP_SECTS");
+}
+while ((word)p<=HBLKSIZE){
+++p;
+bytes-=HBLKSIZE;
+if (0==bytes)return;
+}
+endp=(word)p+bytes;
+if (endp<=(word)p){
+bytes-=HBLKSIZE;
+if (0==bytes)return;
+endp-=HBLKSIZE;
+}
+phdr=GC_install_header(p);
+if (0==phdr){
+return;
+}
+GC_ASSERT(endp > (word)p&&endp==(word)p+bytes);
+GC_heap_sects[GC_n_heap_sects].hs_start=(ptr_t)p;
+GC_heap_sects[GC_n_heap_sects].hs_bytes=bytes;
+GC_n_heap_sects++;
+phdr->hb_sz=bytes;
+phdr->hb_flags=0;
+GC_freehblk(p);
+GC_heapsize+=bytes;
+GC_collect_at_heapsize+=bytes;
+if (GC_collect_at_heapsize < GC_heapsize)
+GC_collect_at_heapsize=GC_WORD_MAX;
+if ((word)p<=(word)GC_least_plausible_heap_addr
+||GC_least_plausible_heap_addr==0){
+GC_least_plausible_heap_addr=(void*)((ptr_t)p - sizeof(word));
+}
+if ((word)p+bytes>=(word)GC_greatest_plausible_heap_addr){
+GC_greatest_plausible_heap_addr=(void*)endp;
+}
+}
+#if!defined(NO_DEBUGGING)
+void GC_print_heap_sects(void)
+{
+unsigned i;
+GC_printf("Total heap size:%lu" IF_USE_MUNMAP(" (%lu unmapped)")"\n",
+(unsigned long)GC_heapsize
+COMMA_IF_USE_MUNMAP((unsigned long)GC_unmapped_bytes));
+for (i=0;i < GC_n_heap_sects;i++){
+ptr_t start=GC_heap_sects[i].hs_start;
+size_t len=GC_heap_sects[i].hs_bytes;
+struct hblk*h;
+unsigned nbl=0;
+for (h=(struct hblk*)start;(word)h < (word)(start+len);h++){
+if (GC_is_black_listed(h,HBLKSIZE))nbl++;
+}
+GC_printf("Section %d from %p to %p %u/%lu blacklisted\n",
+i,(void*)start,(void*)&start[len],
+nbl,(unsigned long)divHBLKSZ(len));
+}
+}
+#endif
+void*GC_least_plausible_heap_addr=(void*)GC_WORD_MAX;
+void*GC_greatest_plausible_heap_addr=0;
+GC_INLINE word GC_max(word x,word y)
+{
+return(x > y?x:y);
+}
+GC_INLINE word GC_min(word x,word y)
+{
+return(x < y?x:y);
+}
+STATIC word GC_max_heapsize=0;
+GC_API void GC_CALL GC_set_max_heap_size(GC_word n)
+{
+GC_max_heapsize=n;
+}
+GC_word GC_max_retries=0;
+GC_INNER GC_bool GC_expand_hp_inner(word n)
+{
+size_t bytes;
+struct hblk*space;
+word expansion_slop;
+GC_ASSERT(I_HOLD_LOCK());
+GC_ASSERT(GC_page_size!=0);
+if (n < MINHINCR)n=MINHINCR;
+bytes=ROUNDUP_PAGESIZE((size_t)n*HBLKSIZE);
+if (GC_max_heapsize!=0
+&&(GC_max_heapsize < (word)bytes
+||GC_heapsize > GC_max_heapsize - (word)bytes)){
+return(FALSE);
+}
+space=GET_MEM(bytes);
+GC_add_to_our_memory((ptr_t)space,bytes);
+if (space==0){
+WARN("Failed to expand heap by %" WARN_PRIdPTR " bytes\n",
+(word)bytes);
+return(FALSE);
+}
+GC_INFOLOG_PRINTF("Grow heap to %lu KiB after %lu bytes allocated\n",
+TO_KiB_UL(GC_heapsize+(word)bytes),
+(unsigned long)GC_bytes_allocd);
+expansion_slop=min_bytes_allocd()+4*MAXHINCR*HBLKSIZE;
+if ((GC_last_heap_addr==0&&!((word)space&SIGNB))
+||(GC_last_heap_addr!=0
+&&(word)GC_last_heap_addr < (word)space)){
+word new_limit=(word)space+(word)bytes+expansion_slop;
+if (new_limit > (word)space){
+GC_greatest_plausible_heap_addr=
+(void*)GC_max((word)GC_greatest_plausible_heap_addr,
+(word)new_limit);
+}
+} else {
+word new_limit=(word)space - expansion_slop;
+if (new_limit < (word)space){
+GC_least_plausible_heap_addr=
+(void*)GC_min((word)GC_least_plausible_heap_addr,
+(word)space - expansion_slop);
+}
+}
+GC_prev_heap_addr=GC_last_heap_addr;
+GC_last_heap_addr=(ptr_t)space;
+GC_add_to_heap(space,bytes);
+GC_collect_at_heapsize=
+GC_heapsize+expansion_slop - 2*MAXHINCR*HBLKSIZE;
+if (GC_collect_at_heapsize < GC_heapsize)
+GC_collect_at_heapsize=GC_WORD_MAX;
+if (GC_on_heap_resize)
+(*GC_on_heap_resize)(GC_heapsize);
+return(TRUE);
+}
+GC_API int GC_CALL GC_expand_hp(size_t bytes)
+{
+int result;
+DCL_LOCK_STATE;
+if (!EXPECT(GC_is_initialized,TRUE))GC_init();
+LOCK();
+result=(int)GC_expand_hp_inner(divHBLKSZ((word)bytes));
+if (result)GC_requested_heapsize+=bytes;
+UNLOCK();
+return(result);
+}
+GC_INNER unsigned GC_fail_count=0;
+#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;
+GC_INNER GC_bool GC_collect_or_expand(word needed_blocks,
+GC_bool ignore_off_page,
+GC_bool retry)
+{
+GC_bool gc_not_stopped=TRUE;
+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
+&&(last_bytes_finalized|GC_bytes_finalized)!=0
+&&(GC_fo_entries - last_fo_entries)
+*GC_allocd_bytes_per_finalizer > GC_bytes_allocd)
+||GC_should_collect())){
+gc_not_stopped=GC_try_to_collect_inner(
+GC_bytes_allocd > 0&&(!GC_dont_expand||!retry)?
+GC_default_stop_func:GC_never_stop_func);
+if (gc_not_stopped==TRUE||!retry){
+last_fo_entries=GC_fo_entries;
+last_bytes_finalized=GC_bytes_finalized;
+RESTORE_CANCEL(cancel_state);
+return(TRUE);
+}
+}
+blocks_to_get=(GC_heapsize - GC_heapsize_at_forced_unmap)
+/(HBLKSIZE*GC_free_space_divisor)
++needed_blocks;
+if (blocks_to_get > MAXHINCR){
+word slop;
+if (ignore_off_page){
+slop=4;
+} else {
+slop=2*divHBLKSZ(BL_LIMIT);
+if (slop > needed_blocks)slop=needed_blocks;
+}
+if (needed_blocks+slop > MAXHINCR){
+blocks_to_get=needed_blocks+slop;
+} else {
+blocks_to_get=MAXHINCR;
+}
+if (blocks_to_get > divHBLKSZ(GC_WORD_MAX))
+blocks_to_get=divHBLKSZ(GC_WORD_MAX);
+}
+if (!GC_expand_hp_inner(blocks_to_get)
+&&(blocks_to_get==needed_blocks
+||!GC_expand_hp_inner(needed_blocks))){
+if (gc_not_stopped==FALSE){
+GC_gcollect_inner();
+GC_ASSERT(GC_bytes_allocd==0);
+} else if (GC_fail_count++< GC_max_retries){
+WARN("Out of Memory!Trying to continue...\n",0);
+GC_gcollect_inner();
+} else {
+#if!defined(AMIGA)||!defined(GC_AMIGA_FASTALLOC)
+WARN("Out of Memory!Heap size:%" WARN_PRIdPTR " MiB."
+" Returning NULL!\n",(GC_heapsize - GC_unmapped_bytes)>>20);
+#endif
+RESTORE_CANCEL(cancel_state);
+return(FALSE);
+}
+} else if (GC_fail_count){
+GC_COND_LOG_PRINTF("Memory available again...\n");
+}
+RESTORE_CANCEL(cancel_state);
+return(TRUE);
+}
+GC_INNER ptr_t GC_allocobj(size_t gran,int kind)
+{
+void**flh=&(GC_obj_kinds[kind].ok_freelist[gran]);
+GC_bool tried_minor=FALSE;
+GC_bool retry=FALSE;
+GC_ASSERT(I_HOLD_LOCK());
+if (gran==0)return(0);
+while (*flh==0){
+ENTER_GC();
+#ifndef GC_DISABLE_INCREMENTAL
+if (GC_incremental&&GC_time_limit!=GC_TIME_UNLIMITED){
+GC_collect_a_little_inner(1);
+}
+#endif
+GC_ASSERT(!GC_is_full_gc
+||NULL==GC_obj_kinds[kind].ok_reclaim_list
+||NULL==GC_obj_kinds[kind].ok_reclaim_list[gran]);
+GC_continue_reclaim(gran,kind);
+EXIT_GC();
+#if defined(CPPCHECK)
+GC_noop1((word)&flh);
+#endif
+if (NULL==*flh){
+GC_new_hblk(gran,kind);
+#if defined(CPPCHECK)
+GC_noop1((word)&flh);
+#endif
+if (NULL==*flh){
+ENTER_GC();
+if (GC_incremental&&GC_time_limit==GC_TIME_UNLIMITED
+&&!tried_minor){
+GC_collect_a_little_inner(1);
+tried_minor=TRUE;
+} else {
+if (!GC_collect_or_expand(1,FALSE,retry)){
+EXIT_GC();
+return(0);
+}
+retry=TRUE;
+}
+EXIT_GC();
+}
+}
+}
+GC_fail_count=0;
+return (ptr_t)(*flh);
+}
+#ifndef MSWINCE
+#include <errno.h>
+#endif
+#include <string.h>
+#ifndef SHORT_DBG_HDRS
+GC_INNER int GC_has_other_debug_info(ptr_t p)
+{
+ptr_t body=(ptr_t)((oh*)p+1);
+word sz=GC_size(p);
+if (HBLKPTR(p)!=HBLKPTR((ptr_t)body)
+||sz < DEBUG_BYTES+EXTRA_BYTES){
+return 0;
+}
+if (((oh*)p)->oh_sf!=(START_FLAG^(word)body)
+&&((word*)p)[BYTES_TO_WORDS(sz)-1]!=(END_FLAG^(word)body)){
+return 0;
+}
+if (((oh*)p)->oh_sz==sz){
+return -1;
+}
+return 1;
+}
+#endif
+#ifdef LINT2
+long GC_random(void)
+{
+static unsigned seed=1;
+seed=(seed*1103515245U+12345)&GC_RAND_MAX;
+return (long)seed;
+}
+#endif
+#ifdef KEEP_BACK_PTRS
+#ifdef LINT2
+#define RANDOM()GC_random()
+#else
+#include <stdlib.h>
+#define GC_RAND_MAX RAND_MAX
+#if defined(__GLIBC__)||defined(SOLARIS)||defined(HPUX)||defined(IRIX5)||defined(OSF1)
+#define RANDOM()random()
+#else
+#define RANDOM()(long)rand()
+#endif
+#endif
+GC_INNER void GC_store_back_pointer(ptr_t source,ptr_t dest)
+{
+if (GC_HAS_DEBUG_INFO(dest)){
+#ifdef PARALLEL_MARK
+AO_store((volatile AO_t*)&((oh*)dest)->oh_back_ptr,
+(AO_t)HIDE_BACK_PTR(source));
+#else
+((oh*)dest)->oh_back_ptr=HIDE_BACK_PTR(source);
+#endif
+}
+}
+GC_INNER void GC_marked_for_finalization(ptr_t dest)
+{
+GC_store_back_pointer(MARKED_FOR_FINALIZATION,dest);
+}
+GC_API GC_ref_kind GC_CALL GC_get_back_ptr_info(void*dest,void**base_p,
+size_t*offset_p)
+{
+oh*hdr=(oh*)GC_base(dest);
+ptr_t bp;
+ptr_t bp_base;
+#ifdef LINT2
+if (!hdr)ABORT("Invalid GC_get_back_ptr_info argument");
+#endif
+if (!GC_HAS_DEBUG_INFO((ptr_t)hdr))return GC_NO_SPACE;
+bp=(ptr_t)GC_REVEAL_POINTER(hdr->oh_back_ptr);
+if (MARKED_FOR_FINALIZATION==bp)return GC_FINALIZER_REFD;
+if (MARKED_FROM_REGISTER==bp)return GC_REFD_FROM_REG;
+if (NOT_MARKED==bp)return GC_UNREFERENCED;
+#if ALIGNMENT==1
+{
+ptr_t alternate_ptr=bp+1;
+ptr_t target=*(ptr_t*)bp;
+ptr_t alternate_target=*(ptr_t*)alternate_ptr;
+if ((word)alternate_target>=(word)GC_least_plausible_heap_addr
+&&(word)alternate_target<=(word)GC_greatest_plausible_heap_addr
+&&((word)target < (word)GC_least_plausible_heap_addr
+||(word)target > (word)GC_greatest_plausible_heap_addr)){
+bp=alternate_ptr;
+}
+}
+#endif
+bp_base=(ptr_t)GC_base(bp);
+if (NULL==bp_base){
+*base_p=bp;
+*offset_p=0;
+return GC_REFD_FROM_ROOT;
+} else {
+if (GC_HAS_DEBUG_INFO(bp_base))bp_base+=sizeof(oh);
+*base_p=bp_base;
+*offset_p=bp - bp_base;
+return GC_REFD_FROM_HEAP;
+}
+}
+GC_API void*GC_CALL GC_generate_random_heap_address(void)
+{
+size_t i;
+word heap_offset=RANDOM();
+if (GC_heapsize > GC_RAND_MAX){
+heap_offset*=GC_RAND_MAX;
+heap_offset+=RANDOM();
+}
+heap_offset%=GC_heapsize;
+for (i=0;;++i){
+size_t size;
+if (i>=GC_n_heap_sects)
+ABORT("GC_generate_random_heap_address:size inconsistency");
+size=GC_heap_sects[i].hs_bytes;
+if (heap_offset < size){
+break;
+} else {
+heap_offset-=size;
+}
+}
+return GC_heap_sects[i].hs_start+heap_offset;
+}
+GC_API void*GC_CALL GC_generate_random_valid_address(void)
+{
+ptr_t result;
+ptr_t base;
+do {
+result=(ptr_t)GC_generate_random_heap_address();
+base=(ptr_t)GC_base(result);
+} while (NULL==base||!GC_is_marked(base));
+return result;
+}
+GC_API void GC_CALL GC_print_backtrace(void*p)
+{
+void*current=p;
+int i;
+GC_ref_kind source;
+size_t offset;
+void*base;
+GC_print_heap_obj((ptr_t)GC_base(current));
+for (i=0;;++i){
+source=GC_get_back_ptr_info(current,&base,&offset);
+if (GC_UNREFERENCED==source){
+GC_err_printf("Reference could not be found\n");
+goto out;
+}
+if (GC_NO_SPACE==source){
+GC_err_printf("No debug info in object:Can't find reference\n");
+goto out;
+}
+GC_err_printf("Reachable via %d levels of pointers from ",i);
+switch(source){
+case GC_REFD_FROM_ROOT:
+GC_err_printf("root at %p\n\n",base);
+goto out;
+case GC_REFD_FROM_REG:
+GC_err_printf("root in register\n\n");
+goto out;
+case GC_FINALIZER_REFD:
+GC_err_printf("list of finalizable objects\n\n");
+goto out;
+case GC_REFD_FROM_HEAP:
+GC_err_printf("offset %ld in object:\n",(long)offset);
+GC_print_heap_obj((ptr_t)GC_base(base));
+break;
+default:
+GC_err_printf("INTERNAL ERROR:UNEXPECTED SOURCE!!!!\n");
+goto out;
+}
+current=base;
+}
+out:;
+}
+GC_INNER void GC_generate_random_backtrace_no_gc(void)
+{
+void*current;
+current=GC_generate_random_valid_address();
+GC_printf("\n****Chosen address %p in object\n",current);
+GC_print_backtrace(current);
+}
+GC_API void GC_CALL GC_generate_random_backtrace(void)
+{
+if (GC_try_to_collect(GC_never_stop_func)==0){
+GC_err_printf("Cannot generate a backtrace:"
+"garbage collection is disabled!\n");
+return;
+}
+GC_generate_random_backtrace_no_gc();
+}
+#endif
+#define CROSSES_HBLK(p,sz)(((word)((p)+sizeof(oh)+(sz)- 1)^(word)(p))>=HBLKSIZE)
+GC_INNER void*GC_store_debug_info_inner(void*p,word sz GC_ATTR_UNUSED,
+const char*string,int linenum)
+{
+word*result=(word*)((oh*)p+1);
+GC_ASSERT(I_HOLD_LOCK());
+GC_ASSERT(GC_size(p)>=sizeof(oh)+sz);
+GC_ASSERT(!(SMALL_OBJ(sz)&&CROSSES_HBLK((ptr_t)p,sz)));
+#ifdef KEEP_BACK_PTRS
+((oh*)p)->oh_back_ptr=HIDE_BACK_PTR(NOT_MARKED);
+#endif
+#ifdef MAKE_BACK_GRAPH
+((oh*)p)->oh_bg_ptr=HIDE_BACK_PTR((ptr_t)0);
+#endif
+((oh*)p)->oh_string=string;
+((oh*)p)->oh_int=linenum;
+#ifndef SHORT_DBG_HDRS
+((oh*)p)->oh_sz=sz;
+((oh*)p)->oh_sf=START_FLAG^(word)result;
+((word*)p)[BYTES_TO_WORDS(GC_size(p))-1]=
+result[SIMPLE_ROUNDED_UP_WORDS(sz)]=END_FLAG^(word)result;
+#endif
+return result;
+}
+static void*store_debug_info(void*p,size_t lb,
+const char*fn,GC_EXTRA_PARAMS)
+{
+void*result;
+DCL_LOCK_STATE;
+if (NULL==p){
+GC_err_printf("%s(%lu)returning NULL (%s:%d)\n",
+fn,(unsigned long)lb,s,i);
+return NULL;
+}
+LOCK();
+if (!GC_debugging_started)
+GC_start_debugging_inner();
+ADD_CALL_CHAIN(p,ra);
+result=GC_store_debug_info_inner(p,(word)lb,s,i);
+UNLOCK();
+return result;
+}
+#ifndef SHORT_DBG_HDRS
+STATIC ptr_t GC_check_annotated_obj(oh*ohdr)
+{
+ptr_t body=(ptr_t)(ohdr+1);
+word gc_sz=GC_size((ptr_t)ohdr);
+if (ohdr->oh_sz+DEBUG_BYTES > gc_sz){
+return((ptr_t)(&(ohdr->oh_sz)));
+}
+if (ohdr->oh_sf!=(START_FLAG^(word)body)){
+return((ptr_t)(&(ohdr->oh_sf)));
+}
+if (((word*)ohdr)[BYTES_TO_WORDS(gc_sz)-1]!=(END_FLAG^(word)body)){
+return (ptr_t)(&((word*)ohdr)[BYTES_TO_WORDS(gc_sz)-1]);
+}
+if (((word*)body)[SIMPLE_ROUNDED_UP_WORDS(ohdr->oh_sz)]
+!=(END_FLAG^(word)body)){
+return (ptr_t)(&((word*)body)[SIMPLE_ROUNDED_UP_WORDS(ohdr->oh_sz)]);
+}
+return(0);
+}
+#endif
+STATIC GC_describe_type_fn GC_describe_type_fns[MAXOBJKINDS]={0};
+GC_API void GC_CALL GC_register_describe_type_fn(int kind,
+GC_describe_type_fn fn)
+{
+GC_describe_type_fns[kind]=fn;
+}
+#define GET_OH_LINENUM(ohdr)((int)(ohdr)->oh_int)
+#ifndef SHORT_DBG_HDRS
+#define IF_NOT_SHORTDBG_HDRS(x)x
+#define COMMA_IFNOT_SHORTDBG_HDRS(x),x
+#else
+#define IF_NOT_SHORTDBG_HDRS(x)
+#define COMMA_IFNOT_SHORTDBG_HDRS(x)
+#endif
+STATIC void GC_print_obj(ptr_t p)
+{
+oh*ohdr=(oh*)GC_base(p);
+ptr_t q;
+hdr*hhdr;
+int kind;
+const char*kind_str;
+char buffer[GC_TYPE_DESCR_LEN+1];
+GC_ASSERT(I_DONT_HOLD_LOCK());
+#ifdef LINT2
+if (!ohdr)ABORT("Invalid GC_print_obj argument");
+#endif
+q=(ptr_t)(ohdr+1);
+hhdr=GC_find_header(q);
+kind=hhdr->hb_obj_kind;
+if (0!=GC_describe_type_fns[kind]&&GC_is_marked(ohdr)){
+buffer[GC_TYPE_DESCR_LEN]=0;
+(GC_describe_type_fns[kind])(q,buffer);
+GC_ASSERT(buffer[GC_TYPE_DESCR_LEN]==0);
+kind_str=buffer;
+} else {
+switch(kind){
+case PTRFREE:
+kind_str="PTRFREE";
+break;
+case NORMAL:
+kind_str="NORMAL";
+break;
+case UNCOLLECTABLE:
+kind_str="UNCOLLECTABLE";
+break;
+#ifdef GC_ATOMIC_UNCOLLECTABLE
+case AUNCOLLECTABLE:
+kind_str="ATOMIC_UNCOLLECTABLE";
+break;
+#endif
+default:
+kind_str=NULL;
+}
+}
+if (NULL!=kind_str){
+GC_err_printf("%p (%s:%d," IF_NOT_SHORTDBG_HDRS(" sz=%lu,")" %s)\n",
+(void*)((ptr_t)ohdr+sizeof(oh)),
+ohdr->oh_string,GET_OH_LINENUM(ohdr)
+COMMA_IFNOT_SHORTDBG_HDRS((unsigned long)ohdr->oh_sz),
+kind_str);
+} else {
+GC_err_printf("%p (%s:%d," IF_NOT_SHORTDBG_HDRS(" sz=%lu,")
+" kind=%d descr=0x%lx)\n",
+(void*)((ptr_t)ohdr+sizeof(oh)),
+ohdr->oh_string,GET_OH_LINENUM(ohdr)
+COMMA_IFNOT_SHORTDBG_HDRS((unsigned long)ohdr->oh_sz),
+kind,(unsigned long)hhdr->hb_descr);
+}
+PRINT_CALL_CHAIN(ohdr);
+}
+STATIC void GC_debug_print_heap_obj_proc(ptr_t p)
+{
+GC_ASSERT(I_DONT_HOLD_LOCK());
+if (GC_HAS_DEBUG_INFO(p)){
+GC_print_obj(p);
+} else {
+GC_default_print_heap_obj_proc(p);
+}
+}
+#ifndef SHORT_DBG_HDRS
+STATIC void GC_print_smashed_obj(const char*msg,void*p,
+ptr_t clobbered_addr)
+{
+oh*ohdr=(oh*)GC_base(p);
+GC_ASSERT(I_DONT_HOLD_LOCK());
+#ifdef LINT2
+if (!ohdr)ABORT("Invalid GC_print_smashed_obj argument");
+#endif
+if ((word)clobbered_addr<=(word)(&ohdr->oh_sz)
+||ohdr->oh_string==0){
+GC_err_printf(
+"%s %p in or near object at %p(<smashed>,appr. sz=%lu)\n",
+msg,(void*)clobbered_addr,p,
+(unsigned long)(GC_size((ptr_t)ohdr)- DEBUG_BYTES));
+} else {
+GC_err_printf("%s %p in or near object at %p (%s:%d,sz=%lu)\n",
+msg,(void*)clobbered_addr,p,
+(word)(ohdr->oh_string)< HBLKSIZE?"(smashed string)":
+ohdr->oh_string[0]=='\0'?"EMPTY(smashed?)":
+ohdr->oh_string,
+GET_OH_LINENUM(ohdr),(unsigned long)(ohdr->oh_sz));
+PRINT_CALL_CHAIN(ohdr);
+}
+}
+STATIC void GC_check_heap_proc (void);
+STATIC void GC_print_all_smashed_proc (void);
+#else
+STATIC void GC_do_nothing(void){}
+#endif
+GC_INNER void GC_start_debugging_inner(void)
+{
+GC_ASSERT(I_HOLD_LOCK());
+#ifndef SHORT_DBG_HDRS
+GC_check_heap=GC_check_heap_proc;
+GC_print_all_smashed=GC_print_all_smashed_proc;
+#else
+GC_check_heap=GC_do_nothing;
+GC_print_all_smashed=GC_do_nothing;
+#endif
+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
+}
+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)
+{
+DCL_LOCK_STATE;
+LOCK();
+GC_register_displacement_inner(offset);
+GC_register_displacement_inner((word)sizeof(oh)+offset);
+UNLOCK();
+}
+#ifdef GC_ADD_CALLER
+#if defined(HAVE_DLADDR)&&defined(GC_HAVE_RETURN_ADDR_PARENT)
+#include <dlfcn.h>
+STATIC void GC_caller_func_offset(word ad,const char**symp,int*offp)
+{
+Dl_info caller;
+if (ad&&dladdr((void*)ad,&caller)&&caller.dli_sname!=NULL){
+*symp=caller.dli_sname;
+*offp=(int)((char*)ad - (char*)caller.dli_saddr);
+}
+if (NULL==*symp){
+*symp="unknown";
+}
+}
+#else
+#define GC_caller_func_offset(ad,symp,offp)(void)(*(symp)="unknown")
+#endif
+#endif
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_debug_malloc(size_t lb,
+GC_EXTRA_PARAMS)
+{
+void*result;
+result=GC_malloc(SIZET_SAT_ADD(lb,DEBUG_BYTES));
+#ifdef GC_ADD_CALLER
+if (s==NULL){
+GC_caller_func_offset(ra,&s,&i);
+}
+#endif
+return store_debug_info(result,lb,"GC_debug_malloc",OPT_RA s,i);
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL
+GC_debug_malloc_ignore_off_page(size_t lb,GC_EXTRA_PARAMS)
+{
+void*result=GC_malloc_ignore_off_page(SIZET_SAT_ADD(lb,DEBUG_BYTES));
+return store_debug_info(result,lb,"GC_debug_malloc_ignore_off_page",
+OPT_RA s,i);
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL
+GC_debug_malloc_atomic_ignore_off_page(size_t lb,GC_EXTRA_PARAMS)
+{
+void*result=GC_malloc_atomic_ignore_off_page(
+SIZET_SAT_ADD(lb,DEBUG_BYTES));
+return store_debug_info(result,lb,
+"GC_debug_malloc_atomic_ignore_off_page",
+OPT_RA s,i);
+}
+STATIC void*GC_debug_generic_malloc(size_t lb,int knd,GC_EXTRA_PARAMS)
+{
+void*result=GC_generic_malloc(SIZET_SAT_ADD(lb,DEBUG_BYTES),knd);
+return store_debug_info(result,lb,"GC_debug_generic_malloc",
+OPT_RA s,i);
+}
+#ifdef DBG_HDRS_ALL
+GC_INNER void*GC_debug_generic_malloc_inner(size_t lb,int k)
+{
+void*result;
+GC_ASSERT(I_HOLD_LOCK());
+result=GC_generic_malloc_inner(SIZET_SAT_ADD(lb,DEBUG_BYTES),k);
+if (NULL==result){
+GC_err_printf("GC internal allocation (%lu bytes)returning NULL\n",
+(unsigned long)lb);
+return(0);
+}
+if (!GC_debugging_started){
+GC_start_debugging_inner();
+}
+ADD_CALL_CHAIN(result,GC_RETURN_ADDR);
+return (GC_store_debug_info_inner(result,(word)lb,"INTERNAL",0));
+}
+GC_INNER void*GC_debug_generic_malloc_inner_ignore_off_page(size_t lb,
+int k)
+{
+void*result;
+GC_ASSERT(I_HOLD_LOCK());
+result=GC_generic_malloc_inner_ignore_off_page(
+SIZET_SAT_ADD(lb,DEBUG_BYTES),k);
+if (NULL==result){
+GC_err_printf("GC internal allocation (%lu bytes)returning NULL\n",
+(unsigned long)lb);
+return(0);
+}
+if (!GC_debugging_started){
+GC_start_debugging_inner();
+}
+ADD_CALL_CHAIN(result,GC_RETURN_ADDR);
+return (GC_store_debug_info_inner(result,(word)lb,"INTERNAL",0));
+}
+#endif
+#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(
+const void*p GC_ATTR_UNUSED){}
+#endif
+GC_API void GC_CALL GC_debug_end_stubborn_change(const void*p)
+{
+const void*q=GC_base_C(p);
+if (NULL==q){
+ABORT_ARG1("GC_debug_end_stubborn_change:bad arg",":%p",p);
+}
+GC_end_stubborn_change(q);
+}
+GC_API void GC_CALL GC_debug_ptr_store_and_dirty(void*p,const void*q)
+{
+*(void**)GC_is_visible(p)=GC_is_valid_displacement((void*)q);
+GC_debug_end_stubborn_change(p);
+REACHABLE_AFTER_DIRTY(q);
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_debug_malloc_atomic(size_t lb,
+GC_EXTRA_PARAMS)
+{
+void*result=GC_malloc_atomic(SIZET_SAT_ADD(lb,DEBUG_BYTES));
+return store_debug_info(result,lb,"GC_debug_malloc_atomic",
+OPT_RA s,i);
+}
+GC_API GC_ATTR_MALLOC char*GC_CALL GC_debug_strdup(const char*str,
+GC_EXTRA_PARAMS)
+{
+char*copy;
+size_t lb;
+if (str==NULL){
+if (GC_find_leak)
+GC_err_printf("strdup(NULL)behavior is undefined\n");
+return NULL;
+}
+lb=strlen(str)+1;
+copy=(char*)GC_debug_malloc_atomic(lb,OPT_RA s,i);
+if (copy==NULL){
+#ifndef MSWINCE
+errno=ENOMEM;
+#endif
+return NULL;
+}
+BCOPY(str,copy,lb);
+return copy;
+}
+GC_API GC_ATTR_MALLOC char*GC_CALL GC_debug_strndup(const char*str,
+size_t size,GC_EXTRA_PARAMS)
+{
+char*copy;
+size_t len=strlen(str);
+if (len > size)
+len=size;
+copy=(char*)GC_debug_malloc_atomic(len+1,OPT_RA s,i);
+if (copy==NULL){
+#ifndef MSWINCE
+errno=ENOMEM;
+#endif
+return NULL;
+}
+if (len > 0)
+BCOPY(str,copy,len);
+copy[len]='\0';
+return copy;
+}
+#ifdef GC_REQUIRE_WCSDUP
+#include <wchar.h>
+GC_API GC_ATTR_MALLOC wchar_t*GC_CALL GC_debug_wcsdup(const wchar_t*str,
+GC_EXTRA_PARAMS)
+{
+size_t lb=(wcslen(str)+1)*sizeof(wchar_t);
+wchar_t*copy=(wchar_t*)GC_debug_malloc_atomic(lb,OPT_RA s,i);
+if (copy==NULL){
+#ifndef MSWINCE
+errno=ENOMEM;
+#endif
+return NULL;
+}
+BCOPY(str,copy,lb);
+return copy;
+}
+#endif
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_debug_malloc_uncollectable(size_t lb,
+GC_EXTRA_PARAMS)
+{
+void*result=GC_malloc_uncollectable(
+SIZET_SAT_ADD(lb,UNCOLLECTABLE_DEBUG_BYTES));
+return store_debug_info(result,lb,"GC_debug_malloc_uncollectable",
+OPT_RA s,i);
+}
+#ifdef GC_ATOMIC_UNCOLLECTABLE
+GC_API GC_ATTR_MALLOC void*GC_CALL
+GC_debug_malloc_atomic_uncollectable(size_t lb,GC_EXTRA_PARAMS)
+{
+void*result=GC_malloc_atomic_uncollectable(
+SIZET_SAT_ADD(lb,UNCOLLECTABLE_DEBUG_BYTES));
+return store_debug_info(result,lb,
+"GC_debug_malloc_atomic_uncollectable",
+OPT_RA s,i);
+}
+#endif
+#ifndef GC_FREED_MEM_MARKER
+#if CPP_WORDSZ==32
+#define GC_FREED_MEM_MARKER 0xdeadbeef
+#else
+#define GC_FREED_MEM_MARKER GC_WORD_C(0xEFBEADDEdeadbeef)
+#endif
+#endif
+GC_API void GC_CALL GC_debug_free(void*p)
+{
+ptr_t base;
+if (0==p)return;
+base=(ptr_t)GC_base(p);
+if (NULL==base){
+#if defined(REDIRECT_MALLOC)&&((defined(NEED_CALLINFO)&&defined(GC_HAVE_BUILTIN_BACKTRACE))||defined(GC_LINUX_THREADS)||defined(GC_SOLARIS_THREADS)||defined(MSWIN32))
+if (!GC_is_heap_ptr(p))return;
+#endif
+ABORT_ARG1("Invalid pointer passed to free()",":%p",p);
+}
+if ((ptr_t)p - (ptr_t)base!=sizeof(oh)){
+#if defined(REDIRECT_FREE)&&defined(USE_PROC_FOR_LIBRARIES)
+#endif
+GC_err_printf(
+"GC_debug_free called on pointer %p w/o debugging info\n",p);
+} else {
+#ifndef SHORT_DBG_HDRS
+ptr_t clobbered=GC_check_annotated_obj((oh*)base);
+word sz=GC_size(base);
+if (clobbered!=0){
+GC_have_errors=TRUE;
+if (((oh*)base)->oh_sz==sz){
+GC_print_smashed_obj(
+"GC_debug_free:found previously deallocated (?)object at",
+p,clobbered);
+return;
+} else {
+GC_print_smashed_obj("GC_debug_free:found smashed location at",
+p,clobbered);
+}
+}
+((oh*)base)->oh_sz=sz;
+#endif
+}
+if (GC_find_leak
+#ifndef SHORT_DBG_HDRS
+&&((ptr_t)p - (ptr_t)base!=sizeof(oh)||!GC_findleak_delay_free)
+#endif
+){
+GC_free(base);
+} else {
+hdr*hhdr=HDR(p);
+if (hhdr->hb_obj_kind==UNCOLLECTABLE
+#ifdef GC_ATOMIC_UNCOLLECTABLE
+||hhdr->hb_obj_kind==AUNCOLLECTABLE
+#endif
+){
+GC_free(base);
+} else {
+word i;
+word sz=hhdr->hb_sz;
+word obj_sz=BYTES_TO_WORDS(sz - sizeof(oh));
+for (i=0;i < obj_sz;++i)
+((word*)p)[i]=GC_FREED_MEM_MARKER;
+GC_ASSERT((word*)p+i==(word*)(base+sz));
+LOCK();
+GC_bytes_freed+=sz;
+UNLOCK();
+}
+}
+}
+#if defined(THREADS)&&defined(DBG_HDRS_ALL)
+GC_INNER void GC_debug_free_inner(void*p)
+{
+ptr_t base=(ptr_t)GC_base(p);
+GC_ASSERT((ptr_t)p - (ptr_t)base==sizeof(oh));
+#ifdef LINT2
+if (!base)ABORT("Invalid GC_debug_free_inner argument");
+#endif
+#ifndef SHORT_DBG_HDRS
+((oh*)base)->oh_sz=GC_size(base);
+#endif
+GC_free_inner(base);
+}
+#endif
+GC_API void*GC_CALL GC_debug_realloc(void*p,size_t lb,GC_EXTRA_PARAMS)
+{
+void*base;
+void*result;
+hdr*hhdr;
+if (p==0){
+return GC_debug_malloc(lb,OPT_RA s,i);
+}
+if (0==lb){
+GC_debug_free(p);
+return NULL;
+}
+#ifdef GC_ADD_CALLER
+if (s==NULL){
+GC_caller_func_offset(ra,&s,&i);
+}
+#endif
+base=GC_base(p);
+if (base==0){
+ABORT_ARG1("Invalid pointer passed to realloc()",":%p",p);
+}
+if ((ptr_t)p - (ptr_t)base!=sizeof(oh)){
+GC_err_printf(
+"GC_debug_realloc called on pointer %p w/o debugging info\n",p);
+return(GC_realloc(p,lb));
+}
+hhdr=HDR(base);
+switch (hhdr->hb_obj_kind){
+case NORMAL:
+result=GC_debug_malloc(lb,OPT_RA s,i);
+break;
+case PTRFREE:
+result=GC_debug_malloc_atomic(lb,OPT_RA s,i);
+break;
+case UNCOLLECTABLE:
+result=GC_debug_malloc_uncollectable(lb,OPT_RA s,i);
+break;
+#ifdef GC_ATOMIC_UNCOLLECTABLE
+case AUNCOLLECTABLE:
+result=GC_debug_malloc_atomic_uncollectable(lb,OPT_RA s,i);
+break;
+#endif
+default:
+result=NULL;
+ABORT_RET("GC_debug_realloc:encountered bad kind");
+}
+if (result!=NULL){
+size_t old_sz;
+#ifdef SHORT_DBG_HDRS
+old_sz=GC_size(base)- sizeof(oh);
+#else
+old_sz=((oh*)base)->oh_sz;
+#endif
+if (old_sz > 0)
+BCOPY(p,result,old_sz < lb?old_sz:lb);
+GC_debug_free(p);
+}
+return(result);
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL
+GC_debug_generic_or_special_malloc(size_t lb,int knd,GC_EXTRA_PARAMS)
+{
+switch (knd){
+case PTRFREE:
+return GC_debug_malloc_atomic(lb,OPT_RA s,i);
+case NORMAL:
+return GC_debug_malloc(lb,OPT_RA s,i);
+case UNCOLLECTABLE:
+return GC_debug_malloc_uncollectable(lb,OPT_RA s,i);
+#ifdef GC_ATOMIC_UNCOLLECTABLE
+case AUNCOLLECTABLE:
+return GC_debug_malloc_atomic_uncollectable(lb,OPT_RA s,i);
+#endif
+default:
+return GC_debug_generic_malloc(lb,knd,OPT_RA s,i);
+}
+}
+#ifndef SHORT_DBG_HDRS
+#ifndef MAX_SMASHED
+#define MAX_SMASHED 20
+#endif
+STATIC ptr_t GC_smashed[MAX_SMASHED]={0};
+STATIC unsigned GC_n_smashed=0;
+STATIC void GC_add_smashed(ptr_t smashed)
+{
+GC_ASSERT(GC_is_marked(GC_base(smashed)));
+GC_smashed[GC_n_smashed]=smashed;
+if (GC_n_smashed < MAX_SMASHED - 1)++GC_n_smashed;
+GC_have_errors=TRUE;
+}
+STATIC void GC_print_all_smashed_proc(void)
+{
+unsigned i;
+GC_ASSERT(I_DONT_HOLD_LOCK());
+if (GC_n_smashed==0)return;
+GC_err_printf("GC_check_heap_block:found %u smashed heap objects:\n",
+GC_n_smashed);
+for (i=0;i < GC_n_smashed;++i){
+ptr_t base=(ptr_t)GC_base(GC_smashed[i]);
+#ifdef LINT2
+if (!base)ABORT("Invalid GC_smashed element");
+#endif
+GC_print_smashed_obj("",base+sizeof(oh),GC_smashed[i]);
+GC_smashed[i]=0;
+}
+GC_n_smashed=0;
+}
+STATIC void GC_check_heap_block(struct hblk*hbp,word dummy GC_ATTR_UNUSED)
+{
+struct hblkhdr*hhdr=HDR(hbp);
+word sz=hhdr->hb_sz;
+word bit_no;
+char*p,*plim;
+p=hbp->hb_body;
+if (sz > MAXOBJBYTES){
+plim=p;
+} else {
+plim=hbp->hb_body+HBLKSIZE - sz;
+}
+for (bit_no=0;(word)p<=(word)plim;
+bit_no+=MARK_BIT_OFFSET(sz),p+=sz){
+if (mark_bit_from_hdr(hhdr,bit_no)&&GC_HAS_DEBUG_INFO((ptr_t)p)){
+ptr_t clobbered=GC_check_annotated_obj((oh*)p);
+if (clobbered!=0)
+GC_add_smashed(clobbered);
+}
+}
+}
+STATIC void GC_check_heap_proc(void)
+{
+GC_STATIC_ASSERT((sizeof(oh)&(GRANULE_BYTES - 1))==0);
+GC_apply_to_all_blocks(GC_check_heap_block,0);
+}
+GC_INNER GC_bool GC_check_leaked(ptr_t base)
+{
+word i;
+word obj_sz;
+word*p;
+if (
+#if defined(KEEP_BACK_PTRS)||defined(MAKE_BACK_GRAPH)
+(*(word*)base&1)!=0&&
+#endif
+GC_has_other_debug_info(base)>=0)
+return TRUE;
+p=(word*)(base+sizeof(oh));
+obj_sz=BYTES_TO_WORDS(HDR(base)->hb_sz - sizeof(oh));
+for (i=0;i < obj_sz;++i)
+if (p[i]!=GC_FREED_MEM_MARKER){
+GC_set_mark_bit(base);
+GC_add_smashed((ptr_t)(&p[i]));
+break;
+}
+return FALSE;
+}
+#endif
+#ifndef GC_NO_FINALIZATION
+struct closure {
+GC_finalization_proc cl_fn;
+void*cl_data;
+};
+STATIC void*GC_make_closure(GC_finalization_proc fn,void*data)
+{
+struct closure*result=
+#ifdef DBG_HDRS_ALL
+(struct closure*)GC_debug_malloc(sizeof (struct closure),
+GC_EXTRAS);
+#else
+(struct closure*)GC_malloc(sizeof (struct closure));
+#endif
+if (result!=0){
+result->cl_fn=fn;
+result->cl_data=data;
+}
+return((void*)result);
+}
+STATIC void GC_CALLBACK GC_debug_invoke_finalizer(void*obj,void*data)
+{
+struct closure*cl=(struct closure*)data;
+(*(cl->cl_fn))((void*)((char*)obj+sizeof(oh)),cl->cl_data);
+}
+#define OFN_UNSET ((GC_finalization_proc)~(signed_word)0)
+static void store_old(void*obj,GC_finalization_proc my_old_fn,
+struct closure*my_old_cd,GC_finalization_proc*ofn,
+void**ocd)
+{
+if (0!=my_old_fn){
+if (my_old_fn==OFN_UNSET){
+return;
+}
+if (my_old_fn!=GC_debug_invoke_finalizer){
+GC_err_printf("Debuggable object at %p had a non-debug finalizer\n",
+obj);
+} else {
+if (ofn)*ofn=my_old_cd->cl_fn;
+if (ocd)*ocd=my_old_cd->cl_data;
+}
+} else {
+if (ofn)*ofn=0;
+if (ocd)*ocd=0;
+}
+}
+GC_API void GC_CALL GC_debug_register_finalizer(void*obj,
+GC_finalization_proc fn,
+void*cd,GC_finalization_proc*ofn,
+void**ocd)
+{
+GC_finalization_proc my_old_fn=OFN_UNSET;
+void*my_old_cd;
+ptr_t base=(ptr_t)GC_base(obj);
+if (NULL==base){
+if (ocd)*ocd=0;
+if (ofn)*ofn=0;
+return;
+}
+if ((ptr_t)obj - base!=sizeof(oh)){
+GC_err_printf("GC_debug_register_finalizer called with"
+" non-base-pointer %p\n",obj);
+}
+if (0==fn){
+GC_register_finalizer(base,0,0,&my_old_fn,&my_old_cd);
+} else {
+cd=GC_make_closure(fn,cd);
+if (cd==0)return;
+GC_register_finalizer(base,GC_debug_invoke_finalizer,
+cd,&my_old_fn,&my_old_cd);
+}
+store_old(obj,my_old_fn,(struct closure*)my_old_cd,ofn,ocd);
+}
+GC_API void GC_CALL GC_debug_register_finalizer_no_order
+(void*obj,GC_finalization_proc fn,
+void*cd,GC_finalization_proc*ofn,
+void**ocd)
+{
+GC_finalization_proc my_old_fn=OFN_UNSET;
+void*my_old_cd;
+ptr_t base=(ptr_t)GC_base(obj);
+if (NULL==base){
+if (ocd)*ocd=0;
+if (ofn)*ofn=0;
+return;
+}
+if ((ptr_t)obj - base!=sizeof(oh)){
+GC_err_printf("GC_debug_register_finalizer_no_order called with"
+" non-base-pointer %p\n",obj);
+}
+if (0==fn){
+GC_register_finalizer_no_order(base,0,0,&my_old_fn,&my_old_cd);
+} else {
+cd=GC_make_closure(fn,cd);
+if (cd==0)return;
+GC_register_finalizer_no_order(base,GC_debug_invoke_finalizer,
+cd,&my_old_fn,&my_old_cd);
+}
+store_old(obj,my_old_fn,(struct closure*)my_old_cd,ofn,ocd);
+}
+GC_API void GC_CALL GC_debug_register_finalizer_unreachable
+(void*obj,GC_finalization_proc fn,
+void*cd,GC_finalization_proc*ofn,
+void**ocd)
+{
+GC_finalization_proc my_old_fn=OFN_UNSET;
+void*my_old_cd;
+ptr_t base=(ptr_t)GC_base(obj);
+if (NULL==base){
+if (ocd)*ocd=0;
+if (ofn)*ofn=0;
+return;
+}
+if ((ptr_t)obj - base!=sizeof(oh)){
+GC_err_printf("GC_debug_register_finalizer_unreachable called with"
+" non-base-pointer %p\n",obj);
+}
+if (0==fn){
+GC_register_finalizer_unreachable(base,0,0,&my_old_fn,&my_old_cd);
+} else {
+cd=GC_make_closure(fn,cd);
+if (cd==0)return;
+GC_register_finalizer_unreachable(base,GC_debug_invoke_finalizer,
+cd,&my_old_fn,&my_old_cd);
+}
+store_old(obj,my_old_fn,(struct closure*)my_old_cd,ofn,ocd);
+}
+GC_API void GC_CALL GC_debug_register_finalizer_ignore_self
+(void*obj,GC_finalization_proc fn,
+void*cd,GC_finalization_proc*ofn,
+void**ocd)
+{
+GC_finalization_proc my_old_fn=OFN_UNSET;
+void*my_old_cd;
+ptr_t base=(ptr_t)GC_base(obj);
+if (NULL==base){
+if (ocd)*ocd=0;
+if (ofn)*ofn=0;
+return;
+}
+if ((ptr_t)obj - base!=sizeof(oh)){
+GC_err_printf("GC_debug_register_finalizer_ignore_self called with"
+" non-base-pointer %p\n",obj);
+}
+if (0==fn){
+GC_register_finalizer_ignore_self(base,0,0,&my_old_fn,&my_old_cd);
+} else {
+cd=GC_make_closure(fn,cd);
+if (cd==0)return;
+GC_register_finalizer_ignore_self(base,GC_debug_invoke_finalizer,
+cd,&my_old_fn,&my_old_cd);
+}
+store_old(obj,my_old_fn,(struct closure*)my_old_cd,ofn,ocd);
+}
+#endif
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_debug_malloc_replacement(size_t lb)
+{
+return GC_debug_malloc(lb,GC_DBG_EXTRAS);
+}
+GC_API void*GC_CALL GC_debug_realloc_replacement(void*p,size_t lb)
+{
+return GC_debug_realloc(p,lb,GC_DBG_EXTRAS);
+}
+#ifndef GC_NO_FINALIZATION
+#ifndef GC_JAVAXFC_H
+#define GC_JAVAXFC_H
+#ifndef GC_H
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+GC_API void GC_CALL GC_finalize_all(void);
+#ifdef GC_THREADS
+#ifndef GC_SUSPEND_THREAD_ID
+#define GC_SUSPEND_THREAD_ID void*
+#endif
+GC_API void GC_CALL GC_suspend_thread(GC_SUSPEND_THREAD_ID);
+GC_API void GC_CALL GC_resume_thread(GC_SUSPEND_THREAD_ID);
+GC_API int GC_CALL GC_is_thread_suspended(GC_SUSPEND_THREAD_ID);
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+typedef void (*finalization_mark_proc)(ptr_t);
+#define HASH3(addr,size,log_size)((((word)(addr)>>3)^((word)(addr)>>(3+(log_size))))&((size)- 1))
+#define HASH2(addr,log_size)HASH3(addr,(word)1<<(log_size),log_size)
+struct hash_chain_entry {
+word hidden_key;
+struct hash_chain_entry*next;
+};
+struct disappearing_link {
+struct hash_chain_entry prolog;
+#define dl_hidden_link prolog.hidden_key
+#define dl_next(x)(struct disappearing_link*)((x)->prolog.next)
+#define dl_set_next(x,y)(void)((x)->prolog.next=(struct hash_chain_entry*)(y))
+word dl_hidden_obj;
+};
+struct finalizable_object {
+struct hash_chain_entry prolog;
+#define fo_hidden_base prolog.hidden_key
+#define fo_next(x)(struct finalizable_object*)((x)->prolog.next)
+#define fo_set_next(x,y)((x)->prolog.next=(struct hash_chain_entry*)(y))
+GC_finalization_proc fo_fn;
+ptr_t fo_client_data;
+word fo_object_size;
+finalization_mark_proc fo_mark_proc;
+};
+#ifdef AO_HAVE_store
+#define SET_FINALIZE_NOW(fo)AO_store((volatile AO_t*)&GC_fnlz_roots.finalize_now,(AO_t)(fo))
+#else
+#define SET_FINALIZE_NOW(fo)(void)(GC_fnlz_roots.finalize_now=(fo))
+#endif
+GC_API void GC_CALL GC_push_finalizer_structures(void)
+{
+GC_ASSERT((word)(&GC_dl_hashtbl.head)% sizeof(word)==0);
+GC_ASSERT((word)(&GC_fnlz_roots)% sizeof(word)==0);
+#ifndef GC_LONG_REFS_NOT_NEEDED
+GC_ASSERT((word)(&GC_ll_hashtbl.head)% sizeof(word)==0);
+GC_PUSH_ALL_SYM(GC_ll_hashtbl.head);
+#endif
+GC_PUSH_ALL_SYM(GC_dl_hashtbl.head);
+GC_PUSH_ALL_SYM(GC_fnlz_roots);
+}
+#ifndef GC_ON_GROW_LOG_SIZE_MIN
+#define GC_ON_GROW_LOG_SIZE_MIN CPP_LOG_HBLKSIZE
+#endif
+STATIC void GC_grow_table(struct hash_chain_entry***table,
+unsigned*log_size_ptr,word*entries_ptr)
+{
+word i;
+struct hash_chain_entry*p;
+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;
+struct hash_chain_entry**new_table;
+GC_ASSERT(I_HOLD_LOCK());
+if (log_old_size>=GC_ON_GROW_LOG_SIZE_MIN&&!GC_incremental){
+IF_CANCEL(int cancel_state;)
+DISABLE_CANCEL(cancel_state);
+(void)GC_try_to_collect_inner(GC_never_stop_func);
+RESTORE_CANCEL(cancel_state);
+if (*entries_ptr < ((word)1<<log_old_size)- (*entries_ptr>>2))
+return;
+}
+new_table=(struct hash_chain_entry**)
+GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
+(size_t)new_size*sizeof(struct hash_chain_entry*),
+NORMAL);
+if (new_table==0){
+if (*table==0){
+ABORT("Insufficient space for initial table allocation");
+} else {
+return;
+}
+}
+for (i=0;i < old_size;i++){
+p=(*table)[i];
+while (p!=0){
+ptr_t real_key=(ptr_t)GC_REVEAL_POINTER(p->hidden_key);
+struct hash_chain_entry*next=p->next;
+size_t new_hash=HASH3(real_key,new_size,log_new_size);
+p->next=new_table[new_hash];
+GC_dirty(p);
+new_table[new_hash]=p;
+p=next;
+}
+}
+*log_size_ptr=log_new_size;
+*table=new_table;
+GC_dirty(new_table);
+}
+GC_API int GC_CALL GC_register_disappearing_link(void**link)
+{
+ptr_t base;
+base=(ptr_t)GC_base(link);
+if (base==0)
+ABORT("Bad arg to GC_register_disappearing_link");
+return(GC_general_register_disappearing_link(link,base));
+}
+STATIC int GC_register_disappearing_link_inner(
+struct dl_hashtbl_s*dl_hashtbl,void**link,
+const void*obj,const char*tbl_log_name)
+{
+struct disappearing_link*curr_dl;
+size_t index;
+struct disappearing_link*new_dl;
+DCL_LOCK_STATE;
+if (EXPECT(GC_find_leak,FALSE))return GC_UNIMPLEMENTED;
+LOCK();
+GC_ASSERT(obj!=NULL&&GC_base_C(obj)==obj);
+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);
+GC_COND_LOG_PRINTF("Grew %s table to %u entries\n",tbl_log_name,
+1U<<dl_hashtbl->log_size);
+}
+index=HASH2(link,dl_hashtbl->log_size);
+for (curr_dl=dl_hashtbl->head[index];curr_dl!=0;
+curr_dl=dl_next(curr_dl)){
+if (curr_dl->dl_hidden_link==GC_HIDE_POINTER(link)){
+curr_dl->dl_hidden_obj=GC_HIDE_POINTER(obj);
+UNLOCK();
+return GC_DUPLICATE;
+}
+}
+new_dl=(struct disappearing_link*)
+GC_INTERNAL_MALLOC(sizeof(struct disappearing_link),NORMAL);
+if (0==new_dl){
+GC_oom_func oom_fn=GC_oom_fn;
+UNLOCK();
+new_dl=(struct disappearing_link*)
+(*oom_fn)(sizeof(struct disappearing_link));
+if (0==new_dl){
+return GC_NO_MEMORY;
+}
+LOCK();
+index=HASH2(link,dl_hashtbl->log_size);
+for (curr_dl=dl_hashtbl->head[index];curr_dl!=0;
+curr_dl=dl_next(curr_dl)){
+if (curr_dl->dl_hidden_link==GC_HIDE_POINTER(link)){
+curr_dl->dl_hidden_obj=GC_HIDE_POINTER(obj);
+UNLOCK();
+#ifndef DBG_HDRS_ALL
+GC_free((void*)new_dl);
+#endif
+return GC_DUPLICATE;
+}
+}
+}
+new_dl->dl_hidden_obj=GC_HIDE_POINTER(obj);
+new_dl->dl_hidden_link=GC_HIDE_POINTER(link);
+dl_set_next(new_dl,dl_hashtbl->head[index]);
+GC_dirty(new_dl);
+dl_hashtbl->head[index]=new_dl;
+dl_hashtbl->entries++;
+GC_dirty(dl_hashtbl->head+index);
+UNLOCK();
+return GC_SUCCESS;
+}
+GC_API int GC_CALL GC_general_register_disappearing_link(void**link,
+const void*obj)
+{
+if (((word)link&(ALIGNMENT-1))!=0||!NONNULL_ARG_NOT_NULL(link))
+ABORT("Bad arg to GC_general_register_disappearing_link");
+return GC_register_disappearing_link_inner(&GC_dl_hashtbl,link,obj,
+"dl");
+}
+#ifdef DBG_HDRS_ALL
+#define FREE_DL_ENTRY(curr_dl)dl_set_next(curr_dl,NULL)
+#else
+#define FREE_DL_ENTRY(curr_dl)GC_free(curr_dl)
+#endif
+GC_INLINE struct disappearing_link*GC_unregister_disappearing_link_inner(
+struct dl_hashtbl_s*dl_hashtbl,void**link)
+{
+struct disappearing_link*curr_dl;
+struct disappearing_link*prev_dl=NULL;
+size_t index;
+GC_ASSERT(I_HOLD_LOCK());
+if (EXPECT(NULL==dl_hashtbl->head,FALSE))return NULL;
+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)){
+if (NULL==prev_dl){
+dl_hashtbl->head[index]=dl_next(curr_dl);
+GC_dirty(dl_hashtbl->head+index);
+} else {
+dl_set_next(prev_dl,dl_next(curr_dl));
+GC_dirty(prev_dl);
+}
+dl_hashtbl->entries--;
+break;
+}
+prev_dl=curr_dl;
+}
+return curr_dl;
+}
+GC_API int GC_CALL GC_unregister_disappearing_link(void**link)
+{
+struct disappearing_link*curr_dl;
+DCL_LOCK_STATE;
+if (((word)link&(ALIGNMENT-1))!=0)return(0);
+LOCK();
+curr_dl=GC_unregister_disappearing_link_inner(&GC_dl_hashtbl,link);
+UNLOCK();
+if (NULL==curr_dl)return 0;
+FREE_DL_ENTRY(curr_dl);
+return 1;
+}
+#ifndef GC_TOGGLE_REFS_NOT_NEEDED
+typedef union toggle_ref_u GCToggleRef;
+STATIC GC_toggleref_func GC_toggleref_callback=0;
+GC_INNER void GC_process_togglerefs(void)
+{
+size_t i;
+size_t new_size=0;
+GC_bool needs_barrier=FALSE;
+GC_ASSERT(I_HOLD_LOCK());
+for (i=0;i < GC_toggleref_array_size;++i){
+GCToggleRef r=GC_toggleref_arr[i];
+void*obj=r.strong_ref;
+if (((word)obj&1)!=0){
+obj=GC_REVEAL_POINTER(r.weak_ref);
+}
+if (NULL==obj){
+continue;
+}
+switch (GC_toggleref_callback(obj)){
+case GC_TOGGLE_REF_DROP:
+break;
+case GC_TOGGLE_REF_STRONG:
+GC_toggleref_arr[new_size++].strong_ref=obj;
+needs_barrier=TRUE;
+break;
+case GC_TOGGLE_REF_WEAK:
+GC_toggleref_arr[new_size++].weak_ref=GC_HIDE_POINTER(obj);
+break;
+default:
+ABORT("Bad toggle-ref status returned by callback");
+}
+}
+if (new_size < GC_toggleref_array_size){
+BZERO(&GC_toggleref_arr[new_size],
+(GC_toggleref_array_size - new_size)*sizeof(GCToggleRef));
+GC_toggleref_array_size=new_size;
+}
+if (needs_barrier)
+GC_dirty(GC_toggleref_arr);
+}
+STATIC void GC_normal_finalize_mark_proc(ptr_t);
+static void push_and_mark_object(void*p)
+{
+GC_normal_finalize_mark_proc((ptr_t)p);
+while (!GC_mark_stack_empty()){
+MARK_FROM_MARK_STACK();
+}
+GC_set_mark_bit(p);
+if (GC_mark_state!=MS_NONE){
+while (!GC_mark_some(0)){
+}
+}
+}
+STATIC void GC_mark_togglerefs(void)
+{
+size_t i;
+if (NULL==GC_toggleref_arr)
+return;
+GC_set_mark_bit(GC_toggleref_arr);
+for (i=0;i < GC_toggleref_array_size;++i){
+void*obj=GC_toggleref_arr[i].strong_ref;
+if (obj!=NULL&&((word)obj&1)==0){
+push_and_mark_object(obj);
+}
+}
+}
+STATIC void GC_clear_togglerefs(void)
+{
+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))){
+GC_toggleref_arr[i].weak_ref=0;
+} else {
+}
+}
+}
+}
+GC_API void GC_CALL GC_set_toggleref_func(GC_toggleref_func fn)
+{
+DCL_LOCK_STATE;
+LOCK();
+GC_toggleref_callback=fn;
+UNLOCK();
+}
+GC_API GC_toggleref_func GC_CALL GC_get_toggleref_func(void)
+{
+GC_toggleref_func fn;
+DCL_LOCK_STATE;
+LOCK();
+fn=GC_toggleref_callback;
+UNLOCK();
+return fn;
+}
+static GC_bool ensure_toggleref_capacity(size_t capacity_inc)
+{
+GC_ASSERT(I_HOLD_LOCK());
+if (NULL==GC_toggleref_arr){
+GC_toggleref_array_capacity=32;
+GC_toggleref_arr=(GCToggleRef*)GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
+GC_toggleref_array_capacity*sizeof(GCToggleRef),
+NORMAL);
+if (NULL==GC_toggleref_arr)
+return FALSE;
+}
+if (GC_toggleref_array_size+capacity_inc
+>=GC_toggleref_array_capacity){
+GCToggleRef*new_array;
+while (GC_toggleref_array_capacity
+< GC_toggleref_array_size+capacity_inc){
+GC_toggleref_array_capacity*=2;
+if ((GC_toggleref_array_capacity
+&((size_t)1<<(sizeof(size_t)*8 - 1)))!=0)
+return FALSE;
+}
+new_array=(GCToggleRef*)GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
+GC_toggleref_array_capacity*sizeof(GCToggleRef),
+NORMAL);
+if (NULL==new_array)
+return FALSE;
+if (EXPECT(GC_toggleref_array_size > 0,TRUE))
+BCOPY(GC_toggleref_arr,new_array,
+GC_toggleref_array_size*sizeof(GCToggleRef));
+GC_INTERNAL_FREE(GC_toggleref_arr);
+GC_toggleref_arr=new_array;
+}
+return TRUE;
+}
+GC_API int GC_CALL GC_toggleref_add(void*obj,int is_strong_ref)
+{
+int res=GC_SUCCESS;
+DCL_LOCK_STATE;
+GC_ASSERT(NONNULL_ARG_NOT_NULL(obj));
+LOCK();
+if (GC_toggleref_callback!=0){
+if (!ensure_toggleref_capacity(1)){
+res=GC_NO_MEMORY;
+} else {
+GC_toggleref_arr[GC_toggleref_array_size].strong_ref=
+is_strong_ref?obj:(void*)GC_HIDE_POINTER(obj);
+if (is_strong_ref)
+GC_dirty(GC_toggleref_arr+GC_toggleref_array_size);
+GC_toggleref_array_size++;
+}
+}
+UNLOCK();
+return res;
+}
+#endif
+STATIC GC_await_finalize_proc GC_object_finalized_proc=0;
+GC_API void GC_CALL GC_set_await_finalize_proc(GC_await_finalize_proc fn)
+{
+DCL_LOCK_STATE;
+LOCK();
+GC_object_finalized_proc=fn;
+UNLOCK();
+}
+GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void)
+{
+GC_await_finalize_proc fn;
+DCL_LOCK_STATE;
+LOCK();
+fn=GC_object_finalized_proc;
+UNLOCK();
+return fn;
+}
+#ifndef GC_LONG_REFS_NOT_NEEDED
+GC_API int GC_CALL GC_register_long_link(void**link,const void*obj)
+{
+if (((word)link&(ALIGNMENT-1))!=0||!NONNULL_ARG_NOT_NULL(link))
+ABORT("Bad arg to GC_register_long_link");
+return GC_register_disappearing_link_inner(&GC_ll_hashtbl,link,obj,
+"long dl");
+}
+GC_API int GC_CALL GC_unregister_long_link(void**link)
+{
+struct disappearing_link*curr_dl;
+DCL_LOCK_STATE;
+if (((word)link&(ALIGNMENT-1))!=0)return(0);
+LOCK();
+curr_dl=GC_unregister_disappearing_link_inner(&GC_ll_hashtbl,link);
+UNLOCK();
+if (NULL==curr_dl)return 0;
+FREE_DL_ENTRY(curr_dl);
+return 1;
+}
+#endif
+#ifndef GC_MOVE_DISAPPEARING_LINK_NOT_NEEDED
+STATIC int GC_move_disappearing_link_inner(
+struct dl_hashtbl_s*dl_hashtbl,
+void**link,void**new_link)
+{
+struct disappearing_link*curr_dl,*new_dl;
+struct disappearing_link*prev_dl=NULL;
+size_t curr_index,new_index;
+word curr_hidden_link,new_hidden_link;
+GC_ASSERT(I_HOLD_LOCK());
+if (EXPECT(NULL==dl_hashtbl->head,FALSE))return GC_NOT_FOUND;
+curr_index=HASH2(link,dl_hashtbl->log_size);
+curr_hidden_link=GC_HIDE_POINTER(link);
+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 (EXPECT(NULL==curr_dl,FALSE)){
+return GC_NOT_FOUND;
+} else if (link==new_link){
+return GC_SUCCESS;
+}
+new_index=HASH2(new_link,dl_hashtbl->log_size);
+new_hidden_link=GC_HIDE_POINTER(new_link);
+for (new_dl=dl_hashtbl->head[new_index];new_dl;
+new_dl=dl_next(new_dl)){
+if (new_dl->dl_hidden_link==new_hidden_link){
+return GC_DUPLICATE;
+}
+}
+if (NULL==prev_dl){
+dl_hashtbl->head[curr_index]=dl_next(curr_dl);
+} else {
+dl_set_next(prev_dl,dl_next(curr_dl));
+GC_dirty(prev_dl);
+}
+curr_dl->dl_hidden_link=new_hidden_link;
+dl_set_next(curr_dl,dl_hashtbl->head[new_index]);
+dl_hashtbl->head[new_index]=curr_dl;
+GC_dirty(curr_dl);
+GC_dirty(dl_hashtbl->head);
+return GC_SUCCESS;
+}
+GC_API int GC_CALL GC_move_disappearing_link(void**link,void**new_link)
+{
+int result;
+DCL_LOCK_STATE;
+if (((word)new_link&(ALIGNMENT-1))!=0
+||!NONNULL_ARG_NOT_NULL(new_link))
+ABORT("Bad new_link arg to GC_move_disappearing_link");
+if (((word)link&(ALIGNMENT-1))!=0)
+return GC_NOT_FOUND;
+LOCK();
+result=GC_move_disappearing_link_inner(&GC_dl_hashtbl,link,new_link);
+UNLOCK();
+return result;
+}
+#ifndef GC_LONG_REFS_NOT_NEEDED
+GC_API int GC_CALL GC_move_long_link(void**link,void**new_link)
+{
+int result;
+DCL_LOCK_STATE;
+if (((word)new_link&(ALIGNMENT-1))!=0
+||!NONNULL_ARG_NOT_NULL(new_link))
+ABORT("Bad new_link arg to GC_move_long_link");
+if (((word)link&(ALIGNMENT-1))!=0)
+return GC_NOT_FOUND;
+LOCK();
+result=GC_move_disappearing_link_inner(&GC_ll_hashtbl,link,new_link);
+UNLOCK();
+return result;
+}
+#endif
+#endif
+STATIC void GC_normal_finalize_mark_proc(ptr_t p)
+{
+#if defined(_MSC_VER)&&defined(I386)
+hdr*hhdr=HDR(p);
+#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
+}
+STATIC void GC_ignore_self_finalize_mark_proc(ptr_t p)
+{
+hdr*hhdr=HDR(p);
+word descr=hhdr->hb_descr;
+ptr_t q;
+ptr_t scan_limit;
+ptr_t target_limit=p+hhdr->hb_sz - 1;
+if ((descr&GC_DS_TAGS)==GC_DS_LENGTH){
+scan_limit=p+descr - sizeof(word);
+} else {
+scan_limit=target_limit+1 - sizeof(word);
+}
+for (q=p;(word)q<=(word)scan_limit;q+=ALIGNMENT){
+word r=*(word*)q;
+if (r < (word)p||r > (word)target_limit){
+GC_PUSH_ONE_HEAP(r,q,GC_mark_stack_top);
+}
+}
+}
+STATIC void GC_null_finalize_mark_proc(ptr_t p GC_ATTR_UNUSED){}
+STATIC void GC_unreachable_finalize_mark_proc(ptr_t p)
+{
+GC_normal_finalize_mark_proc(p);
+}
+STATIC void GC_register_finalizer_inner(void*obj,
+GC_finalization_proc fn,void*cd,
+GC_finalization_proc*ofn,void**ocd,
+finalization_mark_proc mp)
+{
+struct finalizable_object*curr_fo;
+size_t index;
+struct finalizable_object*new_fo=0;
+hdr*hhdr=NULL;
+DCL_LOCK_STATE;
+if (EXPECT(GC_find_leak,FALSE))return;
+LOCK();
+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,
+&GC_log_fo_table_size,&GC_fo_entries);
+GC_COND_LOG_PRINTF("Grew fo table to %u entries\n",
+1U<<GC_log_fo_table_size);
+}
+for (;;){
+struct finalizable_object*prev_fo=NULL;
+GC_oom_func oom_fn;
+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));
+if (curr_fo->fo_hidden_base==GC_HIDE_POINTER(obj)){
+if (ocd)*ocd=(void*)(curr_fo->fo_client_data);
+if (ofn)*ofn=curr_fo->fo_fn;
+if (prev_fo==0){
+GC_fnlz_roots.fo_head[index]=fo_next(curr_fo);
+} else {
+fo_set_next(prev_fo,fo_next(curr_fo));
+GC_dirty(prev_fo);
+}
+if (fn==0){
+GC_fo_entries--;
+#if!defined(THREADS)&&!defined(DBG_HDRS_ALL)
+GC_free((void*)curr_fo);
+#endif
+} else {
+curr_fo->fo_fn=fn;
+curr_fo->fo_client_data=(ptr_t)cd;
+curr_fo->fo_mark_proc=mp;
+GC_dirty(curr_fo);
+if (prev_fo==0){
+GC_fnlz_roots.fo_head[index]=curr_fo;
+} else {
+fo_set_next(prev_fo,curr_fo);
+GC_dirty(prev_fo);
+}
+}
+if (NULL==prev_fo)
+GC_dirty(GC_fnlz_roots.fo_head+index);
+UNLOCK();
+#ifndef DBG_HDRS_ALL
+GC_free((void*)new_fo);
+#endif
+return;
+}
+prev_fo=curr_fo;
+curr_fo=fo_next(curr_fo);
+}
+if (EXPECT(new_fo!=0,FALSE)){
+GC_ASSERT(fn!=0);
+#ifdef LINT2
+if (NULL==hhdr)ABORT("Bad hhdr in GC_register_finalizer_inner");
+#endif
+break;
+}
+if (fn==0){
+if (ocd)*ocd=0;
+if (ofn)*ofn=0;
+UNLOCK();
+return;
+}
+GET_HDR(obj,hhdr);
+if (EXPECT(0==hhdr,FALSE)){
+if (ocd)*ocd=0;
+if (ofn)*ofn=0;
+UNLOCK();
+return;
+}
+new_fo=(struct finalizable_object*)
+GC_INTERNAL_MALLOC(sizeof(struct finalizable_object),NORMAL);
+if (EXPECT(new_fo!=0,TRUE))
+break;
+oom_fn=GC_oom_fn;
+UNLOCK();
+new_fo=(struct finalizable_object*)
+(*oom_fn)(sizeof(struct finalizable_object));
+if (0==new_fo){
+return;
+}
+LOCK();
+}
+GC_ASSERT(GC_size(new_fo)>=sizeof(struct finalizable_object));
+if (ocd)*ocd=0;
+if (ofn)*ofn=0;
+new_fo->fo_hidden_base=GC_HIDE_POINTER(obj);
+new_fo->fo_fn=fn;
+new_fo->fo_client_data=(ptr_t)cd;
+new_fo->fo_object_size=hhdr->hb_sz;
+new_fo->fo_mark_proc=mp;
+fo_set_next(new_fo,GC_fnlz_roots.fo_head[index]);
+GC_dirty(new_fo);
+GC_fo_entries++;
+GC_fnlz_roots.fo_head[index]=new_fo;
+GC_dirty(GC_fnlz_roots.fo_head+index);
+UNLOCK();
+}
+GC_API void GC_CALL GC_register_finalizer(void*obj,
+GC_finalization_proc fn,void*cd,
+GC_finalization_proc*ofn,void**ocd)
+{
+GC_register_finalizer_inner(obj,fn,cd,ofn,
+ocd,GC_normal_finalize_mark_proc);
+}
+GC_API void GC_CALL GC_register_finalizer_ignore_self(void*obj,
+GC_finalization_proc fn,void*cd,
+GC_finalization_proc*ofn,void**ocd)
+{
+GC_register_finalizer_inner(obj,fn,cd,ofn,
+ocd,GC_ignore_self_finalize_mark_proc);
+}
+GC_API void GC_CALL GC_register_finalizer_no_order(void*obj,
+GC_finalization_proc fn,void*cd,
+GC_finalization_proc*ofn,void**ocd)
+{
+GC_register_finalizer_inner(obj,fn,cd,ofn,
+ocd,GC_null_finalize_mark_proc);
+}
+static GC_bool need_unreachable_finalization=FALSE;
+GC_API void GC_CALL GC_register_finalizer_unreachable(void*obj,
+GC_finalization_proc fn,void*cd,
+GC_finalization_proc*ofn,void**ocd)
+{
+need_unreachable_finalization=TRUE;
+GC_ASSERT(GC_java_finalization);
+GC_register_finalizer_inner(obj,fn,cd,ofn,
+ocd,GC_unreachable_finalize_mark_proc);
+}
+#ifndef NO_DEBUGGING
+STATIC void GC_dump_finalization_links(
+const struct dl_hashtbl_s*dl_hashtbl)
+{
+size_t dl_size=(size_t)1<<dl_hashtbl->log_size;
+size_t i;
+if (NULL==dl_hashtbl->head)return;
+for (i=0;i < dl_size;i++){
+struct disappearing_link*curr_dl;
+for (curr_dl=dl_hashtbl->head[i];curr_dl!=0;
+curr_dl=dl_next(curr_dl)){
+ptr_t real_ptr=(ptr_t)GC_REVEAL_POINTER(curr_dl->dl_hidden_obj);
+ptr_t real_link=(ptr_t)GC_REVEAL_POINTER(curr_dl->dl_hidden_link);
+GC_printf("Object:%p,link:%p\n",
+(void*)real_ptr,(void*)real_link);
+}
+}
+}
+GC_API void GC_CALL GC_dump_finalization(void)
+{
+struct finalizable_object*curr_fo;
+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);
+#ifndef GC_LONG_REFS_NOT_NEEDED
+GC_printf("Disappearing long links:\n");
+GC_dump_finalization_links(&GC_ll_hashtbl);
+#endif
+GC_printf("Finalizers:\n");
+for (i=0;i < fo_size;i++){
+for (curr_fo=GC_fnlz_roots.fo_head[i];
+curr_fo!=NULL;curr_fo=fo_next(curr_fo)){
+ptr_t real_ptr=(ptr_t)GC_REVEAL_POINTER(curr_fo->fo_hidden_base);
+GC_printf("Finalizable object:%p\n",(void*)real_ptr);
+}
+}
+}
+#endif
+#ifndef SMALL_CONFIG
+STATIC word GC_old_dl_entries=0;
+#ifndef GC_LONG_REFS_NOT_NEEDED
+STATIC word GC_old_ll_entries=0;
+#endif
+#endif
+#ifndef THREADS
+STATIC int GC_finalizer_nested=0;
+STATIC unsigned GC_finalizer_skipped=0;
+STATIC unsigned char*GC_check_finalizer_nested(void)
+{
+unsigned nesting_level=*(unsigned char*)&GC_finalizer_nested;
+if (nesting_level){
+if (++GC_finalizer_skipped < (1U<<nesting_level))return NULL;
+GC_finalizer_skipped=0;
+}
+*(char*)&GC_finalizer_nested=(char)(nesting_level+1);
+return (unsigned char*)&GC_finalizer_nested;
+}
+#endif
+GC_INLINE void GC_make_disappearing_links_disappear(
+struct dl_hashtbl_s*dl_hashtbl,
+GC_bool is_remove_dangling)
+{
+size_t i;
+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;
+for (i=0;i < dl_size;i++){
+struct disappearing_link*curr_dl,*next_dl;
+struct disappearing_link*prev_dl=NULL;
+for (curr_dl=dl_hashtbl->head[i];curr_dl!=NULL;curr_dl=next_dl){
+next_dl=dl_next(curr_dl);
+if (is_remove_dangling){
+ptr_t real_link=(ptr_t)GC_base(GC_REVEAL_POINTER(
+curr_dl->dl_hidden_link));
+if (NULL==real_link||EXPECT(GC_is_marked(real_link),TRUE)){
+prev_dl=curr_dl;
+continue;
+}
+} else {
+if (EXPECT(GC_is_marked((ptr_t)GC_REVEAL_POINTER(
+curr_dl->dl_hidden_obj)),TRUE)){
+prev_dl=curr_dl;
+continue;
+}
+*(ptr_t*)GC_REVEAL_POINTER(curr_dl->dl_hidden_link)=NULL;
+}
+if (NULL==prev_dl){
+dl_hashtbl->head[i]=next_dl;
+needs_barrier=TRUE;
+} else {
+dl_set_next(prev_dl,next_dl);
+GC_dirty(prev_dl);
+}
+GC_clear_mark_bit(curr_dl);
+dl_hashtbl->entries--;
+}
+}
+if (needs_barrier)
+GC_dirty(dl_hashtbl->head);
+}
+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=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());
+#ifndef SMALL_CONFIG
+GC_old_dl_entries=GC_dl_hashtbl.entries;
+#ifndef GC_LONG_REFS_NOT_NEEDED
+GC_old_ll_entries=GC_ll_hashtbl.entries;
+#endif
+#endif
+#ifndef GC_TOGGLE_REFS_NOT_NEEDED
+GC_mark_togglerefs();
+#endif
+GC_make_disappearing_links_disappear(&GC_dl_hashtbl,FALSE);
+GC_ASSERT(GC_mark_state==MS_NONE);
+for (i=0;i < fo_size;i++){
+for (curr_fo=GC_fnlz_roots.fo_head[i];
+curr_fo!=NULL;curr_fo=fo_next(curr_fo)){
+GC_ASSERT(GC_size(curr_fo)>=sizeof(struct finalizable_object));
+real_ptr=(ptr_t)GC_REVEAL_POINTER(curr_fo->fo_hidden_base);
+if (!GC_is_marked(real_ptr)){
+GC_MARKED_FOR_FINALIZATION(real_ptr);
+GC_MARK_FO(real_ptr,curr_fo->fo_mark_proc);
+if (GC_is_marked(real_ptr)){
+WARN("Finalization cycle involving %p\n",real_ptr);
+}
+}
+}
+}
+GC_bytes_finalized=0;
+for (i=0;i < fo_size;i++){
+curr_fo=GC_fnlz_roots.fo_head[i];
+prev_fo=0;
+while (curr_fo!=0){
+real_ptr=(ptr_t)GC_REVEAL_POINTER(curr_fo->fo_hidden_base);
+if (!GC_is_marked(real_ptr)){
+if (!GC_java_finalization){
+GC_set_mark_bit(real_ptr);
+}
+next_fo=fo_next(curr_fo);
+if (NULL==prev_fo){
+GC_fnlz_roots.fo_head[i]=next_fo;
+if (GC_object_finalized_proc){
+GC_dirty(GC_fnlz_roots.fo_head+i);
+} else {
+needs_barrier=TRUE;
+}
+} else {
+fo_set_next(prev_fo,next_fo);
+GC_dirty(prev_fo);
+}
+GC_fo_entries--;
+if (GC_object_finalized_proc)
+GC_object_finalized_proc(real_ptr);
+fo_set_next(curr_fo,GC_fnlz_roots.finalize_now);
+GC_dirty(curr_fo);
+SET_FINALIZE_NOW(curr_fo);
+curr_fo->fo_hidden_base=
+(word)GC_REVEAL_POINTER(curr_fo->fo_hidden_base);
+GC_bytes_finalized+=
+curr_fo->fo_object_size
++sizeof(struct finalizable_object);
+GC_ASSERT(GC_is_marked(GC_base(curr_fo)));
+curr_fo=next_fo;
+} else {
+prev_fo=curr_fo;
+curr_fo=fo_next(curr_fo);
+}
+}
+}
+if (GC_java_finalization){
+for (curr_fo=GC_fnlz_roots.finalize_now;
+curr_fo!=NULL;curr_fo=fo_next(curr_fo)){
+real_ptr=(ptr_t)curr_fo->fo_hidden_base;
+if (!GC_is_marked(real_ptr)){
+if (curr_fo->fo_mark_proc==GC_null_finalize_mark_proc){
+GC_MARK_FO(real_ptr,GC_normal_finalize_mark_proc);
+}
+if (curr_fo->fo_mark_proc!=GC_unreachable_finalize_mark_proc){
+GC_set_mark_bit(real_ptr);
+}
+}
+}
+if (need_unreachable_finalization){
+curr_fo=GC_fnlz_roots.finalize_now;
+GC_ASSERT(NULL==curr_fo||GC_fnlz_roots.fo_head!=NULL);
+prev_fo=NULL;
+while (curr_fo!=NULL){
+next_fo=fo_next(curr_fo);
+if (curr_fo->fo_mark_proc==GC_unreachable_finalize_mark_proc){
+real_ptr=(ptr_t)curr_fo->fo_hidden_base;
+if (!GC_is_marked(real_ptr)){
+GC_set_mark_bit(real_ptr);
+} else {
+if (NULL==prev_fo){
+SET_FINALIZE_NOW(next_fo);
+} else {
+fo_set_next(prev_fo,next_fo);
+GC_dirty(prev_fo);
+}
+curr_fo->fo_hidden_base=
+GC_HIDE_POINTER(curr_fo->fo_hidden_base);
+GC_bytes_finalized-=
+curr_fo->fo_object_size+sizeof(struct finalizable_object);
+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++;
+GC_fnlz_roots.fo_head[i]=curr_fo;
+curr_fo=prev_fo;
+needs_barrier=TRUE;
+}
+}
+prev_fo=curr_fo;
+curr_fo=next_fo;
+}
+}
+}
+if (needs_barrier)
+GC_dirty(GC_fnlz_roots.fo_head);
+GC_make_disappearing_links_disappear(&GC_dl_hashtbl,TRUE);
+#ifndef GC_TOGGLE_REFS_NOT_NEEDED
+GC_clear_togglerefs();
+#endif
+#ifndef GC_LONG_REFS_NOT_NEEDED
+GC_make_disappearing_links_disappear(&GC_ll_hashtbl,FALSE);
+GC_make_disappearing_links_disappear(&GC_ll_hashtbl,TRUE);
+#endif
+if (GC_fail_count){
+#ifdef THREADS
+GC_reset_finalizer_nested();
+#else
+GC_finalizer_nested=0;
+#endif
+}
+}
+#ifndef JAVA_FINALIZATION_NOT_NEEDED
+STATIC void GC_enqueue_all_finalizers(void)
+{
+struct finalizable_object*next_fo;
+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());
+GC_bytes_finalized=0;
+for (i=0;i < fo_size;i++){
+struct finalizable_object*curr_fo=GC_fnlz_roots.fo_head[i];
+GC_fnlz_roots.fo_head[i]=NULL;
+while (curr_fo!=NULL){
+ptr_t real_ptr=(ptr_t)GC_REVEAL_POINTER(curr_fo->fo_hidden_base);
+GC_MARK_FO(real_ptr,GC_normal_finalize_mark_proc);
+GC_set_mark_bit(real_ptr);
+next_fo=fo_next(curr_fo);
+fo_set_next(curr_fo,GC_fnlz_roots.finalize_now);
+GC_dirty(curr_fo);
+SET_FINALIZE_NOW(curr_fo);
+curr_fo->fo_hidden_base=
+(word)GC_REVEAL_POINTER(curr_fo->fo_hidden_base);
+GC_bytes_finalized+=
+curr_fo->fo_object_size+sizeof(struct finalizable_object);
+curr_fo=next_fo;
+}
+}
+GC_fo_entries=0;
+}
+GC_API void GC_CALL GC_finalize_all(void)
+{
+DCL_LOCK_STATE;
+LOCK();
+while (GC_fo_entries > 0){
+GC_enqueue_all_finalizers();
+UNLOCK();
+GC_invoke_finalizers();
+LOCK();
+}
+UNLOCK();
+}
+#endif
+GC_API int GC_CALL GC_should_invoke_finalizers(void)
+{
+#ifdef AO_HAVE_load
+return AO_load((volatile AO_t*)&GC_fnlz_roots.finalize_now)!=0;
+#else
+return GC_fnlz_roots.finalize_now!=NULL;
+#endif
+}
+GC_API int GC_CALL GC_invoke_finalizers(void)
+{
+int count=0;
+word bytes_freed_before=0;
+DCL_LOCK_STATE;
+while (GC_should_invoke_finalizers()){
+struct finalizable_object*curr_fo;
+#ifdef THREADS
+LOCK();
+#endif
+if (count==0){
+bytes_freed_before=GC_bytes_freed;
+}
+curr_fo=GC_fnlz_roots.finalize_now;
+#ifdef THREADS
+if (curr_fo!=NULL)
+SET_FINALIZE_NOW(fo_next(curr_fo));
+UNLOCK();
+if (curr_fo==0)break;
+#else
+GC_fnlz_roots.finalize_now=fo_next(curr_fo);
+#endif
+fo_set_next(curr_fo,0);
+(*(curr_fo->fo_fn))((ptr_t)(curr_fo->fo_hidden_base),
+curr_fo->fo_client_data);
+curr_fo->fo_client_data=0;
+++count;
+}
+if (count!=0
+#if defined(THREADS)&&!defined(THREAD_SANITIZER)
+&&bytes_freed_before!=GC_bytes_freed
+#endif
+){
+LOCK();
+GC_finalizer_bytes_freed+=(GC_bytes_freed - bytes_freed_before);
+UNLOCK();
+}
+return count;
+}
+static word last_finalizer_notification=0;
+GC_INNER void GC_notify_or_invoke_finalizers(void)
+{
+GC_finalizer_notifier_proc notifier_fn=0;
+#if defined(KEEP_BACK_PTRS)||defined(MAKE_BACK_GRAPH)
+static word last_back_trace_gc_no=1;
+#endif
+DCL_LOCK_STATE;
+#if defined(THREADS)&&!defined(KEEP_BACK_PTRS)&&!defined(MAKE_BACK_GRAPH)
+if (!GC_should_invoke_finalizers())
+return;
+#endif
+LOCK();
+#if defined(KEEP_BACK_PTRS)||defined(MAKE_BACK_GRAPH)
+if (GC_gc_no > last_back_trace_gc_no){
+#ifdef KEEP_BACK_PTRS
+long i;
+last_back_trace_gc_no=GC_WORD_MAX;
+for (i=0;i < GC_backtraces;++i){
+UNLOCK();
+GC_generate_random_backtrace_no_gc();
+LOCK();
+}
+last_back_trace_gc_no=GC_gc_no;
+#endif
+#ifdef MAKE_BACK_GRAPH
+if (GC_print_back_height){
+GC_print_back_graph_stats();
+}
+#endif
+}
+#endif
+if (NULL==GC_fnlz_roots.finalize_now){
+UNLOCK();
+return;
+}
+if (!GC_finalize_on_demand){
+unsigned char*pnested=GC_check_finalizer_nested();
+UNLOCK();
+if (pnested!=NULL){
+(void)GC_invoke_finalizers();
+*pnested=0;
+#ifndef THREADS
+GC_ASSERT(NULL==GC_fnlz_roots.finalize_now);
+#endif
+}
+return;
+}
+if (last_finalizer_notification!=GC_gc_no){
+notifier_fn=GC_finalizer_notifier;
+last_finalizer_notification=GC_gc_no;
+}
+UNLOCK();
+if (notifier_fn!=0)
+(*notifier_fn)();
+}
+#ifndef SMALL_CONFIG
+#ifndef GC_LONG_REFS_NOT_NEEDED
+#define IF_LONG_REFS_PRESENT_ELSE(x,y)(x)
+#else
+#define IF_LONG_REFS_PRESENT_ELSE(x,y)(y)
+#endif
+GC_INNER void GC_print_finalization_stats(void)
+{
+struct finalizable_object*fo;
+unsigned long ready=0;
+GC_log_printf("%lu finalization entries;"
+" %lu/%lu short/long disappearing links alive\n",
+(unsigned long)GC_fo_entries,
+(unsigned long)GC_dl_hashtbl.entries,
+(unsigned long)IF_LONG_REFS_PRESENT_ELSE(
+GC_ll_hashtbl.entries,0));
+for (fo=GC_fnlz_roots.finalize_now;fo!=NULL;fo=fo_next(fo))
+++ready;
+GC_log_printf("%lu finalization-ready objects;"
+" %ld/%ld short/long links cleared\n",
+ready,
+(long)GC_old_dl_entries - (long)GC_dl_hashtbl.entries,
+(long)IF_LONG_REFS_PRESENT_ELSE(
+GC_old_ll_entries - GC_ll_hashtbl.entries,0));
+}
+#endif
+#endif
+#ifdef ENABLE_DISCLAIM
+#ifndef GC_DISCLAIM_H
+#define GC_DISCLAIM_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+GC_API void GC_CALL GC_init_finalized_malloc(void);
+typedef int (GC_CALLBACK*GC_disclaim_proc)(void*);
+GC_API void GC_CALL GC_register_disclaim_proc(int,
+GC_disclaim_proc,
+int)GC_ATTR_NONNULL(2);
+struct GC_finalizer_closure {
+GC_finalization_proc proc;
+void*cd;
+};
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_finalized_malloc(size_t,
+const struct GC_finalizer_closure*)GC_ATTR_NONNULL(2);
+#ifdef __cplusplus
+}
+#endif
+#endif
+#if defined(KEEP_BACK_PTRS)||defined(MAKE_BACK_GRAPH)
+#define FINALIZER_CLOSURE_FLAG 0x2
+#else
+#define FINALIZER_CLOSURE_FLAG 0x1
+#endif
+STATIC int GC_CALLBACK GC_finalized_disclaim(void*obj)
+{
+word fc_word=*(word*)obj;
+if ((fc_word&FINALIZER_CLOSURE_FLAG)!=0){
+const struct GC_finalizer_closure*fc
+=(struct GC_finalizer_closure*)(fc_word
+&~(word)FINALIZER_CLOSURE_FLAG);
+GC_ASSERT(!GC_find_leak);
+(*fc->proc)((word*)obj+1,fc->cd);
+}
+return 0;
+}
+GC_API void GC_CALL GC_init_finalized_malloc(void)
+{
+DCL_LOCK_STATE;
+GC_init();
+LOCK();
+if (GC_finalized_kind!=0){
+UNLOCK();
+return;
+}
+GC_register_displacement_inner(sizeof(word));
+GC_register_displacement_inner(FINALIZER_CLOSURE_FLAG);
+GC_register_displacement_inner(sizeof(oh)+FINALIZER_CLOSURE_FLAG);
+GC_finalized_kind=GC_new_kind_inner(GC_new_free_list_inner(),
+GC_DS_LENGTH,TRUE,TRUE);
+GC_ASSERT(GC_finalized_kind!=0);
+GC_register_disclaim_proc(GC_finalized_kind,GC_finalized_disclaim,TRUE);
+UNLOCK();
+}
+GC_API void GC_CALL GC_register_disclaim_proc(int kind,GC_disclaim_proc proc,
+int mark_unconditionally)
+{
+GC_ASSERT((unsigned)kind < MAXOBJKINDS);
+GC_ASSERT(NONNULL_ARG_NOT_NULL(proc));
+if (!EXPECT(GC_find_leak,FALSE)){
+GC_obj_kinds[kind].ok_disclaim_proc=proc;
+GC_obj_kinds[kind].ok_mark_unconditionally=
+(GC_bool)mark_unconditionally;
+}
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_finalized_malloc(size_t lb,
+const struct GC_finalizer_closure*fclos)
+{
+word*op;
+GC_ASSERT(GC_finalized_kind!=0);
+GC_ASSERT(NONNULL_ARG_NOT_NULL(fclos));
+GC_ASSERT(((word)fclos&FINALIZER_CLOSURE_FLAG)==0);
+op=(word*)GC_malloc_kind(SIZET_SAT_ADD(lb,sizeof(word)),
+GC_finalized_kind);
+if (EXPECT(NULL==op,FALSE))
+return NULL;
+*op=(word)fclos|FINALIZER_CLOSURE_FLAG;
+GC_dirty(op);
+REACHABLE_AFTER_DIRTY(fclos);
+return op+1;
+}
+#endif
+#include <stdio.h>
+#include <string.h>
+STATIC GC_bool GC_alloc_reclaim_list(struct obj_kind*kind)
+{
+struct hblk**result=(struct hblk**)
+GC_scratch_alloc((MAXOBJGRANULES+1)*sizeof(struct hblk*));
+if (result==0)return(FALSE);
+BZERO(result,(MAXOBJGRANULES+1)*sizeof(struct hblk*));
+kind->ok_reclaim_list=result;
+return(TRUE);
+}
+GC_INNER ptr_t GC_alloc_large(size_t lb,int k,unsigned flags)
+{
+struct hblk*h;
+word n_blocks;
+ptr_t result;
+GC_bool retry=FALSE;
+GC_ASSERT(I_HOLD_LOCK());
+lb=ROUNDUP_GRANULE_SIZE(lb);
+n_blocks=OBJ_SZ_TO_BLOCKS_CHECKED(lb);
+if (!EXPECT(GC_is_initialized,TRUE)){
+DCL_LOCK_STATE;
+UNLOCK();
+GC_init();
+LOCK();
+}
+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){
+GC_merge_unmapped();
+h=GC_allochblk(lb,k,flags);
+}
+#endif
+while (0==h&&GC_collect_or_expand(n_blocks,flags!=0,retry)){
+h=GC_allochblk(lb,k,flags);
+retry=TRUE;
+}
+if (h==0){
+result=0;
+} else {
+size_t total_bytes=n_blocks*HBLKSIZE;
+if (n_blocks > 1){
+GC_large_allocd_bytes+=total_bytes;
+if (GC_large_allocd_bytes > GC_max_large_allocd_bytes)
+GC_max_large_allocd_bytes=GC_large_allocd_bytes;
+}
+result=h->hb_body;
+}
+return result;
+}
+STATIC ptr_t GC_alloc_large_and_clear(size_t lb,int k,unsigned flags)
+{
+ptr_t result;
+GC_ASSERT(I_HOLD_LOCK());
+result=GC_alloc_large(lb,k,flags);
+if (result!=NULL
+&&(GC_debugging_started||GC_obj_kinds[k].ok_init)){
+word n_blocks=OBJ_SZ_TO_BLOCKS(lb);
+BZERO(result,n_blocks*HBLKSIZE);
+}
+return result;
+}
+STATIC void GC_extend_size_map(size_t i)
+{
+size_t orig_granule_sz=ROUNDED_UP_GRANULES(i);
+size_t granule_sz;
+size_t byte_sz=GRANULES_TO_BYTES(orig_granule_sz);
+size_t smaller_than_i=byte_sz - (byte_sz>>3);
+size_t low_limit;
+size_t number_of_objs;
+GC_ASSERT(I_HOLD_LOCK());
+GC_ASSERT(0==GC_size_map[i]);
+if (0==GC_size_map[smaller_than_i]){
+low_limit=byte_sz - (byte_sz>>2);
+granule_sz=orig_granule_sz;
+while (GC_size_map[low_limit]!=0)
+low_limit++;
+} else {
+low_limit=smaller_than_i+1;
+while (GC_size_map[low_limit]!=0)
+low_limit++;
+granule_sz=ROUNDED_UP_GRANULES(low_limit);
+granule_sz+=granule_sz>>3;
+if (granule_sz < orig_granule_sz)
+granule_sz=orig_granule_sz;
+}
+granule_sz=(granule_sz+1)&~1;
+if (granule_sz > MAXOBJGRANULES)
+granule_sz=MAXOBJGRANULES;
+number_of_objs=HBLK_GRANULES/granule_sz;
+GC_ASSERT(number_of_objs!=0);
+granule_sz=(HBLK_GRANULES/number_of_objs)&~1;
+byte_sz=GRANULES_TO_BYTES(granule_sz)- EXTRA_BYTES;
+for (;low_limit<=byte_sz;low_limit++)
+GC_size_map[low_limit]=granule_sz;
+}
+GC_INNER void*GC_generic_malloc_inner(size_t lb,int k)
+{
+void*op;
+GC_ASSERT(I_HOLD_LOCK());
+GC_ASSERT(k < MAXOBJKINDS);
+if (SMALL_OBJ(lb)){
+struct obj_kind*kind=GC_obj_kinds+k;
+size_t lg=GC_size_map[lb];
+void**opp=&(kind->ok_freelist[lg]);
+op=*opp;
+if (EXPECT(0==op,FALSE)){
+if (lg==0){
+if (!EXPECT(GC_is_initialized,TRUE)){
+DCL_LOCK_STATE;
+UNLOCK();
+GC_init();
+LOCK();
+lg=GC_size_map[lb];
+}
+if (0==lg){
+GC_extend_size_map(lb);
+lg=GC_size_map[lb];
+GC_ASSERT(lg!=0);
+}
+opp=&(kind->ok_freelist[lg]);
+op=*opp;
+}
+if (0==op){
+if (0==kind->ok_reclaim_list&&
+!GC_alloc_reclaim_list(kind))
+return NULL;
+op=GC_allocobj(lg,k);
+if (0==op)
+return NULL;
+}
+}
+*opp=obj_link(op);
+obj_link(op)=0;
+GC_bytes_allocd+=GRANULES_TO_BYTES((word)lg);
+} else {
+op=(ptr_t)GC_alloc_large_and_clear(ADD_SLOP(lb),k,0);
+if (op!=NULL)
+GC_bytes_allocd+=lb;
+}
+return op;
+}
+#if defined(DBG_HDRS_ALL)||defined(GC_GCJ_SUPPORT)||!defined(GC_NO_FINALIZATION)
+GC_INNER void*GC_generic_malloc_inner_ignore_off_page(size_t lb,int k)
+{
+word lb_adjusted;
+void*op;
+GC_ASSERT(I_HOLD_LOCK());
+if (lb<=HBLKSIZE)
+return GC_generic_malloc_inner(lb,k);
+GC_ASSERT(k < MAXOBJKINDS);
+lb_adjusted=ADD_SLOP(lb);
+op=GC_alloc_large_and_clear(lb_adjusted,k,IGNORE_OFF_PAGE);
+if (op!=NULL)
+GC_bytes_allocd+=lb_adjusted;
+return op;
+}
+#endif
+#ifdef GC_COLLECT_AT_MALLOC
+#if defined(CPPCHECK)
+size_t GC_dbg_collect_at_malloc_min_lb=16*1024;
+#else
+size_t GC_dbg_collect_at_malloc_min_lb=(GC_COLLECT_AT_MALLOC);
+#endif
+#endif
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_generic_malloc(size_t lb,int k)
+{
+void*result;
+DCL_LOCK_STATE;
+GC_ASSERT(k < MAXOBJKINDS);
+if (EXPECT(GC_have_errors,FALSE))
+GC_print_all_errors();
+GC_INVOKE_FINALIZERS();
+GC_DBG_COLLECT_AT_MALLOC(lb);
+if (SMALL_OBJ(lb)){
+LOCK();
+result=GC_generic_malloc_inner(lb,k);
+UNLOCK();
+} else {
+size_t lg;
+size_t lb_rounded;
+word n_blocks;
+GC_bool init;
+lg=ROUNDED_UP_GRANULES(lb);
+lb_rounded=GRANULES_TO_BYTES(lg);
+n_blocks=OBJ_SZ_TO_BLOCKS(lb_rounded);
+init=GC_obj_kinds[k].ok_init;
+LOCK();
+result=(ptr_t)GC_alloc_large(lb_rounded,k,0);
+if (0!=result){
+if (GC_debugging_started){
+BZERO(result,n_blocks*HBLKSIZE);
+} else {
+#ifdef THREADS
+((word*)result)[0]=0;
+((word*)result)[1]=0;
+((word*)result)[GRANULES_TO_WORDS(lg)-1]=0;
+((word*)result)[GRANULES_TO_WORDS(lg)-2]=0;
+#endif
+}
+GC_bytes_allocd+=lb_rounded;
+}
+UNLOCK();
+if (init&&!GC_debugging_started&&0!=result){
+BZERO(result,n_blocks*HBLKSIZE);
+}
+}
+if (0==result){
+return((*GC_get_oom_fn())(lb));
+} else {
+return(result);
+}
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_malloc_kind_global(size_t lb,int k)
+{
+GC_ASSERT(k < MAXOBJKINDS);
+if (SMALL_OBJ(lb)){
+void*op;
+void**opp;
+size_t lg;
+DCL_LOCK_STATE;
+GC_DBG_COLLECT_AT_MALLOC(lb);
+LOCK();
+lg=GC_size_map[lb];
+opp=&GC_obj_kinds[k].ok_freelist[lg];
+op=*opp;
+if (EXPECT(op!=NULL,TRUE)){
+if (k==PTRFREE){
+*opp=obj_link(op);
+} else {
+GC_ASSERT(0==obj_link(op)
+||((word)obj_link(op)
+<=(word)GC_greatest_plausible_heap_addr
+&&(word)obj_link(op)
+>=(word)GC_least_plausible_heap_addr));
+*opp=obj_link(op);
+obj_link(op)=0;
+}
+GC_bytes_allocd+=GRANULES_TO_BYTES((word)lg);
+UNLOCK();
+return op;
+}
+UNLOCK();
+}
+return GC_clear_stack(GC_generic_malloc(lb,k));
+}
+#if defined(THREADS)&&!defined(THREAD_LOCAL_ALLOC)
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_malloc_kind(size_t lb,int k)
+{
+return GC_malloc_kind_global(lb,k);
+}
+#endif
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_malloc_atomic(size_t lb)
+{
+return GC_malloc_kind(lb,PTRFREE);
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_malloc(size_t lb)
+{
+return GC_malloc_kind(lb,NORMAL);
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_generic_malloc_uncollectable(
+size_t lb,int k)
+{
+void*op;
+DCL_LOCK_STATE;
+GC_ASSERT(k < MAXOBJKINDS);
+if (SMALL_OBJ(lb)){
+void**opp;
+size_t lg;
+GC_DBG_COLLECT_AT_MALLOC(lb);
+if (EXTRA_BYTES!=0&&lb!=0)lb--;
+LOCK();
+lg=GC_size_map[lb];
+opp=&GC_obj_kinds[k].ok_freelist[lg];
+op=*opp;
+if (EXPECT(op!=NULL,TRUE)){
+*opp=obj_link(op);
+obj_link(op)=0;
+GC_bytes_allocd+=GRANULES_TO_BYTES((word)lg);
+GC_non_gc_bytes+=GRANULES_TO_BYTES((word)lg);
+UNLOCK();
+} else {
+UNLOCK();
+op=GC_generic_malloc(lb,k);
+}
+GC_ASSERT(0==op||GC_is_marked(op));
+} else {
+op=GC_generic_malloc(lb,k);
+if (op){
+hdr*hhdr=HDR(op);
+GC_ASSERT(((word)op&(HBLKSIZE - 1))==0);
+LOCK();
+set_mark_bit_from_hdr(hhdr,0);
+#ifndef THREADS
+GC_ASSERT(hhdr->hb_n_marks==0);
+#endif
+hhdr->hb_n_marks=1;
+UNLOCK();
+}
+}
+return op;
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_malloc_uncollectable(size_t lb)
+{
+return GC_generic_malloc_uncollectable(lb,UNCOLLECTABLE);
+}
+#ifdef GC_ATOMIC_UNCOLLECTABLE
+GC_API GC_ATTR_MALLOC void*GC_CALL
+GC_malloc_atomic_uncollectable(size_t lb)
+{
+return GC_generic_malloc_uncollectable(lb,AUNCOLLECTABLE);
+}
+#endif
+#if defined(REDIRECT_MALLOC)&&!defined(REDIRECT_MALLOC_IN_HEADER)
+#ifndef MSWINCE
+#include <errno.h>
+#endif
+#define GC_debug_malloc_replacement(lb)GC_debug_malloc(lb,GC_DBG_EXTRAS)
+#if defined(CPPCHECK)
+#define REDIRECT_MALLOC_F GC_malloc
+#else
+#define REDIRECT_MALLOC_F REDIRECT_MALLOC
+#endif
+void*malloc(size_t lb)
+{
+#if defined(I386)&&defined(GC_SOLARIS_THREADS)
+if (!EXPECT(GC_is_initialized,TRUE))return sbrk(lb);
+#endif
+return (void*)REDIRECT_MALLOC_F(lb);
+}
+#if defined(GC_LINUX_THREADS)
+STATIC ptr_t GC_libpthread_start=0;
+STATIC ptr_t GC_libpthread_end=0;
+STATIC ptr_t GC_libld_start=0;
+STATIC ptr_t GC_libld_end=0;
+STATIC void GC_init_lib_bounds(void)
+{
+IF_CANCEL(int cancel_state;)
+if (GC_libpthread_start!=0)return;
+DISABLE_CANCEL(cancel_state);
+GC_init();
+if (!GC_text_mapping("libpthread-",
+&GC_libpthread_start,&GC_libpthread_end)){
+WARN("Failed to find libpthread.so text mapping:Expect crash\n",0);
+GC_libpthread_start=(ptr_t)1;
+}
+if (!GC_text_mapping("ld-",&GC_libld_start,&GC_libld_end)){
+WARN("Failed to find ld.so text mapping:Expect crash\n",0);
+}
+RESTORE_CANCEL(cancel_state);
+}
+#endif
+void*calloc(size_t n,size_t lb)
+{
+if ((lb|n)> GC_SQRT_SIZE_MAX
+&&lb&&n > GC_SIZE_MAX/lb)
+return (*GC_get_oom_fn())(GC_SIZE_MAX);
+#if defined(GC_LINUX_THREADS)
+{
+static GC_bool lib_bounds_set=FALSE;
+ptr_t caller=(ptr_t)__builtin_return_address(0);
+if (!EXPECT(lib_bounds_set,TRUE)){
+GC_init_lib_bounds();
+lib_bounds_set=TRUE;
+}
+if (((word)caller>=(word)GC_libpthread_start
+&&(word)caller < (word)GC_libpthread_end)
+||((word)caller>=(word)GC_libld_start
+&&(word)caller < (word)GC_libld_end))
+return GC_generic_malloc_uncollectable(n*lb,UNCOLLECTABLE);
+}
+#endif
+return (void*)REDIRECT_MALLOC_F(n*lb);
+}
+#ifndef strdup
+char*strdup(const char*s)
+{
+size_t lb=strlen(s)+1;
+char*result=(char*)REDIRECT_MALLOC_F(lb);
+if (result==0){
+errno=ENOMEM;
+return 0;
+}
+BCOPY(s,result,lb);
+return result;
+}
+#endif
+#ifndef strndup
+char*strndup(const char*str,size_t size)
+{
+char*copy;
+size_t len=strlen(str);
+if (len > size)
+len=size;
+copy=(char*)REDIRECT_MALLOC_F(len+1);
+if (copy==NULL){
+errno=ENOMEM;
+return NULL;
+}
+if (EXPECT(len > 0,TRUE))
+BCOPY(str,copy,len);
+copy[len]='\0';
+return copy;
+}
+#endif
+#undef GC_debug_malloc_replacement
+#endif
+GC_API void GC_CALL GC_free(void*p)
+{
+struct hblk*h;
+hdr*hhdr;
+size_t sz;
+size_t ngranules;
+int knd;
+struct obj_kind*ok;
+DCL_LOCK_STATE;
+if (p){
+} else {
+return;
+}
+#ifdef LOG_ALLOCS
+GC_log_printf("GC_free(%p)after GC #%lu\n",
+p,(unsigned long)GC_gc_no);
+#endif
+h=HBLKPTR(p);
+hhdr=HDR(h);
+#if defined(REDIRECT_MALLOC)&&((defined(NEED_CALLINFO)&&defined(GC_HAVE_BUILTIN_BACKTRACE))||defined(GC_SOLARIS_THREADS)||defined(GC_LINUX_THREADS)||defined(MSWIN32))
+if (0==hhdr)return;
+#endif
+GC_ASSERT(GC_base(p)==p);
+sz=(size_t)hhdr->hb_sz;
+ngranules=BYTES_TO_GRANULES(sz);
+knd=hhdr->hb_obj_kind;
+ok=&GC_obj_kinds[knd];
+if (EXPECT(ngranules<=MAXOBJGRANULES,TRUE)){
+void**flh;
+LOCK();
+GC_bytes_freed+=sz;
+if (IS_UNCOLLECTABLE(knd))GC_non_gc_bytes-=sz;
+if (ok->ok_init&&EXPECT(sz > sizeof(word),TRUE)){
+BZERO((word*)p+1,sz-sizeof(word));
+}
+flh=&(ok->ok_freelist[ngranules]);
+obj_link(p)=*flh;
+*flh=(ptr_t)p;
+UNLOCK();
+} else {
+size_t nblocks=OBJ_SZ_TO_BLOCKS(sz);
+LOCK();
+GC_bytes_freed+=sz;
+if (IS_UNCOLLECTABLE(knd))GC_non_gc_bytes-=sz;
+if (nblocks > 1){
+GC_large_allocd_bytes-=nblocks*HBLKSIZE;
+}
+GC_freehblk(h);
+UNLOCK();
+}
+}
+#ifdef THREADS
+GC_INNER void GC_free_inner(void*p)
+{
+struct hblk*h;
+hdr*hhdr;
+size_t sz;
+size_t ngranules;
+int knd;
+struct obj_kind*ok;
+h=HBLKPTR(p);
+hhdr=HDR(h);
+knd=hhdr->hb_obj_kind;
+sz=(size_t)hhdr->hb_sz;
+ngranules=BYTES_TO_GRANULES(sz);
+ok=&GC_obj_kinds[knd];
+if (ngranules<=MAXOBJGRANULES){
+void**flh;
+GC_bytes_freed+=sz;
+if (IS_UNCOLLECTABLE(knd))GC_non_gc_bytes-=sz;
+if (ok->ok_init&&EXPECT(sz > sizeof(word),TRUE)){
+BZERO((word*)p+1,sz-sizeof(word));
+}
+flh=&(ok->ok_freelist[ngranules]);
+obj_link(p)=*flh;
+*flh=(ptr_t)p;
+} else {
+size_t nblocks=OBJ_SZ_TO_BLOCKS(sz);
+GC_bytes_freed+=sz;
+if (IS_UNCOLLECTABLE(knd))GC_non_gc_bytes-=sz;
+if (nblocks > 1){
+GC_large_allocd_bytes-=nblocks*HBLKSIZE;
+}
+GC_freehblk(h);
+}
+}
+#endif
+#if defined(REDIRECT_MALLOC)&&!defined(REDIRECT_FREE)
+#define REDIRECT_FREE GC_free
+#endif
+#if defined(REDIRECT_FREE)&&!defined(REDIRECT_MALLOC_IN_HEADER)
+#if defined(CPPCHECK)
+#define REDIRECT_FREE_F GC_free
+#else
+#define REDIRECT_FREE_F REDIRECT_FREE
+#endif
+void free(void*p)
+{
+#ifndef IGNORE_FREE
+#if defined(GC_LINUX_THREADS)&&!defined(USE_PROC_FOR_LIBRARIES)
+ptr_t caller=(ptr_t)__builtin_return_address(0);
+if (((word)caller>=(word)GC_libpthread_start
+&&(word)caller < (word)GC_libpthread_end)
+||((word)caller>=(word)GC_libld_start
+&&(word)caller < (word)GC_libld_end)){
+GC_free(p);
+return;
+}
+#endif
+REDIRECT_FREE_F(p);
+#endif
+}
+#endif
+#include <stdio.h>
+#include <string.h>
+#ifndef MSWINCE
+#include <errno.h>
+#endif
+#ifndef GC_ALLOC_PTRS_H
+#define GC_ALLOC_PTRS_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+GC_API void**const GC_objfreelist_ptr;
+GC_API void**const GC_aobjfreelist_ptr;
+GC_API void**const GC_uobjfreelist_ptr;
+#ifdef GC_ATOMIC_UNCOLLECTABLE
+GC_API void**const GC_auobjfreelist_ptr;
+#endif
+GC_API void GC_CALL GC_incr_bytes_allocd(size_t bytes);
+GC_API void GC_CALL GC_incr_bytes_freed(size_t bytes);
+#ifdef __cplusplus
+}
+#endif
+#endif
+void**const GC_objfreelist_ptr=GC_objfreelist;
+void**const GC_aobjfreelist_ptr=GC_aobjfreelist;
+void**const GC_uobjfreelist_ptr=GC_uobjfreelist;
+#ifdef GC_ATOMIC_UNCOLLECTABLE
+void**const GC_auobjfreelist_ptr=GC_auobjfreelist;
+#endif
+GC_API int GC_CALL GC_get_kind_and_size(const void*p,size_t*psize)
+{
+hdr*hhdr=HDR(p);
+if (psize!=NULL){
+*psize=(size_t)hhdr->hb_sz;
+}
+return hhdr->hb_obj_kind;
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_generic_or_special_malloc(size_t lb,
+int knd)
+{
+switch(knd){
+case PTRFREE:
+case NORMAL:
+return GC_malloc_kind(lb,knd);
+case UNCOLLECTABLE:
+#ifdef GC_ATOMIC_UNCOLLECTABLE
+case AUNCOLLECTABLE:
+#endif
+return GC_generic_malloc_uncollectable(lb,knd);
+default:
+return GC_generic_malloc(lb,knd);
+}
+}
+GC_API void*GC_CALL GC_realloc(void*p,size_t lb)
+{
+struct hblk*h;
+hdr*hhdr;
+void*result;
+size_t sz;
+size_t orig_sz;
+int obj_kind;
+if (p==0)return(GC_malloc(lb));
+if (0==lb){
+#ifndef IGNORE_FREE
+GC_free(p);
+#endif
+return NULL;
+}
+h=HBLKPTR(p);
+hhdr=HDR(h);
+sz=(size_t)hhdr->hb_sz;
+obj_kind=hhdr->hb_obj_kind;
+orig_sz=sz;
+if (sz > MAXOBJBYTES){
+word descr=GC_obj_kinds[obj_kind].ok_descriptor;
+sz=(sz+HBLKSIZE-1)&~HBLKMASK;
+if (GC_obj_kinds[obj_kind].ok_relocate_descr)
+descr+=sz;
+#ifdef AO_HAVE_store
+GC_STATIC_ASSERT(sizeof(hhdr->hb_sz)==sizeof(AO_t));
+AO_store((volatile AO_t*)&hhdr->hb_sz,(AO_t)sz);
+AO_store((volatile AO_t*)&hhdr->hb_descr,(AO_t)descr);
+#else
+{
+DCL_LOCK_STATE;
+LOCK();
+hhdr->hb_sz=sz;
+hhdr->hb_descr=descr;
+UNLOCK();
+}
+#endif
+#ifdef MARK_BIT_PER_OBJ
+GC_ASSERT(hhdr->hb_inv_sz==LARGE_INV_SZ);
+#endif
+#ifdef MARK_BIT_PER_GRANULE
+GC_ASSERT((hhdr->hb_flags&LARGE_BLOCK)!=0
+&&hhdr->hb_map[ANY_INDEX]==1);
+#endif
+if (IS_UNCOLLECTABLE(obj_kind))GC_non_gc_bytes+=(sz - orig_sz);
+}
+if (ADD_SLOP(lb)<=sz){
+if (lb>=(sz>>1)){
+if (orig_sz > lb){
+BZERO(((ptr_t)p)+lb,orig_sz - lb);
+}
+return(p);
+}
+sz=lb;
+}
+result=GC_generic_or_special_malloc((word)lb,obj_kind);
+if (result!=NULL){
+BCOPY(p,result,sz);
+#ifndef IGNORE_FREE
+GC_free(p);
+#endif
+}
+return result;
+}
+#if defined(REDIRECT_MALLOC)&&!defined(REDIRECT_REALLOC)
+#define REDIRECT_REALLOC GC_realloc
+#endif
+#ifdef REDIRECT_REALLOC
+#define GC_debug_realloc_replacement(p,lb)GC_debug_realloc(p,lb,GC_DBG_EXTRAS)
+#if!defined(REDIRECT_MALLOC_IN_HEADER)
+void*realloc(void*p,size_t lb)
+{
+return(REDIRECT_REALLOC(p,lb));
+}
+#endif
+#undef GC_debug_realloc_replacement
+#endif
+GC_API GC_ATTR_MALLOC void*GC_CALL
+GC_generic_malloc_ignore_off_page(size_t lb,int k)
+{
+void*result;
+size_t lg;
+size_t lb_rounded;
+word n_blocks;
+GC_bool init;
+DCL_LOCK_STATE;
+if (SMALL_OBJ(lb))
+return GC_generic_malloc(lb,k);
+GC_ASSERT(k < MAXOBJKINDS);
+lg=ROUNDED_UP_GRANULES(lb);
+lb_rounded=GRANULES_TO_BYTES(lg);
+n_blocks=OBJ_SZ_TO_BLOCKS(lb_rounded);
+init=GC_obj_kinds[k].ok_init;
+if (EXPECT(GC_have_errors,FALSE))
+GC_print_all_errors();
+GC_INVOKE_FINALIZERS();
+GC_DBG_COLLECT_AT_MALLOC(lb);
+LOCK();
+result=(ptr_t)GC_alloc_large(ADD_SLOP(lb),k,IGNORE_OFF_PAGE);
+if (NULL==result){
+GC_oom_func oom_fn=GC_oom_fn;
+UNLOCK();
+return (*oom_fn)(lb);
+}
+if (GC_debugging_started){
+BZERO(result,n_blocks*HBLKSIZE);
+} else {
+#ifdef THREADS
+((word*)result)[0]=0;
+((word*)result)[1]=0;
+((word*)result)[GRANULES_TO_WORDS(lg)-1]=0;
+((word*)result)[GRANULES_TO_WORDS(lg)-2]=0;
+#endif
+}
+GC_bytes_allocd+=lb_rounded;
+UNLOCK();
+if (init&&!GC_debugging_started){
+BZERO(result,n_blocks*HBLKSIZE);
+}
+return(result);
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_malloc_ignore_off_page(size_t lb)
+{
+return GC_generic_malloc_ignore_off_page(lb,NORMAL);
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL
+GC_malloc_atomic_ignore_off_page(size_t lb)
+{
+return GC_generic_malloc_ignore_off_page(lb,PTRFREE);
+}
+GC_API void GC_CALL GC_incr_bytes_allocd(size_t n)
+{
+GC_bytes_allocd+=n;
+}
+GC_API void GC_CALL GC_incr_bytes_freed(size_t n)
+{
+GC_bytes_freed+=n;
+}
+GC_API size_t GC_CALL GC_get_expl_freed_bytes_since_gc(void)
+{
+return (size_t)GC_bytes_freed;
+}
+#ifdef PARALLEL_MARK
+STATIC volatile AO_t GC_bytes_allocd_tmp=0;
+#endif
+GC_API void GC_CALL GC_generic_malloc_many(size_t lb,int k,void**result)
+{
+void*op;
+void*p;
+void**opp;
+size_t lw;
+size_t lg;
+signed_word my_bytes_allocd=0;
+struct obj_kind*ok=&(GC_obj_kinds[k]);
+struct hblk**rlh;
+DCL_LOCK_STATE;
+GC_ASSERT(lb!=0&&(lb&(GRANULE_BYTES-1))==0);
+if (!SMALL_OBJ(lb)||GC_manual_vdb){
+op=GC_generic_malloc(lb,k);
+if (EXPECT(0!=op,TRUE))
+obj_link(op)=0;
+*result=op;
+#ifndef GC_DISABLE_INCREMENTAL
+if (GC_manual_vdb&&GC_is_heap_ptr(result)){
+GC_dirty_inner(result);
+REACHABLE_AFTER_DIRTY(op);
+}
+#endif
+return;
+}
+GC_ASSERT(k < MAXOBJKINDS);
+lw=BYTES_TO_WORDS(lb);
+lg=BYTES_TO_GRANULES(lb);
+if (EXPECT(GC_have_errors,FALSE))
+GC_print_all_errors();
+GC_INVOKE_FINALIZERS();
+GC_DBG_COLLECT_AT_MALLOC(lb);
+if (!EXPECT(GC_is_initialized,TRUE))GC_init();
+LOCK();
+if (GC_incremental&&!GC_dont_gc){
+ENTER_GC();
+GC_collect_a_little_inner(1);
+EXIT_GC();
+}
+rlh=ok->ok_reclaim_list;
+if (rlh!=NULL){
+struct hblk*hbp;
+hdr*hhdr;
+for (rlh+=lg;(hbp=*rlh)!=NULL;){
+hhdr=HDR(hbp);
+*rlh=hhdr->hb_next;
+GC_ASSERT(hhdr->hb_sz==lb);
+hhdr->hb_last_reclaimed=(unsigned short)GC_gc_no;
+#ifdef PARALLEL_MARK
+if (GC_parallel){
+signed_word my_bytes_allocd_tmp=
+(signed_word)AO_load(&GC_bytes_allocd_tmp);
+GC_ASSERT(my_bytes_allocd_tmp>=0);
+if (my_bytes_allocd_tmp!=0){
+(void)AO_fetch_and_add(&GC_bytes_allocd_tmp,
+(AO_t)(-my_bytes_allocd_tmp));
+GC_bytes_allocd+=my_bytes_allocd_tmp;
+}
+GC_acquire_mark_lock();
+++GC_fl_builder_count;
+UNLOCK();
+GC_release_mark_lock();
+}
+#endif
+op=GC_reclaim_generic(hbp,hhdr,lb,
+ok->ok_init,0,&my_bytes_allocd);
+if (op!=0){
+#ifdef PARALLEL_MARK
+if (GC_parallel){
+*result=op;
+(void)AO_fetch_and_add(&GC_bytes_allocd_tmp,
+(AO_t)my_bytes_allocd);
+GC_acquire_mark_lock();
+--GC_fl_builder_count;
+if (GC_fl_builder_count==0)GC_notify_all_builder();
+#ifdef THREAD_SANITIZER
+GC_release_mark_lock();
+LOCK();
+GC_bytes_found+=my_bytes_allocd;
+UNLOCK();
+#else
+GC_bytes_found+=my_bytes_allocd;
+GC_release_mark_lock();
+#endif
+(void)GC_clear_stack(0);
+return;
+}
+#endif
+GC_bytes_found+=my_bytes_allocd;
+GC_bytes_allocd+=my_bytes_allocd;
+goto out;
+}
+#ifdef PARALLEL_MARK
+if (GC_parallel){
+GC_acquire_mark_lock();
+--GC_fl_builder_count;
+if (GC_fl_builder_count==0)GC_notify_all_builder();
+GC_release_mark_lock();
+LOCK();
+}
+#endif
+}
+}
+opp=&(GC_obj_kinds[k].ok_freelist[lg]);
+if ( (op=*opp)!=0){
+*opp=0;
+my_bytes_allocd=0;
+for (p=op;p!=0;p=obj_link(p)){
+my_bytes_allocd+=lb;
+if ((word)my_bytes_allocd>=HBLKSIZE){
+*opp=obj_link(p);
+obj_link(p)=0;
+break;
+}
+}
+GC_bytes_allocd+=my_bytes_allocd;
+goto out;
+}
+{
+struct hblk*h=GC_allochblk(lb,k,0);
+if (h){
+if (IS_UNCOLLECTABLE(k))GC_set_hdr_marks(HDR(h));
+GC_bytes_allocd+=HBLKSIZE - HBLKSIZE % lb;
+#ifdef PARALLEL_MARK
+if (GC_parallel){
+GC_acquire_mark_lock();
+++GC_fl_builder_count;
+UNLOCK();
+GC_release_mark_lock();
+op=GC_build_fl(h,lw,
+(ok->ok_init||GC_debugging_started),0);
+*result=op;
+GC_acquire_mark_lock();
+--GC_fl_builder_count;
+if (GC_fl_builder_count==0)GC_notify_all_builder();
+GC_release_mark_lock();
+(void)GC_clear_stack(0);
+return;
+}
+#endif
+op=GC_build_fl(h,lw,(ok->ok_init||GC_debugging_started),0);
+goto out;
+}
+}
+op=GC_generic_malloc_inner(lb,k);
+if (0!=op)obj_link(op)=0;
+out:
+*result=op;
+UNLOCK();
+(void)GC_clear_stack(0);
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_malloc_many(size_t lb)
+{
+void*result;
+lb=SIZET_SAT_ADD(lb,EXTRA_BYTES+GRANULE_BYTES - 1)
+&~(GRANULE_BYTES - 1);
+GC_generic_malloc_many(lb,NORMAL,&result);
+return result;
+}
+#include <limits.h>
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_memalign(size_t align,size_t lb)
+{
+size_t new_lb;
+size_t offset;
+ptr_t result;
+if (align<=GRANULE_BYTES)return GC_malloc(lb);
+if (align>=HBLKSIZE/2||lb>=HBLKSIZE/2){
+if (align > HBLKSIZE){
+return (*GC_get_oom_fn())(LONG_MAX-1024);
+}
+return GC_malloc(lb<=HBLKSIZE?HBLKSIZE:lb);
+}
+new_lb=SIZET_SAT_ADD(lb,align - 1);
+result=(ptr_t)GC_malloc(new_lb);
+offset=(word)result % align;
+if (offset!=0){
+offset=align - offset;
+if (!GC_all_interior_pointers){
+GC_STATIC_ASSERT(VALID_OFFSET_SZ<=HBLKSIZE);
+GC_ASSERT(offset < VALID_OFFSET_SZ);
+GC_register_displacement(offset);
+}
+}
+result+=offset;
+GC_ASSERT((word)result % align==0);
+return result;
+}
+GC_API int GC_CALL GC_posix_memalign(void**memptr,size_t align,size_t lb)
+{
+size_t align_minus_one=align - 1;
+if (align < sizeof(void*)||(align_minus_one&align)!=0){
+#ifdef MSWINCE
+return ERROR_INVALID_PARAMETER;
+#else
+return EINVAL;
+#endif
+}
+if ((*memptr=GC_memalign(align,lb))==NULL){
+#ifdef MSWINCE
+return ERROR_NOT_ENOUGH_MEMORY;
+#else
+return ENOMEM;
+#endif
+}
+return 0;
+}
+GC_API GC_ATTR_MALLOC char*GC_CALL GC_strdup(const char*s)
+{
+char*copy;
+size_t lb;
+if (s==NULL)return NULL;
+lb=strlen(s)+1;
+copy=(char*)GC_malloc_atomic(lb);
+if (NULL==copy){
+#ifndef MSWINCE
+errno=ENOMEM;
+#endif
+return NULL;
+}
+BCOPY(s,copy,lb);
+return copy;
+}
+GC_API GC_ATTR_MALLOC char*GC_CALL GC_strndup(const char*str,size_t size)
+{
+char*copy;
+size_t len=strlen(str);
+if (len > size)
+len=size;
+copy=(char*)GC_malloc_atomic(len+1);
+if (copy==NULL){
+#ifndef MSWINCE
+errno=ENOMEM;
+#endif
+return NULL;
+}
+if (EXPECT(len > 0,TRUE))
+BCOPY(str,copy,len);
+copy[len]='\0';
+return copy;
+}
+#ifdef GC_REQUIRE_WCSDUP
+#include <wchar.h>
+GC_API GC_ATTR_MALLOC wchar_t*GC_CALL GC_wcsdup(const wchar_t*str)
+{
+size_t lb=(wcslen(str)+1)*sizeof(wchar_t);
+wchar_t*copy=(wchar_t*)GC_malloc_atomic(lb);
+if (copy==NULL){
+#ifndef MSWINCE
+errno=ENOMEM;
+#endif
+return NULL;
+}
+BCOPY(str,copy,lb);
+return copy;
+}
+#endif
+#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)
+{
+}
+#endif
+GC_API void GC_CALL GC_end_stubborn_change(const void*p)
+{
+GC_dirty(p);
+}
+GC_API void GC_CALL GC_ptr_store_and_dirty(void*p,const void*q)
+{
+*(const void**)p=q;
+GC_dirty(p);
+REACHABLE_AFTER_DIRTY(q);
+}
+#if defined(__MINGW32__)&&!defined(__MINGW_EXCPT_DEFINE_PSDK)&&defined(__i386__)
+#define __MINGW_EXCPT_DEFINE_PSDK 1
+#endif
+#include <stdio.h>
+#if defined(MSWIN32)&&defined(__GNUC__)
+#include <excpt.h>
+#endif
+GC_ATTR_NOINLINE
+void GC_noop6(word arg1 GC_ATTR_UNUSED,word arg2 GC_ATTR_UNUSED,
+word arg3 GC_ATTR_UNUSED,word arg4 GC_ATTR_UNUSED,
+word arg5 GC_ATTR_UNUSED,word arg6 GC_ATTR_UNUSED)
+{
+#if defined(AO_HAVE_compiler_barrier)&&!defined(BASE_ATOMIC_OPS_EMULATED)
+AO_compiler_barrier();
+#else
+GC_noop1(0);
+#endif
+}
+volatile word GC_noop_sink;
+GC_ATTR_NO_SANITIZE_THREAD
+GC_API void GC_CALL GC_noop1(word x)
+{
+GC_noop_sink=x;
+}
+GC_INNER struct obj_kind GC_obj_kinds[MAXOBJKINDS]={
+{&GC_aobjfreelist[0],0,
+GC_DS_LENGTH,FALSE,FALSE
+OK_DISCLAIM_INITZ },
+{&GC_objfreelist[0],0,
+GC_DS_LENGTH,
+TRUE,TRUE
+OK_DISCLAIM_INITZ },
+{&GC_uobjfreelist[0],0,
+GC_DS_LENGTH,TRUE,TRUE
+OK_DISCLAIM_INITZ },
+#ifdef GC_ATOMIC_UNCOLLECTABLE
+{&GC_auobjfreelist[0],0,
+GC_DS_LENGTH,FALSE,FALSE
+OK_DISCLAIM_INITZ },
+#endif
+};
+#ifndef INITIAL_MARK_STACK_SIZE
+#define INITIAL_MARK_STACK_SIZE (1*HBLKSIZE)
+#endif
+#if!defined(GC_DISABLE_INCREMENTAL)
+STATIC word GC_n_rescuing_pages=0;
+#endif
+#ifdef PARALLEL_MARK
+GC_INNER GC_bool GC_parallel_mark_disabled=FALSE;
+#endif
+GC_INNER GC_bool GC_collection_in_progress(void)
+{
+return(GC_mark_state!=MS_NONE);
+}
+GC_INNER void GC_clear_hdr_marks(hdr*hhdr)
+{
+size_t last_bit;
+#ifdef AO_HAVE_load
+last_bit=FINAL_MARK_BIT((size_t)AO_load((volatile AO_t*)&hhdr->hb_sz));
+#else
+last_bit=FINAL_MARK_BIT((size_t)hhdr->hb_sz);
+#endif
+BZERO(hhdr->hb_marks,sizeof(hhdr->hb_marks));
+set_mark_bit_from_hdr(hhdr,last_bit);
+hhdr->hb_n_marks=0;
+}
+GC_INNER void GC_set_hdr_marks(hdr*hhdr)
+{
+unsigned i;
+size_t sz=(size_t)hhdr->hb_sz;
+unsigned n_marks=(unsigned)FINAL_MARK_BIT(sz);
+#ifdef USE_MARK_BYTES
+for (i=0;i<=n_marks;i+=(unsigned)MARK_BIT_OFFSET(sz)){
+hhdr->hb_marks[i]=1;
+}
+#else
+for (i=0;i < divWORDSZ(n_marks+WORDSZ);++i){
+hhdr->hb_marks[i]=GC_WORD_MAX;
+}
+#endif
+#ifdef MARK_BIT_PER_OBJ
+hhdr->hb_n_marks=n_marks;
+#else
+hhdr->hb_n_marks=HBLK_OBJS(sz);
+#endif
+}
+static void clear_marks_for_block(struct hblk*h,word dummy GC_ATTR_UNUSED)
+{
+hdr*hhdr=HDR(h);
+if (IS_UNCOLLECTABLE(hhdr->hb_obj_kind))return;
+GC_clear_hdr_marks(hhdr);
+}
+GC_API void GC_CALL GC_set_mark_bit(const void*p)
+{
+struct hblk*h=HBLKPTR(p);
+hdr*hhdr=HDR(h);
+word bit_no=MARK_BIT_NO((ptr_t)p - (ptr_t)h,hhdr->hb_sz);
+if (!mark_bit_from_hdr(hhdr,bit_no)){
+set_mark_bit_from_hdr(hhdr,bit_no);
+++hhdr->hb_n_marks;
+}
+}
+GC_API void GC_CALL GC_clear_mark_bit(const void*p)
+{
+struct hblk*h=HBLKPTR(p);
+hdr*hhdr=HDR(h);
+word bit_no=MARK_BIT_NO((ptr_t)p - (ptr_t)h,hhdr->hb_sz);
+if (mark_bit_from_hdr(hhdr,bit_no)){
+size_t n_marks=hhdr->hb_n_marks;
+GC_ASSERT(n_marks!=0);
+clear_mark_bit_from_hdr(hhdr,bit_no);
+n_marks--;
+#ifdef PARALLEL_MARK
+if (n_marks!=0||!GC_parallel)
+hhdr->hb_n_marks=n_marks;
+#else
+hhdr->hb_n_marks=n_marks;
+#endif
+}
+}
+GC_API int GC_CALL GC_is_marked(const void*p)
+{
+struct hblk*h=HBLKPTR(p);
+hdr*hhdr=HDR(h);
+word bit_no=MARK_BIT_NO((ptr_t)p - (ptr_t)h,hhdr->hb_sz);
+return (int)mark_bit_from_hdr(hhdr,bit_no);
+}
+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;
+GC_scan_ptr=NULL;
+}
+GC_INNER void GC_initiate_gc(void)
+{
+GC_ASSERT(I_HOLD_LOCK());
+#ifndef GC_DISABLE_INCREMENTAL
+if (GC_incremental){
+#ifdef CHECKSUMS
+GC_read_dirty(FALSE);
+GC_check_dirty();
+#else
+GC_read_dirty(GC_mark_state==MS_INVALID);
+#endif
+}
+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");
+}
+GC_scan_ptr=NULL;
+}
+#ifdef PARALLEL_MARK
+STATIC void GC_do_parallel_mark(void);
+#endif
+#ifdef GC_DISABLE_INCREMENTAL
+#define GC_push_next_marked_dirty(h)GC_push_next_marked(h)
+#else
+STATIC struct hblk*GC_push_next_marked_dirty(struct hblk*h);
+#endif
+STATIC struct hblk*GC_push_next_marked(struct hblk*h);
+STATIC struct hblk*GC_push_next_marked_uncollectable(struct hblk*h);
+static void alloc_mark_stack(size_t);
+#ifdef WRAP_MARK_SOME
+STATIC GC_bool GC_mark_some_inner(ptr_t cold_gc_frame)
+#else
+GC_INNER GC_bool GC_mark_some(ptr_t cold_gc_frame)
+#endif
+{
+switch(GC_mark_state){
+case MS_NONE:
+break;
+case MS_PUSH_RESCUERS:
+if ((word)GC_mark_stack_top
+>=(word)(GC_mark_stack_limit - INITIAL_MARK_STACK_SIZE/2)){
+GC_mark_stack_too_small=TRUE;
+MARK_FROM_MARK_STACK();
+break;
+} else {
+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);
+#endif
+GC_push_roots(FALSE,cold_gc_frame);
+GC_objects_are_marked=TRUE;
+if (GC_mark_state!=MS_INVALID){
+GC_mark_state=MS_ROOTS_PUSHED;
+}
+}
+}
+break;
+case MS_PUSH_UNCOLLECTABLE:
+if ((word)GC_mark_stack_top
+>=(word)(GC_mark_stack+GC_mark_stack_size/4)){
+#ifdef PARALLEL_MARK
+if (GC_parallel)GC_mark_stack_too_small=TRUE;
+#endif
+MARK_FROM_MARK_STACK();
+break;
+} else {
+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){
+GC_mark_state=MS_ROOTS_PUSHED;
+}
+}
+}
+break;
+case MS_ROOTS_PUSHED:
+#ifdef PARALLEL_MARK
+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;
+if (GC_mark_stack_too_small){
+alloc_mark_stack(2*GC_mark_stack_size);
+}
+if (GC_mark_state==MS_ROOTS_PUSHED){
+GC_mark_state=MS_NONE;
+return(TRUE);
+}
+break;
+}
+#endif
+if ((word)GC_mark_stack_top>=(word)GC_mark_stack){
+MARK_FROM_MARK_STACK();
+break;
+} else {
+GC_mark_state=MS_NONE;
+if (GC_mark_stack_too_small){
+alloc_mark_stack(2*GC_mark_stack_size);
+}
+return(TRUE);
+}
+case MS_INVALID:
+case MS_PARTIALLY_INVALID:
+if (!GC_objects_are_marked){
+GC_mark_state=MS_PUSH_UNCOLLECTABLE;
+break;
+}
+if ((word)GC_mark_stack_top>=(word)GC_mark_stack){
+MARK_FROM_MARK_STACK();
+break;
+}
+if (NULL==GC_scan_ptr&&GC_mark_state==MS_INVALID){
+if (GC_mark_stack_too_small){
+alloc_mark_stack(2*GC_mark_stack_size);
+}
+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){
+GC_mark_state=MS_ROOTS_PUSHED;
+}
+}
+break;
+default:
+ABORT("GC_mark_some:bad state");
+}
+return(FALSE);
+}
+#ifdef WRAP_MARK_SOME
+#if (defined(MSWIN32)||defined(MSWINCE))&&defined(__GNUC__)
+typedef struct {
+EXCEPTION_REGISTRATION ex_reg;
+void*alt_path;
+} ext_ex_regn;
+static EXCEPTION_DISPOSITION mark_ex_handler(
+struct _EXCEPTION_RECORD*ex_rec,
+void*est_frame,
+struct _CONTEXT*context,
+void*disp_ctxt GC_ATTR_UNUSED)
+{
+if (ex_rec->ExceptionCode==STATUS_ACCESS_VIOLATION){
+ext_ex_regn*xer=(ext_ex_regn*)est_frame;
+context->Esp=context->Ebp;
+context->Ebp=*((DWORD*)context->Esp);
+context->Esp=context->Esp - 8;
+context->Eip=(DWORD)(xer->alt_path);
+return ExceptionContinueExecution;
+} else {
+return ExceptionContinueSearch;
+}
+}
+#endif
+GC_INNER GC_bool GC_mark_some(ptr_t cold_gc_frame)
+{
+GC_bool ret_val;
+#if defined(MSWIN32)||defined(MSWINCE)
+#ifndef __GNUC__
+__try {
+ret_val=GC_mark_some_inner(cold_gc_frame);
+} __except (GetExceptionCode()==EXCEPTION_ACCESS_VIOLATION?
+EXCEPTION_EXECUTE_HANDLER:EXCEPTION_CONTINUE_SEARCH){
+goto handle_ex;
+}
+#if defined(GC_WIN32_THREADS)&&!defined(GC_PTHREADS)
+if (GC_started_thread_while_stopped())
+goto handle_thr_start;
+#endif
+rm_handler:
+return ret_val;
+#else
+ext_ex_regn er;
+#if GC_GNUC_PREREQ(4,7)||GC_CLANG_PREREQ(3,3)
+#pragma GCC diagnostic push
+#if defined(__clang__)||GC_GNUC_PREREQ(6,4)
+#pragma GCC diagnostic ignored "-Wpedantic"
+#else
+#pragma GCC diagnostic ignored "-pedantic"
+#endif
+er.alt_path=&&handle_ex;
+#pragma GCC diagnostic pop
+#elif!defined(CPPCHECK)
+er.alt_path=&&handle_ex;
+#endif
+er.ex_reg.handler=mark_ex_handler;
+__asm__ __volatile__ ("movl %%fs:0,%0":"=r" (er.ex_reg.prev));
+__asm__ __volatile__ ("movl %0,%%fs:0"::"r" (&er));
+ret_val=GC_mark_some_inner(cold_gc_frame);
+if (er.alt_path==0)
+goto handle_ex;
+#if defined(GC_WIN32_THREADS)&&!defined(GC_PTHREADS)
+if (GC_started_thread_while_stopped())
+goto handle_thr_start;
+#endif
+rm_handler:
+__asm__ __volatile__ ("mov %0,%%fs:0"::"r" (er.ex_reg.prev));
+return ret_val;
+#endif
+#else
+#ifndef DEFAULT_VDB
+if (GC_auto_incremental){
+WARN("Incremental GC incompatible with/proc roots\n",0);
+}
+#endif
+GC_setup_temporary_fault_handler();
+if(SETJMP(GC_jmp_buf)!=0)goto handle_ex;
+ret_val=GC_mark_some_inner(cold_gc_frame);
+rm_handler:
+GC_reset_fault_handler();
+return ret_val;
+#endif
+handle_ex:
+{
+static word warned_gc_no;
+if (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
+#ifdef REGISTER_LIBRARIES_EARLY
+START_WORLD();
+GC_cond_register_dynamic_libraries();
+STOP_WORLD();
+#endif
+GC_invalidate_mark_state();
+GC_scan_ptr=NULL;
+ret_val=FALSE;
+goto rm_handler;
+}
+#endif
+GC_INNER void GC_invalidate_mark_state(void)
+{
+GC_mark_state=MS_INVALID;
+GC_mark_stack_top=GC_mark_stack-1;
+}
+GC_INNER mse*GC_signal_mark_stack_overflow(mse*msp)
+{
+GC_mark_state=MS_INVALID;
+#ifdef PARALLEL_MARK
+if (!GC_parallel)
+GC_mark_stack_too_small=TRUE;
+#else
+GC_mark_stack_too_small=TRUE;
+#endif
+GC_COND_LOG_PRINTF("Mark stack overflow;current size=%lu entries\n",
+(unsigned long)GC_mark_stack_size);
+return(msp - GC_MARK_STACK_DISCARDS);
+}
+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;
+ptr_t current_p;
+word current;
+ptr_t limit=0;
+word descr;
+ptr_t greatest_ha=(ptr_t)GC_greatest_plausible_heap_addr;
+ptr_t least_ha=(ptr_t)GC_least_plausible_heap_addr;
+DECLARE_HDR_CACHE;
+#define SPLIT_RANGE_WORDS 128
+GC_objects_are_marked=TRUE;
+INIT_HDR_CACHE;
+#ifdef OS2
+while ((word)mark_stack_top>=(word)mark_stack&&credit>=0)
+#else
+while (((((word)mark_stack_top - (word)mark_stack)|(word)credit)
+&SIGNB)==0)
+#endif
+{
+current_p=mark_stack_top->mse_start;
+descr=mark_stack_top->mse_descr.w;
+retry:
+if (descr&((~(WORDS_TO_BYTES(SPLIT_RANGE_WORDS)- 1))|GC_DS_TAGS)){
+word tag=descr&GC_DS_TAGS;
+GC_STATIC_ASSERT(GC_DS_TAGS==0x3);
+switch(tag){
+case GC_DS_LENGTH:
+GC_ASSERT(descr < (word)GC_greatest_plausible_heap_addr
+- (word)GC_least_plausible_heap_addr
+||(word)(current_p+descr)
+<=(word)GC_least_plausible_heap_addr
+||(word)current_p>=(word)GC_greatest_plausible_heap_addr);
+#ifdef PARALLEL_MARK
+#define SHARE_BYTES 2048
+if (descr > SHARE_BYTES&&GC_parallel
+&&(word)mark_stack_top < (word)(mark_stack_limit - 1)){
+word new_size=(descr/2)&~(word)(sizeof(word)-1);
+mark_stack_top->mse_start=current_p;
+mark_stack_top->mse_descr.w=new_size+sizeof(word);
+mark_stack_top++;
+#ifdef ENABLE_TRACE
+if ((word)GC_trace_addr>=(word)current_p
+&&(word)GC_trace_addr < (word)(current_p+descr)){
+GC_log_printf("GC #%u:large section;start %p,len %lu,"
+" splitting (parallel)at %p\n",
+(unsigned)GC_gc_no,(void*)current_p,
+(unsigned long)descr,
+(void*)(current_p+new_size));
+}
+#endif
+current_p+=new_size;
+descr-=new_size;
+goto retry;
+}
+#endif
+mark_stack_top->mse_start=
+limit=current_p+WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);
+mark_stack_top->mse_descr.w=
+descr - WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);
+#ifdef ENABLE_TRACE
+if ((word)GC_trace_addr>=(word)current_p
+&&(word)GC_trace_addr < (word)(current_p+descr)){
+GC_log_printf("GC #%u:large section;start %p,len %lu,"
+" splitting at %p\n",
+(unsigned)GC_gc_no,(void*)current_p,
+(unsigned long)descr,(void*)limit);
+}
+#endif
+limit+=sizeof(word)- ALIGNMENT;
+break;
+case GC_DS_BITMAP:
+mark_stack_top--;
+#ifdef ENABLE_TRACE
+if ((word)GC_trace_addr>=(word)current_p
+&&(word)GC_trace_addr < (word)(current_p
++WORDS_TO_BYTES(WORDSZ-2))){
+GC_log_printf("GC #%u:tracing from %p bitmap descr %lu\n",
+(unsigned)GC_gc_no,(void*)current_p,
+(unsigned long)descr);
+}
+#endif
+descr&=~GC_DS_TAGS;
+credit-=WORDS_TO_BYTES(WORDSZ/2);
+while (descr!=0){
+if ((descr&SIGNB)!=0){
+current=*(word*)current_p;
+FIXUP_POINTER(current);
+if (current>=(word)least_ha&&current < (word)greatest_ha){
+PREFETCH((ptr_t)current);
+#ifdef ENABLE_TRACE
+if (GC_trace_addr==current_p){
+GC_log_printf("GC #%u:considering(3)%p->%p\n",
+(unsigned)GC_gc_no,(void*)current_p,
+(void*)current);
+}
+#endif
+PUSH_CONTENTS((ptr_t)current,mark_stack_top,
+mark_stack_limit,current_p);
+}
+}
+descr<<=1;
+current_p+=sizeof(word);
+}
+continue;
+case GC_DS_PROC:
+mark_stack_top--;
+#ifdef ENABLE_TRACE
+if ((word)GC_trace_addr>=(word)current_p
+&&GC_base(current_p)!=0
+&&GC_base(current_p)==GC_base(GC_trace_addr)){
+GC_log_printf("GC #%u:tracing from %p,proc descr %lu\n",
+(unsigned)GC_gc_no,(void*)current_p,
+(unsigned long)descr);
+}
+#endif
+credit-=GC_PROC_BYTES;
+mark_stack_top=(*PROC(descr))((word*)current_p,mark_stack_top,
+mark_stack_limit,ENV(descr));
+continue;
+case GC_DS_PER_OBJECT:
+if ((signed_word)descr>=0){
+descr=*(word*)(current_p+descr - GC_DS_PER_OBJECT);
+} else {
+ptr_t type_descr=*(ptr_t*)current_p;
+if (EXPECT(0==type_descr,FALSE)){
+mark_stack_top--;
+continue;
+}
+descr=*(word*)(type_descr
+- ((signed_word)descr+(GC_INDIR_PER_OBJ_BIAS
+- GC_DS_PER_OBJECT)));
+}
+if (0==descr){
+mark_stack_top--;
+continue;
+}
+goto retry;
+}
+} else {
+mark_stack_top--;
+#ifndef SMALL_CONFIG
+if (descr < sizeof(word))
+continue;
+#endif
+#ifdef ENABLE_TRACE
+if ((word)GC_trace_addr>=(word)current_p
+&&(word)GC_trace_addr < (word)(current_p+descr)){
+GC_log_printf("GC #%u:small object;start %p,len %lu\n",
+(unsigned)GC_gc_no,(void*)current_p,
+(unsigned long)descr);
+}
+#endif
+limit=current_p+(word)descr;
+}
+GC_ASSERT(!((word)current_p&(ALIGNMENT-1)));
+credit-=limit - current_p;
+limit-=sizeof(word);
+{
+#define PREF_DIST 4
+#ifndef SMALL_CONFIG
+word deferred;
+for(;;){
+PREFETCH(limit - PREF_DIST*CACHE_LINE_SIZE);
+GC_ASSERT((word)limit>=(word)current_p);
+deferred=*(word*)limit;
+FIXUP_POINTER(deferred);
+limit-=ALIGNMENT;
+if (deferred>=(word)least_ha&&deferred < (word)greatest_ha){
+PREFETCH((ptr_t)deferred);
+break;
+}
+if ((word)current_p > (word)limit)goto next_object;
+deferred=*(word*)limit;
+FIXUP_POINTER(deferred);
+limit-=ALIGNMENT;
+if (deferred>=(word)least_ha&&deferred < (word)greatest_ha){
+PREFETCH((ptr_t)deferred);
+break;
+}
+if ((word)current_p > (word)limit)goto next_object;
+}
+#endif
+while ((word)current_p<=(word)limit){
+current=*(word*)current_p;
+FIXUP_POINTER(current);
+PREFETCH(current_p+PREF_DIST*CACHE_LINE_SIZE);
+if (current>=(word)least_ha&&current < (word)greatest_ha){
+PREFETCH((ptr_t)current);
+#ifdef ENABLE_TRACE
+if (GC_trace_addr==current_p){
+GC_log_printf("GC #%u:considering(1)%p->%p\n",
+(unsigned)GC_gc_no,(void*)current_p,
+(void*)current);
+}
+#endif
+PUSH_CONTENTS((ptr_t)current,mark_stack_top,
+mark_stack_limit,current_p);
+}
+current_p+=ALIGNMENT;
+}
+#ifndef SMALL_CONFIG
+#ifdef ENABLE_TRACE
+if (GC_trace_addr==current_p){
+GC_log_printf("GC #%u:considering(2)%p->%p\n",
+(unsigned)GC_gc_no,(void*)current_p,
+(void*)deferred);
+}
+#endif
+PUSH_CONTENTS((ptr_t)deferred,mark_stack_top,
+mark_stack_limit,current_p);
+next_object:;
+#endif
+}
+}
+return mark_stack_top;
+}
+#ifdef PARALLEL_MARK
+STATIC GC_bool GC_help_wanted=FALSE;
+STATIC unsigned GC_helper_count=0;
+STATIC unsigned GC_active_count=0;
+GC_INNER word GC_mark_no=0;
+#ifdef LINT2
+#define LOCAL_MARK_STACK_SIZE (HBLKSIZE/8)
+#else
+#define LOCAL_MARK_STACK_SIZE HBLKSIZE
+#endif
+GC_INNER void GC_wait_for_markers_init(void)
+{
+signed_word count;
+if (GC_markers_m1==0)
+return;
+#ifndef CAN_HANDLE_FORK
+GC_ASSERT(NULL==GC_main_local_mark_stack);
+#else
+if (NULL==GC_main_local_mark_stack)
+#endif
+{
+size_t bytes_to_get=
+ROUNDUP_PAGESIZE_IF_MMAP(LOCAL_MARK_STACK_SIZE*sizeof(mse));
+GC_ASSERT(GC_page_size!=0);
+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)GC_main_local_mark_stack,bytes_to_get);
+}
+GC_acquire_mark_lock();
+GC_fl_builder_count+=GC_markers_m1;
+count=GC_fl_builder_count;
+GC_release_mark_lock();
+if (count!=0){
+GC_ASSERT(count > 0);
+GC_wait_for_reclaim();
+}
+}
+STATIC mse*GC_steal_mark_stack(mse*low,mse*high,mse*local,
+unsigned max,mse**next)
+{
+mse*p;
+mse*top=local - 1;
+unsigned i=0;
+GC_ASSERT((word)high>=(word)(low - 1)
+&&(word)(high - low+1)<=GC_mark_stack_size);
+for (p=low;(word)p<=(word)high&&i<=max;++p){
+word descr=(word)AO_load(&p->mse_descr.ao);
+if (descr!=0){
+AO_store_release_write(&p->mse_descr.ao,0);
+++top;
+top->mse_descr.w=descr;
+top->mse_start=p->mse_start;
+GC_ASSERT((descr&GC_DS_TAGS)!=GC_DS_LENGTH
+||descr < (word)GC_greatest_plausible_heap_addr
+- (word)GC_least_plausible_heap_addr
+||(word)(p->mse_start+descr)
+<=(word)GC_least_plausible_heap_addr
+||(word)p->mse_start
+>=(word)GC_greatest_plausible_heap_addr);
+++i;
+if ((descr&GC_DS_TAGS)==GC_DS_LENGTH)i+=(int)(descr>>8);
+}
+}
+*next=p;
+return top;
+}
+STATIC void GC_return_mark_stack(mse*low,mse*high)
+{
+mse*my_top;
+mse*my_start;
+size_t stack_size;
+if ((word)high < (word)low)return;
+stack_size=high - low+1;
+GC_acquire_mark_lock();
+my_top=GC_mark_stack_top;
+my_start=my_top+1;
+if ((word)(my_start - GC_mark_stack+stack_size)
+> (word)GC_mark_stack_size){
+GC_COND_LOG_PRINTF("No room to copy back mark stack\n");
+GC_mark_state=MS_INVALID;
+GC_mark_stack_too_small=TRUE;
+} else {
+BCOPY(low,my_start,stack_size*sizeof(mse));
+GC_ASSERT((mse*)AO_load((volatile AO_t*)(&GC_mark_stack_top))
+==my_top);
+AO_store_release_write((volatile AO_t*)(&GC_mark_stack_top),
+(AO_t)(my_top+stack_size));
+}
+GC_release_mark_lock();
+GC_notify_all_marker();
+}
+#ifndef N_LOCAL_ITERS
+#define N_LOCAL_ITERS 1
+#endif
+static GC_bool has_inactive_helpers(void)
+{
+GC_bool res;
+GC_acquire_mark_lock();
+res=GC_active_count < GC_helper_count;
+GC_release_mark_lock();
+return res;
+}
+STATIC void GC_do_local_mark(mse*local_mark_stack,mse*local_top)
+{
+unsigned n;
+for (;;){
+for (n=0;n < N_LOCAL_ITERS;++n){
+local_top=GC_mark_from(local_top,local_mark_stack,
+local_mark_stack+LOCAL_MARK_STACK_SIZE);
+if ((word)local_top < (word)local_mark_stack)return;
+if ((word)(local_top - local_mark_stack)
+>=LOCAL_MARK_STACK_SIZE/2){
+GC_return_mark_stack(local_mark_stack,local_top);
+return;
+}
+}
+if ((word)AO_load((volatile AO_t*)&GC_mark_stack_top)
+< (word)AO_load(&GC_first_nonempty)
+&&(word)local_top > (word)(local_mark_stack+1)
+&&has_inactive_helpers()){
+mse*new_bottom=local_mark_stack
++(local_top - local_mark_stack)/2;
+GC_ASSERT((word)new_bottom > (word)local_mark_stack
+&&(word)new_bottom < (word)local_top);
+GC_return_mark_stack(local_mark_stack,new_bottom - 1);
+memmove(local_mark_stack,new_bottom,
+(local_top - new_bottom+1)*sizeof(mse));
+local_top-=(new_bottom - local_mark_stack);
+}
+}
+}
+#ifndef ENTRIES_TO_GET
+#define ENTRIES_TO_GET 5
+#endif
+STATIC void GC_mark_local(mse*local_mark_stack,int id)
+{
+mse*my_first_nonempty;
+GC_active_count++;
+my_first_nonempty=(mse*)AO_load(&GC_first_nonempty);
+GC_ASSERT((word)GC_mark_stack<=(word)my_first_nonempty);
+GC_ASSERT((word)my_first_nonempty
+<=(word)AO_load((volatile AO_t*)&GC_mark_stack_top)+sizeof(mse));
+GC_VERBOSE_LOG_PRINTF("Starting mark helper %d\n",id);
+GC_release_mark_lock();
+for (;;){
+size_t n_on_stack;
+unsigned n_to_get;
+mse*my_top;
+mse*local_top;
+mse*global_first_nonempty=(mse*)AO_load(&GC_first_nonempty);
+GC_ASSERT((word)my_first_nonempty>=(word)GC_mark_stack&&
+(word)my_first_nonempty<=
+(word)AO_load((volatile AO_t*)&GC_mark_stack_top)
++sizeof(mse));
+GC_ASSERT((word)global_first_nonempty>=(word)GC_mark_stack);
+if ((word)my_first_nonempty < (word)global_first_nonempty){
+my_first_nonempty=global_first_nonempty;
+} else if ((word)global_first_nonempty < (word)my_first_nonempty){
+(void)AO_compare_and_swap(&GC_first_nonempty,
+(AO_t)global_first_nonempty,
+(AO_t)my_first_nonempty);
+}
+my_top=(mse*)AO_load_acquire((volatile AO_t*)(&GC_mark_stack_top));
+if ((word)my_top < (word)my_first_nonempty){
+GC_acquire_mark_lock();
+my_top=GC_mark_stack_top;
+n_on_stack=my_top - my_first_nonempty+1;
+if (0==n_on_stack){
+GC_active_count--;
+GC_ASSERT(GC_active_count<=GC_helper_count);
+if (0==GC_active_count)GC_notify_all_marker();
+while (GC_active_count > 0
+&&(word)AO_load(&GC_first_nonempty)
+> (word)GC_mark_stack_top){
+GC_wait_marker();
+}
+if (GC_active_count==0
+&&(word)AO_load(&GC_first_nonempty)
+> (word)GC_mark_stack_top){
+GC_bool need_to_notify=FALSE;
+GC_helper_count--;
+if (0==GC_helper_count)need_to_notify=TRUE;
+GC_VERBOSE_LOG_PRINTF("Finished mark helper %d\n",id);
+if (need_to_notify)GC_notify_all_marker();
+return;
+}
+GC_active_count++;
+GC_ASSERT(GC_active_count > 0);
+GC_release_mark_lock();
+continue;
+} else {
+GC_release_mark_lock();
+}
+} else {
+n_on_stack=my_top - my_first_nonempty+1;
+}
+n_to_get=ENTRIES_TO_GET;
+if (n_on_stack < 2*ENTRIES_TO_GET)n_to_get=1;
+local_top=GC_steal_mark_stack(my_first_nonempty,my_top,
+local_mark_stack,n_to_get,
+&my_first_nonempty);
+GC_ASSERT((word)my_first_nonempty>=(word)GC_mark_stack&&
+(word)my_first_nonempty<=
+(word)AO_load((volatile AO_t*)&GC_mark_stack_top)
++sizeof(mse));
+GC_do_local_mark(local_mark_stack,local_top);
+}
+}
+STATIC void GC_do_parallel_mark(void)
+{
+GC_acquire_mark_lock();
+GC_ASSERT(I_HOLD_LOCK());
+if (GC_help_wanted||GC_active_count!=0||GC_helper_count!=0)
+ABORT("Tried to start parallel mark in bad state");
+GC_VERBOSE_LOG_PRINTF("Starting marking for mark phase number %lu\n",
+(unsigned long)GC_mark_no);
+GC_first_nonempty=(AO_t)GC_mark_stack;
+GC_active_count=0;
+GC_helper_count=1;
+GC_help_wanted=TRUE;
+GC_notify_all_marker();
+GC_mark_local(GC_main_local_mark_stack,0);
+GC_help_wanted=FALSE;
+while (GC_helper_count > 0){
+GC_wait_marker();
+}
+GC_VERBOSE_LOG_PRINTF("Finished marking for mark phase number %lu\n",
+(unsigned long)GC_mark_no);
+GC_mark_no++;
+GC_release_mark_lock();
+GC_notify_all_marker();
+}
+GC_INNER void GC_help_marker(word my_mark_no)
+{
+#define my_id my_id_mse.mse_descr.w
+mse my_id_mse;
+mse local_mark_stack[LOCAL_MARK_STACK_SIZE];
+GC_ASSERT(GC_parallel);
+while (GC_mark_no < my_mark_no
+||(!GC_help_wanted&&GC_mark_no==my_mark_no)){
+GC_wait_marker();
+}
+my_id=GC_helper_count;
+if (GC_mark_no!=my_mark_no||my_id > (unsigned)GC_markers_m1){
+return;
+}
+GC_helper_count=(unsigned)my_id+1;
+GC_mark_local(local_mark_stack,(int)my_id);
+#undef my_id
+}
+#endif
+GC_INNER void GC_scratch_recycle_inner(void*ptr,size_t bytes)
+{
+if (ptr!=NULL){
+size_t page_offset=(word)ptr&(GC_page_size - 1);
+size_t displ=0;
+size_t recycled_bytes;
+GC_ASSERT(bytes!=0);
+GC_ASSERT(GC_page_size!=0);
+if (page_offset!=0)
+displ=GC_page_size - page_offset;
+recycled_bytes=(bytes - displ)&~(GC_page_size - 1);
+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);
+}
+}
+static void alloc_mark_stack(size_t n)
+{
+mse*new_stack=(mse*)GC_scratch_alloc(n*sizeof(struct GC_ms_entry));
+#ifdef GWW_VDB
+static GC_bool GC_incremental_at_stack_alloc=FALSE;
+GC_bool recycle_old=!GC_auto_incremental
+||GC_incremental_at_stack_alloc;
+GC_incremental_at_stack_alloc=GC_auto_incremental;
+#else
+#define recycle_old TRUE
+#endif
+GC_mark_stack_too_small=FALSE;
+if (GC_mark_stack!=NULL){
+if (new_stack!=0){
+if (recycle_old){
+GC_scratch_recycle_inner(GC_mark_stack,
+GC_mark_stack_size*sizeof(struct GC_ms_entry));
+}
+GC_mark_stack=new_stack;
+GC_mark_stack_size=n;
+GC_mark_stack_limit=new_stack+n;
+GC_COND_LOG_PRINTF("Grew mark stack to %lu frames\n",
+(unsigned long)GC_mark_stack_size);
+} else {
+WARN("Failed to grow mark stack to %" WARN_PRIdPTR " frames\n",n);
+}
+} else if (NULL==new_stack){
+GC_err_printf("No space for mark stack\n");
+EXIT();
+} else {
+GC_mark_stack=new_stack;
+GC_mark_stack_size=n;
+GC_mark_stack_limit=new_stack+n;
+}
+GC_mark_stack_top=GC_mark_stack-1;
+}
+GC_INNER void GC_mark_init(void)
+{
+alloc_mark_stack(INITIAL_MARK_STACK_SIZE);
+}
+GC_API void GC_CALL GC_push_all(void*bottom,void*top)
+{
+word length;
+bottom=(void*)(((word)bottom+ALIGNMENT-1)&~(ALIGNMENT-1));
+top=(void*)((word)top&~(ALIGNMENT-1));
+if ((word)bottom>=(word)top)return;
+GC_mark_stack_top++;
+if ((word)GC_mark_stack_top>=(word)GC_mark_stack_limit){
+ABORT("Unexpected mark stack overflow");
+}
+length=(word)top - (word)bottom;
+#if GC_DS_TAGS > ALIGNMENT - 1
+length+=GC_DS_TAGS;
+length&=~GC_DS_TAGS;
+#endif
+GC_mark_stack_top->mse_start=(ptr_t)bottom;
+GC_mark_stack_top->mse_descr.w=length;
+}
+#ifndef GC_DISABLE_INCREMENTAL
+STATIC void GC_push_selected(ptr_t bottom,ptr_t top,
+GC_bool (*dirty_fn)(struct hblk*))
+{
+struct hblk*h;
+bottom=(ptr_t)(((word)bottom+ALIGNMENT-1)&~(ALIGNMENT-1));
+top=(ptr_t)(((word)top)&~(ALIGNMENT-1));
+if ((word)bottom>=(word)top)return;
+h=HBLKPTR(bottom+HBLKSIZE);
+if ((word)top<=(word)h){
+if ((*dirty_fn)(h-1)){
+GC_push_all(bottom,top);
+}
+return;
+}
+if ((*dirty_fn)(h-1)){
+if ((word)(GC_mark_stack_top - GC_mark_stack)
+> 3*GC_mark_stack_size/4){
+GC_push_all(bottom,top);
+return;
+}
+GC_push_all(bottom,h);
+}
+while ((word)(h+1)<=(word)top){
+if ((*dirty_fn)(h)){
+if ((word)(GC_mark_stack_top - GC_mark_stack)
+> 3*GC_mark_stack_size/4){
+GC_push_all(h,top);
+return;
+} else {
+GC_push_all(h,h+1);
+}
+}
+h++;
+}
+if ((ptr_t)h!=top&&(*dirty_fn)(h)){
+GC_push_all(h,top);
+}
+}
+GC_API void GC_CALL GC_push_conditional(void*bottom,void*top,int all)
+{
+if (!all){
+GC_push_selected((ptr_t)bottom,(ptr_t)top,GC_page_was_dirty);
+} else {
+#ifdef PROC_VDB
+if (GC_auto_incremental){
+GC_push_selected((ptr_t)bottom,(ptr_t)top,GC_page_was_ever_dirty);
+} else
+#endif
+{
+GC_push_all(bottom,top);
+}
+}
+}
+#else
+GC_API void GC_CALL GC_push_conditional(void*bottom,void*top,
+int all GC_ATTR_UNUSED)
+{
+GC_push_all(bottom,top);
+}
+#endif
+#if defined(AMIGA)||defined(MACOS)||defined(GC_DARWIN_THREADS)
+void GC_push_one(word p)
+{
+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,
+mse*mark_stack_limit,
+void**src GC_ATTR_UNUSED)
+{
+hdr*hhdr;
+PREFETCH(obj);
+GET_HDR(obj,hhdr);
+if ((EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr),FALSE)
+&&(!GC_all_interior_pointers
+||NULL==(hhdr=GC_find_header((ptr_t)GC_base(obj)))))
+||EXPECT(HBLK_IS_FREE(hhdr),FALSE)){
+GC_ADD_TO_BLACK_LIST_NORMAL(obj,(ptr_t)src);
+return mark_stack_ptr;
+}
+return GC_push_contents_hdr((ptr_t)obj,mark_stack_ptr,mark_stack_limit,
+(ptr_t)src,hhdr,TRUE);
+}
+#if defined(PRINT_BLACK_LIST)||defined(KEEP_BACK_PTRS)
+GC_INNER void GC_mark_and_push_stack(ptr_t p,ptr_t source)
+#else
+GC_INNER void GC_mark_and_push_stack(ptr_t p)
+#define source ((ptr_t)0)
+#endif
+{
+hdr*hhdr;
+ptr_t r=p;
+PREFETCH(p);
+GET_HDR(p,hhdr);
+if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr),FALSE)){
+if (NULL==hhdr
+||(r=(ptr_t)GC_base(p))==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);
+return;
+}
+#ifdef THREADS
+GC_dirty(p);
+#endif
+GC_mark_stack_top=GC_push_contents_hdr(r,GC_mark_stack_top,
+GC_mark_stack_limit,
+source,hhdr,FALSE);
+}
+#undef source
+#ifdef TRACE_BUF
+#ifndef TRACE_ENTRIES
+#define TRACE_ENTRIES 1000
+#endif
+struct trace_entry {
+char*kind;
+word gc_no;
+word bytes_allocd;
+word arg1;
+word arg2;
+} GC_trace_buf[TRACE_ENTRIES]={ { NULL,0,0,0,0 } };
+void GC_add_trace_entry(char*kind,word arg1,word arg2)
+{
+GC_trace_buf[GC_trace_buf_ptr].kind=kind;
+GC_trace_buf[GC_trace_buf_ptr].gc_no=GC_gc_no;
+GC_trace_buf[GC_trace_buf_ptr].bytes_allocd=GC_bytes_allocd;
+GC_trace_buf[GC_trace_buf_ptr].arg1=arg1^0x80000000;
+GC_trace_buf[GC_trace_buf_ptr].arg2=arg2^0x80000000;
+GC_trace_buf_ptr++;
+if (GC_trace_buf_ptr>=TRACE_ENTRIES)GC_trace_buf_ptr=0;
+}
+GC_API void GC_CALL GC_print_trace_inner(word gc_no)
+{
+int i;
+for (i=GC_trace_buf_ptr-1;i!=GC_trace_buf_ptr;i--){
+struct trace_entry*p;
+if (i < 0)i=TRACE_ENTRIES-1;
+p=GC_trace_buf+i;
+if (p->gc_no < gc_no||p->kind==0){
+return;
+}
+GC_printf("Trace:%s (gc:%u,bytes:%lu)0x%lX,0x%lX\n",
+p->kind,(unsigned)p->gc_no,
+(unsigned long)p->bytes_allocd,
+(long)p->arg1^0x80000000L,(long)p->arg2^0x80000000L);
+}
+GC_printf("Trace incomplete\n");
+}
+GC_API void GC_CALL GC_print_trace(word gc_no)
+{
+DCL_LOCK_STATE;
+LOCK();
+GC_print_trace_inner(gc_no);
+UNLOCK();
+}
+#endif
+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)
+{
+word*b=(word*)(((word)bottom+ALIGNMENT-1)&~(ALIGNMENT-1));
+word*t=(word*)(((word)top)&~(ALIGNMENT-1));
+REGISTER word*p;
+REGISTER word*lim;
+REGISTER ptr_t greatest_ha=(ptr_t)GC_greatest_plausible_heap_addr;
+REGISTER ptr_t least_ha=(ptr_t)GC_least_plausible_heap_addr;
+#define GC_greatest_plausible_heap_addr greatest_ha
+#define GC_least_plausible_heap_addr least_ha
+if (top==0)return;
+lim=t - 1;
+for (p=b;(word)p<=(word)lim;
+p=(word*)(((ptr_t)p)+ALIGNMENT)){
+REGISTER word q=*p;
+GC_PUSH_ONE_STACK(q,p);
+}
+#undef GC_greatest_plausible_heap_addr
+#undef GC_least_plausible_heap_addr
+}
+GC_INNER void GC_push_all_stack(ptr_t bottom,ptr_t top)
+{
+#ifndef NEED_FIXUP_POINTER
+if (GC_all_interior_pointers
+#if defined(THREADS)&&defined(MPROTECT_VDB)
+&&!GC_auto_incremental
+#endif
+&&(word)GC_mark_stack_top
+< (word)(GC_mark_stack_limit - INITIAL_MARK_STACK_SIZE/8)){
+GC_push_all(bottom,top);
+} else
+#endif
+{
+GC_push_all_eager(bottom,top);
+}
+}
+#if defined(WRAP_MARK_SOME)&&defined(PARALLEL_MARK)
+GC_ATTR_NO_SANITIZE_ADDR GC_ATTR_NO_SANITIZE_MEMORY
+GC_ATTR_NO_SANITIZE_THREAD
+GC_INNER void GC_push_conditional_eager(void*bottom,void*top,
+GC_bool all)
+{
+word*b=(word*)(((word)bottom+ALIGNMENT-1)&~(ALIGNMENT-1));
+word*t=(word*)(((word)top)&~(ALIGNMENT-1));
+REGISTER word*p;
+REGISTER word*lim;
+REGISTER ptr_t greatest_ha=(ptr_t)GC_greatest_plausible_heap_addr;
+REGISTER ptr_t least_ha=(ptr_t)GC_least_plausible_heap_addr;
+#define GC_greatest_plausible_heap_addr greatest_ha
+#define GC_least_plausible_heap_addr least_ha
+if (top==NULL)
+return;
+(void)all;
+lim=t - 1;
+for (p=b;(word)p<=(word)lim;p=(word*)((ptr_t)p+ALIGNMENT)){
+REGISTER word q=*p;
+GC_PUSH_ONE_HEAP(q,p,GC_mark_stack_top);
+}
+#undef GC_greatest_plausible_heap_addr
+#undef GC_least_plausible_heap_addr
+}
+#endif
+#if!defined(SMALL_CONFIG)&&!defined(USE_MARK_BYTES)&&defined(MARK_BIT_PER_GRANULE)
+#if GC_GRANULE_WORDS==1
+#define USE_PUSH_MARKED_ACCELERATORS
+#define PUSH_GRANULE(q)do { word qcontents=(q)[0];GC_PUSH_ONE_HEAP(qcontents,q,GC_mark_stack_top);} while (0)
+#elif GC_GRANULE_WORDS==2
+#define USE_PUSH_MARKED_ACCELERATORS
+#define PUSH_GRANULE(q)do { word qcontents=(q)[0];GC_PUSH_ONE_HEAP(qcontents,q,GC_mark_stack_top);qcontents=(q)[1];GC_PUSH_ONE_HEAP(qcontents,(q)+1,GC_mark_stack_top);} while (0)
+#elif GC_GRANULE_WORDS==4
+#define USE_PUSH_MARKED_ACCELERATORS
+#define PUSH_GRANULE(q)do { word qcontents=(q)[0];GC_PUSH_ONE_HEAP(qcontents,q,GC_mark_stack_top);qcontents=(q)[1];GC_PUSH_ONE_HEAP(qcontents,(q)+1,GC_mark_stack_top);qcontents=(q)[2];GC_PUSH_ONE_HEAP(qcontents,(q)+2,GC_mark_stack_top);qcontents=(q)[3];GC_PUSH_ONE_HEAP(qcontents,(q)+3,GC_mark_stack_top);} while (0)
+#endif
+#endif
+#ifdef USE_PUSH_MARKED_ACCELERATORS
+STATIC void GC_push_marked1(struct hblk*h,hdr*hhdr)
+{
+word*mark_word_addr=&(hhdr->hb_marks[0]);
+word*p;
+word*plim;
+ptr_t greatest_ha=(ptr_t)GC_greatest_plausible_heap_addr;
+ptr_t least_ha=(ptr_t)GC_least_plausible_heap_addr;
+mse*mark_stack_top=GC_mark_stack_top;
+mse*mark_stack_limit=GC_mark_stack_limit;
+#undef GC_mark_stack_top
+#undef GC_mark_stack_limit
+#define GC_mark_stack_top mark_stack_top
+#define GC_mark_stack_limit mark_stack_limit
+#define GC_greatest_plausible_heap_addr greatest_ha
+#define GC_least_plausible_heap_addr least_ha
+p=(word*)(h->hb_body);
+plim=(word*)(((word)h)+HBLKSIZE);
+while ((word)p < (word)plim){
+word mark_word=*mark_word_addr++;
+word*q=p;
+while(mark_word!=0){
+if (mark_word&1){
+PUSH_GRANULE(q);
+}
+q+=GC_GRANULE_WORDS;
+mark_word>>=1;
+}
+p+=WORDSZ*GC_GRANULE_WORDS;
+}
+#undef GC_greatest_plausible_heap_addr
+#undef GC_least_plausible_heap_addr
+#undef GC_mark_stack_top
+#undef GC_mark_stack_limit
+#define GC_mark_stack_limit GC_arrays._mark_stack_limit
+#define GC_mark_stack_top GC_arrays._mark_stack_top
+GC_mark_stack_top=mark_stack_top;
+}
+#ifndef UNALIGNED_PTRS
+STATIC void GC_push_marked2(struct hblk*h,hdr*hhdr)
+{
+word*mark_word_addr=&(hhdr->hb_marks[0]);
+word*p;
+word*plim;
+ptr_t greatest_ha=(ptr_t)GC_greatest_plausible_heap_addr;
+ptr_t least_ha=(ptr_t)GC_least_plausible_heap_addr;
+mse*mark_stack_top=GC_mark_stack_top;
+mse*mark_stack_limit=GC_mark_stack_limit;
+#undef GC_mark_stack_top
+#undef GC_mark_stack_limit
+#define GC_mark_stack_top mark_stack_top
+#define GC_mark_stack_limit mark_stack_limit
+#define GC_greatest_plausible_heap_addr greatest_ha
+#define GC_least_plausible_heap_addr least_ha
+p=(word*)(h->hb_body);
+plim=(word*)(((word)h)+HBLKSIZE);
+while ((word)p < (word)plim){
+word mark_word=*mark_word_addr++;
+word*q=p;
+while(mark_word!=0){
+if (mark_word&1){
+PUSH_GRANULE(q);
+PUSH_GRANULE(q+GC_GRANULE_WORDS);
+}
+q+=2*GC_GRANULE_WORDS;
+mark_word>>=2;
+}
+p+=WORDSZ*GC_GRANULE_WORDS;
+}
+#undef GC_greatest_plausible_heap_addr
+#undef GC_least_plausible_heap_addr
+#undef GC_mark_stack_top
+#undef GC_mark_stack_limit
+#define GC_mark_stack_limit GC_arrays._mark_stack_limit
+#define GC_mark_stack_top GC_arrays._mark_stack_top
+GC_mark_stack_top=mark_stack_top;
+}
+#if GC_GRANULE_WORDS < 4
+STATIC void GC_push_marked4(struct hblk*h,hdr*hhdr)
+{
+word*mark_word_addr=&(hhdr->hb_marks[0]);
+word*p;
+word*plim;
+ptr_t greatest_ha=(ptr_t)GC_greatest_plausible_heap_addr;
+ptr_t least_ha=(ptr_t)GC_least_plausible_heap_addr;
+mse*mark_stack_top=GC_mark_stack_top;
+mse*mark_stack_limit=GC_mark_stack_limit;
+#undef GC_mark_stack_top
+#undef GC_mark_stack_limit
+#define GC_mark_stack_top mark_stack_top
+#define GC_mark_stack_limit mark_stack_limit
+#define GC_greatest_plausible_heap_addr greatest_ha
+#define GC_least_plausible_heap_addr least_ha
+p=(word*)(h->hb_body);
+plim=(word*)(((word)h)+HBLKSIZE);
+while ((word)p < (word)plim){
+word mark_word=*mark_word_addr++;
+word*q=p;
+while(mark_word!=0){
+if (mark_word&1){
+PUSH_GRANULE(q);
+PUSH_GRANULE(q+GC_GRANULE_WORDS);
+PUSH_GRANULE(q+2*GC_GRANULE_WORDS);
+PUSH_GRANULE(q+3*GC_GRANULE_WORDS);
+}
+q+=4*GC_GRANULE_WORDS;
+mark_word>>=4;
+}
+p+=WORDSZ*GC_GRANULE_WORDS;
+}
+#undef GC_greatest_plausible_heap_addr
+#undef GC_least_plausible_heap_addr
+#undef GC_mark_stack_top
+#undef GC_mark_stack_limit
+#define GC_mark_stack_limit GC_arrays._mark_stack_limit
+#define GC_mark_stack_top GC_arrays._mark_stack_top
+GC_mark_stack_top=mark_stack_top;
+}
+#endif
+#endif
+#endif
+STATIC void GC_push_marked(struct hblk*h,hdr*hhdr)
+{
+word sz=hhdr->hb_sz;
+word descr=hhdr->hb_descr;
+ptr_t p;
+word bit_no;
+ptr_t lim;
+mse*GC_mark_stack_top_reg;
+mse*mark_stack_limit=GC_mark_stack_limit;
+if (( GC_DS_LENGTH)==descr)return;
+if (GC_block_empty(hhdr))return;
+#if!defined(GC_DISABLE_INCREMENTAL)
+GC_n_rescuing_pages++;
+#endif
+GC_objects_are_marked=TRUE;
+if (sz > MAXOBJBYTES){
+lim=h->hb_body;
+} else {
+lim=(ptr_t)((word)(h+1)->hb_body - sz);
+}
+switch(BYTES_TO_GRANULES(sz)){
+#if defined(USE_PUSH_MARKED_ACCELERATORS)
+case 1:
+GC_push_marked1(h,hhdr);
+break;
+#if!defined(UNALIGNED_PTRS)
+case 2:
+GC_push_marked2(h,hhdr);
+break;
+#if GC_GRANULE_WORDS < 4
+case 4:
+GC_push_marked4(h,hhdr);
+break;
+#endif
+#endif
+#else
+case 1:
+#endif
+default:
+GC_mark_stack_top_reg=GC_mark_stack_top;
+for (p=h->hb_body,bit_no=0;(word)p<=(word)lim;
+p+=sz,bit_no+=MARK_BIT_OFFSET(sz)){
+if (mark_bit_from_hdr(hhdr,bit_no)){
+GC_mark_stack_top_reg=GC_push_obj(p,hhdr,GC_mark_stack_top_reg,
+mark_stack_limit);
+}
+}
+GC_mark_stack_top=GC_mark_stack_top_reg;
+}
+}
+#ifdef ENABLE_DISCLAIM
+STATIC void GC_push_unconditionally(struct hblk*h,hdr*hhdr)
+{
+word sz=hhdr->hb_sz;
+word descr=hhdr->hb_descr;
+ptr_t p;
+ptr_t lim;
+mse*GC_mark_stack_top_reg;
+mse*mark_stack_limit=GC_mark_stack_limit;
+if (( GC_DS_LENGTH)==descr)
+return;
+#if!defined(GC_DISABLE_INCREMENTAL)
+GC_n_rescuing_pages++;
+#endif
+GC_objects_are_marked=TRUE;
+if (sz > MAXOBJBYTES)
+lim=h->hb_body;
+else
+lim=(ptr_t)((word)(h+1)->hb_body - sz);
+GC_mark_stack_top_reg=GC_mark_stack_top;
+for (p=h->hb_body;(word)p<=(word)lim;p+=sz)
+if ((*(word*)p&0x3)!=0)
+GC_mark_stack_top_reg=GC_push_obj(p,hhdr,GC_mark_stack_top_reg,
+mark_stack_limit);
+GC_mark_stack_top=GC_mark_stack_top_reg;
+}
+#endif
+#ifndef GC_DISABLE_INCREMENTAL
+STATIC GC_bool GC_block_was_dirty(struct hblk*h,hdr*hhdr)
+{
+word sz=hhdr->hb_sz;
+if (sz<=MAXOBJBYTES){
+return(GC_page_was_dirty(h));
+} else {
+ptr_t p=(ptr_t)h;
+while ((word)p < (word)h+sz){
+if (GC_page_was_dirty((struct hblk*)p))return(TRUE);
+p+=HBLKSIZE;
+}
+return(FALSE);
+}
+}
+#endif
+STATIC struct hblk*GC_push_next_marked(struct hblk*h)
+{
+hdr*hhdr=HDR(h);
+if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr)||HBLK_IS_FREE(hhdr),FALSE)){
+h=GC_next_block(h,FALSE);
+if (NULL==h)return NULL;
+hhdr=GC_find_header((ptr_t)h);
+} else {
+#ifdef LINT2
+if (NULL==h)ABORT("Bad HDR()definition");
+#endif
+}
+GC_push_marked(h,hhdr);
+return(h+OBJ_SZ_TO_BLOCKS(hhdr->hb_sz));
+}
+#ifndef GC_DISABLE_INCREMENTAL
+STATIC struct hblk*GC_push_next_marked_dirty(struct hblk*h)
+{
+hdr*hhdr=HDR(h);
+if (!GC_incremental)ABORT("Dirty bits not set up");
+for (;;){
+if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr)
+||HBLK_IS_FREE(hhdr),FALSE)){
+h=GC_next_block(h,FALSE);
+if (NULL==h)return NULL;
+hhdr=GC_find_header((ptr_t)h);
+} else {
+#ifdef LINT2
+if (NULL==h)ABORT("Bad HDR()definition");
+#endif
+}
+if (GC_block_was_dirty(h,hhdr))
+break;
+h+=OBJ_SZ_TO_BLOCKS(hhdr->hb_sz);
+hhdr=HDR(h);
+}
+#ifdef ENABLE_DISCLAIM
+if ((hhdr->hb_flags&MARK_UNCONDITIONALLY)!=0){
+GC_push_unconditionally(h,hhdr);
+} else
+#endif
+{
+GC_push_marked(h,hhdr);
+}
+return(h+OBJ_SZ_TO_BLOCKS(hhdr->hb_sz));
+}
+#endif
+STATIC struct hblk*GC_push_next_marked_uncollectable(struct hblk*h)
+{
+hdr*hhdr=HDR(h);
+for (;;){
+if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr)
+||HBLK_IS_FREE(hhdr),FALSE)){
+h=GC_next_block(h,FALSE);
+if (NULL==h)return NULL;
+hhdr=GC_find_header((ptr_t)h);
+} else {
+#ifdef LINT2
+if (NULL==h)ABORT("Bad HDR()definition");
+#endif
+}
+if (hhdr->hb_obj_kind==UNCOLLECTABLE){
+GC_push_marked(h,hhdr);
+break;
+}
+#ifdef ENABLE_DISCLAIM
+if ((hhdr->hb_flags&MARK_UNCONDITIONALLY)!=0){
+GC_push_unconditionally(h,hhdr);
+break;
+}
+#endif
+h+=OBJ_SZ_TO_BLOCKS(hhdr->hb_sz);
+hhdr=HDR(h);
+}
+return(h+OBJ_SZ_TO_BLOCKS(hhdr->hb_sz));
+}
+#include <stdio.h>
+int GC_no_dls=0;
+#if!defined(NO_DEBUGGING)||defined(GC_ASSERTIONS)
+GC_INNER word GC_compute_root_size(void)
+{
+int i;
+word size=0;
+for (i=0;i < n_root_sets;i++){
+size+=GC_static_roots[i].r_end - GC_static_roots[i].r_start;
+}
+return size;
+}
+#endif
+#if!defined(NO_DEBUGGING)
+void GC_print_static_roots(void)
+{
+int i;
+word size;
+for (i=0;i < n_root_sets;i++){
+GC_printf("From %p to %p%s\n",
+(void*)GC_static_roots[i].r_start,
+(void*)GC_static_roots[i].r_end,
+GC_static_roots[i].r_tmp?" (temporary)":"");
+}
+GC_printf("GC_root_size:%lu\n",(unsigned long)GC_root_size);
+if ((size=GC_compute_root_size())!=GC_root_size)
+GC_err_printf("GC_root_size incorrect!!Should be:%lu\n",
+(unsigned long)size);
+}
+#endif
+#ifndef THREADS
+GC_INNER GC_bool GC_is_static_root(void*p)
+{
+static int last_root_set=MAX_ROOT_SETS;
+int i;
+if (last_root_set < n_root_sets
+&&(word)p>=(word)GC_static_roots[last_root_set].r_start
+&&(word)p < (word)GC_static_roots[last_root_set].r_end)
+return(TRUE);
+for (i=0;i < n_root_sets;i++){
+if ((word)p>=(word)GC_static_roots[i].r_start
+&&(word)p < (word)GC_static_roots[i].r_end){
+last_root_set=i;
+return(TRUE);
+}
+}
+return(FALSE);
+}
+#endif
+#if!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(CYGWIN32)
+GC_INLINE int rt_hash(ptr_t addr)
+{
+word result=(word)addr;
+#if CPP_WORDSZ > 8*LOG_RT_SIZE
+result^=result>>8*LOG_RT_SIZE;
+#endif
+#if CPP_WORDSZ > 4*LOG_RT_SIZE
+result^=result>>4*LOG_RT_SIZE;
+#endif
+result^=result>>2*LOG_RT_SIZE;
+result^=result>>LOG_RT_SIZE;
+result&=(RT_SIZE-1);
+return(result);
+}
+GC_INNER void*GC_roots_present(ptr_t b)
+{
+int h=rt_hash(b);
+struct roots*p=GC_root_index[h];
+while (p!=0){
+if (p->r_start==(ptr_t)b)return(p);
+p=p->r_next;
+}
+return NULL;
+}
+GC_INLINE void add_roots_to_index(struct roots*p)
+{
+int h=rt_hash(p->r_start);
+p->r_next=GC_root_index[h];
+GC_root_index[h]=p;
+}
+#endif
+GC_INNER word GC_root_size=0;
+GC_API void GC_CALL GC_add_roots(void*b,void*e)
+{
+DCL_LOCK_STATE;
+if (!EXPECT(GC_is_initialized,TRUE))GC_init();
+LOCK();
+GC_add_roots_inner((ptr_t)b,(ptr_t)e,FALSE);
+UNLOCK();
+}
+void GC_add_roots_inner(ptr_t b,ptr_t e,GC_bool tmp)
+{
+GC_ASSERT((word)b<=(word)e);
+b=(ptr_t)(((word)b+(sizeof(word)- 1))&~(word)(sizeof(word)- 1));
+e=(ptr_t)((word)e&~(word)(sizeof(word)- 1));
+if ((word)b>=(word)e)return;
+#if defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32)
+{
+int i;
+struct roots*old=NULL;
+for (i=0;i < n_root_sets;i++){
+old=GC_static_roots+i;
+if ((word)b<=(word)old->r_end
+&&(word)e>=(word)old->r_start){
+if ((word)b < (word)old->r_start){
+GC_root_size+=old->r_start - b;
+old->r_start=b;
+}
+if ((word)e > (word)old->r_end){
+GC_root_size+=e - old->r_end;
+old->r_end=e;
+}
+old->r_tmp&=tmp;
+break;
+}
+}
+if (i < n_root_sets){
+struct roots*other;
+for (i++;i < n_root_sets;i++){
+other=GC_static_roots+i;
+b=other->r_start;
+e=other->r_end;
+if ((word)b<=(word)old->r_end
+&&(word)e>=(word)old->r_start){
+if ((word)b < (word)old->r_start){
+GC_root_size+=old->r_start - b;
+old->r_start=b;
+}
+if ((word)e > (word)old->r_end){
+GC_root_size+=e - old->r_end;
+old->r_end=e;
+}
+old->r_tmp&=other->r_tmp;
+GC_root_size-=(other->r_end - other->r_start);
+other->r_start=GC_static_roots[n_root_sets-1].r_start;
+other->r_end=GC_static_roots[n_root_sets-1].r_end;
+n_root_sets--;
+}
+}
+return;
+}
+}
+#else
+{
+struct roots*old=(struct roots*)GC_roots_present(b);
+if (old!=0){
+if ((word)e<=(word)old->r_end){
+old->r_tmp&=tmp;
+return;
+}
+if (old->r_tmp==tmp||!tmp){
+GC_root_size+=e - old->r_end;
+old->r_end=e;
+old->r_tmp=tmp;
+return;
+}
+b=old->r_end;
+}
+}
+#endif
+if (n_root_sets==MAX_ROOT_SETS){
+ABORT("Too many root sets");
+}
+#ifdef DEBUG_ADD_DEL_ROOTS
+GC_log_printf("Adding data root section %d:%p .. %p%s\n",
+n_root_sets,(void*)b,(void*)e,
+tmp?" (temporary)":"");
+#endif
+GC_static_roots[n_root_sets].r_start=(ptr_t)b;
+GC_static_roots[n_root_sets].r_end=(ptr_t)e;
+GC_static_roots[n_root_sets].r_tmp=tmp;
+#if!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(CYGWIN32)
+GC_static_roots[n_root_sets].r_next=0;
+add_roots_to_index(GC_static_roots+n_root_sets);
+#endif
+GC_root_size+=e - b;
+n_root_sets++;
+}
+GC_API void GC_CALL GC_clear_roots(void)
+{
+DCL_LOCK_STATE;
+if (!EXPECT(GC_is_initialized,TRUE))GC_init();
+LOCK();
+#ifdef THREADS
+GC_roots_were_cleared=TRUE;
+#endif
+n_root_sets=0;
+GC_root_size=0;
+#if!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(CYGWIN32)
+BZERO(GC_root_index,RT_SIZE*sizeof(void*));
+#endif
+#ifdef DEBUG_ADD_DEL_ROOTS
+GC_log_printf("Clear all data root sections\n");
+#endif
+UNLOCK();
+}
+STATIC void GC_remove_root_at_pos(int i)
+{
+#ifdef DEBUG_ADD_DEL_ROOTS
+GC_log_printf("Remove data root section at %d:%p .. %p%s\n",
+i,(void*)GC_static_roots[i].r_start,
+(void*)GC_static_roots[i].r_end,
+GC_static_roots[i].r_tmp?" (temporary)":"");
+#endif
+GC_root_size-=(GC_static_roots[i].r_end - GC_static_roots[i].r_start);
+GC_static_roots[i].r_start=GC_static_roots[n_root_sets-1].r_start;
+GC_static_roots[i].r_end=GC_static_roots[n_root_sets-1].r_end;
+GC_static_roots[i].r_tmp=GC_static_roots[n_root_sets-1].r_tmp;
+n_root_sets--;
+}
+#if!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(CYGWIN32)
+STATIC void GC_rebuild_root_index(void)
+{
+int i;
+BZERO(GC_root_index,RT_SIZE*sizeof(void*));
+for (i=0;i < n_root_sets;i++)
+add_roots_to_index(GC_static_roots+i);
+}
+#endif
+#if defined(DYNAMIC_LOADING)||defined(MSWIN32)||defined(MSWINCE)||defined(PCR)||defined(CYGWIN32)
+STATIC void GC_remove_tmp_roots(void)
+{
+int i;
+#if!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(CYGWIN32)
+int old_n_roots=n_root_sets;
+#endif
+for (i=0;i < n_root_sets;){
+if (GC_static_roots[i].r_tmp){
+GC_remove_root_at_pos(i);
+} else {
+i++;
+}
+}
+#if!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(CYGWIN32)
+if (n_root_sets < old_n_roots)
+GC_rebuild_root_index();
+#endif
+}
+#endif
+#if!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(CYGWIN32)
+STATIC void GC_remove_roots_inner(ptr_t b,ptr_t e);
+GC_API void GC_CALL GC_remove_roots(void*b,void*e)
+{
+DCL_LOCK_STATE;
+if ((((word)b+(sizeof(word)- 1))&~(word)(sizeof(word)- 1))>=
+((word)e&~(word)(sizeof(word)- 1)))
+return;
+LOCK();
+GC_remove_roots_inner((ptr_t)b,(ptr_t)e);
+UNLOCK();
+}
+STATIC void GC_remove_roots_inner(ptr_t b,ptr_t e)
+{
+int i;
+GC_bool rebuild=FALSE;
+for (i=0;i < n_root_sets;){
+if ((word)GC_static_roots[i].r_start>=(word)b
+&&(word)GC_static_roots[i].r_end<=(word)e){
+GC_remove_root_at_pos(i);
+rebuild=TRUE;
+} else {
+i++;
+}
+}
+if (rebuild)
+GC_rebuild_root_index();
+}
+#endif
+#ifdef USE_PROC_FOR_LIBRARIES
+GC_INLINE void swap_static_roots(int i,int j)
+{
+ptr_t r_start=GC_static_roots[i].r_start;
+ptr_t r_end=GC_static_roots[i].r_end;
+GC_bool r_tmp=GC_static_roots[i].r_tmp;
+GC_static_roots[i].r_start=GC_static_roots[j].r_start;
+GC_static_roots[i].r_end=GC_static_roots[j].r_end;
+GC_static_roots[i].r_tmp=GC_static_roots[j].r_tmp;
+GC_static_roots[j].r_start=r_start;
+GC_static_roots[j].r_end=r_end;
+GC_static_roots[j].r_tmp=r_tmp;
+}
+GC_INNER void GC_remove_roots_subregion(ptr_t b,ptr_t e)
+{
+int i;
+GC_bool rebuild=FALSE;
+GC_ASSERT(I_HOLD_LOCK());
+GC_ASSERT((word)b % sizeof(word)==0&&(word)e % sizeof(word)==0);
+for (i=0;i < n_root_sets;i++){
+ptr_t r_start,r_end;
+if (GC_static_roots[i].r_tmp){
+#ifdef GC_ASSERTIONS
+int j;
+for (j=i+1;j < n_root_sets;j++){
+GC_ASSERT(GC_static_roots[j].r_tmp);
+}
+#endif
+break;
+}
+r_start=GC_static_roots[i].r_start;
+r_end=GC_static_roots[i].r_end;
+if (!EXPECT((word)e<=(word)r_start||(word)r_end<=(word)b,TRUE)){
+#ifdef DEBUG_ADD_DEL_ROOTS
+GC_log_printf("Removing %p .. %p from root section %d (%p .. %p)\n",
+(void*)b,(void*)e,
+i,(void*)r_start,(void*)r_end);
+#endif
+if ((word)r_start < (word)b){
+GC_root_size-=r_end - b;
+GC_static_roots[i].r_end=b;
+if ((word)e < (word)r_end){
+int j;
+if (rebuild){
+GC_rebuild_root_index();
+rebuild=FALSE;
+}
+GC_add_roots_inner(e,r_end,FALSE);
+for (j=i+1;j < n_root_sets;j++)
+if (GC_static_roots[j].r_tmp)
+break;
+if (j < n_root_sets-1&&!GC_static_roots[n_root_sets-1].r_tmp){
+swap_static_roots(j,n_root_sets - 1);
+rebuild=TRUE;
+}
+}
+} else {
+if ((word)e < (word)r_end){
+GC_root_size-=e - r_start;
+GC_static_roots[i].r_start=e;
+} else {
+GC_remove_root_at_pos(i);
+if (i < n_root_sets - 1&&GC_static_roots[i].r_tmp
+&&!GC_static_roots[i+1].r_tmp){
+int j;
+for (j=i+2;j < n_root_sets;j++)
+if (GC_static_roots[j].r_tmp)
+break;
+swap_static_roots(i,j - 1);
+}
+i--;
+}
+rebuild=TRUE;
+}
+}
+}
+if (rebuild)
+GC_rebuild_root_index();
+}
+#endif
+#if!defined(NO_DEBUGGING)
+GC_API int GC_CALL GC_is_tmp_root(void*p)
+{
+static int last_root_set=MAX_ROOT_SETS;
+int i;
+if (last_root_set < n_root_sets
+&&(word)p>=(word)GC_static_roots[last_root_set].r_start
+&&(word)p < (word)GC_static_roots[last_root_set].r_end)
+return GC_static_roots[last_root_set].r_tmp;
+for (i=0;i < n_root_sets;i++){
+if ((word)p>=(word)GC_static_roots[i].r_start
+&&(word)p < (word)GC_static_roots[i].r_end){
+last_root_set=i;
+return GC_static_roots[i].r_tmp;
+}
+}
+return(FALSE);
+}
+#endif
+GC_INNER ptr_t GC_approx_sp(void)
+{
+volatile word sp;
+#if defined(S390)&&!defined(CPPCHECK)&&(__clang_major__ < 8)
+sp=(word)&sp;
+#elif defined(CPPCHECK)||(__GNUC__>=4&&!defined(STACK_NOT_SCANNED))
+sp=(word)__builtin_frame_address(0);
+#else
+sp=(word)&sp;
+#endif
+return((ptr_t)sp);
+}
+GC_API void GC_CALL GC_clear_exclusion_table(void)
+{
+GC_excl_table_entries=0;
+}
+STATIC struct exclusion*GC_next_exclusion(ptr_t start_addr)
+{
+size_t low=0;
+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;
+if ((word)GC_excl_table[mid].e_end<=(word)start_addr){
+low=mid+1;
+} else {
+high=mid;
+}
+}
+if ((word)GC_excl_table[low].e_end<=(word)start_addr)return 0;
+return GC_excl_table+low;
+}
+GC_INNER void GC_exclude_static_roots_inner(void*start,void*finish)
+{
+struct exclusion*next;
+size_t next_index;
+GC_ASSERT((word)start % sizeof(word)==0);
+GC_ASSERT((word)start < (word)finish);
+if (0==GC_excl_table_entries){
+next=0;
+} else {
+next=GC_next_exclusion((ptr_t)start);
+}
+if (0!=next){
+size_t i;
+if ((word)(next->e_start)< (word)finish){
+ABORT("Exclusion ranges overlap");
+}
+if ((word)(next->e_start)==(word)finish){
+next->e_start=(ptr_t)start;
+return;
+}
+next_index=next - GC_excl_table;
+for (i=GC_excl_table_entries;i > next_index;--i){
+GC_excl_table[i]=GC_excl_table[i-1];
+}
+} else {
+next_index=GC_excl_table_entries;
+}
+if (GC_excl_table_entries==MAX_EXCLUSIONS)ABORT("Too many exclusions");
+GC_excl_table[next_index].e_start=(ptr_t)start;
+GC_excl_table[next_index].e_end=(ptr_t)finish;
+++GC_excl_table_entries;
+}
+GC_API void GC_CALL GC_exclude_static_roots(void*b,void*e)
+{
+DCL_LOCK_STATE;
+if (b==e)return;
+b=(void*)((word)b&~(word)(sizeof(word)- 1));
+e=(void*)(((word)e+(sizeof(word)- 1))&~(word)(sizeof(word)- 1));
+if (NULL==e)
+e=(void*)(~(word)(sizeof(word)- 1));
+LOCK();
+GC_exclude_static_roots_inner(b,e);
+UNLOCK();
+}
+#if defined(WRAP_MARK_SOME)&&defined(PARALLEL_MARK)
+#define GC_PUSH_CONDITIONAL(b,t,all)(GC_parallel?GC_push_conditional_eager(b,t,all):GC_push_conditional(b,t,all))
+#elif defined(GC_DISABLE_INCREMENTAL)
+#define GC_PUSH_CONDITIONAL(b,t,all)GC_push_all(b,t)
+#else
+#define GC_PUSH_CONDITIONAL(b,t,all)GC_push_conditional(b,t,all)
+#endif
+STATIC void GC_push_conditional_with_exclusions(ptr_t bottom,ptr_t top,
+GC_bool all GC_ATTR_UNUSED)
+{
+while ((word)bottom < (word)top){
+struct exclusion*next=GC_next_exclusion(bottom);
+ptr_t excl_start;
+if (0==next
+||(word)(excl_start=next->e_start)>=(word)top){
+GC_PUSH_CONDITIONAL(bottom,top,all);
+break;
+}
+if ((word)excl_start > (word)bottom)
+GC_PUSH_CONDITIONAL(bottom,excl_start,all);
+bottom=next->e_end;
+}
+}
+#ifdef IA64
+GC_INNER void GC_push_all_register_sections(ptr_t bs_lo,ptr_t bs_hi,
+int eager,struct GC_traced_stack_sect_s*traced_stack_sect)
+{
+while (traced_stack_sect!=NULL){
+ptr_t frame_bs_lo=traced_stack_sect->backing_store_end;
+GC_ASSERT((word)frame_bs_lo<=(word)bs_hi);
+if (eager){
+GC_push_all_eager(frame_bs_lo,bs_hi);
+} else {
+GC_push_all_stack(frame_bs_lo,bs_hi);
+}
+bs_hi=traced_stack_sect->saved_backing_store_ptr;
+traced_stack_sect=traced_stack_sect->prev;
+}
+GC_ASSERT((word)bs_lo<=(word)bs_hi);
+if (eager){
+GC_push_all_eager(bs_lo,bs_hi);
+} else {
+GC_push_all_stack(bs_lo,bs_hi);
+}
+}
+#endif
+#ifdef THREADS
+GC_INNER void GC_push_all_stack_sections(ptr_t lo,ptr_t hi,
+struct GC_traced_stack_sect_s*traced_stack_sect)
+{
+while (traced_stack_sect!=NULL){
+GC_ASSERT((word)lo HOTTER_THAN (word)traced_stack_sect);
+#ifdef STACK_GROWS_UP
+GC_push_all_stack((ptr_t)traced_stack_sect,lo);
+#else
+GC_push_all_stack(lo,(ptr_t)traced_stack_sect);
+#endif
+lo=traced_stack_sect->saved_stack_ptr;
+GC_ASSERT(lo!=NULL);
+traced_stack_sect=traced_stack_sect->prev;
+}
+GC_ASSERT(!((word)hi HOTTER_THAN (word)lo));
+#ifdef STACK_GROWS_UP
+GC_push_all_stack(hi,lo);
+#else
+GC_push_all_stack(lo,hi);
+#endif
+}
+#else
+STATIC void GC_push_all_stack_partially_eager(ptr_t bottom,ptr_t top,
+ptr_t cold_gc_frame)
+{
+#ifndef NEED_FIXUP_POINTER
+if (GC_all_interior_pointers){
+if (0==cold_gc_frame){
+GC_push_all_stack(bottom,top);
+return;
+}
+GC_ASSERT((word)bottom<=(word)cold_gc_frame
+&&(word)cold_gc_frame<=(word)top);
+#ifdef STACK_GROWS_DOWN
+GC_push_all(cold_gc_frame - sizeof(ptr_t),top);
+GC_push_all_eager(bottom,cold_gc_frame);
+#else
+GC_push_all(bottom,cold_gc_frame+sizeof(ptr_t));
+GC_push_all_eager(cold_gc_frame,top);
+#endif
+} else
+#endif
+{
+GC_push_all_eager(bottom,top);
+}
+#ifdef TRACE_BUF
+GC_add_trace_entry("GC_push_all_stack",(word)bottom,(word)top);
+#endif
+}
+STATIC void GC_push_all_stack_part_eager_sections(ptr_t lo,ptr_t hi,
+ptr_t cold_gc_frame,struct GC_traced_stack_sect_s*traced_stack_sect)
+{
+GC_ASSERT(traced_stack_sect==NULL||cold_gc_frame==NULL||
+(word)cold_gc_frame HOTTER_THAN (word)traced_stack_sect);
+while (traced_stack_sect!=NULL){
+GC_ASSERT((word)lo HOTTER_THAN (word)traced_stack_sect);
+#ifdef STACK_GROWS_UP
+GC_push_all_stack_partially_eager((ptr_t)traced_stack_sect,lo,
+cold_gc_frame);
+#else
+GC_push_all_stack_partially_eager(lo,(ptr_t)traced_stack_sect,
+cold_gc_frame);
+#endif
+lo=traced_stack_sect->saved_stack_ptr;
+GC_ASSERT(lo!=NULL);
+traced_stack_sect=traced_stack_sect->prev;
+cold_gc_frame=NULL;
+}
+GC_ASSERT(!((word)hi HOTTER_THAN (word)lo));
+#ifdef STACK_GROWS_UP
+GC_push_all_stack_partially_eager(hi,lo,cold_gc_frame);
+#else
+GC_push_all_stack_partially_eager(lo,hi,cold_gc_frame);
+#endif
+}
+#endif
+STATIC void GC_push_current_stack(ptr_t cold_gc_frame,
+void*context GC_ATTR_UNUSED)
+{
+#if defined(THREADS)
+#ifdef STACK_GROWS_DOWN
+GC_push_all_eager(GC_approx_sp(),cold_gc_frame);
+#else
+GC_push_all_eager(cold_gc_frame,GC_approx_sp());
+#endif
+#else
+GC_push_all_stack_part_eager_sections(GC_approx_sp(),GC_stackbottom,
+cold_gc_frame,GC_traced_stack_sect);
+#ifdef IA64
+{
+ptr_t bsp=GC_save_regs_ret_val;
+ptr_t cold_gc_bs_pointer=bsp - 2048;
+if (GC_all_interior_pointers
+&&(word)cold_gc_bs_pointer > (word)BACKING_STORE_BASE){
+if (GC_traced_stack_sect!=NULL
+&&(word)cold_gc_bs_pointer
+< (word)GC_traced_stack_sect->backing_store_end)
+cold_gc_bs_pointer=
+GC_traced_stack_sect->backing_store_end;
+GC_push_all_register_sections(BACKING_STORE_BASE,
+cold_gc_bs_pointer,FALSE,GC_traced_stack_sect);
+GC_push_all_eager(cold_gc_bs_pointer,bsp);
+} else {
+GC_push_all_register_sections(BACKING_STORE_BASE,bsp,
+TRUE,GC_traced_stack_sect);
+}
+}
+#endif
+#endif
+}
+GC_INNER void (*GC_push_typed_structures)(void)=0;
+GC_INNER void GC_cond_register_dynamic_libraries(void)
+{
+#if (defined(DYNAMIC_LOADING)&&!defined(MSWIN_XBOX1))||defined(CYGWIN32)||defined(MSWIN32)||defined(MSWINCE)||defined(PCR)
+GC_remove_tmp_roots();
+if (!GC_no_dls)GC_register_dynamic_libraries();
+#else
+GC_no_dls=TRUE;
+#endif
+}
+STATIC void GC_push_regs_and_stack(ptr_t cold_gc_frame)
+{
+#ifdef THREADS
+if (NULL==cold_gc_frame)
+return;
+#endif
+GC_with_callee_saves_pushed(GC_push_current_stack,cold_gc_frame);
+}
+GC_INNER void GC_push_roots(GC_bool all,ptr_t cold_gc_frame GC_ATTR_UNUSED)
+{
+int i;
+unsigned kind;
+#if!defined(REGISTER_LIBRARIES_EARLY)
+GC_cond_register_dynamic_libraries();
+#endif
+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);
+}
+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);
+}
+}
+#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();
+#if defined(THREAD_LOCAL_ALLOC)
+if (GC_world_stopped)
+GC_mark_thread_local_free_lists();
+#endif
+#ifndef STACK_NOT_SCANNED
+GC_push_regs_and_stack(cold_gc_frame);
+#endif
+if (GC_push_other_roots!=0){
+(*GC_push_other_roots)();
+}
+}
+#ifdef ENABLE_DISCLAIM
+#endif
+#include <stdio.h>
+GC_INNER signed_word GC_bytes_found=0;
+#if defined(PARALLEL_MARK)
+GC_INNER signed_word GC_fl_builder_count=0;
+#endif
+#ifndef MAX_LEAKED
+#define MAX_LEAKED 40
+#endif
+STATIC ptr_t GC_leaked[MAX_LEAKED]={ NULL };
+STATIC unsigned GC_n_leaked=0;
+GC_INNER GC_bool GC_have_errors=FALSE;
+#if!defined(EAGER_SWEEP)&&defined(ENABLE_DISCLAIM)
+STATIC void GC_reclaim_unconditionally_marked(void);
+#endif
+GC_INLINE void GC_add_leaked(ptr_t leaked)
+{
+#ifndef SHORT_DBG_HDRS
+if (GC_findleak_delay_free&&!GC_check_leaked(leaked))
+return;
+#endif
+GC_have_errors=TRUE;
+if (GC_n_leaked < MAX_LEAKED){
+GC_leaked[GC_n_leaked++]=leaked;
+GC_set_mark_bit(leaked);
+}
+}
+GC_INNER void GC_print_all_errors(void)
+{
+static GC_bool printing_errors=FALSE;
+GC_bool have_errors;
+unsigned i,n_leaked;
+ptr_t leaked[MAX_LEAKED];
+DCL_LOCK_STATE;
+LOCK();
+if (printing_errors){
+UNLOCK();
+return;
+}
+have_errors=GC_have_errors;
+printing_errors=TRUE;
+n_leaked=GC_n_leaked;
+if (n_leaked > 0){
+GC_ASSERT(n_leaked<=MAX_LEAKED);
+BCOPY(GC_leaked,leaked,n_leaked*sizeof(ptr_t));
+GC_n_leaked=0;
+BZERO(GC_leaked,n_leaked*sizeof(ptr_t));
+}
+UNLOCK();
+if (GC_debugging_started){
+GC_print_all_smashed();
+} else {
+have_errors=FALSE;
+}
+if (n_leaked > 0){
+GC_err_printf("Found %u leaked objects:\n",n_leaked);
+have_errors=TRUE;
+}
+for (i=0;i < n_leaked;i++){
+ptr_t p=leaked[i];
+#ifndef SKIP_LEAKED_OBJECTS_PRINTING
+GC_print_heap_obj(p);
+#endif
+GC_free(p);
+}
+if (have_errors
+#ifndef GC_ABORT_ON_LEAK
+&&GETENV("GC_ABORT_ON_LEAK")!=NULL
+#endif
+){
+ABORT("Leaked or smashed objects encountered");
+}
+LOCK();
+printing_errors=FALSE;
+UNLOCK();
+}
+GC_INNER GC_bool GC_block_empty(hdr*hhdr)
+{
+return (hhdr->hb_n_marks==0);
+}
+STATIC GC_bool GC_block_nearly_full(hdr*hhdr,word sz)
+{
+return hhdr->hb_n_marks > HBLK_OBJS(sz)*7/8;
+}
+STATIC ptr_t GC_reclaim_clear(struct hblk*hbp,hdr*hhdr,word sz,
+ptr_t list,signed_word*count)
+{
+word bit_no=0;
+word*p,*q,*plim;
+signed_word n_bytes_found=0;
+GC_ASSERT(hhdr==GC_find_header((ptr_t)hbp));
+#ifndef THREADS
+GC_ASSERT(sz==hhdr->hb_sz);
+#else
+#endif
+GC_ASSERT((sz&(BYTES_PER_WORD-1))==0);
+p=(word*)(hbp->hb_body);
+plim=(word*)(hbp->hb_body+HBLKSIZE - sz);
+while ((word)p<=(word)plim){
+if (mark_bit_from_hdr(hhdr,bit_no)){
+p=(word*)((ptr_t)p+sz);
+} else {
+n_bytes_found+=sz;
+obj_link(p)=list;
+list=((ptr_t)p);
+q=(word*)((ptr_t)p+sz);
+#ifdef USE_MARK_BYTES
+GC_ASSERT(!(sz&1)
+&&!((word)p&(2*sizeof(word)- 1)));
+p[1]=0;
+p+=2;
+while ((word)p < (word)q){
+CLEAR_DOUBLE(p);
+p+=2;
+}
+#else
+p++;
+while ((word)p < (word)q){
+*p++=0;
+}
+#endif
+}
+bit_no+=MARK_BIT_OFFSET(sz);
+}
+*count+=n_bytes_found;
+return(list);
+}
+STATIC ptr_t GC_reclaim_uninit(struct hblk*hbp,hdr*hhdr,word sz,
+ptr_t list,signed_word*count)
+{
+word bit_no=0;
+word*p,*plim;
+signed_word n_bytes_found=0;
+#ifndef THREADS
+GC_ASSERT(sz==hhdr->hb_sz);
+#endif
+p=(word*)(hbp->hb_body);
+plim=(word*)((ptr_t)hbp+HBLKSIZE - sz);
+while ((word)p<=(word)plim){
+if (!mark_bit_from_hdr(hhdr,bit_no)){
+n_bytes_found+=sz;
+obj_link(p)=list;
+list=((ptr_t)p);
+}
+p=(word*)((ptr_t)p+sz);
+bit_no+=MARK_BIT_OFFSET(sz);
+}
+*count+=n_bytes_found;
+return(list);
+}
+#ifdef ENABLE_DISCLAIM
+STATIC ptr_t GC_disclaim_and_reclaim(struct hblk*hbp,hdr*hhdr,word sz,
+ptr_t list,signed_word*count)
+{
+word bit_no=0;
+word*p,*q,*plim;
+signed_word n_bytes_found=0;
+struct obj_kind*ok=&GC_obj_kinds[hhdr->hb_obj_kind];
+int (GC_CALLBACK*disclaim)(void*)=ok->ok_disclaim_proc;
+#ifndef THREADS
+GC_ASSERT(sz==hhdr->hb_sz);
+#endif
+p=(word*)(hbp->hb_body);
+plim=(word*)((ptr_t)p+HBLKSIZE - sz);
+while ((word)p<=(word)plim){
+int marked=mark_bit_from_hdr(hhdr,bit_no);
+if (!marked&&(*disclaim)(p)){
+set_mark_bit_from_hdr(hhdr,bit_no);
+hhdr->hb_n_marks++;
+marked=1;
+}
+if (marked)
+p=(word*)((ptr_t)p+sz);
+else {
+n_bytes_found+=sz;
+obj_link(p)=list;
+list=((ptr_t)p);
+q=(word*)((ptr_t)p+sz);
+#ifdef USE_MARK_BYTES
+GC_ASSERT((sz&1)==0);
+GC_ASSERT(((word)p&(2*sizeof(word)- 1))==0);
+p[1]=0;
+p+=2;
+while ((word)p < (word)q){
+CLEAR_DOUBLE(p);
+p+=2;
+}
+#else
+p++;
+while ((word)p < (word)q){
+*p++=0;
+}
+#endif
+}
+bit_no+=MARK_BIT_OFFSET(sz);
+}
+*count+=n_bytes_found;
+return list;
+}
+#endif
+STATIC void GC_reclaim_check(struct hblk*hbp,hdr*hhdr,word sz)
+{
+word bit_no;
+ptr_t p,plim;
+#ifndef THREADS
+GC_ASSERT(sz==hhdr->hb_sz);
+#endif
+p=hbp->hb_body;
+plim=p+HBLKSIZE - sz;
+for (bit_no=0;(word)p<=(word)plim;
+p+=sz,bit_no+=MARK_BIT_OFFSET(sz)){
+if (!mark_bit_from_hdr(hhdr,bit_no)){
+GC_add_leaked(p);
+}
+}
+}
+#ifdef AO_HAVE_load
+#define IS_PTRFREE_SAFE(hhdr)(AO_load((volatile AO_t*)&(hhdr)->hb_descr)==0)
+#else
+#define IS_PTRFREE_SAFE(hhdr)((hhdr)->hb_descr==0)
+#endif
+GC_INNER ptr_t GC_reclaim_generic(struct hblk*hbp,hdr*hhdr,size_t sz,
+GC_bool init,ptr_t list,
+signed_word*count)
+{
+ptr_t result;
+GC_ASSERT(GC_find_header((ptr_t)hbp)==hhdr);
+#ifndef GC_DISABLE_INCREMENTAL
+GC_remove_protection(hbp,1,IS_PTRFREE_SAFE(hhdr));
+#endif
+#ifdef ENABLE_DISCLAIM
+if ((hhdr->hb_flags&HAS_DISCLAIM)!=0){
+result=GC_disclaim_and_reclaim(hbp,hhdr,sz,list,count);
+} else
+#endif
+if (init||GC_debugging_started){
+result=GC_reclaim_clear(hbp,hhdr,sz,list,count);
+} else {
+GC_ASSERT(IS_PTRFREE_SAFE(hhdr));
+result=GC_reclaim_uninit(hbp,hhdr,sz,list,count);
+}
+if (IS_UNCOLLECTABLE(hhdr->hb_obj_kind))GC_set_hdr_marks(hhdr);
+return result;
+}
+STATIC void GC_reclaim_small_nonempty_block(struct hblk*hbp,word sz,
+GC_bool report_if_found)
+{
+hdr*hhdr=HDR(hbp);
+struct obj_kind*ok=&GC_obj_kinds[hhdr->hb_obj_kind];
+void**flh=&(ok->ok_freelist[BYTES_TO_GRANULES(sz)]);
+hhdr->hb_last_reclaimed=(unsigned short)GC_gc_no;
+if (report_if_found){
+GC_reclaim_check(hbp,hhdr,sz);
+} else {
+*flh=GC_reclaim_generic(hbp,hhdr,sz,ok->ok_init,
+(ptr_t)(*flh),&GC_bytes_found);
+}
+}
+#ifdef ENABLE_DISCLAIM
+STATIC void GC_disclaim_and_reclaim_or_free_small_block(struct hblk*hbp)
+{
+hdr*hhdr=HDR(hbp);
+word sz=hhdr->hb_sz;
+struct obj_kind*ok=&GC_obj_kinds[hhdr->hb_obj_kind];
+void**flh=&(ok->ok_freelist[BYTES_TO_GRANULES(sz)]);
+void*flh_next;
+hhdr->hb_last_reclaimed=(unsigned short)GC_gc_no;
+flh_next=GC_reclaim_generic(hbp,hhdr,sz,ok->ok_init,
+(ptr_t)(*flh),&GC_bytes_found);
+if (hhdr->hb_n_marks)
+*flh=flh_next;
+else {
+GC_bytes_found+=HBLKSIZE;
+GC_freehblk(hbp);
+}
+}
+#endif
+STATIC void GC_reclaim_block(struct hblk*hbp,word report_if_found)
+{
+hdr*hhdr=HDR(hbp);
+word sz;
+struct obj_kind*ok=&GC_obj_kinds[hhdr->hb_obj_kind];
+#ifdef AO_HAVE_load
+sz=(word)AO_load((volatile AO_t*)&hhdr->hb_sz);
+#else
+sz=hhdr->hb_sz;
+#endif
+if( sz > MAXOBJBYTES){
+if(!mark_bit_from_hdr(hhdr,0)){
+if (report_if_found){
+GC_add_leaked((ptr_t)hbp);
+} else {
+word blocks;
+#ifdef ENABLE_DISCLAIM
+if (EXPECT(hhdr->hb_flags&HAS_DISCLAIM,0)){
+if ((*ok->ok_disclaim_proc)(hbp)){
+set_mark_bit_from_hdr(hhdr,0);
+goto in_use;
+}
+}
+#endif
+blocks=OBJ_SZ_TO_BLOCKS(sz);
+#if defined(CPPCHECK)
+GC_noop1((word)&blocks);
+#endif
+if (blocks > 1){
+GC_large_allocd_bytes-=blocks*HBLKSIZE;
+}
+GC_bytes_found+=sz;
+GC_freehblk(hbp);
+}
+} else {
+#ifdef ENABLE_DISCLAIM
+in_use:
+#endif
+if (IS_PTRFREE_SAFE(hhdr)){
+GC_atomic_in_use+=sz;
+} else {
+GC_composite_in_use+=sz;
+}
+}
+} else {
+GC_bool empty=GC_block_empty(hhdr);
+#ifdef PARALLEL_MARK
+GC_ASSERT(hhdr->hb_n_marks<=2*(HBLKSIZE/sz+1)+16);
+#else
+GC_ASSERT(sz*hhdr->hb_n_marks<=HBLKSIZE);
+#endif
+if (report_if_found){
+GC_reclaim_small_nonempty_block(hbp,sz,
+TRUE);
+} else if (empty){
+#ifdef ENABLE_DISCLAIM
+if ((hhdr->hb_flags&HAS_DISCLAIM)!=0){
+GC_disclaim_and_reclaim_or_free_small_block(hbp);
+} else
+#endif
+{
+GC_bytes_found+=HBLKSIZE;
+GC_freehblk(hbp);
+}
+} else if (GC_find_leak||!GC_block_nearly_full(hhdr,sz)){
+struct hblk**rlh=ok->ok_reclaim_list;
+if (rlh!=NULL){
+rlh+=BYTES_TO_GRANULES(sz);
+hhdr->hb_next=*rlh;
+*rlh=hbp;
+}
+}
+if (IS_PTRFREE_SAFE(hhdr)){
+GC_atomic_in_use+=sz*hhdr->hb_n_marks;
+} else {
+GC_composite_in_use+=sz*hhdr->hb_n_marks;
+}
+}
+}
+#if!defined(NO_DEBUGGING)
+struct Print_stats
+{
+size_t number_of_blocks;
+size_t total_bytes;
+};
+#ifdef USE_MARK_BYTES
+unsigned GC_n_set_marks(hdr*hhdr)
+{
+unsigned result=0;
+word i;
+word sz=hhdr->hb_sz;
+word offset=MARK_BIT_OFFSET(sz);
+word limit=FINAL_MARK_BIT(sz);
+for (i=0;i < limit;i+=offset){
+result+=hhdr->hb_marks[i];
+}
+GC_ASSERT(hhdr->hb_marks[limit]);
+return(result);
+}
+#else
+static unsigned set_bits(word n)
+{
+word m=n;
+unsigned result=0;
+while (m > 0){
+if (m&1)result++;
+m>>=1;
+}
+return(result);
+}
+unsigned GC_n_set_marks(hdr*hhdr)
+{
+unsigned result=0;
+word i;
+word n_mark_words;
+#ifdef MARK_BIT_PER_OBJ
+word n_objs=HBLK_OBJS(hhdr->hb_sz);
+if (0==n_objs)n_objs=1;
+n_mark_words=divWORDSZ(n_objs+WORDSZ - 1);
+#else
+n_mark_words=MARK_BITS_SZ;
+#endif
+for (i=0;i < n_mark_words - 1;i++){
+result+=set_bits(hhdr->hb_marks[i]);
+}
+#ifdef MARK_BIT_PER_OBJ
+result+=set_bits((hhdr->hb_marks[n_mark_words - 1])
+<<(n_mark_words*WORDSZ - n_objs));
+#else
+result+=set_bits(hhdr->hb_marks[n_mark_words - 1]);
+#endif
+return result;
+}
+#endif
+STATIC void GC_print_block_descr(struct hblk*h,
+word raw_ps)
+{
+hdr*hhdr=HDR(h);
+size_t bytes=hhdr->hb_sz;
+struct Print_stats*ps;
+unsigned n_marks=GC_n_set_marks(hhdr);
+unsigned n_objs=(unsigned)HBLK_OBJS(bytes);
+if (0==n_objs)n_objs=1;
+if (hhdr->hb_n_marks!=n_marks){
+GC_printf("%u,%u,%u!=%u,%u\n",hhdr->hb_obj_kind,(unsigned)bytes,
+(unsigned)hhdr->hb_n_marks,n_marks,n_objs);
+} else {
+GC_printf("%u,%u,%u,%u\n",hhdr->hb_obj_kind,(unsigned)bytes,
+n_marks,n_objs);
+}
+ps=(struct Print_stats*)raw_ps;
+ps->total_bytes+=(bytes+(HBLKSIZE-1))&~(HBLKSIZE-1);
+ps->number_of_blocks++;
+}
+void GC_print_block_list(void)
+{
+struct Print_stats pstats;
+GC_printf("kind(0=ptrfree,1=normal,2=unc.),"
+"size_in_bytes,#_marks_set,#objs\n");
+pstats.number_of_blocks=0;
+pstats.total_bytes=0;
+GC_apply_to_all_blocks(GC_print_block_descr,(word)&pstats);
+GC_printf("blocks=%lu,bytes=%lu\n",
+(unsigned long)pstats.number_of_blocks,
+(unsigned long)pstats.total_bytes);
+}
+GC_API void GC_CALL GC_print_free_list(int kind,size_t sz_in_granules)
+{
+void*flh_next;
+int n;
+GC_ASSERT(kind < MAXOBJKINDS);
+GC_ASSERT(sz_in_granules<=MAXOBJGRANULES);
+flh_next=GC_obj_kinds[kind].ok_freelist[sz_in_granules];
+for (n=0;flh_next;n++){
+GC_printf("Free object in heap block %p [%d]:%p\n",
+(void*)HBLKPTR(flh_next),n,flh_next);
+flh_next=obj_link(flh_next);
+}
+}
+#endif
+STATIC void GC_clear_fl_links(void**flp)
+{
+void*next=*flp;
+while (0!=next){
+*flp=0;
+flp=&(obj_link(next));
+next=*flp;
+}
+}
+GC_INNER void GC_start_reclaim(GC_bool report_if_found)
+{
+unsigned kind;
+#if defined(PARALLEL_MARK)
+GC_ASSERT(0==GC_fl_builder_count);
+#endif
+GC_composite_in_use=0;
+GC_atomic_in_use=0;
+for (kind=0;kind < GC_n_kinds;kind++){
+struct hblk**rlist=GC_obj_kinds[kind].ok_reclaim_list;
+GC_bool should_clobber=(GC_obj_kinds[kind].ok_descriptor!=0);
+if (rlist==0)continue;
+if (!report_if_found){
+void**fop;
+void**lim=&(GC_obj_kinds[kind].ok_freelist[MAXOBJGRANULES+1]);
+for (fop=GC_obj_kinds[kind].ok_freelist;
+(word)fop < (word)lim;(*(word**)&fop)++){
+if (*fop!=0){
+if (should_clobber){
+GC_clear_fl_links(fop);
+} else {
+*fop=0;
+}
+}
+}
+}
+BZERO(rlist,(MAXOBJGRANULES+1)*sizeof(void*));
+}
+GC_apply_to_all_blocks(GC_reclaim_block,(word)report_if_found);
+#ifdef EAGER_SWEEP
+GC_reclaim_all((GC_stop_func)0,FALSE);
+#elif defined(ENABLE_DISCLAIM)
+GC_reclaim_unconditionally_marked();
+#endif
+#if defined(PARALLEL_MARK)
+GC_ASSERT(0==GC_fl_builder_count);
+#endif
+}
+GC_INNER void GC_continue_reclaim(word sz,int kind)
+{
+hdr*hhdr;
+struct hblk*hbp;
+struct obj_kind*ok=&(GC_obj_kinds[kind]);
+struct hblk**rlh=ok->ok_reclaim_list;
+void**flh=&(ok->ok_freelist[sz]);
+if (NULL==rlh)
+return;
+for (rlh+=sz;(hbp=*rlh)!=NULL;){
+hhdr=HDR(hbp);
+*rlh=hhdr->hb_next;
+GC_reclaim_small_nonempty_block(hbp,hhdr->hb_sz,FALSE);
+if (*flh!=0)
+break;
+}
+}
+GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func,GC_bool ignore_old)
+{
+word sz;
+unsigned kind;
+hdr*hhdr;
+struct hblk*hbp;
+struct obj_kind*ok;
+struct hblk**rlp;
+struct hblk**rlh;
+#ifndef NO_CLOCK
+CLOCK_TYPE start_time=CLOCK_TYPE_INITIALIZER;
+if (GC_print_stats==VERBOSE)
+GET_TIME(start_time);
+#endif
+for (kind=0;kind < GC_n_kinds;kind++){
+ok=&(GC_obj_kinds[kind]);
+rlp=ok->ok_reclaim_list;
+if (rlp==0)continue;
+for (sz=1;sz<=MAXOBJGRANULES;sz++){
+for (rlh=rlp+sz;(hbp=*rlh)!=NULL;){
+if (stop_func!=(GC_stop_func)0&&(*stop_func)()){
+return(FALSE);
+}
+hhdr=HDR(hbp);
+*rlh=hhdr->hb_next;
+if (!ignore_old
+||(word)hhdr->hb_last_reclaimed==GC_gc_no - 1){
+GC_reclaim_small_nonempty_block(hbp,hhdr->hb_sz,FALSE);
+}
+}
+}
+}
+#ifndef NO_CLOCK
+if (GC_print_stats==VERBOSE){
+CLOCK_TYPE done_time;
+GET_TIME(done_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);
+}
+#if!defined(EAGER_SWEEP)&&defined(ENABLE_DISCLAIM)
+STATIC void GC_reclaim_unconditionally_marked(void)
+{
+word sz;
+unsigned kind;
+hdr*hhdr;
+struct hblk*hbp;
+struct obj_kind*ok;
+struct hblk**rlp;
+struct hblk**rlh;
+for (kind=0;kind < GC_n_kinds;kind++){
+ok=&(GC_obj_kinds[kind]);
+if (!ok->ok_mark_unconditionally)
+continue;
+rlp=ok->ok_reclaim_list;
+if (rlp==0)
+continue;
+for (sz=1;sz<=MAXOBJGRANULES;sz++){
+rlh=rlp+sz;
+while ((hbp=*rlh)!=0){
+hhdr=HDR(hbp);
+*rlh=hhdr->hb_next;
+GC_reclaim_small_nonempty_block(hbp,hhdr->hb_sz,FALSE);
+}
+}
+}
+}
+#endif
+struct enumerate_reachable_s {
+GC_reachable_object_proc proc;
+void*client_data;
+};
+STATIC void GC_do_enumerate_reachable_objects(struct hblk*hbp,word ped)
+{
+struct hblkhdr*hhdr=HDR(hbp);
+size_t sz=(size_t)hhdr->hb_sz;
+size_t bit_no;
+char*p,*plim;
+if (GC_block_empty(hhdr)){
+return;
+}
+p=hbp->hb_body;
+if (sz > MAXOBJBYTES){
+plim=p;
+} else {
+plim=hbp->hb_body+HBLKSIZE - sz;
+}
+for (bit_no=0;p<=plim;bit_no+=MARK_BIT_OFFSET(sz),p+=sz){
+if (mark_bit_from_hdr(hhdr,bit_no)){
+((struct enumerate_reachable_s*)ped)->proc(p,sz,
+((struct enumerate_reachable_s*)ped)->client_data);
+}
+}
+}
+GC_API void GC_CALL GC_enumerate_reachable_objects_inner(
+GC_reachable_object_proc proc,
+void*client_data)
+{
+struct enumerate_reachable_s ed;
+GC_ASSERT(I_HOLD_LOCK());
+ed.proc=proc;
+ed.client_data=client_data;
+GC_apply_to_all_blocks(GC_do_enumerate_reachable_objects,(word)&ed);
+}
+#ifndef GC_TYPED_H
+#define GC_TYPED_H
+#ifndef GC_H
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef GC_word*GC_bitmap;
+#define GC_WORDSZ (8*sizeof(GC_word))
+#define GC_get_bit(bm,index)(((bm)[(index)/GC_WORDSZ]>>((index)% GC_WORDSZ))&1)
+#define GC_set_bit(bm,index)((bm)[(index)/GC_WORDSZ]|=(GC_word)1<<((index)% GC_WORDSZ))
+#define GC_WORD_OFFSET(t,f)(offsetof(t,f)/sizeof(GC_word))
+#define GC_WORD_LEN(t)(sizeof(t)/sizeof(GC_word))
+#define GC_BITMAP_SIZE(t)((GC_WORD_LEN(t)+GC_WORDSZ - 1)/GC_WORDSZ)
+typedef GC_word GC_descr;
+GC_API GC_descr GC_CALL GC_make_descriptor(const GC_word*,
+size_t);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_malloc_explicitly_typed(size_t,
+GC_descr);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1)void*GC_CALL
+GC_malloc_explicitly_typed_ignore_off_page(size_t,
+GC_descr);
+GC_API GC_ATTR_MALLOC GC_ATTR_CALLOC_SIZE(1,2)void*GC_CALL
+GC_calloc_explicitly_typed(size_t,
+size_t,
+GC_descr);
+#ifdef GC_DEBUG
+#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)
+#define GC_CALLOC_EXPLICITLY_TYPED(n,bytes,d)GC_calloc_explicitly_typed(n,bytes,d)
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+#define TYPD_EXTRA_BYTES (sizeof(word)- EXTRA_BYTES)
+STATIC int GC_explicit_kind=0;
+STATIC int GC_array_kind=0;
+struct LeafDescriptor {
+word ld_tag;
+#define LEAF_TAG 1
+size_t ld_size;
+size_t ld_nelements;
+GC_descr ld_descriptor;
+};
+struct ComplexArrayDescriptor {
+word ad_tag;
+#define ARRAY_TAG 2
+size_t ad_nelements;
+union ComplexDescriptor*ad_element_descr;
+};
+struct SequenceDescriptor {
+word sd_tag;
+#define SEQUENCE_TAG 3
+union ComplexDescriptor*sd_first;
+union ComplexDescriptor*sd_second;
+};
+typedef union ComplexDescriptor {
+struct LeafDescriptor ld;
+struct ComplexArrayDescriptor ad;
+struct SequenceDescriptor sd;
+} complex_descriptor;
+#define TAG ad.ad_tag
+#define ED_INITIAL_SIZE 100
+STATIC int GC_typed_mark_proc_index=0;
+STATIC int GC_array_mark_proc_index=0;
+STATIC void GC_push_typed_structures_proc(void)
+{
+GC_PUSH_ALL_SYM(GC_ext_descriptors);
+}
+STATIC signed_word GC_add_ext_descriptor(const word*bm,word nbits)
+{
+size_t nwords=divWORDSZ(nbits+WORDSZ-1);
+signed_word result;
+size_t i;
+word last_part;
+size_t extra_bits;
+DCL_LOCK_STATE;
+LOCK();
+while (GC_avail_descr+nwords>=GC_ed_size){
+typed_ext_descr_t*newExtD;
+size_t new_size;
+word ed_size=GC_ed_size;
+if (ed_size==0){
+GC_ASSERT((word)(&GC_ext_descriptors)% sizeof(word)==0);
+GC_push_typed_structures=GC_push_typed_structures_proc;
+UNLOCK();
+new_size=ED_INITIAL_SIZE;
+} else {
+UNLOCK();
+new_size=2*ed_size;
+if (new_size > MAX_ENV)return(-1);
+}
+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(typed_ext_descr_t));
+}
+GC_ed_size=new_size;
+GC_ext_descriptors=newExtD;
+}
+}
+result=GC_avail_descr;
+for (i=0;i < nwords-1;i++){
+GC_ext_descriptors[result+i].ed_bitmap=bm[i];
+GC_ext_descriptors[result+i].ed_continued=TRUE;
+}
+last_part=bm[i];
+extra_bits=nwords*WORDSZ - nbits;
+last_part<<=extra_bits;
+last_part>>=extra_bits;
+GC_ext_descriptors[result+i].ed_bitmap=last_part;
+GC_ext_descriptors[result+i].ed_continued=FALSE;
+GC_avail_descr+=nwords;
+UNLOCK();
+return(result);
+}
+STATIC GC_descr GC_bm_table[WORDSZ/2];
+STATIC GC_descr GC_double_descr(GC_descr descriptor,word nwords)
+{
+if ((descriptor&GC_DS_TAGS)==GC_DS_LENGTH){
+descriptor=GC_bm_table[BYTES_TO_WORDS((word)descriptor)];
+};
+descriptor|=(descriptor&~GC_DS_TAGS)>>nwords;
+return(descriptor);
+}
+STATIC complex_descriptor*
+GC_make_sequence_descriptor(complex_descriptor*first,
+complex_descriptor*second);
+#define COMPLEX 2
+#define LEAF 1
+#define SIMPLE 0
+#define NO_MEM (-1)
+STATIC int GC_make_array_descriptor(size_t nelements,size_t size,
+GC_descr descriptor,GC_descr*simple_d,
+complex_descriptor**complex_d,
+struct LeafDescriptor*leaf)
+{
+#define OPT_THRESHOLD 50
+if ((descriptor&GC_DS_TAGS)==GC_DS_LENGTH){
+if (descriptor==(GC_descr)size){
+*simple_d=nelements*descriptor;
+return(SIMPLE);
+} else if ((word)descriptor==0){
+*simple_d=(GC_descr)0;
+return(SIMPLE);
+}
+}
+if (nelements<=OPT_THRESHOLD){
+if (nelements<=1){
+if (nelements==1){
+*simple_d=descriptor;
+return(SIMPLE);
+} else {
+*simple_d=(GC_descr)0;
+return(SIMPLE);
+}
+}
+} else if (size<=BITMAP_BITS/2
+&&(descriptor&GC_DS_TAGS)!=GC_DS_PROC
+&&(size&(sizeof(word)-1))==0){
+int result=
+GC_make_array_descriptor(nelements/2,2*size,
+GC_double_descr(descriptor,
+BYTES_TO_WORDS(size)),
+simple_d,complex_d,leaf);
+if ((nelements&1)==0){
+return(result);
+} else {
+struct LeafDescriptor*one_element=
+(struct LeafDescriptor*)
+GC_malloc_atomic(sizeof(struct LeafDescriptor));
+if (result==NO_MEM||one_element==0)return(NO_MEM);
+one_element->ld_tag=LEAF_TAG;
+one_element->ld_size=size;
+one_element->ld_nelements=1;
+one_element->ld_descriptor=descriptor;
+switch(result){
+case SIMPLE:
+{
+struct LeafDescriptor*beginning=
+(struct LeafDescriptor*)
+GC_malloc_atomic(sizeof(struct LeafDescriptor));
+if (beginning==0)return(NO_MEM);
+beginning->ld_tag=LEAF_TAG;
+beginning->ld_size=size;
+beginning->ld_nelements=1;
+beginning->ld_descriptor=*simple_d;
+*complex_d=GC_make_sequence_descriptor(
+(complex_descriptor*)beginning,
+(complex_descriptor*)one_element);
+break;
+}
+case LEAF:
+{
+struct LeafDescriptor*beginning=
+(struct LeafDescriptor*)
+GC_malloc_atomic(sizeof(struct LeafDescriptor));
+if (beginning==0)return(NO_MEM);
+beginning->ld_tag=LEAF_TAG;
+beginning->ld_size=leaf->ld_size;
+beginning->ld_nelements=leaf->ld_nelements;
+beginning->ld_descriptor=leaf->ld_descriptor;
+*complex_d=GC_make_sequence_descriptor(
+(complex_descriptor*)beginning,
+(complex_descriptor*)one_element);
+break;
+}
+case COMPLEX:
+*complex_d=GC_make_sequence_descriptor(
+*complex_d,
+(complex_descriptor*)one_element);
+break;
+}
+return(COMPLEX);
+}
+}
+leaf->ld_size=size;
+leaf->ld_nelements=nelements;
+leaf->ld_descriptor=descriptor;
+return(LEAF);
+}
+STATIC complex_descriptor*
+GC_make_sequence_descriptor(complex_descriptor*first,
+complex_descriptor*second)
+{
+struct SequenceDescriptor*result=
+(struct SequenceDescriptor*)
+GC_malloc(sizeof(struct SequenceDescriptor));
+if (result!=0){
+result->sd_tag=SEQUENCE_TAG;
+result->sd_first=first;
+result->sd_second=second;
+GC_dirty(result);
+REACHABLE_AFTER_DIRTY(first);
+REACHABLE_AFTER_DIRTY(second);
+}
+return((complex_descriptor*)result);
+}
+STATIC mse*GC_typed_mark_proc(word*addr,mse*mark_stack_ptr,
+mse*mark_stack_limit,word env);
+STATIC mse*GC_array_mark_proc(word*addr,mse*mark_stack_ptr,
+mse*mark_stack_limit,word env);
+STATIC void GC_init_explicit_typing(void)
+{
+unsigned i;
+GC_STATIC_ASSERT(sizeof(struct LeafDescriptor)% sizeof(word)==0);
+GC_explicit_kind=GC_new_kind_inner(GC_new_free_list_inner(),
+(WORDS_TO_BYTES((word)-1)|GC_DS_PER_OBJECT),
+TRUE,TRUE);
+GC_typed_mark_proc_index=GC_new_proc_inner(GC_typed_mark_proc);
+GC_array_mark_proc_index=GC_new_proc_inner(GC_array_mark_proc);
+GC_array_kind=GC_new_kind_inner(GC_new_free_list_inner(),
+GC_MAKE_PROC(GC_array_mark_proc_index,0),
+FALSE,TRUE);
+GC_bm_table[0]=GC_DS_BITMAP;
+for (i=1;i < WORDSZ/2;i++){
+GC_bm_table[i]=(((word)-1)<<(WORDSZ - i))|GC_DS_BITMAP;
+}
+}
+STATIC mse*GC_typed_mark_proc(word*addr,mse*mark_stack_ptr,
+mse*mark_stack_limit,word env)
+{
+word bm=GC_ext_descriptors[env].ed_bitmap;
+word*current_p=addr;
+word current;
+ptr_t greatest_ha=(ptr_t)GC_greatest_plausible_heap_addr;
+ptr_t least_ha=(ptr_t)GC_least_plausible_heap_addr;
+DECLARE_HDR_CACHE;
+INIT_HDR_CACHE;
+for (;bm!=0;bm>>=1,current_p++){
+if (bm&1){
+current=*current_p;
+FIXUP_POINTER(current);
+if (current>=(word)least_ha&&current<=(word)greatest_ha){
+PUSH_CONTENTS((ptr_t)current,mark_stack_ptr,
+mark_stack_limit,(ptr_t)current_p);
+}
+}
+}
+if (GC_ext_descriptors[env].ed_continued){
+mark_stack_ptr++;
+if ((word)mark_stack_ptr>=(word)mark_stack_limit){
+mark_stack_ptr=GC_signal_mark_stack_overflow(mark_stack_ptr);
+}
+mark_stack_ptr->mse_start=(ptr_t)(addr+WORDSZ);
+mark_stack_ptr->mse_descr.w=
+GC_MAKE_PROC(GC_typed_mark_proc_index,env+1);
+}
+return(mark_stack_ptr);
+}
+STATIC word GC_descr_obj_size(complex_descriptor*d)
+{
+switch(d->TAG){
+case LEAF_TAG:
+return(d->ld.ld_nelements*d->ld.ld_size);
+case ARRAY_TAG:
+return(d->ad.ad_nelements
+*GC_descr_obj_size(d->ad.ad_element_descr));
+case SEQUENCE_TAG:
+return(GC_descr_obj_size(d->sd.sd_first)
++GC_descr_obj_size(d->sd.sd_second));
+default:
+ABORT_RET("Bad complex descriptor");
+return 0;
+}
+}
+STATIC mse*GC_push_complex_descriptor(word*addr,complex_descriptor*d,
+mse*msp,mse*msl)
+{
+ptr_t current=(ptr_t)addr;
+word nelements;
+word sz;
+word i;
+switch(d->TAG){
+case LEAF_TAG:
+{
+GC_descr descr=d->ld.ld_descriptor;
+nelements=d->ld.ld_nelements;
+if (msl - msp<=(ptrdiff_t)nelements)return(0);
+sz=d->ld.ld_size;
+for (i=0;i < nelements;i++){
+msp++;
+msp->mse_start=current;
+msp->mse_descr.w=descr;
+current+=sz;
+}
+return(msp);
+}
+case ARRAY_TAG:
+{
+complex_descriptor*descr=d->ad.ad_element_descr;
+nelements=d->ad.ad_nelements;
+sz=GC_descr_obj_size(descr);
+for (i=0;i < nelements;i++){
+msp=GC_push_complex_descriptor((word*)current,descr,
+msp,msl);
+if (msp==0)return(0);
+current+=sz;
+}
+return(msp);
+}
+case SEQUENCE_TAG:
+{
+sz=GC_descr_obj_size(d->sd.sd_first);
+msp=GC_push_complex_descriptor((word*)current,d->sd.sd_first,
+msp,msl);
+if (msp==0)return(0);
+current+=sz;
+msp=GC_push_complex_descriptor((word*)current,d->sd.sd_second,
+msp,msl);
+return(msp);
+}
+default:
+ABORT_RET("Bad complex descriptor");
+return 0;
+}
+}
+STATIC mse*GC_array_mark_proc(word*addr,mse*mark_stack_ptr,
+mse*mark_stack_limit,
+word env GC_ATTR_UNUSED)
+{
+hdr*hhdr=HDR(addr);
+word sz=hhdr->hb_sz;
+word nwords=BYTES_TO_WORDS(sz);
+complex_descriptor*descr=(complex_descriptor*)(addr[nwords-1]);
+mse*orig_mark_stack_ptr=mark_stack_ptr;
+mse*new_mark_stack_ptr;
+if (descr==0){
+return(orig_mark_stack_ptr);
+}
+new_mark_stack_ptr=GC_push_complex_descriptor(addr,descr,
+mark_stack_ptr,
+mark_stack_limit-1);
+if (new_mark_stack_ptr==0){
+if (NULL==mark_stack_ptr)ABORT("Bad mark_stack_ptr");
+#ifdef PARALLEL_MARK
+if (GC_mark_stack+GC_mark_stack_size==mark_stack_limit)
+#endif
+{
+GC_mark_stack_too_small=TRUE;
+}
+new_mark_stack_ptr=orig_mark_stack_ptr+1;
+new_mark_stack_ptr->mse_start=(ptr_t)addr;
+new_mark_stack_ptr->mse_descr.w=sz|GC_DS_LENGTH;
+} else {
+new_mark_stack_ptr++;
+new_mark_stack_ptr->mse_start=(ptr_t)(addr+nwords - 1);
+new_mark_stack_ptr->mse_descr.w=sizeof(word)|GC_DS_LENGTH;
+}
+return new_mark_stack_ptr;
+}
+GC_API GC_descr GC_CALL GC_make_descriptor(const GC_word*bm,size_t len)
+{
+signed_word last_set_bit=len - 1;
+GC_descr result;
+DCL_LOCK_STATE;
+#if defined(AO_HAVE_load_acquire)&&defined(AO_HAVE_store_release)
+if (!EXPECT(AO_load_acquire(&GC_explicit_typing_initialized),TRUE)){
+LOCK();
+if (!GC_explicit_typing_initialized){
+GC_init_explicit_typing();
+AO_store_release(&GC_explicit_typing_initialized,TRUE);
+}
+UNLOCK();
+}
+#else
+LOCK();
+if (!EXPECT(GC_explicit_typing_initialized,TRUE)){
+GC_init_explicit_typing();
+GC_explicit_typing_initialized=TRUE;
+}
+UNLOCK();
+#endif
+while (last_set_bit>=0&&!GC_get_bit(bm,last_set_bit))
+last_set_bit--;
+if (last_set_bit < 0)return(0);
+#if ALIGNMENT==CPP_WORDSZ/8
+{
+signed_word i;
+for (i=0;i < last_set_bit;i++){
+if (!GC_get_bit(bm,i)){
+break;
+}
+}
+if (i==last_set_bit){
+return (WORDS_TO_BYTES(last_set_bit+1)|GC_DS_LENGTH);
+}
+}
+#endif
+if ((word)last_set_bit < BITMAP_BITS){
+signed_word i;
+result=SIGNB;
+for (i=last_set_bit - 1;i>=0;i--){
+result>>=1;
+if (GC_get_bit(bm,i))result|=SIGNB;
+}
+result|=GC_DS_BITMAP;
+} else {
+signed_word index=GC_add_ext_descriptor(bm,(word)last_set_bit+1);
+if (index==-1)return(WORDS_TO_BYTES(last_set_bit+1)|GC_DS_LENGTH);
+result=GC_MAKE_PROC(GC_typed_mark_proc_index,(word)index);
+}
+return result;
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_malloc_explicitly_typed(size_t lb,
+GC_descr d)
+{
+word*op;
+size_t lg;
+GC_ASSERT(GC_explicit_typing_initialized);
+lb=SIZET_SAT_ADD(lb,TYPD_EXTRA_BYTES);
+op=(word*)GC_malloc_kind(lb,GC_explicit_kind);
+if (EXPECT(NULL==op,FALSE))
+return NULL;
+lg=BYTES_TO_GRANULES(GC_size(op));
+op[GRANULES_TO_WORDS(lg)- 1]=d;
+GC_dirty(op+GRANULES_TO_WORDS(lg)- 1);
+REACHABLE_AFTER_DIRTY(d);
+return op;
+}
+#define GENERAL_MALLOC_IOP(lb,k)GC_clear_stack(GC_generic_malloc_ignore_off_page(lb,k))
+GC_API GC_ATTR_MALLOC void*GC_CALL
+GC_malloc_explicitly_typed_ignore_off_page(size_t lb,GC_descr d)
+{
+ptr_t op;
+size_t lg;
+DCL_LOCK_STATE;
+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];
+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);
+if (0==op)return 0;
+lg=BYTES_TO_GRANULES(GC_size(op));
+} else {
+*opp=obj_link(op);
+obj_link(op)=0;
+GC_bytes_allocd+=GRANULES_TO_BYTES((word)lg);
+UNLOCK();
+}
+} else {
+op=(ptr_t)GENERAL_MALLOC_IOP(lb,GC_explicit_kind);
+if (NULL==op)return NULL;
+lg=BYTES_TO_GRANULES(GC_size(op));
+}
+((word*)op)[GRANULES_TO_WORDS(lg)- 1]=d;
+GC_dirty(op+GRANULES_TO_WORDS(lg)- 1);
+REACHABLE_AFTER_DIRTY(d);
+return op;
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_calloc_explicitly_typed(size_t n,
+size_t lb,GC_descr d)
+{
+word*op;
+size_t lg;
+GC_descr simple_descr;
+complex_descriptor*complex_descr;
+int descr_type;
+struct LeafDescriptor leaf;
+GC_ASSERT(GC_explicit_typing_initialized);
+descr_type=GC_make_array_descriptor((word)n,(word)lb,d,&simple_descr,
+&complex_descr,&leaf);
+if ((lb|n)> GC_SQRT_SIZE_MAX
+&&lb > 0&&n > GC_SIZE_MAX/lb)
+return (*GC_get_oom_fn())(GC_SIZE_MAX);
+lb*=n;
+switch(descr_type){
+case NO_MEM:return(0);
+case SIMPLE:
+return GC_malloc_explicitly_typed(lb,simple_descr);
+case LEAF:
+lb=SIZET_SAT_ADD(lb,
+sizeof(struct LeafDescriptor)+TYPD_EXTRA_BYTES);
+break;
+case COMPLEX:
+lb=SIZET_SAT_ADD(lb,TYPD_EXTRA_BYTES);
+break;
+}
+op=(word*)GC_malloc_kind(lb,GC_array_kind);
+if (EXPECT(NULL==op,FALSE))
+return NULL;
+lg=BYTES_TO_GRANULES(GC_size(op));
+if (descr_type==LEAF){
+volatile struct LeafDescriptor*lp=
+(struct LeafDescriptor*)
+(op+GRANULES_TO_WORDS(lg)
+- (BYTES_TO_WORDS(sizeof(struct LeafDescriptor))+1));
+lp->ld_tag=LEAF_TAG;
+lp->ld_size=leaf.ld_size;
+lp->ld_nelements=leaf.ld_nelements;
+lp->ld_descriptor=leaf.ld_descriptor;
+((volatile word*)op)[GRANULES_TO_WORDS(lg)- 1]=(word)lp;
+} else {
+#ifndef GC_NO_FINALIZATION
+size_t lw=GRANULES_TO_WORDS(lg);
+op[lw - 1]=(word)complex_descr;
+GC_dirty(op+lw - 1);
+REACHABLE_AFTER_DIRTY(complex_descr);
+if (EXPECT(GC_general_register_disappearing_link(
+(void**)(op+lw - 1),op)
+==GC_NO_MEMORY,FALSE))
+#endif
+{
+return (*GC_get_oom_fn())(lb);
+}
+}
+return op;
+}
+#include <stdio.h>
+#include <limits.h>
+#include <stdarg.h>
+#ifndef MSWINCE
+#include <signal.h>
+#endif
+#ifdef GC_SOLARIS_THREADS
+#include <sys/syscall.h>
+#endif
+#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
+#ifdef THREADS
+#ifdef PCR
+#include "il/PCR_IL.h"
+GC_INNER PCR_Th_ML GC_allocate_ml;
+#elif defined(SN_TARGET_PSP2)
+GC_INNER WapiMutex GC_allocate_ml_PSP2={ 0,NULL };
+#elif defined(SN_TARGET_ORBIS)||defined(SN_TARGET_PS3)
+#include <pthread.h>
+GC_INNER pthread_mutex_t GC_allocate_ml;
+#endif
+#endif
+#ifdef DYNAMIC_LOADING
+#define GC_REGISTER_MAIN_STATIC_DATA()GC_register_main_static_data()
+#elif defined(GC_DONT_REGISTER_MAIN_STATIC_DATA)
+#define GC_REGISTER_MAIN_STATIC_DATA()FALSE
+#else
+#define GC_REGISTER_MAIN_STATIC_DATA()TRUE
+#endif
+#ifdef NEED_CANCEL_DISABLE_COUNT
+__thread unsigned char GC_cancel_disable_count=0;
+#endif
+GC_FAR struct _GC_arrays GC_arrays;
+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;
+ptr_t GC_stackbottom=0;
+#ifdef IA64
+ptr_t GC_register_stackbottom=0;
+#endif
+int GC_dont_gc=FALSE;
+int GC_dont_precollect=FALSE;
+GC_bool GC_quiet=0;
+#if!defined(NO_CLOCK)||!defined(SMALL_CONFIG)
+int GC_print_stats=0;
+#endif
+#ifdef GC_PRINT_BACK_HEIGHT
+GC_INNER GC_bool GC_print_back_height=TRUE;
+#else
+GC_INNER GC_bool GC_print_back_height=FALSE;
+#endif
+#ifndef NO_DEBUGGING
+#ifdef GC_DUMP_REGULARLY
+GC_INNER GC_bool GC_dump_regularly=TRUE;
+#else
+GC_INNER GC_bool GC_dump_regularly=FALSE;
+#endif
+#ifndef NO_CLOCK
+STATIC CLOCK_TYPE GC_init_time;
+#endif
+#endif
+#ifdef KEEP_BACK_PTRS
+GC_INNER long GC_backtraces=0;
+#endif
+#ifdef FIND_LEAK
+int GC_find_leak=1;
+#else
+int GC_find_leak=0;
+#endif
+#ifndef SHORT_DBG_HDRS
+#ifdef GC_FINDLEAK_DELAY_FREE
+GC_INNER GC_bool GC_findleak_delay_free=TRUE;
+#else
+GC_INNER GC_bool GC_findleak_delay_free=FALSE;
+#endif
+#endif
+#ifdef ALL_INTERIOR_POINTERS
+int GC_all_interior_pointers=1;
+#else
+int GC_all_interior_pointers=0;
+#endif
+#ifdef FINALIZE_ON_DEMAND
+int GC_finalize_on_demand=1;
+#else
+int GC_finalize_on_demand=0;
+#endif
+#ifdef JAVA_FINALIZATION
+int GC_java_finalization=1;
+#else
+int GC_java_finalization=0;
+#endif
+GC_finalizer_notifier_proc GC_finalizer_notifier=
+(GC_finalizer_notifier_proc)0;
+#ifdef GC_FORCE_UNMAP_ON_GCOLLECT
+GC_INNER GC_bool GC_force_unmap_on_gcollect=TRUE;
+#else
+GC_INNER GC_bool GC_force_unmap_on_gcollect=FALSE;
+#endif
+#ifndef GC_LARGE_ALLOC_WARN_INTERVAL
+#define GC_LARGE_ALLOC_WARN_INTERVAL 5
+#endif
+GC_INNER long GC_large_alloc_warn_interval=GC_LARGE_ALLOC_WARN_INTERVAL;
+STATIC void*GC_CALLBACK GC_default_oom_fn(
+size_t bytes_requested GC_ATTR_UNUSED)
+{
+return(0);
+}
+GC_oom_func GC_oom_fn=GC_default_oom_fn;
+#ifdef CAN_HANDLE_FORK
+#ifdef HANDLE_FORK
+GC_INNER int GC_handle_fork=1;
+#else
+GC_INNER int GC_handle_fork=FALSE;
+#endif
+#elif!defined(HAVE_NO_FORK)
+GC_API void GC_CALL GC_atfork_prepare(void)
+{
+#ifdef THREADS
+ABORT("fork()handling unsupported");
+#endif
+}
+GC_API void GC_CALL GC_atfork_parent(void)
+{
+}
+GC_API void GC_CALL GC_atfork_child(void)
+{
+}
+#endif
+GC_API void GC_CALL GC_set_handle_fork(int value GC_ATTR_UNUSED)
+{
+#ifdef CAN_HANDLE_FORK
+if (!GC_is_initialized)
+GC_handle_fork=value>=-1?value:1;
+#elif defined(THREADS)||(defined(DARWIN)&&defined(MPROTECT_VDB))
+if (!GC_is_initialized&&value){
+#ifndef SMALL_CONFIG
+GC_init();
+#ifndef THREADS
+if (GC_manual_vdb)
+return;
+#endif
+#endif
+ABORT("fork()handling unsupported");
+}
+#else
+#endif
+}
+STATIC void GC_init_size_map(void)
+{
+size_t i;
+GC_size_map[0]=1;
+for (i=1;i<=GRANULES_TO_BYTES(TINY_FREELISTS-1)- EXTRA_BYTES;i++){
+GC_size_map[i]=ROUNDED_UP_GRANULES(i);
+#ifndef _MSC_VER
+GC_ASSERT(GC_size_map[i] < TINY_FREELISTS);
+#endif
+}
+}
+#ifndef SMALL_CLEAR_SIZE
+#define SMALL_CLEAR_SIZE 256
+#endif
+#if defined(ALWAYS_SMALL_CLEAR_STACK)||defined(STACK_NOT_SCANNED)
+GC_API void*GC_CALL GC_clear_stack(void*arg)
+{
+#ifndef STACK_NOT_SCANNED
+word volatile dummy[SMALL_CLEAR_SIZE];
+BZERO(( void*)dummy,sizeof(dummy));
+#endif
+return arg;
+}
+#else
+#ifdef THREADS
+#define BIG_CLEAR_SIZE 2048
+#else
+STATIC word GC_stack_last_cleared=0;
+STATIC ptr_t GC_min_sp=NULL;
+STATIC ptr_t GC_high_water=NULL;
+STATIC word GC_bytes_allocd_at_reset=0;
+#define DEGRADE_RATE 50
+#endif
+#if defined(ASM_CLEAR_CODE)
+void*GC_clear_stack_inner(void*,ptr_t);
+#else
+void*GC_clear_stack_inner(void*arg,
+#if defined(__APPLE_CC__)&&!GC_CLANG_PREREQ(6,0)
+volatile
+#endif
+ptr_t limit)
+{
+#define CLEAR_SIZE 213
+volatile word dummy[CLEAR_SIZE];
+BZERO(( void*)dummy,sizeof(dummy));
+if ((word)GC_approx_sp()COOLER_THAN (word)limit){
+(void)GC_clear_stack_inner(arg,limit);
+}
+#if defined(CPPCHECK)
+GC_noop1(dummy[0]);
+#else
+GC_noop1(COVERT_DATAFLOW(dummy));
+#endif
+return(arg);
+}
+#endif
+#ifdef THREADS
+GC_ATTR_NO_SANITIZE_THREAD
+static unsigned next_random_no(void)
+{
+static unsigned random_no=0;
+return++random_no % 13;
+}
+#endif
+GC_API void*GC_CALL GC_clear_stack(void*arg)
+{
+ptr_t sp=GC_approx_sp();
+#ifdef THREADS
+word volatile dummy[SMALL_CLEAR_SIZE];
+#endif
+#define SLOP 400
+#define GC_SLOP 4000
+#define CLEAR_THRESHOLD 100000
+#ifdef THREADS
+if (next_random_no()==0){
+ptr_t limit=sp;
+MAKE_HOTTER(limit,BIG_CLEAR_SIZE*sizeof(word));
+limit=(ptr_t)((word)limit&~0xf);
+return GC_clear_stack_inner(arg,limit);
+}
+BZERO((void*)dummy,SMALL_CLEAR_SIZE*sizeof(word));
+#else
+if (GC_gc_no > GC_stack_last_cleared){
+if (GC_stack_last_cleared==0)
+GC_high_water=(ptr_t)GC_stackbottom;
+GC_min_sp=GC_high_water;
+GC_stack_last_cleared=GC_gc_no;
+GC_bytes_allocd_at_reset=GC_bytes_allocd;
+}
+MAKE_COOLER(GC_high_water,WORDS_TO_BYTES(DEGRADE_RATE)+GC_SLOP);
+if ((word)sp HOTTER_THAN (word)GC_high_water){
+GC_high_water=sp;
+}
+MAKE_HOTTER(GC_high_water,GC_SLOP);
+{
+ptr_t limit=GC_min_sp;
+MAKE_HOTTER(limit,SLOP);
+if ((word)sp COOLER_THAN (word)limit){
+limit=(ptr_t)((word)limit&~0xf);
+GC_min_sp=sp;
+return GC_clear_stack_inner(arg,limit);
+}
+}
+if (GC_bytes_allocd - GC_bytes_allocd_at_reset > CLEAR_THRESHOLD){
+GC_min_sp=sp;
+MAKE_HOTTER(GC_min_sp,CLEAR_THRESHOLD/4);
+if ((word)GC_min_sp HOTTER_THAN (word)GC_high_water)
+GC_min_sp=GC_high_water;
+GC_bytes_allocd_at_reset=GC_bytes_allocd;
+}
+#endif
+return arg;
+}
+#endif
+GC_API void*GC_CALL GC_base(void*p)
+{
+ptr_t r;
+struct hblk*h;
+bottom_index*bi;
+hdr*candidate_hdr;
+r=(ptr_t)p;
+if (!EXPECT(GC_is_initialized,TRUE))return 0;
+h=HBLKPTR(r);
+GET_BI(r,bi);
+candidate_hdr=HDR_FROM_BI(bi,r);
+if (candidate_hdr==0)return(0);
+while (IS_FORWARDING_ADDR_OR_NIL(candidate_hdr)){
+h=FORWARDED_ADDR(h,candidate_hdr);
+r=(ptr_t)h;
+candidate_hdr=HDR(h);
+}
+if (HBLK_IS_FREE(candidate_hdr))return(0);
+r=(ptr_t)((word)r&~(WORDS_TO_BYTES(1)- 1));
+{
+size_t offset=HBLKDISPL(r);
+word sz=candidate_hdr->hb_sz;
+size_t obj_displ=offset % sz;
+ptr_t limit;
+r-=obj_displ;
+limit=r+sz;
+if ((word)limit > (word)(h+1)&&sz<=HBLKSIZE){
+return(0);
+}
+if ((word)p>=(word)limit)return(0);
+}
+return((void*)r);
+}
+GC_API int GC_CALL GC_is_heap_ptr(const void*p)
+{
+bottom_index*bi;
+GC_ASSERT(GC_is_initialized);
+GET_BI(p,bi);
+return HDR_FROM_BI(bi,p)!=0;
+}
+GC_API size_t GC_CALL GC_size(const void*p)
+{
+hdr*hhdr=HDR(p);
+return (size_t)hhdr->hb_sz;
+}
+GC_API size_t GC_CALL GC_get_heap_size(void)
+{
+return (size_t)(GC_heapsize - GC_unmapped_bytes);
+}
+GC_API size_t GC_CALL GC_get_free_bytes(void)
+{
+return (size_t)(GC_large_free_bytes - GC_unmapped_bytes);
+}
+GC_API size_t GC_CALL GC_get_unmapped_bytes(void)
+{
+return (size_t)GC_unmapped_bytes;
+}
+GC_API size_t GC_CALL GC_get_bytes_since_gc(void)
+{
+return (size_t)GC_bytes_allocd;
+}
+GC_API size_t GC_CALL GC_get_total_bytes(void)
+{
+return (size_t)(GC_bytes_allocd+GC_bytes_allocd_before_gc);
+}
+#ifndef GC_GET_HEAP_USAGE_NOT_NEEDED
+GC_API size_t GC_CALL GC_get_size_map_at(int i)
+{
+if ((unsigned)i > MAXOBJBYTES)
+return GC_SIZE_MAX;
+return GRANULES_TO_BYTES(GC_size_map[i]);
+}
+GC_API void GC_CALL GC_get_heap_usage_safe(GC_word*pheap_size,
+GC_word*pfree_bytes,GC_word*punmapped_bytes,
+GC_word*pbytes_since_gc,GC_word*ptotal_bytes)
+{
+DCL_LOCK_STATE;
+LOCK();
+if (pheap_size!=NULL)
+*pheap_size=GC_heapsize - GC_unmapped_bytes;
+if (pfree_bytes!=NULL)
+*pfree_bytes=GC_large_free_bytes - GC_unmapped_bytes;
+if (punmapped_bytes!=NULL)
+*punmapped_bytes=GC_unmapped_bytes;
+if (pbytes_since_gc!=NULL)
+*pbytes_since_gc=GC_bytes_allocd;
+if (ptotal_bytes!=NULL)
+*ptotal_bytes=GC_bytes_allocd+GC_bytes_allocd_before_gc;
+UNLOCK();
+}
+GC_INNER word GC_reclaimed_bytes_before_gc=0;
+static void fill_prof_stats(struct GC_prof_stats_s*pstats)
+{
+pstats->heapsize_full=GC_heapsize;
+pstats->free_bytes_full=GC_large_free_bytes;
+pstats->unmapped_bytes=GC_unmapped_bytes;
+pstats->bytes_allocd_since_gc=GC_bytes_allocd;
+pstats->allocd_bytes_before_gc=GC_bytes_allocd_before_gc;
+pstats->non_gc_bytes=GC_non_gc_bytes;
+pstats->gc_no=GC_gc_no;
+#ifdef PARALLEL_MARK
+pstats->markers_m1=(word)((signed_word)GC_markers_m1);
+#else
+pstats->markers_m1=0;
+#endif
+pstats->bytes_reclaimed_since_gc=GC_bytes_found > 0?
+(word)GC_bytes_found:0;
+pstats->reclaimed_bytes_before_gc=GC_reclaimed_bytes_before_gc;
+pstats->expl_freed_bytes_since_gc=GC_bytes_freed;
+}
+#include <string.h>
+GC_API size_t GC_CALL GC_get_prof_stats(struct GC_prof_stats_s*pstats,
+size_t stats_sz)
+{
+struct GC_prof_stats_s stats;
+DCL_LOCK_STATE;
+LOCK();
+fill_prof_stats(stats_sz>=sizeof(stats)?pstats:&stats);
+UNLOCK();
+if (stats_sz==sizeof(stats)){
+return sizeof(stats);
+} else if (stats_sz > sizeof(stats)){
+memset((char*)pstats+sizeof(stats),0xff,stats_sz - sizeof(stats));
+return sizeof(stats);
+} else {
+if (EXPECT(stats_sz > 0,TRUE))
+BCOPY(&stats,pstats,stats_sz);
+return stats_sz;
+}
+}
+#ifdef THREADS
+GC_API size_t GC_CALL GC_get_prof_stats_unsafe(
+struct GC_prof_stats_s*pstats,
+size_t stats_sz)
+{
+struct GC_prof_stats_s stats;
+if (stats_sz>=sizeof(stats)){
+fill_prof_stats(pstats);
+if (stats_sz > sizeof(stats))
+memset((char*)pstats+sizeof(stats),0xff,
+stats_sz - sizeof(stats));
+return sizeof(stats);
+} else {
+if (EXPECT(stats_sz > 0,TRUE)){
+fill_prof_stats(&stats);
+BCOPY(&stats,pstats,stats_sz);
+}
+return stats_sz;
+}
+}
+#endif
+#endif
+#if defined(GC_DARWIN_THREADS)||defined(GC_OPENBSD_UTHREADS)||defined(GC_WIN32_THREADS)||(defined(NACL)&&defined(THREADS))
+GC_API void GC_CALL GC_set_suspend_signal(int sig GC_ATTR_UNUSED)
+{
+}
+GC_API void GC_CALL GC_set_thr_restart_signal(int sig GC_ATTR_UNUSED)
+{
+}
+GC_API int GC_CALL GC_get_suspend_signal(void)
+{
+return -1;
+}
+GC_API int GC_CALL GC_get_thr_restart_signal(void)
+{
+return -1;
+}
+#endif
+#if!defined(_MAX_PATH)&&(defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32))
+#define _MAX_PATH MAX_PATH
+#endif
+#ifdef GC_READ_ENV_FILE
+STATIC char*GC_envfile_content=NULL;
+STATIC unsigned GC_envfile_length=0;
+#ifndef GC_ENVFILE_MAXLEN
+#define GC_ENVFILE_MAXLEN 0x4000
+#endif
+#define GC_ENV_FILE_EXT ".gc.env"
+STATIC void GC_envfile_init(void)
+{
+#if defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32)
+HANDLE hFile;
+char*content;
+unsigned ofs;
+unsigned len;
+DWORD nBytesRead;
+TCHAR path[_MAX_PATH+0x10];
+len=(unsigned)GetModuleFileName(NULL,path,
+_MAX_PATH+1);
+if (len > 4&&path[len - 4]==(TCHAR)'.'){
+len-=4;
+}
+BCOPY(TEXT(GC_ENV_FILE_EXT),&path[len],sizeof(TEXT(GC_ENV_FILE_EXT)));
+hFile=CreateFile(path,GENERIC_READ,
+FILE_SHARE_READ|FILE_SHARE_WRITE,
+NULL,OPEN_EXISTING,
+FILE_ATTRIBUTE_NORMAL,NULL);
+if (hFile==INVALID_HANDLE_VALUE)
+return;
+len=(unsigned)GetFileSize(hFile,NULL);
+if (len<=1||len>=GC_ENVFILE_MAXLEN){
+CloseHandle(hFile);
+return;
+}
+GC_ASSERT(GC_page_size!=0);
+content=(char*)GET_MEM(ROUNDUP_PAGESIZE_IF_MMAP((size_t)len+1));
+if (content==NULL){
+CloseHandle(hFile);
+return;
+}
+ofs=0;
+nBytesRead=(DWORD)-1L;
+while (ReadFile(hFile,content+ofs,len - ofs+1,&nBytesRead,
+NULL)&&nBytesRead!=0){
+if ((ofs+=nBytesRead)> len)
+break;
+}
+CloseHandle(hFile);
+if (ofs!=len||nBytesRead!=0)
+return;
+content[ofs]='\0';
+while (ofs--> 0){
+if (content[ofs]=='\r'||content[ofs]=='\n')
+content[ofs]='\0';
+}
+GC_ASSERT(NULL==GC_envfile_content);
+GC_envfile_length=len+1;
+GC_envfile_content=content;
+#endif
+}
+GC_INNER char*GC_envfile_getenv(const char*name)
+{
+char*p;
+char*end_of_content;
+unsigned namelen;
+#ifndef NO_GETENV
+p=getenv(name);
+if (p!=NULL)
+return*p!='\0'?p:NULL;
+#endif
+p=GC_envfile_content;
+if (p==NULL)
+return NULL;
+namelen=strlen(name);
+if (namelen==0)
+return NULL;
+for (end_of_content=p+GC_envfile_length;
+p!=end_of_content;p+=strlen(p)+1){
+if (strncmp(p,name,namelen)==0&&*(p+=namelen)=='='){
+p++;
+return*p!='\0'?p:NULL;
+}
+}
+return NULL;
+}
+#endif
+GC_INNER GC_bool GC_is_initialized=FALSE;
+GC_API int GC_CALL GC_is_init_called(void)
+{
+return GC_is_initialized;
+}
+#if defined(GC_WIN32_THREADS)&&((defined(MSWIN32)&&!defined(CONSOLE_LOG))||defined(MSWINCE))
+GC_INNER CRITICAL_SECTION GC_write_cs;
+#endif
+#ifndef DONT_USE_ATEXIT
+#if!defined(PCR)&&!defined(SMALL_CONFIG)
+static GC_bool skip_gc_atexit=FALSE;
+#else
+#define skip_gc_atexit FALSE
+#endif
+STATIC void GC_exit_check(void)
+{
+if (GC_find_leak&&!skip_gc_atexit){
+#ifdef THREADS
+GC_in_thread_creation=TRUE;
+GC_gcollect();
+GC_in_thread_creation=FALSE;
+#else
+GC_gcollect();
+#endif
+}
+}
+#endif
+#if defined(UNIX_LIKE)&&!defined(NO_DEBUGGING)
+static void looping_handler(int sig)
+{
+GC_err_printf("Caught signal %d:looping in handler\n",sig);
+for (;;){
+}
+}
+static GC_bool installed_looping_handler=FALSE;
+static void maybe_install_looping_handler(void)
+{
+if (!installed_looping_handler&&0!=GETENV("GC_LOOP_ON_ABORT")){
+GC_set_and_save_fault_handler(looping_handler);
+installed_looping_handler=TRUE;
+}
+}
+#else
+#define maybe_install_looping_handler()
+#endif
+#define GC_DEFAULT_STDOUT_FD 1
+#define GC_DEFAULT_STDERR_FD 2
+#if!defined(OS2)&&!defined(MACOS)&&!defined(GC_ANDROID_LOG)&&!defined(NN_PLATFORM_CTR)&&!defined(NINTENDO_SWITCH)&&(!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;
+#ifndef MSWIN32
+GC_API void GC_CALL GC_set_log_fd(int fd)
+{
+GC_log=fd;
+}
+#endif
+#endif
+#ifdef MSGBOX_ON_ERROR
+STATIC void GC_win32_MessageBoxA(const char*msg,const char*caption,
+unsigned flags)
+{
+#ifndef DONT_USE_USER32_DLL
+(void)MessageBoxA(NULL,msg,caption,flags);
+#else
+HINSTANCE hU32=LoadLibrary(TEXT("user32.dll"));
+if (hU32){
+FARPROC pfn=GetProcAddress(hU32,"MessageBoxA");
+if (pfn)
+(void)(*(int (WINAPI*)(HWND,LPCSTR,LPCSTR,UINT))(word)pfn)(
+NULL,msg,caption,flags);
+(void)FreeLibrary(hU32);
+}
+#endif
+}
+#endif
+#if defined(THREADS)&&defined(UNIX_LIKE)&&!defined(NO_GETCONTEXT)
+static void callee_saves_pushed_dummy_fn(ptr_t data GC_ATTR_UNUSED,
+void*context GC_ATTR_UNUSED){}
+#endif
+#ifndef SMALL_CONFIG
+#ifdef MANUAL_VDB
+static GC_bool manual_vdb_allowed=TRUE;
+#else
+static GC_bool manual_vdb_allowed=FALSE;
+#endif
+GC_API void GC_CALL GC_set_manual_vdb_allowed(int value)
+{
+manual_vdb_allowed=(GC_bool)value;
+}
+GC_API int GC_CALL GC_get_manual_vdb_allowed(void)
+{
+return (int)manual_vdb_allowed;
+}
+#endif
+STATIC word GC_parse_mem_size_arg(const char*str)
+{
+word result=0;
+if (*str!='\0'){
+char*endptr;
+char ch;
+result=(word)STRTOULL(str,&endptr,10);
+ch=*endptr;
+if (ch!='\0'){
+if (*(endptr+1)!='\0')
+return 0;
+switch (ch){
+case 'K':
+case 'k':
+result<<=10;
+break;
+case 'M':
+case 'm':
+result<<=20;
+break;
+case 'G':
+case 'g':
+result<<=30;
+break;
+default:
+result=0;
+}
+}
+}
+return result;
+}
+#define GC_LOG_STD_NAME "gc.log"
+GC_API void GC_CALL GC_init(void)
+{
+word initial_heap_sz;
+IF_CANCEL(int cancel_state;)
+#if defined(GC_ASSERTIONS)&&defined(GC_ALWAYS_MULTITHREADED)
+DCL_LOCK_STATE;
+#endif
+if (EXPECT(GC_is_initialized,TRUE))return;
+#ifdef REDIRECT_MALLOC
+{
+static GC_bool init_started=FALSE;
+if (init_started)
+ABORT("Redirected malloc()called during GC init");
+init_started=TRUE;
+}
+#endif
+#if defined(GC_INITIAL_HEAP_SIZE)&&!defined(CPPCHECK)
+initial_heap_sz=GC_INITIAL_HEAP_SIZE;
+#else
+initial_heap_sz=MINHINCR*HBLKSIZE;
+#endif
+DISABLE_CANCEL(cancel_state);
+#ifdef THREADS
+#ifndef GC_ALWAYS_MULTITHREADED
+GC_ASSERT(!GC_need_to_lock);
+#endif
+#ifdef SN_TARGET_PS3
+{
+pthread_mutexattr_t mattr;
+if (0!=pthread_mutexattr_init(&mattr)){
+ABORT("pthread_mutexattr_init failed");
+}
+if (0!=pthread_mutex_init(&GC_allocate_ml,&mattr)){
+ABORT("pthread_mutex_init failed");
+}
+(void)pthread_mutexattr_destroy(&mattr);
+}
+#endif
+#endif
+#if defined(GC_WIN32_THREADS)&&!defined(GC_PTHREADS)
+#ifndef SPIN_COUNT
+#define SPIN_COUNT 4000
+#endif
+#ifdef MSWINRT_FLAVOR
+InitializeCriticalSectionAndSpinCount(&GC_allocate_ml,SPIN_COUNT);
+#else
+{
+#ifndef MSWINCE
+FARPROC pfn=0;
+HMODULE hK32=GetModuleHandle(TEXT("kernel32.dll"));
+if (hK32)
+pfn=GetProcAddress(hK32,
+"InitializeCriticalSectionAndSpinCount");
+if (pfn){
+(*(BOOL (WINAPI*)(LPCRITICAL_SECTION,DWORD))(word)pfn)(
+&GC_allocate_ml,SPIN_COUNT);
+} else
+#endif
+InitializeCriticalSection(&GC_allocate_ml);
+}
+#endif
+#endif
+#if defined(GC_WIN32_THREADS)&&((defined(MSWIN32)&&!defined(CONSOLE_LOG))||defined(MSWINCE))
+InitializeCriticalSection(&GC_write_cs);
+#endif
+GC_setpagesize();
+#ifdef MSWIN32
+GC_init_win32();
+#endif
+#ifdef GC_READ_ENV_FILE
+GC_envfile_init();
+#endif
+#if!defined(NO_CLOCK)||!defined(SMALL_CONFIG)
+#ifdef GC_PRINT_VERBOSE_STATS
+GC_print_stats=VERBOSE;
+#else
+if (0!=GETENV("GC_PRINT_VERBOSE_STATS")){
+GC_print_stats=VERBOSE;
+} else if (0!=GETENV("GC_PRINT_STATS")){
+GC_print_stats=1;
+}
+#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"));
+#ifdef GC_LOG_TO_FILE_ALWAYS
+if (NULL==file_name)
+file_name=GC_LOG_STD_NAME;
+#else
+if (0!=file_name)
+#endif
+{
+#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 {
+char*str;
+GC_log=log_d;
+str=GETENV("GC_ONLY_LOG_TO_FILE");
+#ifdef GC_ONLY_LOG_TO_FILE
+if (str!=NULL&&*str=='0'&&*(str+1)=='\0')
+#else
+if (str==NULL||(*str=='0'&&*(str+1)=='\0'))
+#endif
+{
+GC_stdout=log_d;
+GC_stderr=log_d;
+}
+}
+}
+}
+#endif
+#if!defined(NO_DEBUGGING)&&!defined(GC_DUMP_REGULARLY)
+if (0!=GETENV("GC_DUMP_REGULARLY")){
+GC_dump_regularly=TRUE;
+}
+#endif
+#ifdef KEEP_BACK_PTRS
+{
+char*backtraces_string=GETENV("GC_BACKTRACES");
+if (0!=backtraces_string){
+GC_backtraces=atol(backtraces_string);
+if (backtraces_string[0]=='\0')GC_backtraces=1;
+}
+}
+#endif
+if (0!=GETENV("GC_FIND_LEAK")){
+GC_find_leak=1;
+}
+#ifndef SHORT_DBG_HDRS
+if (0!=GETENV("GC_FINDLEAK_DELAY_FREE")){
+GC_findleak_delay_free=TRUE;
+}
+#endif
+if (0!=GETENV("GC_ALL_INTERIOR_POINTERS")){
+GC_all_interior_pointers=1;
+}
+if (0!=GETENV("GC_DONT_GC")){
+GC_dont_gc=1;
+}
+if (0!=GETENV("GC_PRINT_BACK_HEIGHT")){
+GC_print_back_height=TRUE;
+}
+if (0!=GETENV("GC_NO_BLACKLIST_WARNING")){
+GC_large_alloc_warn_interval=LONG_MAX;
+}
+{
+char*addr_string=GETENV("GC_TRACE");
+if (0!=addr_string){
+#ifndef ENABLE_TRACE
+WARN("Tracing not enabled:Ignoring GC_TRACE value\n",0);
+#else
+word addr=(word)STRTOULL(addr_string,NULL,16);
+if (addr < 0x1000)
+WARN("Unlikely trace address:%p\n",(void*)addr);
+GC_trace_addr=(ptr_t)addr;
+#endif
+}
+}
+#ifdef GC_COLLECT_AT_MALLOC
+{
+char*string=GETENV("GC_COLLECT_AT_MALLOC");
+if (0!=string){
+size_t min_lb=(size_t)STRTOULL(string,NULL,10);
+if (min_lb > 0)
+GC_dbg_collect_at_malloc_min_lb=min_lb;
+}
+}
+#endif
+#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 > 0){
+GC_time_limit=time_limit;
+}
+}
+}
+#endif
+#ifndef SMALL_CONFIG
+{
+char*full_freq_string=GETENV("GC_FULL_FREQUENCY");
+if (full_freq_string!=NULL){
+int full_freq=atoi(full_freq_string);
+if (full_freq > 0)
+GC_full_freq=full_freq;
+}
+}
+#endif
+{
+char*interval_string=GETENV("GC_LARGE_ALLOC_WARN_INTERVAL");
+if (0!=interval_string){
+long interval=atol(interval_string);
+if (interval<=0){
+WARN("GC_LARGE_ALLOC_WARN_INTERVAL environment variable has "
+"bad value:Ignoring\n",0);
+} else {
+GC_large_alloc_warn_interval=interval;
+}
+}
+}
+{
+char*space_divisor_string=GETENV("GC_FREE_SPACE_DIVISOR");
+if (space_divisor_string!=NULL){
+int space_divisor=atoi(space_divisor_string);
+if (space_divisor > 0)
+GC_free_space_divisor=(unsigned)space_divisor;
+}
+}
+#ifdef USE_MUNMAP
+{
+char*string=GETENV("GC_UNMAP_THRESHOLD");
+if (string!=NULL){
+if (*string=='0'&&*(string+1)=='\0'){
+GC_unmap_threshold=0;
+} else {
+int unmap_threshold=atoi(string);
+if (unmap_threshold > 0)
+GC_unmap_threshold=unmap_threshold;
+}
+}
+}
+{
+char*string=GETENV("GC_FORCE_UNMAP_ON_GCOLLECT");
+if (string!=NULL){
+if (*string=='0'&&*(string+1)=='\0'){
+GC_force_unmap_on_gcollect=FALSE;
+} else {
+GC_force_unmap_on_gcollect=TRUE;
+}
+}
+}
+{
+char*string=GETENV("GC_USE_ENTIRE_HEAP");
+if (string!=NULL){
+if (*string=='0'&&*(string+1)=='\0'){
+GC_use_entire_heap=FALSE;
+} else {
+GC_use_entire_heap=TRUE;
+}
+}
+}
+#endif
+#if!defined(NO_DEBUGGING)&&!defined(NO_CLOCK)
+GET_TIME(GC_init_time);
+#endif
+maybe_install_looping_handler();
+#if ALIGNMENT > GC_DS_TAGS
+if (EXTRA_BYTES!=0)
+GC_obj_kinds[NORMAL].ok_descriptor=(word)(-ALIGNMENT)|GC_DS_LENGTH;
+#endif
+GC_exclude_static_roots_inner(beginGC_arrays,endGC_arrays);
+GC_exclude_static_roots_inner(beginGC_obj_kinds,endGC_obj_kinds);
+#ifdef SEPARATE_GLOBALS
+GC_exclude_static_roots_inner(beginGC_objfreelist,endGC_objfreelist);
+GC_exclude_static_roots_inner(beginGC_aobjfreelist,endGC_aobjfreelist);
+#endif
+#if defined(USE_PROC_FOR_LIBRARIES)&&defined(GC_LINUX_THREADS)
+WARN("USE_PROC_FOR_LIBRARIES+GC_LINUX_THREADS performs poorly.\n",0);
+#endif
+#if defined(SEARCH_FOR_DATA_START)
+GC_init_linux_data_start();
+#endif
+#if defined(NETBSD)&&defined(__ELF__)
+GC_init_netbsd_elf();
+#endif
+#if!defined(THREADS)||defined(GC_PTHREADS)||defined(NN_PLATFORM_CTR)||defined(NINTENDO_SWITCH)||defined(GC_WIN32_THREADS)||defined(GC_SOLARIS_THREADS)
+if (GC_stackbottom==0){
+GC_stackbottom=GC_get_main_stack_base();
+#if (defined(LINUX)||defined(HPUX))&&defined(IA64)
+GC_register_stackbottom=GC_get_register_stack_base();
+#endif
+} else {
+#if (defined(LINUX)||defined(HPUX))&&defined(IA64)
+if (GC_register_stackbottom==0){
+WARN("GC_register_stackbottom should be set with GC_stackbottom\n",0);
+GC_register_stackbottom=GC_get_register_stack_base();
+}
+#endif
+}
+#endif
+#if!defined(CPPCHECK)
+GC_STATIC_ASSERT(sizeof(ptr_t)==sizeof(word));
+GC_STATIC_ASSERT(sizeof(signed_word)==sizeof(word));
+#if!defined(_AUX_SOURCE)||defined(__GNUC__)
+GC_STATIC_ASSERT((word)(-1)> (word)0);
+#endif
+GC_STATIC_ASSERT((signed_word)(-1)< (signed_word)0);
+#endif
+GC_STATIC_ASSERT(sizeof (struct hblk)==HBLKSIZE);
+#ifndef THREADS
+GC_ASSERT(!((word)GC_stackbottom HOTTER_THAN (word)GC_approx_sp()));
+#endif
+#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)
+#else
+if (manual_vdb_allowed){
+GC_manual_vdb=TRUE;
+GC_incremental=TRUE;
+} else
+#endif
+{
+GC_incremental=GC_dirty_init();
+GC_ASSERT(GC_bytes_allocd==0);
+}
+}
+#endif
+if (GC_REGISTER_MAIN_STATIC_DATA())GC_register_data_segments();
+GC_init_headers();
+GC_bl_init();
+GC_mark_init();
+{
+char*sz_str=GETENV("GC_INITIAL_HEAP_SIZE");
+if (sz_str!=NULL){
+initial_heap_sz=GC_parse_mem_size_arg(sz_str);
+if (initial_heap_sz<=MINHINCR*HBLKSIZE){
+WARN("Bad initial heap size %s - ignoring it.\n",sz_str);
+}
+}
+}
+{
+char*sz_str=GETENV("GC_MAXIMUM_HEAP_SIZE");
+if (sz_str!=NULL){
+word max_heap_sz=GC_parse_mem_size_arg(sz_str);
+if (max_heap_sz < initial_heap_sz){
+WARN("Bad maximum heap size %s - ignoring it.\n",sz_str);
+}
+if (0==GC_max_retries)GC_max_retries=2;
+GC_set_max_heap_size(max_heap_sz);
+}
+}
+#if defined(GC_ASSERTIONS)&&defined(GC_ALWAYS_MULTITHREADED)
+LOCK();
+#endif
+if (!GC_expand_hp_inner(divHBLKSZ(initial_heap_sz))){
+GC_err_printf("Can't start up:not enough memory\n");
+EXIT();
+} else {
+GC_requested_heapsize+=initial_heap_sz;
+}
+if (GC_all_interior_pointers)
+GC_initialize_offsets();
+GC_register_displacement_inner(0L);
+#if defined(GC_LINUX_THREADS)&&defined(REDIRECT_MALLOC)
+if (!GC_all_interior_pointers){
+GC_register_displacement_inner(sizeof(void*));
+}
+#endif
+GC_init_size_map();
+#ifdef PCR
+if (PCR_IL_Lock(PCR_Bool_false,PCR_allSigsBlocked,PCR_waitForever)
+!=PCR_ERes_okay){
+ABORT("Can't lock load state");
+} else if (PCR_IL_Unlock()!=PCR_ERes_okay){
+ABORT("Can't unlock load state");
+}
+PCR_IL_Unlock();
+GC_pcr_install();
+#endif
+GC_is_initialized=TRUE;
+#if defined(GC_PTHREADS)||defined(GC_WIN32_THREADS)
+GC_thr_init();
+#ifdef PARALLEL_MARK
+#if defined(GC_ASSERTIONS)&&defined(GC_ALWAYS_MULTITHREADED)
+UNLOCK();
+#endif
+GC_start_mark_threads_inner();
+#if defined(GC_ASSERTIONS)&&defined(GC_ALWAYS_MULTITHREADED)
+LOCK();
+#endif
+#endif
+#endif
+COND_DUMP;
+if (!GC_dont_precollect||GC_incremental){
+GC_gcollect_inner();
+}
+#if defined(GC_ASSERTIONS)&&defined(GC_ALWAYS_MULTITHREADED)
+UNLOCK();
+#endif
+#if defined(THREADS)&&defined(UNIX_LIKE)&&!defined(NO_GETCONTEXT)
+if (GC_dont_gc||GC_dont_precollect)
+GC_with_callee_saves_pushed(callee_saves_pushed_dummy_fn,NULL);
+#endif
+#ifndef DONT_USE_ATEXIT
+if (GC_find_leak){
+atexit(GC_exit_check);
+}
+#endif
+#if defined(PARALLEL_MARK)||defined(THREAD_LOCAL_ALLOC)||(defined(GC_ALWAYS_MULTITHREADED)&&defined(GC_WIN32_THREADS)&&!defined(GC_NO_THREADS_DISCOVERY))
+GC_init_parallel();
+#endif
+#if defined(DYNAMIC_LOADING)&&defined(DARWIN)
+GC_init_dyld();
+#endif
+RESTORE_CANCEL(cancel_state);
+}
+GC_API void GC_CALL GC_enable_incremental(void)
+{
+#if!defined(GC_DISABLE_INCREMENTAL)&&!defined(KEEP_BACK_PTRS)
+DCL_LOCK_STATE;
+if (!GC_find_leak&&0==GETENV("GC_DISABLE_INCREMENTAL")){
+LOCK();
+if (!GC_incremental){
+GC_setpagesize();
+maybe_install_looping_handler();
+if (!GC_is_initialized){
+UNLOCK();
+GC_incremental=TRUE;
+GC_init();
+LOCK();
+} else {
+#if!defined(BASE_ATOMIC_OPS_EMULATED)&&!defined(CHECKSUMS)&&!defined(REDIRECT_MALLOC)&&!defined(REDIRECT_MALLOC_IN_HEADER)&&!defined(SMALL_CONFIG)
+if (manual_vdb_allowed){
+GC_manual_vdb=TRUE;
+GC_incremental=TRUE;
+} else
+#endif
+{
+GC_incremental=GC_dirty_init();
+}
+}
+if (GC_incremental&&!GC_dont_gc){
+IF_CANCEL(int cancel_state;)
+DISABLE_CANCEL(cancel_state);
+if (GC_bytes_allocd > 0){
+GC_gcollect_inner();
+}
+GC_read_dirty(FALSE);
+RESTORE_CANCEL(cancel_state);
+}
+}
+UNLOCK();
+return;
+}
+#endif
+GC_init();
+}
+#if defined(THREADS)
+GC_API void GC_CALL GC_start_mark_threads(void)
+{
+#if defined(PARALLEL_MARK)&&defined(CAN_HANDLE_FORK)&&!defined(THREAD_SANITIZER)
+IF_CANCEL(int cancel_state;)
+DISABLE_CANCEL(cancel_state);
+GC_start_mark_threads_inner();
+RESTORE_CANCEL(cancel_state);
+#else
+GC_ASSERT(I_DONT_HOLD_LOCK());
+#endif
+}
+#endif
+GC_API void GC_CALL GC_deinit(void)
+{
+if (GC_is_initialized){
+GC_is_initialized=FALSE;
+#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(CONSOLE_LOG))||defined(MSWINCE)
+#if defined(_MSC_VER)&&defined(_DEBUG)&&!defined(MSWINCE)
+#include <crtdbg.h>
+#endif
+STATIC HANDLE GC_log=0;
+#ifdef THREADS
+#if defined(PARALLEL_MARK)&&!defined(GC_ALWAYS_MULTITHREADED)
+#define IF_NEED_TO_LOCK(x)if (GC_parallel||GC_need_to_lock)x
+#else
+#define IF_NEED_TO_LOCK(x)if (GC_need_to_lock)x
+#endif
+#else
+#define IF_NEED_TO_LOCK(x)
+#endif
+#ifdef MSWINRT_FLAVOR
+#include <windows.storage.h>
+DECLSPEC_IMPORT HRESULT WINAPI RoGetActivationFactory(
+HSTRING activatableClassId,
+REFIID iid,void**factory);
+static GC_bool getWinRTLogPath(wchar_t*buf,size_t bufLen)
+{
+static const GUID kIID_IApplicationDataStatics={
+0x5612147B,0xE843,0x45E3,
+0x94,0xD8,0x06,0x16,0x9E,0x3C,0x8E,0x17
+};
+static const GUID kIID_IStorageItem={
+0x4207A996,0xCA2F,0x42F7,
+0xBD,0xE8,0x8B,0x10,0x45,0x7A,0x7F,0x30
+};
+GC_bool result=FALSE;
+HSTRING_HEADER appDataClassNameHeader;
+HSTRING appDataClassName;
+__x_ABI_CWindows_CStorage_CIApplicationDataStatics*appDataStatics=0;
+GC_ASSERT(bufLen > 0);
+if (SUCCEEDED(WindowsCreateStringReference(
+RuntimeClass_Windows_Storage_ApplicationData,
+(sizeof(RuntimeClass_Windows_Storage_ApplicationData)-1)
+/sizeof(wchar_t),
+&appDataClassNameHeader,&appDataClassName))
+&&SUCCEEDED(RoGetActivationFactory(appDataClassName,
+&kIID_IApplicationDataStatics,
+&appDataStatics))){
+__x_ABI_CWindows_CStorage_CIApplicationData*appData=NULL;
+__x_ABI_CWindows_CStorage_CIStorageFolder*tempFolder=NULL;
+__x_ABI_CWindows_CStorage_CIStorageItem*tempFolderItem=NULL;
+HSTRING tempPath=NULL;
+if (SUCCEEDED(appDataStatics->lpVtbl->get_Current(appDataStatics,
+&appData))
+&&SUCCEEDED(appData->lpVtbl->get_TemporaryFolder(appData,
+&tempFolder))
+&&SUCCEEDED(tempFolder->lpVtbl->QueryInterface(tempFolder,
+&kIID_IStorageItem,
+&tempFolderItem))
+&&SUCCEEDED(tempFolderItem->lpVtbl->get_Path(tempFolderItem,
+&tempPath))){
+UINT32 tempPathLen;
+const wchar_t*tempPathBuf=
+WindowsGetStringRawBuffer(tempPath,&tempPathLen);
+buf[0]='\0';
+if (wcsncat_s(buf,bufLen,tempPathBuf,tempPathLen)==0
+&&wcscat_s(buf,bufLen,L"\\")==0
+&&wcscat_s(buf,bufLen,TEXT(GC_LOG_STD_NAME))==0)
+result=TRUE;
+WindowsDeleteString(tempPath);
+}
+if (tempFolderItem!=NULL)
+tempFolderItem->lpVtbl->Release(tempFolderItem);
+if (tempFolder!=NULL)
+tempFolder->lpVtbl->Release(tempFolder);
+if (appData!=NULL)
+appData->lpVtbl->Release(appData);
+appDataStatics->lpVtbl->Release(appDataStatics);
+}
+return result;
+}
+#endif
+STATIC HANDLE GC_CreateLogFile(void)
+{
+HANDLE hFile;
+#ifdef MSWINRT_FLAVOR
+TCHAR pathBuf[_MAX_PATH+0x10];
+hFile=INVALID_HANDLE_VALUE;
+if (getWinRTLogPath(pathBuf,_MAX_PATH+1)){
+CREATEFILE2_EXTENDED_PARAMETERS extParams;
+BZERO(&extParams,sizeof(extParams));
+extParams.dwSize=sizeof(extParams);
+extParams.dwFileAttributes=FILE_ATTRIBUTE_NORMAL;
+extParams.dwFileFlags=GC_print_stats==VERBOSE?0
+:FILE_FLAG_WRITE_THROUGH;
+hFile=CreateFile2(pathBuf,GENERIC_WRITE,FILE_SHARE_READ,
+CREATE_ALWAYS,&extParams);
+}
+#else
+TCHAR*logPath;
+#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];
+logPath=pathBuf;
+#endif
+#ifndef NO_GETENV_WIN32
+if (GetEnvironmentVariable(TEXT("GC_LOG_FILE"),pathBuf,
+_MAX_PATH+1)- 1U < (DWORD)_MAX_PATH){
+appendToFile=TRUE;
+} else
+#endif
+{
+#ifdef OLD_WIN32_LOG_FILE
+logPath=TEXT(GC_LOG_STD_NAME);
+#else
+int len=(int)GetModuleFileName(NULL,pathBuf,
+_MAX_PATH+1);
+if (len > 4&&pathBuf[len - 4]==(TCHAR)'.'){
+len-=4;
+}
+BCOPY(TEXT(".")TEXT(GC_LOG_STD_NAME),&pathBuf[len],
+sizeof(TEXT(".")TEXT(GC_LOG_STD_NAME)));
+#endif
+}
+hFile=CreateFile(logPath,GENERIC_WRITE,FILE_SHARE_READ,
+NULL,
+appendToFile?OPEN_ALWAYS:CREATE_ALWAYS,
+GC_print_stats==VERBOSE?FILE_ATTRIBUTE_NORMAL:
+FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
+NULL);
+#ifndef NO_GETENV_WIN32
+if (appendToFile&&hFile!=INVALID_HANDLE_VALUE){
+LONG posHigh=0;
+(void)SetFilePointer(hFile,0,&posHigh,FILE_END);
+}
+#endif
+#undef appendToFile
+#endif
+return hFile;
+}
+STATIC int GC_write(const char*buf,size_t len)
+{
+BOOL res;
+DWORD written;
+#if defined(THREADS)&&defined(GC_ASSERTIONS)
+static GC_bool inside_write=FALSE;
+if (inside_write)
+return -1;
+#endif
+if (len==0)
+return 0;
+IF_NEED_TO_LOCK(EnterCriticalSection(&GC_write_cs));
+#if defined(THREADS)&&defined(GC_ASSERTIONS)
+if (GC_write_disabled){
+inside_write=TRUE;
+ABORT("Assertion failure:GC_write called with write_disabled");
+}
+#endif
+if (GC_log==0){
+GC_log=GC_CreateLogFile();
+}
+if (GC_log==INVALID_HANDLE_VALUE){
+IF_NEED_TO_LOCK(LeaveCriticalSection(&GC_write_cs));
+#ifdef NO_DEBUGGING
+return 0;
+#else
+return -1;
+#endif
+}
+res=WriteFile(GC_log,buf,(DWORD)len,&written,NULL);
+#if defined(_MSC_VER)&&defined(_DEBUG)&&!defined(NO_CRT)
+#ifdef MSWINCE
+{
+WCHAR wbuf[1024];
+wbuf[MultiByteToWideChar(CP_ACP,0,
+buf,len,wbuf,
+sizeof(wbuf)/sizeof(wbuf[0])- 1)]=0;
+OutputDebugStringW(wbuf);
+}
+#else
+_CrtDbgReport(_CRT_WARN,NULL,0,NULL,"%.*s",len,buf);
+#endif
+#endif
+IF_NEED_TO_LOCK(LeaveCriticalSection(&GC_write_cs));
+return res?(int)written:-1;
+}
+#define WRITE(f,buf,len)GC_write(buf,len)
+#elif defined(OS2)||defined(MACOS)
+STATIC FILE*GC_stdout=NULL;
+STATIC FILE*GC_stderr=NULL;
+STATIC FILE*GC_log=NULL;
+STATIC void GC_set_files(void)
+{
+if (GC_stdout==NULL){
+GC_stdout=stdout;
+}
+if (GC_stderr==NULL){
+GC_stderr=stderr;
+}
+if (GC_log==NULL){
+GC_log=stderr;
+}
+}
+GC_INLINE int GC_write(FILE*f,const char*buf,size_t len)
+{
+int res=fwrite(buf,1,len,f);
+fflush(f);
+return res;
+}
+#define WRITE(f,buf,len)(GC_set_files(),GC_write(f,buf,len))
+#elif defined(GC_ANDROID_LOG)
+#include <android/log.h>
+#ifndef GC_ANDROID_LOG_TAG
+#define GC_ANDROID_LOG_TAG "BDWGC"
+#endif
+#define GC_stdout ANDROID_LOG_DEBUG
+#define GC_stderr ANDROID_LOG_ERROR
+#define GC_log GC_stdout
+#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)
+#else
+#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
+STATIC int GC_write(int fd,const char*buf,size_t len)
+{
+#if defined(ECOS)||defined(SN_TARGET_ORBIS)||defined(SN_TARGET_PSP2)||defined(NOSYS)
+#ifdef ECOS
+#else
+#endif
+return len;
+#else
+int bytes_written=0;
+IF_CANCEL(int cancel_state;)
+DISABLE_CANCEL(cancel_state);
+while ((unsigned)bytes_written < len){
+#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)
+continue;
+RESTORE_CANCEL(cancel_state);
+return(result);
+}
+bytes_written+=result;
+}
+RESTORE_CANCEL(cancel_state);
+return(bytes_written);
+#endif
+}
+#define WRITE(f,buf,len)GC_write(f,buf,len)
+#endif
+#define BUFSZ 1024
+#if defined(DJGPP)||defined(__STRICT_ANSI__)
+#define GC_VSNPRINTF(buf,bufsz,format,args)vsprintf(buf,format,args)
+#elif defined(_MSC_VER)
+#ifdef MSWINCE
+#define GC_VSNPRINTF StringCchVPrintfA
+#else
+#define GC_VSNPRINTF _vsnprintf
+#endif
+#else
+#define GC_VSNPRINTF vsnprintf
+#endif
+#define GC_PRINTF_FILLBUF(buf,format)do { va_list args;va_start(args,format);(buf)[sizeof(buf)- 1]=0x15;(void)GC_VSNPRINTF(buf,sizeof(buf)- 1,format,args);va_end(args);if ((buf)[sizeof(buf)- 1]!=0x15)ABORT("GC_printf clobbered stack");} while (0)
+void GC_printf(const char*format,...)
+{
+if (!GC_quiet){
+char buf[BUFSZ+1];
+GC_PRINTF_FILLBUF(buf,format);
+#ifdef NACL
+(void)WRITE(GC_stdout,buf,strlen(buf));
+#else
+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
+}
+}
+void GC_err_printf(const char*format,...)
+{
+char buf[BUFSZ+1];
+GC_PRINTF_FILLBUF(buf,format);
+GC_err_puts(buf);
+}
+void GC_log_printf(const char*format,...)
+{
+char buf[BUFSZ+1];
+GC_PRINTF_FILLBUF(buf,format);
+#ifdef NACL
+(void)WRITE(GC_log,buf,strlen(buf));
+#else
+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
+}
+#ifndef GC_ANDROID_LOG
+#define GC_warn_printf GC_err_printf
+#else
+GC_INNER void GC_info_log_printf(const char*format,...)
+{
+char buf[BUFSZ+1];
+GC_PRINTF_FILLBUF(buf,format);
+(void)WRITE(ANDROID_LOG_INFO,buf,0);
+}
+GC_INNER void GC_verbose_log_printf(const char*format,...)
+{
+char buf[BUFSZ+1];
+GC_PRINTF_FILLBUF(buf,format);
+(void)WRITE(ANDROID_LOG_VERBOSE,buf,0);
+}
+STATIC void GC_warn_printf(const char*format,...)
+{
+char buf[BUFSZ+1];
+GC_PRINTF_FILLBUF(buf,format);
+(void)WRITE(ANDROID_LOG_WARN,buf,0);
+}
+#endif
+void GC_err_puts(const char*s)
+{
+(void)WRITE(GC_stderr,s,strlen(s));
+}
+STATIC void GC_CALLBACK GC_default_warn_proc(char*msg,GC_word arg)
+{
+GC_warn_printf(msg,arg);
+}
+GC_INNER GC_warn_proc GC_current_warn_proc=GC_default_warn_proc;
+GC_API void GC_CALLBACK GC_ignore_warn_proc(char*msg,GC_word arg)
+{
+if (GC_print_stats){
+GC_default_warn_proc(msg,arg);
+}
+}
+GC_API void GC_CALL GC_set_warn_proc(GC_warn_proc p)
+{
+DCL_LOCK_STATE;
+GC_ASSERT(NONNULL_ARG_NOT_NULL(p));
+#ifdef GC_WIN32_THREADS
+#ifdef CYGWIN32
+GC_ASSERT(GC_is_initialized);
+#else
+if (!GC_is_initialized)GC_init();
+#endif
+#endif
+LOCK();
+GC_current_warn_proc=p;
+UNLOCK();
+}
+GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void)
+{
+GC_warn_proc result;
+DCL_LOCK_STATE;
+LOCK();
+result=GC_current_warn_proc;
+UNLOCK();
+return(result);
+}
+#if!defined(PCR)&&!defined(SMALL_CONFIG)
+STATIC void GC_CALLBACK GC_default_on_abort(const char*msg)
+{
+#ifndef DONT_USE_ATEXIT
+skip_gc_atexit=TRUE;
+#endif
+if (msg!=NULL){
+#ifdef MSGBOX_ON_ERROR
+GC_win32_MessageBoxA(msg,"Fatal error in GC",MB_ICONERROR|MB_OK);
+#endif
+#ifndef GC_ANDROID_LOG
+#if defined(GC_WIN32_THREADS)&&defined(GC_ASSERTIONS)&&((defined(MSWIN32)&&!defined(CONSOLE_LOG))||defined(MSWINCE))
+if (!GC_write_disabled)
+#endif
+{
+if (WRITE(GC_stderr,msg,strlen(msg))>=0)
+(void)WRITE(GC_stderr,"\n",1);
+}
+#else
+__android_log_assert("*",GC_ANDROID_LOG_TAG,"%s\n",msg);
+#endif
+}
+#if!defined(NO_DEBUGGING)&&!defined(GC_ANDROID_LOG)
+if (GETENV("GC_LOOP_ON_ABORT")!=NULL){
+for(;;){
+}
+}
+#endif
+}
+GC_abort_func GC_on_abort=GC_default_on_abort;
+GC_API void GC_CALL GC_set_abort_func(GC_abort_func fn)
+{
+DCL_LOCK_STATE;
+GC_ASSERT(NONNULL_ARG_NOT_NULL(fn));
+LOCK();
+GC_on_abort=fn;
+UNLOCK();
+}
+GC_API GC_abort_func GC_CALL GC_get_abort_func(void)
+{
+GC_abort_func fn;
+DCL_LOCK_STATE;
+LOCK();
+fn=GC_on_abort;
+UNLOCK();
+return fn;
+}
+#endif
+GC_API void GC_CALL GC_enable(void)
+{
+DCL_LOCK_STATE;
+LOCK();
+GC_ASSERT(GC_dont_gc!=0);
+GC_dont_gc--;
+UNLOCK();
+}
+GC_API void GC_CALL GC_disable(void)
+{
+DCL_LOCK_STATE;
+LOCK();
+GC_dont_gc++;
+UNLOCK();
+}
+GC_API int GC_CALL GC_is_disabled(void)
+{
+return GC_dont_gc!=0;
+}
+GC_API void**GC_CALL GC_new_free_list_inner(void)
+{
+void*result;
+GC_ASSERT(I_HOLD_LOCK());
+result=GC_INTERNAL_MALLOC((MAXOBJGRANULES+1)*sizeof(ptr_t),PTRFREE);
+if (NULL==result)ABORT("Failed to allocate freelist for new kind");
+BZERO(result,(MAXOBJGRANULES+1)*sizeof(ptr_t));
+return (void**)result;
+}
+GC_API void**GC_CALL GC_new_free_list(void)
+{
+void**result;
+DCL_LOCK_STATE;
+LOCK();
+result=GC_new_free_list_inner();
+UNLOCK();
+return result;
+}
+GC_API unsigned GC_CALL GC_new_kind_inner(void**fl,GC_word descr,
+int adjust,int clear)
+{
+unsigned result=GC_n_kinds;
+GC_ASSERT(NONNULL_ARG_NOT_NULL(fl));
+GC_ASSERT(adjust==FALSE||adjust==TRUE);
+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;
+GC_obj_kinds[result].ok_descriptor=descr;
+GC_obj_kinds[result].ok_relocate_descr=adjust;
+GC_obj_kinds[result].ok_init=(GC_bool)clear;
+#ifdef ENABLE_DISCLAIM
+GC_obj_kinds[result].ok_mark_unconditionally=FALSE;
+GC_obj_kinds[result].ok_disclaim_proc=0;
+#endif
+} else {
+ABORT("Too many kinds");
+}
+return result;
+}
+GC_API unsigned GC_CALL GC_new_kind(void**fl,GC_word descr,int adjust,
+int clear)
+{
+unsigned result;
+DCL_LOCK_STATE;
+LOCK();
+result=GC_new_kind_inner(fl,descr,adjust,clear);
+UNLOCK();
+return result;
+}
+GC_API unsigned GC_CALL GC_new_proc_inner(GC_mark_proc proc)
+{
+unsigned result=GC_n_mark_procs;
+if (result < MAX_MARK_PROCS){
+GC_n_mark_procs++;
+GC_mark_procs[result]=proc;
+} else {
+ABORT("Too many mark procedures");
+}
+return result;
+}
+GC_API unsigned GC_CALL GC_new_proc(GC_mark_proc proc)
+{
+unsigned result;
+DCL_LOCK_STATE;
+LOCK();
+result=GC_new_proc_inner(proc);
+UNLOCK();
+return result;
+}
+GC_API void*GC_CALL GC_call_with_alloc_lock(GC_fn_type fn,void*client_data)
+{
+void*result;
+DCL_LOCK_STATE;
+#ifdef THREADS
+LOCK();
+#endif
+result=(*fn)(client_data);
+#ifdef THREADS
+UNLOCK();
+#endif
+return(result);
+}
+GC_API void*GC_CALL GC_call_with_stack_base(GC_stack_base_func fn,void*arg)
+{
+struct GC_stack_base base;
+void*result;
+base.mem_base=(void*)&base;
+#ifdef IA64
+base.reg_base=(void*)GC_save_regs_in_stack();
+#endif
+result=fn(&base,arg);
+GC_noop1(COVERT_DATAFLOW(&base));
+return result;
+}
+#ifndef THREADS
+GC_INNER ptr_t GC_blocked_sp=NULL;
+#ifdef IA64
+STATIC ptr_t GC_blocked_register_sp=NULL;
+#endif
+GC_INNER struct GC_traced_stack_sect_s*GC_traced_stack_sect=NULL;
+GC_API void*GC_CALL GC_call_with_gc_active(GC_fn_type fn,
+void*client_data)
+{
+struct GC_traced_stack_sect_s stacksect;
+GC_ASSERT(GC_is_initialized);
+if ((word)GC_stackbottom HOTTER_THAN (word)(&stacksect))
+GC_stackbottom=(ptr_t)COVERT_DATAFLOW(&stacksect);
+if (GC_blocked_sp==NULL){
+client_data=fn(client_data);
+GC_noop1(COVERT_DATAFLOW(&stacksect));
+return client_data;
+}
+stacksect.saved_stack_ptr=GC_blocked_sp;
+#ifdef IA64
+stacksect.backing_store_end=GC_save_regs_in_stack();
+stacksect.saved_backing_store_ptr=GC_blocked_register_sp;
+#endif
+stacksect.prev=GC_traced_stack_sect;
+GC_blocked_sp=NULL;
+GC_traced_stack_sect=&stacksect;
+client_data=fn(client_data);
+GC_ASSERT(GC_blocked_sp==NULL);
+GC_ASSERT(GC_traced_stack_sect==&stacksect);
+#if defined(CPPCHECK)
+GC_noop1((word)GC_traced_stack_sect - (word)GC_blocked_sp);
+#endif
+GC_traced_stack_sect=stacksect.prev;
+#ifdef IA64
+GC_blocked_register_sp=stacksect.saved_backing_store_ptr;
+#endif
+GC_blocked_sp=stacksect.saved_stack_ptr;
+return client_data;
+}
+STATIC void GC_do_blocking_inner(ptr_t data,void*context GC_ATTR_UNUSED)
+{
+struct blocking_data*d=(struct blocking_data*)data;
+GC_ASSERT(GC_is_initialized);
+GC_ASSERT(GC_blocked_sp==NULL);
+#ifdef SPARC
+GC_blocked_sp=GC_save_regs_in_stack();
+#else
+GC_blocked_sp=(ptr_t)&d;
+#endif
+#ifdef IA64
+GC_blocked_register_sp=GC_save_regs_in_stack();
+#endif
+d->client_data=(d->fn)(d->client_data);
+#ifdef SPARC
+GC_ASSERT(GC_blocked_sp!=NULL);
+#else
+GC_ASSERT(GC_blocked_sp==(ptr_t)(&d));
+#endif
+#if defined(CPPCHECK)
+GC_noop1((word)GC_blocked_sp);
+#endif
+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);
+(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;
+}
+#endif
+GC_API void*GC_CALL GC_do_blocking(GC_fn_type fn,void*client_data)
+{
+struct blocking_data my_data;
+my_data.fn=fn;
+my_data.client_data=client_data;
+GC_with_callee_saves_pushed(GC_do_blocking_inner,(ptr_t)(&my_data));
+return my_data.client_data;
+}
+#if!defined(NO_DEBUGGING)
+GC_API void GC_CALL GC_dump(void)
+{
+DCL_LOCK_STATE;
+LOCK();
+GC_dump_named(NULL);
+UNLOCK();
+}
+GC_API void GC_CALL GC_dump_named(const char*name)
+{
+#ifndef NO_CLOCK
+CLOCK_TYPE current_time;
+GET_TIME(current_time);
+#endif
+if (name!=NULL){
+GC_printf("***GC Dump %s\n",name);
+} else {
+GC_printf("***GC Dump collection #%lu\n",(unsigned long)GC_gc_no);
+}
+#ifndef NO_CLOCK
+GC_printf("Time since GC init:%lu ms\n",
+MS_TIME_DIFF(current_time,GC_init_time));
+#endif
+GC_printf("\n***Static roots:\n");
+GC_print_static_roots();
+GC_printf("\n***Heap sections:\n");
+GC_print_heap_sects();
+GC_printf("\n***Free blocks:\n");
+GC_print_hblkfreelist();
+GC_printf("\n***Blocks in use:\n");
+GC_print_block_list();
+}
+#endif
+static void block_add_size(struct hblk*h,word pbytes)
+{
+hdr*hhdr=HDR(h);
+*(word*)pbytes+=(WORDS_TO_BYTES(hhdr->hb_sz)+(HBLKSIZE - 1))
+&~(word)(HBLKSIZE - 1);
+}
+GC_API size_t GC_CALL GC_get_memory_use(void)
+{
+word bytes=0;
+DCL_LOCK_STATE;
+LOCK();
+GC_apply_to_all_blocks(block_add_size,(word)(&bytes));
+UNLOCK();
+return (size_t)bytes;
+}
+GC_API GC_word GC_CALL GC_get_gc_no(void)
+{
+return GC_gc_no;
+}
+#ifdef THREADS
+GC_API int GC_CALL GC_get_parallel(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)
+{
+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)
+{
+DCL_LOCK_STATE;
+LOCK();
+GC_on_thread_event=fn;
+UNLOCK();
+}
+GC_API GC_on_thread_event_proc GC_CALL GC_get_on_thread_event(void)
+{
+GC_on_thread_event_proc fn;
+DCL_LOCK_STATE;
+LOCK();
+fn=GC_on_thread_event;
+UNLOCK();
+return fn;
+}
+#endif
+GC_API void GC_CALL GC_set_oom_fn(GC_oom_func fn)
+{
+GC_ASSERT(NONNULL_ARG_NOT_NULL(fn));
+DCL_LOCK_STATE;
+LOCK();
+GC_oom_fn=fn;
+UNLOCK();
+}
+GC_API GC_oom_func GC_CALL GC_get_oom_fn(void)
+{
+GC_oom_func fn;
+DCL_LOCK_STATE;
+LOCK();
+fn=GC_oom_fn;
+UNLOCK();
+return fn;
+}
+GC_API void GC_CALL GC_set_on_heap_resize(GC_on_heap_resize_proc fn)
+{
+DCL_LOCK_STATE;
+LOCK();
+GC_on_heap_resize=fn;
+UNLOCK();
+}
+GC_API GC_on_heap_resize_proc GC_CALL GC_get_on_heap_resize(void)
+{
+GC_on_heap_resize_proc fn;
+DCL_LOCK_STATE;
+LOCK();
+fn=GC_on_heap_resize;
+UNLOCK();
+return fn;
+}
+GC_API void GC_CALL GC_set_finalizer_notifier(GC_finalizer_notifier_proc fn)
+{
+DCL_LOCK_STATE;
+LOCK();
+GC_finalizer_notifier=fn;
+UNLOCK();
+}
+GC_API GC_finalizer_notifier_proc GC_CALL GC_get_finalizer_notifier(void)
+{
+GC_finalizer_notifier_proc fn;
+DCL_LOCK_STATE;
+LOCK();
+fn=GC_finalizer_notifier;
+UNLOCK();
+return fn;
+}
+GC_API void GC_CALL GC_set_find_leak(int value)
+{
+GC_find_leak=value;
+}
+GC_API int GC_CALL GC_get_find_leak(void)
+{
+return GC_find_leak;
+}
+GC_API void GC_CALL GC_set_all_interior_pointers(int value)
+{
+DCL_LOCK_STATE;
+GC_all_interior_pointers=value?1:0;
+if (GC_is_initialized){
+LOCK();
+GC_initialize_offsets();
+if (!GC_all_interior_pointers)
+GC_bl_init_no_interiors();
+UNLOCK();
+}
+}
+GC_API int GC_CALL GC_get_all_interior_pointers(void)
+{
+return GC_all_interior_pointers;
+}
+GC_API void GC_CALL GC_set_finalize_on_demand(int value)
+{
+GC_ASSERT(value!=-1);
+GC_finalize_on_demand=value;
+}
+GC_API int GC_CALL GC_get_finalize_on_demand(void)
+{
+return GC_finalize_on_demand;
+}
+GC_API void GC_CALL GC_set_java_finalization(int value)
+{
+GC_ASSERT(value!=-1);
+GC_java_finalization=value;
+}
+GC_API int GC_CALL GC_get_java_finalization(void)
+{
+return GC_java_finalization;
+}
+GC_API void GC_CALL GC_set_dont_expand(int value)
+{
+GC_ASSERT(value!=-1);
+GC_dont_expand=value;
+}
+GC_API int GC_CALL GC_get_dont_expand(void)
+{
+return GC_dont_expand;
+}
+GC_API void GC_CALL GC_set_no_dls(int value)
+{
+GC_ASSERT(value!=-1);
+GC_no_dls=value;
+}
+GC_API int GC_CALL GC_get_no_dls(void)
+{
+return GC_no_dls;
+}
+GC_API void GC_CALL GC_set_non_gc_bytes(GC_word value)
+{
+GC_non_gc_bytes=value;
+}
+GC_API GC_word GC_CALL GC_get_non_gc_bytes(void)
+{
+return GC_non_gc_bytes;
+}
+GC_API void GC_CALL GC_set_free_space_divisor(GC_word value)
+{
+GC_ASSERT(value > 0);
+GC_free_space_divisor=value;
+}
+GC_API GC_word GC_CALL GC_get_free_space_divisor(void)
+{
+return GC_free_space_divisor;
+}
+GC_API void GC_CALL GC_set_max_retries(GC_word value)
+{
+GC_ASSERT((GC_signed_word)value!=-1);
+GC_max_retries=value;
+}
+GC_API GC_word GC_CALL GC_get_max_retries(void)
+{
+return GC_max_retries;
+}
+GC_API void GC_CALL GC_set_dont_precollect(int value)
+{
+GC_ASSERT(value!=-1);
+GC_dont_precollect=value;
+}
+GC_API int GC_CALL GC_get_dont_precollect(void)
+{
+return GC_dont_precollect;
+}
+GC_API void GC_CALL GC_set_full_freq(int value)
+{
+GC_ASSERT(value>=0);
+GC_full_freq=value;
+}
+GC_API int GC_CALL GC_get_full_freq(void)
+{
+return GC_full_freq;
+}
+GC_API void GC_CALL GC_set_time_limit(unsigned long value)
+{
+GC_ASSERT((long)value!=-1L);
+GC_time_limit=value;
+}
+GC_API unsigned long GC_CALL GC_get_time_limit(void)
+{
+return GC_time_limit;
+}
+GC_API void GC_CALL GC_set_force_unmap_on_gcollect(int value)
+{
+GC_force_unmap_on_gcollect=(GC_bool)value;
+}
+GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void)
+{
+return (int)GC_force_unmap_on_gcollect;
+}
+GC_API void GC_CALL GC_abort_on_oom(void)
+{
+GC_err_printf("Insufficient memory for the allocation\n");
+EXIT();
+}
+#ifdef THREADS
+GC_API void GC_CALL GC_stop_world_external(void)
+{
+GC_ASSERT(GC_is_initialized);
+LOCK();
+#ifdef THREAD_LOCAL_ALLOC
+GC_ASSERT(!GC_world_stopped);
+#endif
+STOP_WORLD();
+#ifdef THREAD_LOCAL_ALLOC
+GC_world_stopped=TRUE;
+#endif
+}
+GC_API void GC_CALL GC_start_world_external(void)
+{
+#ifdef THREAD_LOCAL_ALLOC
+GC_ASSERT(GC_world_stopped);
+GC_world_stopped=FALSE;
+#else
+GC_ASSERT(GC_is_initialized);
+#endif
+START_WORLD();
+UNLOCK();
+}
+#endif
+#if!defined(OS2)&&!defined(PCR)&&!defined(AMIGA)&&!defined(MACOS)&&!defined(MSWINCE)&&!defined(SN_TARGET_ORBIS)&&!defined(SN_TARGET_PSP2)&&!defined(__CC_ARM)
+#include <sys/types.h>
+#if!defined(MSWIN32)&&!defined(MSWIN_XBOX1)
+#include <unistd.h>
+#endif
+#endif
+#include <stdio.h>
+#if defined(MSWINCE)||defined(SN_TARGET_PS3)
+#define SIGSEGV 0
+#else
+#include <signal.h>
+#endif
+#if defined(UNIX_LIKE)||defined(CYGWIN32)||defined(NACL)||defined(SYMBIAN)
+#include <fcntl.h>
+#endif
+#if defined(LINUX)||defined(LINUX_STACKBOTTOM)
+#include <ctype.h>
+#endif
+#ifdef AMIGA
+#define GC_AMIGA_DEF
+#if!defined(GC_AMIGA_DEF)&&!defined(GC_AMIGA_SB)&&!defined(GC_AMIGA_DS)&&!defined(GC_AMIGA_AM)
+#include <stdio.h>
+#include <signal.h>
+#define GC_AMIGA_DEF
+#define GC_AMIGA_SB
+#define GC_AMIGA_DS
+#define GC_AMIGA_AM
+#endif
+#ifdef GC_AMIGA_DEF
+#ifndef __GNUC__
+#include <exec/exec.h>
+#endif
+#include <proto/exec.h>
+#include <proto/dos.h>
+#include <dos/dosextens.h>
+#include <workbench/startup.h>
+#endif
+#ifdef GC_AMIGA_SB
+ptr_t GC_get_main_stack_base(void)
+{
+struct Process*proc=(struct Process*)SysBase->ThisTask;
+if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS
+&&proc->pr_CLI!=NULL){
+return (char*)proc->pr_ReturnAddr+sizeof(ULONG);
+} else {
+return (char*)proc->pr_Task.tc_SPUpper;
+}
+}
+#endif
+#ifdef GC_AMIGA_DS
+void GC_register_data_segments(void)
+{
+struct Process*proc;
+struct CommandLineInterface*cli;
+BPTR myseglist;
+ULONG*data;
+#ifdef __GNUC__
+ULONG dataSegSize;
+GC_bool found_segment=FALSE;
+extern char __data_size[];
+dataSegSize=__data_size+8;
+#endif
+proc=(struct Process*)SysBase->ThisTask;
+myseglist=proc->pr_SegList;
+if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS){
+if (proc->pr_CLI!=NULL){
+cli=BADDR(proc->pr_CLI);
+myseglist=cli->cli_Module;
+}
+} else {
+ABORT("Not a Process.");
+}
+if (myseglist==NULL){
+ABORT("Arrrgh.. can't find segments,aborting");
+}
+for (data=(ULONG*)BADDR(myseglist);data!=NULL;
+data=(ULONG*)BADDR(data[0])){
+if ((ULONG)GC_register_data_segments < (ULONG)(&data[1])
+||(ULONG)GC_register_data_segments > (ULONG)(&data[1])
++data[-1]){
+#ifdef __GNUC__
+if (dataSegSize==data[-1]){
+found_segment=TRUE;
+}
+#endif
+GC_add_roots_inner((char*)&data[1],
+((char*)&data[1])+data[-1],FALSE);
+}
+}
+#ifdef __GNUC__
+if (!found_segment){
+ABORT("Can`t find correct Segments.\nSolution:Use an newer version of ixemul.library");
+}
+#endif
+}
+#endif
+#ifdef GC_AMIGA_AM
+#ifndef GC_AMIGA_FASTALLOC
+void*GC_amiga_allocwrapper(size_t size,void*(*AllocFunction)(size_t size2)){
+return (*AllocFunction)(size);
+}
+void*(*GC_amiga_allocwrapper_do)(size_t size,void*(*AllocFunction)(size_t size2))
+=GC_amiga_allocwrapper;
+#else
+void*GC_amiga_allocwrapper_firsttime(size_t size,void*(*AllocFunction)(size_t size2));
+void*(*GC_amiga_allocwrapper_do)(size_t size,void*(*AllocFunction)(size_t size2))
+=GC_amiga_allocwrapper_firsttime;
+struct GC_Amiga_AllocedMemoryHeader{
+ULONG size;
+struct GC_Amiga_AllocedMemoryHeader*next;
+};
+struct GC_Amiga_AllocedMemoryHeader*GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader*)(int)~(NULL);
+ULONG GC_AMIGA_MEMF=MEMF_FAST|MEMF_CLEAR;
+#ifndef GC_AMIGA_ONLYFAST
+BOOL GC_amiga_dontalloc=FALSE;
+#endif
+#ifdef GC_AMIGA_PRINTSTATS
+int succ=0,succ2=0;
+int nsucc=0,nsucc2=0;
+int nullretries=0;
+int numcollects=0;
+int chipa=0;
+int allochip=0;
+int allocfast=0;
+int cur0=0;
+int cur1=0;
+int cur10=0;
+int cur50=0;
+int cur150=0;
+int cur151=0;
+int ncur0=0;
+int ncur1=0;
+int ncur10=0;
+int ncur50=0;
+int ncur150=0;
+int ncur151=0;
+#endif
+void GC_amiga_free_all_mem(void){
+struct GC_Amiga_AllocedMemoryHeader*gc_am=(struct GC_Amiga_AllocedMemoryHeader*)(~(int)(GC_AMIGAMEM));
+#ifdef GC_AMIGA_PRINTSTATS
+printf("\n\n"
+"%d bytes of chip-mem,and %d bytes of fast-mem where allocated from the OS.\n",
+allochip,allocfast
+);
+printf(
+"%d bytes of chip-mem were returned from the GC_AMIGA_FASTALLOC supported allocating functions.\n",
+chipa
+);
+printf("\n");
+printf("GC_gcollect was called %d times to avoid returning NULL or start allocating with the MEMF_ANY flag.\n",numcollects);
+printf("%d of them was a success. (the others had to use allocation from the OS.)\n",nullretries);
+printf("\n");
+printf("Succeeded forcing %d gc-allocations (%d bytes)of chip-mem to be fast-mem.\n",succ,succ2);
+printf("Failed forcing %d gc-allocations (%d bytes)of chip-mem to be fast-mem.\n",nsucc,nsucc2);
+printf("\n");
+printf(
+"Number of retries before succeeding a chip->fast force:\n"
+"0:%d,1:%d,2-9:%d,10-49:%d,50-149:%d,>150:%d\n",
+cur0,cur1,cur10,cur50,cur150,cur151
+);
+printf(
+"Number of retries before giving up a chip->fast force:\n"
+"0:%d,1:%d,2-9:%d,10-49:%d,50-149:%d,>150:%d\n",
+ncur0,ncur1,ncur10,ncur50,ncur150,ncur151
+);
+#endif
+while(gc_am!=NULL){
+struct GC_Amiga_AllocedMemoryHeader*temp=gc_am->next;
+FreeMem(gc_am,gc_am->size);
+gc_am=(struct GC_Amiga_AllocedMemoryHeader*)(~(int)(temp));
+}
+}
+#ifndef GC_AMIGA_ONLYFAST
+char*chipmax;
+size_t latestsize;
+#endif
+#ifdef GC_AMIGA_FASTALLOC
+void*GC_amiga_get_mem(size_t size){
+struct GC_Amiga_AllocedMemoryHeader*gc_am;
+#ifndef GC_AMIGA_ONLYFAST
+if(GC_amiga_dontalloc==TRUE){
+return NULL;
+}
+if(GC_AMIGA_MEMF==(MEMF_ANY|MEMF_CLEAR)&&size>100000&&latestsize<50000)return NULL;
+#endif
+gc_am=AllocMem((ULONG)(size+sizeof(struct GC_Amiga_AllocedMemoryHeader)),GC_AMIGA_MEMF);
+if(gc_am==NULL)return NULL;
+gc_am->next=GC_AMIGAMEM;
+gc_am->size=size+sizeof(struct GC_Amiga_AllocedMemoryHeader);
+GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader*)(~(int)(gc_am));
+#ifdef GC_AMIGA_PRINTSTATS
+if((char*)gc_am<chipmax){
+allochip+=size;
+}else{
+allocfast+=size;
+}
+#endif
+return gc_am+1;
+}
+#endif
+#ifndef GC_AMIGA_ONLYFAST
+#ifdef GC_AMIGA_RETRY
+void*GC_amiga_rec_alloc(size_t size,void*(*AllocFunction)(size_t size2),const int rec){
+void*ret;
+ret=(*AllocFunction)(size);
+#ifdef GC_AMIGA_PRINTSTATS
+if((char*)ret>chipmax||ret==NULL){
+if(ret==NULL){
+nsucc++;
+nsucc2+=size;
+if(rec==0)ncur0++;
+if(rec==1)ncur1++;
+if(rec>1&&rec<10)ncur10++;
+if(rec>=10&&rec<50)ncur50++;
+if(rec>=50&&rec<150)ncur150++;
+if(rec>=150)ncur151++;
+}else{
+succ++;
+succ2+=size;
+if(rec==0)cur0++;
+if(rec==1)cur1++;
+if(rec>1&&rec<10)cur10++;
+if(rec>=10&&rec<50)cur50++;
+if(rec>=50&&rec<150)cur150++;
+if(rec>=150)cur151++;
+}
+}
+#endif
+if (((char*)ret)<=chipmax&&ret!=NULL&&(rec<(size>500000?9:size/5000))){
+ret=GC_amiga_rec_alloc(size,AllocFunction,rec+1);
+}
+return ret;
+}
+#endif
+void*GC_amiga_allocwrapper_any(size_t size,void*(*AllocFunction)(size_t size2)){
+void*ret;
+GC_amiga_dontalloc=TRUE;
+latestsize=size;
+ret=(*AllocFunction)(size);
+if(((char*)ret)<=chipmax){
+if(ret==NULL){
+#ifdef GC_AMIGA_GC
+if(!GC_dont_gc){
+GC_gcollect();
+#ifdef GC_AMIGA_PRINTSTATS
+numcollects++;
+#endif
+ret=(*AllocFunction)(size);
+}
+if(ret==NULL)
+#endif
+{
+GC_amiga_dontalloc=FALSE;
+ret=(*AllocFunction)(size);
+if(ret==NULL){
+WARN("Out of Memory!Returning NIL!\n",0);
+}
+}
+#ifdef GC_AMIGA_PRINTSTATS
+else{
+nullretries++;
+}
+if(ret!=NULL&&(char*)ret<=chipmax)chipa+=size;
+#endif
+}
+#ifdef GC_AMIGA_RETRY
+else{
+void*ret2;
+if(
+AllocFunction!=GC_malloc_uncollectable
+#ifdef GC_ATOMIC_UNCOLLECTABLE
+&&AllocFunction!=GC_malloc_atomic_uncollectable
+#endif
+){
+ret2=GC_amiga_rec_alloc(size,AllocFunction,0);
+}else{
+ret2=(*AllocFunction)(size);
+#ifdef GC_AMIGA_PRINTSTATS
+if((char*)ret2<chipmax||ret2==NULL){
+nsucc++;
+nsucc2+=size;
+ncur0++;
+}else{
+succ++;
+succ2+=size;
+cur0++;
+}
+#endif
+}
+if(((char*)ret2)>chipmax){
+GC_free(ret);
+ret=ret2;
+}else{
+GC_free(ret2);
+}
+}
+#endif
+}
+#if defined(CPPCHECK)
+if (GC_amiga_dontalloc)
+#endif
+GC_amiga_dontalloc=FALSE;
+return ret;
+}
+void (*GC_amiga_toany)(void)=NULL;
+void GC_amiga_set_toany(void (*func)(void)){
+GC_amiga_toany=func;
+}
+#endif
+void*GC_amiga_allocwrapper_fast(size_t size,void*(*AllocFunction)(size_t size2)){
+void*ret;
+ret=(*AllocFunction)(size);
+if(ret==NULL){
+#ifdef GC_AMIGA_GC
+if(!GC_dont_gc){
+GC_gcollect();
+#ifdef GC_AMIGA_PRINTSTATS
+numcollects++;
+#endif
+ret=(*AllocFunction)(size);
+}
+if(ret==NULL)
+#endif
+{
+#ifndef GC_AMIGA_ONLYFAST
+GC_AMIGA_MEMF=MEMF_ANY|MEMF_CLEAR;
+if(GC_amiga_toany!=NULL)(*GC_amiga_toany)();
+GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any;
+return GC_amiga_allocwrapper_any(size,AllocFunction);
+#endif
+}
+#ifdef GC_AMIGA_PRINTSTATS
+else{
+nullretries++;
+}
+#endif
+}
+return ret;
+}
+void*GC_amiga_allocwrapper_firsttime(size_t size,void*(*AllocFunction)(size_t size2)){
+atexit(&GC_amiga_free_all_mem);
+chipmax=(char*)SysBase->MaxLocMem;
+GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_fast;
+return GC_amiga_allocwrapper_fast(size,AllocFunction);
+}
+#endif
+void*GC_amiga_realloc(void*old_object,size_t new_size_in_bytes){
+#ifndef GC_AMIGA_FASTALLOC
+return GC_realloc(old_object,new_size_in_bytes);
+#else
+void*ret;
+latestsize=new_size_in_bytes;
+ret=GC_realloc(old_object,new_size_in_bytes);
+if(ret==NULL&&new_size_in_bytes!=0
+&&GC_AMIGA_MEMF==(MEMF_FAST|MEMF_CLEAR)){
+#ifdef GC_AMIGA_GC
+if(!GC_dont_gc){
+GC_gcollect();
+#ifdef GC_AMIGA_PRINTSTATS
+numcollects++;
+#endif
+ret=GC_realloc(old_object,new_size_in_bytes);
+}
+if(ret==NULL)
+#endif
+{
+#ifndef GC_AMIGA_ONLYFAST
+GC_AMIGA_MEMF=MEMF_ANY|MEMF_CLEAR;
+if(GC_amiga_toany!=NULL)(*GC_amiga_toany)();
+GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any;
+ret=GC_realloc(old_object,new_size_in_bytes);
+#endif
+}
+#ifdef GC_AMIGA_PRINTSTATS
+else{
+nullretries++;
+}
+#endif
+}
+if(ret==NULL&&new_size_in_bytes!=0){
+WARN("Out of Memory!Returning NIL!\n",0);
+}
+#ifdef GC_AMIGA_PRINTSTATS
+if(((char*)ret)<chipmax&&ret!=NULL){
+chipa+=new_size_in_bytes;
+}
+#endif
+return ret;
+#endif
+}
+#endif
+#undef GC_AMIGA_DEF
+#endif
+#ifdef MACOS
+#include <Processes.h>
+#endif
+#ifdef IRIX5
+#include <sys/uio.h>
+#include <malloc.h>
+#endif
+#if defined(MMAP_SUPPORTED)||defined(ADD_HEAP_GUARD_PAGES)
+#if defined(USE_MUNMAP)&&!defined(USE_MMAP)&&!defined(CPPCHECK)
+#error Invalid config:USE_MUNMAP requires USE_MMAP
+#endif
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <errno.h>
+#endif
+#ifdef DARWIN
+#include <mach-o/getsect.h>
+#endif
+#ifdef DJGPP
+typedef long unsigned int caddr_t;
+#endif
+#ifdef PCR
+#include "mm/PCR_MM.h"
+#endif
+#if defined(GC_DARWIN_THREADS)&&defined(MPROTECT_VDB)
+#ifndef GC_DARWIN_STOP_WORLD_H
+#define GC_DARWIN_STOP_WORLD_H
+#if!defined(GC_DARWIN_THREADS)
+#error darwin_stop_world.h included without GC_DARWIN_THREADS defined
+#endif
+#include <mach/mach.h>
+#include <mach/thread_act.h>
+EXTERN_C_BEGIN
+struct thread_stop_info {
+mach_port_t mach_thread;
+ptr_t stack_ptr;
+};
+#ifndef DARWIN_DONT_PARSE_STACK
+GC_INNER ptr_t GC_FindTopOfStack(unsigned long);
+#endif
+#ifdef MPROTECT_VDB
+GC_INNER void GC_mprotect_stop(void);
+GC_INNER void GC_mprotect_resume(void);
+#ifndef GC_NO_THREADS_DISCOVERY
+GC_INNER void GC_darwin_register_mach_handler_thread(mach_port_t thread);
+#endif
+#endif
+#if defined(PARALLEL_MARK)&&!defined(GC_NO_THREADS_DISCOVERY)
+GC_INNER GC_bool GC_is_mach_marker(thread_act_t);
+#endif
+EXTERN_C_END
+#endif
+#endif
+#if!defined(NO_EXECUTE_PERMISSION)
+STATIC GC_bool GC_pages_executable=TRUE;
+#else
+STATIC GC_bool GC_pages_executable=FALSE;
+#endif
+#define IGNORE_PAGES_EXECUTABLE 1
+#ifdef NEED_PROC_MAPS
+STATIC ssize_t GC_repeat_read(int fd,char*buf,size_t count)
+{
+#define READ read
+size_t num_read=0;
+ASSERT_CANCEL_DISABLED();
+while (num_read < count){
+ssize_t result=READ(fd,buf+num_read,count - num_read);
+if (result < 0)return result;
+if (result==0)break;
+num_read+=result;
+}
+#undef READ
+return num_read;
+}
+#ifdef THREADS
+STATIC size_t GC_get_file_len(int f)
+{
+size_t total=0;
+ssize_t result;
+#define GET_FILE_LEN_BUF_SZ 500
+char buf[GET_FILE_LEN_BUF_SZ];
+do {
+result=read(f,buf,GET_FILE_LEN_BUF_SZ);
+if (result==-1)return 0;
+total+=result;
+} while (result > 0);
+return total;
+}
+STATIC size_t GC_get_maps_len(void)
+{
+int f=open("/proc/self/maps",O_RDONLY);
+size_t result;
+if (f < 0)return 0;
+result=GC_get_file_len(f);
+close(f);
+return result;
+}
+#endif
+GC_INNER char*GC_get_maps(void)
+{
+ssize_t result;
+static char*maps_buf=NULL;
+static size_t maps_buf_sz=1;
+size_t maps_size;
+#ifdef THREADS
+size_t old_maps_size=0;
+#endif
+GC_ASSERT(I_HOLD_LOCK());
+#ifdef THREADS
+maps_size=GC_get_maps_len();
+if (0==maps_size)return 0;
+#else
+maps_size=4000;
+#endif
+do {
+int f;
+while (maps_size>=maps_buf_sz){
+#ifdef LINT2
+GC_noop1((word)maps_buf);
+#else
+GC_scratch_recycle_no_gww(maps_buf,maps_buf_sz);
+#endif
+while (maps_size>=maps_buf_sz)maps_buf_sz*=2;
+maps_buf=GC_scratch_alloc(maps_buf_sz);
+#ifdef THREADS
+maps_size=GC_get_maps_len();
+if (0==maps_size)return 0;
+#endif
+if (maps_buf==0)return 0;
+}
+GC_ASSERT(maps_buf_sz>=maps_size+1);
+f=open("/proc/self/maps",O_RDONLY);
+if (-1==f)return 0;
+#ifdef THREADS
+old_maps_size=maps_size;
+#endif
+maps_size=0;
+do {
+result=GC_repeat_read(f,maps_buf,maps_buf_sz-1);
+if (result<=0){
+close(f);
+return 0;
+}
+maps_size+=result;
+} while ((size_t)result==maps_buf_sz-1);
+close(f);
+#ifdef THREADS
+if (maps_size > old_maps_size){
+WARN("Unexpected asynchronous/proc/self/maps growth"
+" (to %" WARN_PRIdPTR " bytes)\n",maps_size);
+}
+#endif
+} while (maps_size>=maps_buf_sz
+#ifdef THREADS
+||maps_size < old_maps_size
+#endif
+);
+maps_buf[maps_size]='\0';
+return maps_buf;
+}
+#if (defined(DYNAMIC_LOADING)&&defined(USE_PROC_FOR_LIBRARIES))||defined(IA64)||defined(INCLUDE_LINUX_THREAD_DESCR)||defined(REDIRECT_MALLOC)
+GC_INNER char*GC_parse_map_entry(char*buf_ptr,ptr_t*start,ptr_t*end,
+char**prot,unsigned int*maj_dev,
+char**mapping_name)
+{
+unsigned char*start_start,*end_start,*maj_dev_start;
+unsigned char*p;
+if (buf_ptr==NULL||*buf_ptr=='\0'){
+return NULL;
+}
+p=(unsigned char*)buf_ptr;
+while (isspace(*p))++p;
+start_start=p;
+GC_ASSERT(isxdigit(*start_start));
+*start=(ptr_t)strtoul((char*)start_start,(char**)&p,16);
+GC_ASSERT(*p=='-');
+++p;
+end_start=p;
+GC_ASSERT(isxdigit(*end_start));
+*end=(ptr_t)strtoul((char*)end_start,(char**)&p,16);
+GC_ASSERT(isspace(*p));
+while (isspace(*p))++p;
+GC_ASSERT(*p=='r'||*p=='-');
+*prot=(char*)p;
+while (!isspace(*p))++p;
+while (isspace(*p))p++;
+GC_ASSERT(isxdigit(*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);
+if (mapping_name==0){
+while (*p&&*p++!='\n');
+} else {
+while (*p&&*p!='\n'&&*p!='/'&&*p!='[')p++;
+*mapping_name=(char*)p;
+while (*p&&*p++!='\n');
+}
+return (char*)p;
+}
+#endif
+#if defined(IA64)||defined(INCLUDE_LINUX_THREAD_DESCR)
+GC_INNER GC_bool GC_enclosing_mapping(ptr_t addr,ptr_t*startp,
+ptr_t*endp)
+{
+char*prot;
+ptr_t my_start,my_end;
+unsigned int maj_dev;
+char*maps=GC_get_maps();
+char*buf_ptr=maps;
+if (0==maps)return(FALSE);
+for (;;){
+buf_ptr=GC_parse_map_entry(buf_ptr,&my_start,&my_end,
+&prot,&maj_dev,0);
+if (buf_ptr==NULL)return FALSE;
+if (prot[1]=='w'&&maj_dev==0){
+if ((word)my_end > (word)addr&&(word)my_start<=(word)addr){
+*startp=my_start;
+*endp=my_end;
+return TRUE;
+}
+}
+}
+return FALSE;
+}
+#endif
+#if defined(REDIRECT_MALLOC)
+GC_INNER GC_bool GC_text_mapping(char*nm,ptr_t*startp,ptr_t*endp)
+{
+size_t nm_len=strlen(nm);
+char*prot;
+char*map_path;
+ptr_t my_start,my_end;
+unsigned int maj_dev;
+char*maps=GC_get_maps();
+char*buf_ptr=maps;
+if (0==maps)return(FALSE);
+for (;;){
+buf_ptr=GC_parse_map_entry(buf_ptr,&my_start,&my_end,
+&prot,&maj_dev,&map_path);
+if (buf_ptr==NULL)return FALSE;
+if (prot[0]=='r'&&prot[1]=='-'&&prot[2]=='x'){
+char*p=map_path;
+while (*p!='\0'&&*p!='\n'&&*p!=' '&&*p!='\t')++p;
+while (*p!='/'&&(word)p>=(word)map_path)--p;
+++p;
+if (strncmp(nm,p,nm_len)==0){
+*startp=my_start;
+*endp=my_end;
+return TRUE;
+}
+}
+}
+return FALSE;
+}
+#endif
+#ifdef IA64
+static ptr_t backing_store_base_from_proc(void)
+{
+ptr_t my_start,my_end;
+if (!GC_enclosing_mapping(GC_save_regs_in_stack(),&my_start,&my_end)){
+GC_COND_LOG_PRINTF("Failed to find backing store base from/proc\n");
+return 0;
+}
+return my_start;
+}
+#endif
+#endif
+#if defined(SEARCH_FOR_DATA_START)
+#if defined(LINUX)||defined(HURD)
+EXTERN_C_BEGIN
+#pragma weak __data_start
+#pragma weak data_start
+extern int __data_start[],data_start[];
+EXTERN_C_END
+#endif
+ptr_t GC_data_start=NULL;
+GC_INNER void GC_init_linux_data_start(void)
+{
+ptr_t data_end=DATAEND;
+#if (defined(LINUX)||defined(HURD))&&defined(USE_PROG_DATA_START)
+if (COVERT_DATAFLOW(__data_start)!=0){
+GC_data_start=(ptr_t)(__data_start);
+} else {
+GC_data_start=(ptr_t)(data_start);
+}
+if (COVERT_DATAFLOW(GC_data_start)!=0){
+if ((word)GC_data_start > (word)data_end)
+ABORT_ARG2("Wrong __data_start/_end pair",
+":%p .. %p",(void*)GC_data_start,(void*)data_end);
+return;
+}
+#ifdef DEBUG_ADD_DEL_ROOTS
+GC_log_printf("__data_start not provided\n");
+#endif
+#endif
+if (GC_no_dls){
+GC_data_start=data_end;
+return;
+}
+GC_data_start=(ptr_t)GC_find_limit(data_end,FALSE);
+}
+#endif
+#ifdef ECOS
+#ifndef ECOS_GC_MEMORY_SIZE
+#define ECOS_GC_MEMORY_SIZE (448*1024)
+#endif
+static char ecos_gc_memory[ECOS_GC_MEMORY_SIZE];
+static char*ecos_gc_brk=ecos_gc_memory;
+static void*tiny_sbrk(ptrdiff_t increment)
+{
+void*p=ecos_gc_brk;
+ecos_gc_brk+=increment;
+if ((word)ecos_gc_brk > (word)(ecos_gc_memory+sizeof(ecos_gc_memory))){
+ecos_gc_brk-=increment;
+return NULL;
+}
+return p;
+}
+#define sbrk tiny_sbrk
+#endif
+#if defined(NETBSD)&&defined(__ELF__)
+ptr_t GC_data_start=NULL;
+EXTERN_C_BEGIN
+extern char**environ;
+EXTERN_C_END
+GC_INNER void GC_init_netbsd_elf(void)
+{
+GC_data_start=(ptr_t)GC_find_limit(&environ,FALSE);
+}
+#endif
+#if defined(ADDRESS_SANITIZER)&&(defined(UNIX_LIKE)||defined(NEED_FIND_LIMIT)||defined(MPROTECT_VDB))&&!defined(CUSTOM_ASAN_DEF_OPTIONS)
+GC_API const char*__asan_default_options(void)
+{
+return "allow_user_segv_handler=1";
+}
+#endif
+#ifdef OPENBSD
+static struct sigaction old_segv_act;
+STATIC JMP_BUF GC_jmp_buf_openbsd;
+STATIC void GC_fault_handler_openbsd(int sig GC_ATTR_UNUSED)
+{
+LONGJMP(GC_jmp_buf_openbsd,1);
+}
+#ifdef GC_OPENBSD_UTHREADS
+#include <sys/syscall.h>
+EXTERN_C_BEGIN
+extern sigset_t __syscall(quad_t,...);
+EXTERN_C_END
+STATIC ptr_t GC_find_limit_openbsd(ptr_t p,ptr_t bound)
+{
+static volatile ptr_t result;
+struct sigaction act;
+word pgsz=(word)sysconf(_SC_PAGESIZE);
+GC_ASSERT((word)bound>=pgsz);
+GC_ASSERT(I_HOLD_LOCK());
+act.sa_handler=GC_fault_handler_openbsd;
+sigemptyset(&act.sa_mask);
+act.sa_flags=SA_NODEFER|SA_RESTART;
+sigaction(SIGSEGV,&act,&old_segv_act);
+if (SETJMP(GC_jmp_buf_openbsd)==0){
+result=(ptr_t)((word)p&~(pgsz-1));
+for (;;){
+if ((word)result>=(word)bound - pgsz){
+result=bound;
+break;
+}
+result+=pgsz;
+GC_noop1((word)(*result));
+}
+}
+#ifdef THREADS
+__syscall(SYS_sigprocmask,SIG_UNBLOCK,sigmask(SIGPROF));
+#endif
+sigaction(SIGSEGV,&old_segv_act,0);
+return(result);
+}
+#endif
+static volatile int firstpass;
+STATIC ptr_t GC_skip_hole_openbsd(ptr_t p,ptr_t bound)
+{
+static volatile ptr_t result;
+struct sigaction act;
+word pgsz=(word)sysconf(_SC_PAGESIZE);
+GC_ASSERT((word)bound>=pgsz);
+GC_ASSERT(I_HOLD_LOCK());
+act.sa_handler=GC_fault_handler_openbsd;
+sigemptyset(&act.sa_mask);
+act.sa_flags=SA_NODEFER|SA_RESTART;
+sigaction(SIGSEGV,&act,&old_segv_act);
+firstpass=1;
+result=(ptr_t)((word)p&~(pgsz-1));
+if (SETJMP(GC_jmp_buf_openbsd)!=0||firstpass){
+firstpass=0;
+if ((word)result>=(word)bound - pgsz){
+result=bound;
+} else {
+result+=pgsz;
+GC_noop1((word)(*result));
+}
+}
+sigaction(SIGSEGV,&old_segv_act,0);
+return(result);
+}
+#endif
+#ifdef OS2
+#include <stddef.h>
+#if!defined(__IBMC__)&&!defined(__WATCOMC__)
+struct exe_hdr {
+unsigned short magic_number;
+unsigned short padding[29];
+long new_exe_offset;
+};
+#define E_MAGIC(x)(x).magic_number
+#define EMAGIC 0x5A4D
+#define E_LFANEW(x)(x).new_exe_offset
+struct e32_exe {
+unsigned char magic_number[2];
+unsigned char byte_order;
+unsigned char word_order;
+unsigned long exe_format_level;
+unsigned short cpu;
+unsigned short os;
+unsigned long padding1[13];
+unsigned long object_table_offset;
+unsigned long object_count;
+unsigned long padding2[31];
+};
+#define E32_MAGIC1(x)(x).magic_number[0]
+#define E32MAGIC1 'L'
+#define E32_MAGIC2(x)(x).magic_number[1]
+#define E32MAGIC2 'X'
+#define E32_BORDER(x)(x).byte_order
+#define E32LEBO 0
+#define E32_WORDER(x)(x).word_order
+#define E32LEWO 0
+#define E32_CPU(x)(x).cpu
+#define E32CPU286 1
+#define E32_OBJTAB(x)(x).object_table_offset
+#define E32_OBJCNT(x)(x).object_count
+struct o32_obj {
+unsigned long size;
+unsigned long base;
+unsigned long flags;
+unsigned long pagemap;
+unsigned long mapsize;
+unsigned long reserved;
+};
+#define O32_FLAGS(x)(x).flags
+#define OBJREAD 0x0001L
+#define OBJWRITE 0x0002L
+#define OBJINVALID 0x0080L
+#define O32_SIZE(x)(x).size
+#define O32_BASE(x)(x).base
+#else
+#ifndef WORD
+#define WORD unsigned short
+#endif
+#ifndef DWORD
+#define DWORD unsigned long
+#endif
+#define EXE386 1
+#include <newexe.h>
+#include <exe386.h>
+#endif
+#define INCL_DOSEXCEPTIONS
+#define INCL_DOSPROCESS
+#define INCL_DOSERRORS
+#define INCL_DOSMODULEMGR
+#define INCL_DOSMEMMGR
+#include <os2.h>
+#endif
+GC_INNER size_t GC_page_size=0;
+#if defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32)
+#ifndef VER_PLATFORM_WIN32_CE
+#define VER_PLATFORM_WIN32_CE 3
+#endif
+#if defined(MSWINCE)&&defined(THREADS)
+GC_INNER GC_bool GC_dont_query_stack_min=FALSE;
+#endif
+GC_INNER SYSTEM_INFO GC_sysinfo;
+GC_INNER void GC_setpagesize(void)
+{
+GetSystemInfo(&GC_sysinfo);
+#if defined(CYGWIN32)&&(defined(MPROTECT_VDB)||defined(USE_MUNMAP))
+GC_page_size=(size_t)GC_sysinfo.dwAllocationGranularity;
+GC_ASSERT(GC_page_size>=(size_t)GC_sysinfo.dwPageSize);
+#else
+GC_page_size=(size_t)GC_sysinfo.dwPageSize;
+#endif
+#if defined(MSWINCE)&&!defined(_WIN32_WCE_EMULATION)
+{
+OSVERSIONINFO verInfo;
+verInfo.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
+if (!GetVersionEx(&verInfo))
+ABORT("GetVersionEx failed");
+if (verInfo.dwPlatformId==VER_PLATFORM_WIN32_CE&&
+verInfo.dwMajorVersion < 6){
+GC_sysinfo.lpMaximumApplicationAddress=(LPVOID)((word)32<<20);
+#ifdef THREADS
+if (verInfo.dwMajorVersion < 5)
+GC_dont_query_stack_min=TRUE;
+#endif
+}
+}
+#endif
+}
+#ifndef CYGWIN32
+#define is_writable(prot)((prot)==PAGE_READWRITE||(prot)==PAGE_WRITECOPY||(prot)==PAGE_EXECUTE_READWRITE||(prot)==PAGE_EXECUTE_WRITECOPY)
+STATIC word GC_get_writable_length(ptr_t p,ptr_t*base)
+{
+MEMORY_BASIC_INFORMATION buf;
+word result;
+word protect;
+result=VirtualQuery(p,&buf,sizeof(buf));
+if (result!=sizeof(buf))ABORT("Weird VirtualQuery result");
+if (base!=0)*base=(ptr_t)(buf.AllocationBase);
+protect=(buf.Protect&~(PAGE_GUARD|PAGE_NOCACHE));
+if (!is_writable(protect)){
+return(0);
+}
+if (buf.State!=MEM_COMMIT)return(0);
+return(buf.RegionSize);
+}
+GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base*sb)
+{
+ptr_t trunc_sp;
+word size;
+if (!GC_page_size)GC_setpagesize();
+trunc_sp=(ptr_t)((word)GC_approx_sp()&~(GC_page_size - 1));
+size=GC_get_writable_length(trunc_sp,0);
+GC_ASSERT(size!=0);
+sb->mem_base=trunc_sp+size;
+return GC_SUCCESS;
+}
+#else
+GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base*sb)
+{
+#ifdef X86_64
+sb->mem_base=((NT_TIB*)NtCurrentTeb())->StackBase;
+#else
+void*_tlsbase;
+__asm__ ("movl %%fs:4,%0"
+:"=r" (_tlsbase));
+sb->mem_base=_tlsbase;
+#endif
+return GC_SUCCESS;
+}
+#endif
+#define HAVE_GET_STACK_BASE
+#else
+GC_INNER void GC_setpagesize(void)
+{
+#if defined(MPROTECT_VDB)||defined(PROC_VDB)||defined(USE_MMAP)
+GC_page_size=(size_t)GETPAGESIZE();
+#if!defined(CPPCHECK)
+if (0==GC_page_size)
+ABORT("getpagesize failed");
+#endif
+#else
+GC_page_size=HBLKSIZE;
+#endif
+}
+#endif
+#ifdef HAIKU
+#include <kernel/OS.h>
+GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base*sb)
+{
+thread_info th;
+get_thread_info(find_thread(NULL),&th);
+sb->mem_base=th.stack_end;
+return GC_SUCCESS;
+}
+#define HAVE_GET_STACK_BASE
+#endif
+#ifdef OS2
+GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base*sb)
+{
+PTIB ptib;
+PPIB ppib;
+if (DosGetInfoBlocks(&ptib,&ppib)!=NO_ERROR){
+WARN("DosGetInfoBlocks failed\n",0);
+return GC_UNIMPLEMENTED;
+}
+sb->mem_base=ptib->tib_pstacklimit;
+return GC_SUCCESS;
+}
+#define HAVE_GET_STACK_BASE
+#endif
+#ifdef AMIGA
+#define GC_AMIGA_SB
+#undef GC_AMIGA_SB
+#define GET_MAIN_STACKBASE_SPECIAL
+#endif
+#if defined(NEED_FIND_LIMIT)||defined(UNIX_LIKE)
+typedef void (*GC_fault_handler_t)(int);
+#if defined(SUNOS5SIGS)||defined(IRIX5)||defined(OSF1)||defined(HAIKU)||defined(HURD)||defined(FREEBSD)||defined(NETBSD)
+static struct sigaction old_segv_act;
+#if defined(_sigargs)||defined(HURD)||defined(NETBSD)||defined(FREEBSD)
+static struct sigaction old_bus_act;
+#endif
+#else
+static GC_fault_handler_t old_segv_handler;
+#ifdef HAVE_SIGBUS
+static GC_fault_handler_t old_bus_handler;
+#endif
+#endif
+GC_INNER void GC_set_and_save_fault_handler(GC_fault_handler_t h)
+{
+#if defined(SUNOS5SIGS)||defined(IRIX5)||defined(OSF1)||defined(HAIKU)||defined(HURD)||defined(FREEBSD)||defined(NETBSD)||defined(OPENBSD)
+struct sigaction act;
+act.sa_handler=h;
+#ifdef SIGACTION_FLAGS_NODEFER_HACK
+act.sa_flags=SA_RESTART|SA_NODEFER;
+#else
+act.sa_flags=SA_RESTART;
+#endif
+(void)sigemptyset(&act.sa_mask);
+#ifdef GC_IRIX_THREADS
+(void)sigaction(SIGSEGV,0,&old_segv_act);
+(void)sigaction(SIGSEGV,&act,0);
+#else
+(void)sigaction(SIGSEGV,&act,&old_segv_act);
+#if defined(IRIX5)&&defined(_sigargs)||defined(HURD)||defined(NETBSD)||defined(FREEBSD)
+(void)sigaction(SIGBUS,&act,&old_bus_act);
+#endif
+#endif
+#else
+old_segv_handler=signal(SIGSEGV,h);
+#ifdef HAVE_SIGBUS
+old_bus_handler=signal(SIGBUS,h);
+#endif
+#endif
+#if defined(CPPCHECK)&&defined(ADDRESS_SANITIZER)
+GC_noop1((word)&__asan_default_options);
+#endif
+}
+#endif
+#if defined(NEED_FIND_LIMIT)||(defined(USE_PROC_FOR_LIBRARIES)&&defined(THREADS))
+#define MIN_PAGE_SIZE 256
+GC_INNER JMP_BUF GC_jmp_buf;
+STATIC void GC_fault_handler(int sig GC_ATTR_UNUSED)
+{
+LONGJMP(GC_jmp_buf,1);
+}
+GC_INNER void GC_setup_temporary_fault_handler(void)
+{
+GC_ASSERT(I_HOLD_LOCK());
+GC_set_and_save_fault_handler(GC_fault_handler);
+}
+GC_INNER void GC_reset_fault_handler(void)
+{
+#if defined(SUNOS5SIGS)||defined(IRIX5)||defined(OSF1)||defined(HAIKU)||defined(HURD)||defined(FREEBSD)||defined(NETBSD)||defined(OPENBSD)
+(void)sigaction(SIGSEGV,&old_segv_act,0);
+#if defined(IRIX5)&&defined(_sigargs)||defined(HURD)||defined(NETBSD)
+(void)sigaction(SIGBUS,&old_bus_act,0);
+#endif
+#else
+(void)signal(SIGSEGV,old_segv_handler);
+#ifdef HAVE_SIGBUS
+(void)signal(SIGBUS,old_bus_handler);
+#endif
+#endif
+}
+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;
+GC_ASSERT(up?(word)bound>=MIN_PAGE_SIZE
+:(word)bound<=~(word)MIN_PAGE_SIZE);
+GC_ASSERT(I_HOLD_LOCK());
+GC_setup_temporary_fault_handler();
+if (SETJMP(GC_jmp_buf)==0){
+result=(ptr_t)(((word)(p))
+&~(MIN_PAGE_SIZE-1));
+for (;;){
+if (up){
+if ((word)result>=(word)bound - MIN_PAGE_SIZE){
+result=bound;
+break;
+}
+result+=MIN_PAGE_SIZE;
+} else {
+if ((word)result<=(word)bound+MIN_PAGE_SIZE){
+result=bound - MIN_PAGE_SIZE;
+break;
+}
+result-=MIN_PAGE_SIZE;
+}
+GC_noop1((word)(*result));
+}
+}
+GC_reset_fault_handler();
+if (!up){
+result+=MIN_PAGE_SIZE;
+}
+return(result);
+}
+void*GC_find_limit(void*p,int up)
+{
+return GC_find_limit_with_bound((ptr_t)p,(GC_bool)up,
+up?(ptr_t)GC_WORD_MAX:0);
+}
+#endif
+#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;
+}
+#ifdef STACK_GROWS_UP
+return (ptr_t)GC_find_limit(GC_approx_sp(),FALSE);
+#else
+return (ptr_t)GC_find_limit(GC_approx_sp(),TRUE);
+#endif
+}
+#endif
+#ifdef HPUX_STACKBOTTOM
+#include <sys/param.h>
+#include <sys/pstat.h>
+GC_INNER ptr_t GC_get_register_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_RSESTACK){
+return (ptr_t)vm_status.pst_vaddr;
+}
+}
+return (ptr_t)(((word)GC_stackbottom - BACKING_STORE_DISPLACEMENT - 1)
+&~(BACKING_STORE_ALIGNMENT - 1));
+}
+#endif
+#ifdef LINUX_STACKBOTTOM
+#include <sys/types.h>
+#include <sys/stat.h>
+#define STAT_SKIP 27
+#ifdef USE_LIBC_PRIVATES
+EXTERN_C_BEGIN
+#pragma weak __libc_stack_end
+extern ptr_t __libc_stack_end;
+#ifdef IA64
+#pragma weak __libc_ia64_register_backing_store_base
+extern ptr_t __libc_ia64_register_backing_store_base;
+#endif
+EXTERN_C_END
+#endif
+#ifdef IA64
+GC_INNER ptr_t GC_get_register_stack_base(void)
+{
+ptr_t result;
+#ifdef USE_LIBC_PRIVATES
+if (0!=&__libc_ia64_register_backing_store_base
+&&0!=__libc_ia64_register_backing_store_base){
+return __libc_ia64_register_backing_store_base;
+}
+#endif
+result=backing_store_base_from_proc();
+if (0==result){
+result=(ptr_t)GC_find_limit(GC_save_regs_in_stack(),FALSE);
+}
+return result;
+}
+#endif
+STATIC ptr_t GC_linux_main_stack_base(void)
+{
+#ifndef STAT_READ
+#define STAT_BUF_SIZE 4096
+#define STAT_READ read
+#endif
+char stat_buf[STAT_BUF_SIZE];
+int f;
+word result;
+int i,buf_offset=0,len;
+#ifdef USE_LIBC_PRIVATES
+if (0!=&__libc_stack_end&&0!=__libc_stack_end){
+#if defined(IA64)
+if (((word)__libc_stack_end&0xfff)+0x10 < 0x1000){
+return __libc_stack_end+0x10;
+}
+#elif defined(SPARC)
+if (__libc_stack_end!=(ptr_t)(unsigned long)0x1)
+return __libc_stack_end;
+#else
+return __libc_stack_end;
+#endif
+}
+#endif
+f=open("/proc/self/stat",O_RDONLY);
+if (f < 0)
+ABORT("Couldn't read/proc/self/stat");
+len=STAT_READ(f,stat_buf,STAT_BUF_SIZE);
+close(f);
+for (i=0;i < STAT_SKIP;++i){
+while (buf_offset < len&&isspace(stat_buf[buf_offset++])){
+}
+while (buf_offset < len&&!isspace(stat_buf[buf_offset++])){
+}
+}
+while (buf_offset < len&&isspace(stat_buf[buf_offset])){
+buf_offset++;
+}
+for (i=0;buf_offset+i < len;i++){
+if (!isdigit(stat_buf[buf_offset+i]))break;
+}
+if (buf_offset+i>=len)ABORT("Could not parse/proc/self/stat");
+stat_buf[buf_offset+i]='\0';
+result=(word)STRTOULL(&stat_buf[buf_offset],NULL,10);
+if (result < 0x100000||(result&(sizeof(word)- 1))!=0)
+ABORT("Absurd stack bottom value");
+return (ptr_t)result;
+}
+#endif
+#ifdef FREEBSD_STACKBOTTOM
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+STATIC ptr_t GC_freebsd_main_stack_base(void)
+{
+int nm[2]={CTL_KERN,KERN_USRSTACK};
+ptr_t base;
+size_t len=sizeof(ptr_t);
+int r=sysctl(nm,2,&base,&len,NULL,0);
+if (r)ABORT("Error getting main stack base");
+return base;
+}
+#endif
+#if defined(ECOS)||defined(NOSYS)
+ptr_t GC_get_main_stack_base(void)
+{
+return STACKBOTTOM;
+}
+#define GET_MAIN_STACKBASE_SPECIAL
+#elif defined(SYMBIAN)
+EXTERN_C_BEGIN
+extern int GC_get_main_symbian_stack_base(void);
+EXTERN_C_END
+ptr_t GC_get_main_stack_base(void)
+{
+return (ptr_t)GC_get_main_symbian_stack_base();
+}
+#define GET_MAIN_STACKBASE_SPECIAL
+#elif defined(__EMSCRIPTEN__)
+#include <emscripten.h>
+static void*emscripten_stack_base;
+static void scan_stack_cb(void*begin,void*end)
+{
+(void)begin;
+emscripten_stack_base=end;
+}
+ptr_t GC_get_main_stack_base(void)
+{
+emscripten_scan_stack(scan_stack_cb);
+return (ptr_t)emscripten_stack_base;
+}
+#define GET_MAIN_STACKBASE_SPECIAL
+#elif!defined(AMIGA)&&!defined(HAIKU)&&!defined(OS2)&&!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(CYGWIN32)&&!defined(GC_OPENBSD_THREADS)&&(!defined(GC_SOLARIS_THREADS)||defined(_STRICT_STDC))
+#if (defined(HAVE_PTHREAD_ATTR_GET_NP)||defined(HAVE_PTHREAD_GETATTR_NP))&&(defined(THREADS)||defined(USE_GET_STACKBASE_FOR_MAIN))
+#include <pthread.h>
+#ifdef HAVE_PTHREAD_NP_H
+#include <pthread_np.h>
+#endif
+#elif defined(DARWIN)&&!defined(NO_PTHREAD_GET_STACKADDR_NP)
+#include <pthread.h>
+#undef STACKBOTTOM
+#define STACKBOTTOM (ptr_t)pthread_get_stackaddr_np(pthread_self())
+#endif
+ptr_t GC_get_main_stack_base(void)
+{
+ptr_t result;
+#if (defined(HAVE_PTHREAD_ATTR_GET_NP)||defined(HAVE_PTHREAD_GETATTR_NP))&&(defined(USE_GET_STACKBASE_FOR_MAIN)||(defined(THREADS)&&!defined(REDIRECT_MALLOC)))
+pthread_attr_t attr;
+void*stackaddr;
+size_t size;
+#ifdef HAVE_PTHREAD_ATTR_GET_NP
+if (pthread_attr_init(&attr)==0
+&&(pthread_attr_get_np(pthread_self(),&attr)==0
+?TRUE:(pthread_attr_destroy(&attr),FALSE)))
+#else
+if (pthread_getattr_np(pthread_self(),&attr)==0)
+#endif
+{
+if (pthread_attr_getstack(&attr,&stackaddr,&size)==0
+&&stackaddr!=NULL){
+(void)pthread_attr_destroy(&attr);
+#ifdef STACK_GROWS_DOWN
+stackaddr=(char*)stackaddr+size;
+#endif
+return (ptr_t)stackaddr;
+}
+(void)pthread_attr_destroy(&attr);
+}
+WARN("pthread_getattr_np or pthread_attr_getstack failed"
+" for main thread\n",0);
+#endif
+#ifdef STACKBOTTOM
+result=STACKBOTTOM;
+#else
+#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();
+#elif defined(FREEBSD_STACKBOTTOM)
+result=GC_freebsd_main_stack_base();
+#elif defined(HEURISTIC2)
+{
+ptr_t sp=GC_approx_sp();
+#ifdef STACK_GROWS_DOWN
+result=(ptr_t)GC_find_limit(sp,TRUE);
+#if defined(HEURISTIC2_LIMIT)&&!defined(CPPCHECK)
+if ((word)result > (word)HEURISTIC2_LIMIT
+&&(word)sp < (word)HEURISTIC2_LIMIT){
+result=HEURISTIC2_LIMIT;
+}
+#endif
+#else
+result=(ptr_t)GC_find_limit(sp,FALSE);
+#if defined(HEURISTIC2_LIMIT)&&!defined(CPPCHECK)
+if ((word)result < (word)HEURISTIC2_LIMIT
+&&(word)sp > (word)HEURISTIC2_LIMIT){
+result=HEURISTIC2_LIMIT;
+}
+#endif
+#endif
+}
+#elif defined(STACK_NOT_SCANNED)||defined(CPPCHECK)
+result=NULL;
+#else
+#error None of HEURISTIC*and*STACKBOTTOM defined!
+#endif
+#if defined(STACK_GROWS_DOWN)&&!defined(CPPCHECK)
+if (result==0)
+result=(ptr_t)(signed_word)(-sizeof(ptr_t));
+#endif
+#endif
+#if!defined(CPPCHECK)
+GC_ASSERT((word)GC_approx_sp()HOTTER_THAN (word)result);
+#endif
+return(result);
+}
+#define GET_MAIN_STACKBASE_SPECIAL
+#endif
+#if (defined(HAVE_PTHREAD_ATTR_GET_NP)||defined(HAVE_PTHREAD_GETATTR_NP))&&defined(THREADS)&&!defined(HAVE_GET_STACK_BASE)
+#include <pthread.h>
+#ifdef HAVE_PTHREAD_NP_H
+#include <pthread_np.h>
+#endif
+GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base*b)
+{
+pthread_attr_t attr;
+size_t size;
+#ifdef IA64
+DCL_LOCK_STATE;
+#endif
+#ifdef HAVE_PTHREAD_ATTR_GET_NP
+if (pthread_attr_init(&attr)!=0)
+ABORT("pthread_attr_init failed");
+if (pthread_attr_get_np(pthread_self(),&attr)!=0){
+WARN("pthread_attr_get_np failed\n",0);
+(void)pthread_attr_destroy(&attr);
+return GC_UNIMPLEMENTED;
+}
+#else
+if (pthread_getattr_np(pthread_self(),&attr)!=0){
+WARN("pthread_getattr_np failed\n",0);
+return GC_UNIMPLEMENTED;
+}
+#endif
+if (pthread_attr_getstack(&attr,&(b->mem_base),&size)!=0){
+ABORT("pthread_attr_getstack failed");
+}
+(void)pthread_attr_destroy(&attr);
+#ifdef STACK_GROWS_DOWN
+b->mem_base=(char*)(b->mem_base)+size;
+#endif
+#ifdef IA64
+LOCK();
+{
+IF_CANCEL(int cancel_state;)
+ptr_t bsp;
+ptr_t next_stack;
+DISABLE_CANCEL(cancel_state);
+bsp=GC_save_regs_in_stack();
+next_stack=GC_greatest_stack_base_below(bsp);
+if (0==next_stack){
+b->reg_base=GC_find_limit(bsp,FALSE);
+} else {
+b->reg_base=GC_find_limit_with_bound(bsp,FALSE,next_stack);
+}
+RESTORE_CANCEL(cancel_state);
+}
+UNLOCK();
+#endif
+return GC_SUCCESS;
+}
+#define HAVE_GET_STACK_BASE
+#endif
+#if defined(GC_DARWIN_THREADS)&&!defined(NO_PTHREAD_GET_STACKADDR_NP)
+#include <pthread.h>
+GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base*b)
+{
+b->mem_base=pthread_get_stackaddr_np(pthread_self());
+GC_ASSERT((word)GC_approx_sp()HOTTER_THAN (word)b->mem_base);
+return GC_SUCCESS;
+}
+#define HAVE_GET_STACK_BASE
+#endif
+#ifdef GC_OPENBSD_THREADS
+#include <sys/signal.h>
+#include <pthread.h>
+#include <pthread_np.h>
+GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base*sb)
+{
+stack_t stack;
+if (pthread_stackseg_np(pthread_self(),&stack))
+ABORT("pthread_stackseg_np(self)failed");
+sb->mem_base=stack.ss_sp;
+return GC_SUCCESS;
+}
+#define HAVE_GET_STACK_BASE
+#endif
+#if defined(GC_SOLARIS_THREADS)&&!defined(_STRICT_STDC)
+#include <thread.h>
+#include <signal.h>
+#include <pthread.h>
+static pthread_t stackbase_main_self=0;
+static void*stackbase_main_ss_sp=NULL;
+GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base*b)
+{
+stack_t s;
+pthread_t self=pthread_self();
+if (self==stackbase_main_self)
+{
+b->mem_base=stackbase_main_ss_sp;
+GC_ASSERT(b->mem_base!=NULL);
+return GC_SUCCESS;
+}
+if (thr_stksegment(&s)){
+ABORT("thr_stksegment failed");
+}
+GC_ASSERT((word)GC_approx_sp()HOTTER_THAN (word)s.ss_sp);
+if (!stackbase_main_self&&thr_main()!=0)
+{
+stackbase_main_ss_sp=s.ss_sp;
+stackbase_main_self=self;
+}
+b->mem_base=s.ss_sp;
+return GC_SUCCESS;
+}
+#define HAVE_GET_STACK_BASE
+#endif
+#ifdef GC_RTEMS_PTHREADS
+GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base*sb)
+{
+sb->mem_base=rtems_get_stack_bottom();
+return GC_SUCCESS;
+}
+#define HAVE_GET_STACK_BASE
+#endif
+#ifndef HAVE_GET_STACK_BASE
+#ifdef NEED_FIND_LIMIT
+GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base*b)
+{
+IF_CANCEL(int cancel_state;)
+DCL_LOCK_STATE;
+LOCK();
+DISABLE_CANCEL(cancel_state);
+#ifdef STACK_GROWS_DOWN
+b->mem_base=GC_find_limit(GC_approx_sp(),TRUE);
+#ifdef IA64
+b->reg_base=GC_find_limit(GC_save_regs_in_stack(),FALSE);
+#endif
+#else
+b->mem_base=GC_find_limit(GC_approx_sp(),FALSE);
+#endif
+RESTORE_CANCEL(cancel_state);
+UNLOCK();
+return GC_SUCCESS;
+}
+#else
+GC_API int GC_CALL GC_get_stack_base(
+struct GC_stack_base*b GC_ATTR_UNUSED)
+{
+#if defined(GET_MAIN_STACKBASE_SPECIAL)&&!defined(THREADS)&&!defined(IA64)
+b->mem_base=GC_get_main_stack_base();
+return GC_SUCCESS;
+#else
+return GC_UNIMPLEMENTED;
+#endif
+}
+#endif
+#endif
+#ifndef GET_MAIN_STACKBASE_SPECIAL
+ptr_t GC_get_main_stack_base(void)
+{
+struct GC_stack_base sb;
+if (GC_get_stack_base(&sb)!=GC_SUCCESS)
+ABORT("GC_get_stack_base failed");
+GC_ASSERT((word)GC_approx_sp()HOTTER_THAN (word)sb.mem_base);
+return (ptr_t)sb.mem_base;
+}
+#endif
+#ifdef OS2
+void GC_register_data_segments(void)
+{
+PTIB ptib;
+PPIB ppib;
+HMODULE module_handle;
+#define PBUFSIZ 512
+UCHAR path[PBUFSIZ];
+FILE*myexefile;
+struct exe_hdr hdrdos;
+struct e32_exe hdr386;
+struct o32_obj seg;
+int nsegs;
+#if defined(CPPCHECK)
+hdrdos.padding[0]=0;
+hdr386.exe_format_level=0;
+hdr386.os=0;
+hdr386.padding1[0]=0;
+hdr386.padding2[0]=0;
+seg.pagemap=0;
+seg.mapsize=0;
+seg.reserved=0;
+#endif
+if (DosGetInfoBlocks(&ptib,&ppib)!=NO_ERROR){
+ABORT("DosGetInfoBlocks failed");
+}
+module_handle=ppib->pib_hmte;
+if (DosQueryModuleName(module_handle,PBUFSIZ,path)!=NO_ERROR){
+ABORT("DosQueryModuleName failed");
+}
+myexefile=fopen(path,"rb");
+if (myexefile==0){
+ABORT_ARG1("Failed to open executable",":%s",path);
+}
+if (fread((char*)(&hdrdos),1,sizeof(hdrdos),myexefile)
+< sizeof(hdrdos)){
+ABORT_ARG1("Could not read MSDOS header"," from:%s",path);
+}
+if (E_MAGIC(hdrdos)!=EMAGIC){
+ABORT_ARG1("Bad DOS magic number"," in file:%s",path);
+}
+if (fseek(myexefile,E_LFANEW(hdrdos),SEEK_SET)!=0){
+ABORT_ARG1("Bad DOS magic number"," in file:%s",path);
+}
+if (fread((char*)(&hdr386),1,sizeof(hdr386),myexefile)
+< sizeof(hdr386)){
+ABORT_ARG1("Could not read OS/2 header"," from:%s",path);
+}
+if (E32_MAGIC1(hdr386)!=E32MAGIC1||E32_MAGIC2(hdr386)!=E32MAGIC2){
+ABORT_ARG1("Bad OS/2 magic number"," in file:%s",path);
+}
+if (E32_BORDER(hdr386)!=E32LEBO||E32_WORDER(hdr386)!=E32LEWO){
+ABORT_ARG1("Bad byte order in executable"," file:%s",path);
+}
+if (E32_CPU(hdr386)==E32CPU286){
+ABORT_ARG1("GC cannot handle 80286 executables",":%s",path);
+}
+if (fseek(myexefile,E_LFANEW(hdrdos)+E32_OBJTAB(hdr386),
+SEEK_SET)!=0){
+ABORT_ARG1("Seek to object table failed"," in file:%s",path);
+}
+for (nsegs=E32_OBJCNT(hdr386);nsegs > 0;nsegs--){
+int flags;
+if (fread((char*)(&seg),1,sizeof(seg),myexefile)< sizeof(seg)){
+ABORT_ARG1("Could not read obj table entry"," from file:%s",path);
+}
+flags=O32_FLAGS(seg);
+if (!(flags&OBJWRITE))continue;
+if (!(flags&OBJREAD))continue;
+if (flags&OBJINVALID){
+GC_err_printf("Object with invalid pages?\n");
+continue;
+}
+GC_add_roots_inner((ptr_t)O32_BASE(seg),
+(ptr_t)(O32_BASE(seg)+O32_SIZE(seg)),FALSE);
+}
+(void)fclose(myexefile);
+}
+#else
+#if defined(GWW_VDB)
+#ifndef MEM_WRITE_WATCH
+#define MEM_WRITE_WATCH 0x200000
+#endif
+#ifndef WRITE_WATCH_FLAG_RESET
+#define WRITE_WATCH_FLAG_RESET 1
+#endif
+#define GC_ULONG_PTR word
+typedef UINT (WINAPI*GetWriteWatch_type)(
+DWORD,PVOID,GC_ULONG_PTR,
+PVOID*,GC_ULONG_PTR*,PULONG);
+static FARPROC GetWriteWatch_func;
+static DWORD GetWriteWatch_alloc_flag;
+#define GC_GWW_AVAILABLE()(GetWriteWatch_func!=0)
+static void detect_GetWriteWatch(void)
+{
+static GC_bool done;
+HMODULE hK32;
+if (done)
+return;
+#if defined(MPROTECT_VDB)
+{
+char*str=GETENV("GC_USE_GETWRITEWATCH");
+#if defined(GC_PREFER_MPROTECT_VDB)
+if (str==NULL||(*str=='0'&&*(str+1)=='\0')){
+done=TRUE;
+return;
+}
+#else
+if (str!=NULL&&*str=='0'&&*(str+1)=='\0'){
+done=TRUE;
+return;
+}
+#endif
+}
+#endif
+#ifdef MSWINRT_FLAVOR
+{
+MEMORY_BASIC_INFORMATION memInfo;
+SIZE_T result=VirtualQuery(GetProcAddress,
+&memInfo,sizeof(memInfo));
+if (result!=sizeof(memInfo))
+ABORT("Weird VirtualQuery result");
+hK32=(HMODULE)memInfo.AllocationBase;
+}
+#else
+hK32=GetModuleHandle(TEXT("kernel32.dll"));
+#endif
+if (hK32!=(HMODULE)0&&
+(GetWriteWatch_func=GetProcAddress(hK32,"GetWriteWatch"))!=0){
+void*page;
+GC_ASSERT(GC_page_size!=0);
+page=VirtualAlloc(NULL,GC_page_size,MEM_WRITE_WATCH|MEM_RESERVE,
+PAGE_READWRITE);
+if (page!=NULL){
+PVOID pages[16];
+GC_ULONG_PTR count=16;
+DWORD page_size;
+if ((*(GetWriteWatch_type)(word)GetWriteWatch_func)(
+WRITE_WATCH_FLAG_RESET,page,
+GC_page_size,pages,&count,
+&page_size)!=0){
+GetWriteWatch_func=0;
+} else {
+GetWriteWatch_alloc_flag=MEM_WRITE_WATCH;
+}
+VirtualFree(page,0,MEM_RELEASE);
+} else {
+GetWriteWatch_func=0;
+}
+}
+#ifndef SMALL_CONFIG
+if (!GetWriteWatch_func){
+GC_COND_LOG_PRINTF("Did not find a usable GetWriteWatch()\n");
+} else {
+GC_COND_LOG_PRINTF("Using GetWriteWatch()\n");
+}
+#endif
+done=TRUE;
+}
+#else
+#define GetWriteWatch_alloc_flag 0
+#endif
+#if defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32)
+#ifdef MSWIN32
+GC_INNER GC_bool GC_no_win32_dlls=FALSE;
+GC_INNER GC_bool GC_wnt=FALSE;
+GC_INNER void GC_init_win32(void)
+{
+#if defined(_WIN64)||(defined(_MSC_VER)&&_MSC_VER>=1800)
+GC_wnt=TRUE;
+#else
+DWORD v=GetVersion();
+GC_wnt=!(v&0x80000000);
+GC_no_win32_dlls|=((!GC_wnt)&&(v&0xff)<=3);
+#endif
+#ifdef USE_MUNMAP
+if (GC_no_win32_dlls){
+GC_unmap_threshold=0;
+}
+#endif
+}
+STATIC ptr_t GC_least_described_address(ptr_t start)
+{
+MEMORY_BASIC_INFORMATION buf;
+LPVOID limit=GC_sysinfo.lpMinimumApplicationAddress;
+ptr_t p=(ptr_t)((word)start&~(GC_page_size - 1));
+GC_ASSERT(GC_page_size!=0);
+for (;;){
+size_t result;
+LPVOID q=(LPVOID)(p - GC_page_size);
+if ((word)q > (word)p||(word)q < (word)limit)break;
+result=VirtualQuery(q,&buf,sizeof(buf));
+if (result!=sizeof(buf)||buf.AllocationBase==0)break;
+p=(ptr_t)(buf.AllocationBase);
+}
+return p;
+}
+#endif
+#if defined(USE_WINALLOC)&&!defined(REDIRECT_MALLOC)
+STATIC size_t GC_max_root_size=100000;
+STATIC struct GC_malloc_heap_list {
+void*allocation_base;
+struct GC_malloc_heap_list*next;
+}*GC_malloc_heap_l=0;
+STATIC GC_bool GC_is_malloc_heap_base(void*p)
+{
+struct GC_malloc_heap_list*q=GC_malloc_heap_l;
+while (0!=q){
+if (q->allocation_base==p)return TRUE;
+q=q->next;
+}
+return FALSE;
+}
+STATIC void*GC_get_allocation_base(void*p)
+{
+MEMORY_BASIC_INFORMATION buf;
+size_t result=VirtualQuery(p,&buf,sizeof(buf));
+if (result!=sizeof(buf)){
+ABORT("Weird VirtualQuery result");
+}
+return buf.AllocationBase;
+}
+GC_INNER void GC_add_current_malloc_heap(void)
+{
+struct GC_malloc_heap_list*new_l=(struct GC_malloc_heap_list*)
+malloc(sizeof(struct GC_malloc_heap_list));
+void*candidate;
+if (NULL==new_l)return;
+candidate=GC_get_allocation_base(new_l);
+if (GC_is_malloc_heap_base(candidate)){
+size_t req_size=10000;
+do {
+void*p=malloc(req_size);
+if (0==p){
+free(new_l);
+return;
+}
+candidate=GC_get_allocation_base(p);
+free(p);
+req_size*=2;
+} while (GC_is_malloc_heap_base(candidate)
+&&req_size < GC_max_root_size/10&&req_size < 500000);
+if (GC_is_malloc_heap_base(candidate)){
+free(new_l);
+return;
+}
+}
+GC_COND_LOG_PRINTF("Found new system malloc AllocationBase at %p\n",
+candidate);
+new_l->allocation_base=candidate;
+new_l->next=GC_malloc_heap_l;
+GC_malloc_heap_l=new_l;
+}
+STATIC void GC_free_malloc_heap_list(void)
+{
+struct GC_malloc_heap_list*q=GC_malloc_heap_l;
+GC_malloc_heap_l=NULL;
+while (q!=NULL){
+struct GC_malloc_heap_list*next=q->next;
+free(q);
+q=next;
+}
+}
+#endif
+GC_INNER GC_bool GC_is_heap_base(void*p)
+{
+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 < (int)GC_n_heap_bases;i++){
+if (GC_heap_bases[i]==p)return TRUE;
+}
+return FALSE;
+}
+#ifdef MSWIN32
+STATIC void GC_register_root_section(ptr_t static_root)
+{
+MEMORY_BASIC_INFORMATION buf;
+LPVOID p;
+char*base;
+char*limit;
+if (!GC_no_win32_dlls)return;
+p=base=limit=GC_least_described_address(static_root);
+while ((word)p < (word)GC_sysinfo.lpMaximumApplicationAddress){
+size_t result=VirtualQuery(p,&buf,sizeof(buf));
+char*new_limit;
+DWORD protect;
+if (result!=sizeof(buf)||buf.AllocationBase==0
+||GC_is_heap_base(buf.AllocationBase))break;
+new_limit=(char*)p+buf.RegionSize;
+protect=buf.Protect;
+if (buf.State==MEM_COMMIT
+&&is_writable(protect)){
+if ((char*)p==limit){
+limit=new_limit;
+} else {
+if (base!=limit)GC_add_roots_inner(base,limit,FALSE);
+base=(char*)p;
+limit=new_limit;
+}
+}
+if ((word)p > (word)new_limit)break;
+p=(LPVOID)new_limit;
+}
+if (base!=limit)GC_add_roots_inner(base,limit,FALSE);
+}
+#endif
+void GC_register_data_segments(void)
+{
+#ifdef MSWIN32
+GC_register_root_section((ptr_t)&GC_pages_executable);
+#endif
+}
+#else
+#if (defined(SVR4)||defined(AIX)||defined(DGUX)||(defined(LINUX)&&defined(SPARC)))&&!defined(PCR)
+ptr_t GC_SysVGetDataStart(size_t max_page_size,ptr_t etext_addr)
+{
+word text_end=((word)(etext_addr)+sizeof(word)- 1)
+&~(word)(sizeof(word)- 1);
+word next_page=((text_end+(word)max_page_size - 1)
+&~((word)max_page_size - 1));
+word page_offset=(text_end&((word)max_page_size - 1));
+volatile ptr_t result=(char*)(next_page+page_offset);
+GC_setup_temporary_fault_handler();
+if (SETJMP(GC_jmp_buf)==0){
+#ifdef AO_HAVE_fetch_and_add
+volatile AO_t zero=0;
+(void)AO_fetch_and_add((volatile AO_t*)result,zero);
+#else
+char v=*result;
+#if defined(CPPCHECK)
+GC_noop1((word)&v);
+#endif
+*result=v;
+#endif
+GC_reset_fault_handler();
+} else {
+GC_reset_fault_handler();
+result=(char*)GC_find_limit(DATAEND,FALSE);
+}
+return ( ptr_t)result;
+}
+#endif
+#ifdef DATASTART_USES_BSDGETDATASTART
+GC_INNER ptr_t GC_FreeBSDGetDataStart(size_t max_page_size,
+ptr_t etext_addr)
+{
+word text_end=((word)(etext_addr)+sizeof(word)- 1)
+&~(word)(sizeof(word)- 1);
+volatile word next_page=(text_end+(word)max_page_size - 1)
+&~((word)max_page_size - 1);
+volatile ptr_t result=(ptr_t)text_end;
+GC_setup_temporary_fault_handler();
+if (SETJMP(GC_jmp_buf)==0){
+for (;next_page < (word)DATAEND;next_page+=(word)max_page_size)
+*(volatile char*)next_page;
+GC_reset_fault_handler();
+} else {
+GC_reset_fault_handler();
+result=(ptr_t)GC_find_limit(DATAEND,FALSE);
+}
+return(result);
+}
+#endif
+#ifdef AMIGA
+#define GC_AMIGA_DS
+#undef GC_AMIGA_DS
+#elif defined(OPENBSD)
+void GC_register_data_segments(void)
+{
+ptr_t region_start=DATASTART;
+if ((word)region_start - 1U>=(word)DATAEND)
+ABORT_ARG2("Wrong DATASTART/END pair",
+":%p .. %p",(void*)region_start,(void*)DATAEND);
+for (;;){
+#ifdef GC_OPENBSD_UTHREADS
+ptr_t region_end=GC_find_limit_openbsd(region_start,DATAEND);
+#else
+ptr_t region_end=GC_find_limit_with_bound(region_start,TRUE,DATAEND);
+#endif
+GC_add_roots_inner(region_start,region_end,FALSE);
+if ((word)region_end>=(word)DATAEND)
+break;
+region_start=GC_skip_hole_openbsd(region_end,DATAEND);
+}
+}
+#else
+#if!defined(PCR)&&!defined(MACOS)&&defined(REDIRECT_MALLOC)&&defined(GC_SOLARIS_THREADS)
+EXTERN_C_BEGIN
+extern caddr_t sbrk(int);
+EXTERN_C_END
+#endif
+void GC_register_data_segments(void)
+{
+#if!defined(PCR)&&!defined(MACOS)
+#if defined(REDIRECT_MALLOC)&&defined(GC_SOLARIS_THREADS)
+GC_ASSERT(DATASTART);
+{
+ptr_t p=(ptr_t)sbrk(0);
+if ((word)DATASTART < (word)p)
+GC_add_roots_inner(DATASTART,p,FALSE);
+}
+#else
+if ((word)DATASTART - 1U>=(word)DATAEND){
+ABORT_ARG2("Wrong DATASTART/END pair",
+":%p .. %p",(void*)DATASTART,(void*)DATAEND);
+}
+GC_add_roots_inner(DATASTART,DATAEND,FALSE);
+#ifdef GC_HAVE_DATAREGION2
+if ((word)DATASTART2 - 1U>=(word)DATAEND2)
+ABORT_ARG2("Wrong DATASTART/END2 pair",
+":%p .. %p",(void*)DATASTART2,(void*)DATAEND2);
+GC_add_roots_inner(DATASTART2,DATAEND2,FALSE);
+#endif
+#endif
+#endif
+#if defined(MACOS)
+{
+#if defined(THINK_C)
+extern void*GC_MacGetDataStart(void);
+GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
+(ptr_t)LMGetCurrentA5(),FALSE);
+#else
+#if defined(__MWERKS__)
+#if!__POWERPC__
+extern void*GC_MacGetDataStart(void);
+#if __option(far_data)
+extern void*GC_MacGetDataEnd(void);
+#endif
+GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
+(ptr_t)LMGetCurrentA5(),FALSE);
+#if __option(far_data)
+GC_add_roots_inner((ptr_t)LMGetCurrentA5(),
+(ptr_t)GC_MacGetDataEnd(),FALSE);
+#endif
+#else
+extern char __data_start__[],__data_end__[];
+GC_add_roots_inner((ptr_t)&__data_start__,
+(ptr_t)&__data_end__,FALSE);
+#endif
+#endif
+#endif
+}
+#endif
+}
+#endif
+#endif
+#endif
+#if!defined(OS2)&&!defined(PCR)&&!defined(AMIGA)&&!defined(USE_WINALLOC)&&!defined(MACOS)&&!defined(DOS4GW)&&!defined(NINTENDO_SWITCH)&&!defined(NONSTOP)&&!defined(SN_TARGET_ORBIS)&&!defined(SN_TARGET_PS3)&&!defined(SN_TARGET_PSP2)&&!defined(RTEMS)&&!defined(__CC_ARM)
+#define SBRK_ARG_T ptrdiff_t
+#if defined(MMAP_SUPPORTED)
+#ifdef USE_MMAP_FIXED
+#define GC_MMAP_FLAGS MAP_FIXED|MAP_PRIVATE
+#else
+#define GC_MMAP_FLAGS MAP_PRIVATE
+#endif
+#ifdef USE_MMAP_ANON
+#define zero_fd -1
+#if defined(MAP_ANONYMOUS)&&!defined(CPPCHECK)
+#define OPT_MAP_ANON MAP_ANONYMOUS
+#else
+#define OPT_MAP_ANON MAP_ANON
+#endif
+#else
+static int zero_fd=-1;
+#define OPT_MAP_ANON 0
+#endif
+#ifndef MSWIN_XBOX1
+#if defined(SYMBIAN)&&!defined(USE_MMAP_ANON)
+EXTERN_C_BEGIN
+extern char*GC_get_private_path_and_zero_file(void);
+EXTERN_C_END
+#endif
+STATIC ptr_t GC_unix_mmap_get_mem(size_t bytes)
+{
+void*result;
+static ptr_t last_addr=HEAP_START;
+#ifndef USE_MMAP_ANON
+static GC_bool initialized=FALSE;
+if (!EXPECT(initialized,TRUE)){
+#ifdef SYMBIAN
+char*path=GC_get_private_path_and_zero_file();
+if (path!=NULL){
+zero_fd=open(path,O_RDWR|O_CREAT,0644);
+free(path);
+}
+#else
+zero_fd=open("/dev/zero",O_RDONLY);
+#endif
+if (zero_fd==-1)
+ABORT("Could not open/dev/zero");
+if (fcntl(zero_fd,F_SETFD,FD_CLOEXEC)==-1)
+WARN("Could not set FD_CLOEXEC for/dev/zero\n",0);
+initialized=TRUE;
+}
+#endif
+GC_ASSERT(GC_page_size!=0);
+if (bytes&(GC_page_size - 1))ABORT("Bad GET_MEM arg");
+result=mmap(last_addr,bytes,(PROT_READ|PROT_WRITE)
+|(GC_pages_executable?PROT_EXEC:0),
+GC_MMAP_FLAGS|OPT_MAP_ANON,zero_fd,0);
+#undef IGNORE_PAGES_EXECUTABLE
+if (EXPECT(MAP_FAILED==result,FALSE)){
+if (HEAP_START==last_addr&&GC_pages_executable&&EACCES==errno)
+ABORT("Cannot allocate executable pages");
+return NULL;
+}
+last_addr=(ptr_t)(((word)result+bytes+GC_page_size - 1)
+&~(GC_page_size - 1));
+#if!defined(LINUX)
+if (last_addr==0){
+munmap(result,~GC_page_size - (size_t)result+1);
+return GC_unix_mmap_get_mem(bytes);
+}
+#else
+GC_ASSERT(last_addr!=0);
+#endif
+if (((word)result % HBLKSIZE)!=0)
+ABORT(
+"GC_unix_get_mem:Memory returned by mmap is not aligned to HBLKSIZE.");
+return((ptr_t)result);
+}
+#endif
+#endif
+#if defined(USE_MMAP)
+ptr_t GC_unix_get_mem(size_t bytes)
+{
+return GC_unix_mmap_get_mem(bytes);
+}
+#else
+STATIC ptr_t GC_unix_sbrk_get_mem(size_t bytes)
+{
+ptr_t result;
+#ifdef IRIX5
+__LOCK_MALLOC();
+#endif
+{
+ptr_t cur_brk=(ptr_t)sbrk(0);
+SBRK_ARG_T lsbs=(word)cur_brk&(GC_page_size-1);
+GC_ASSERT(GC_page_size!=0);
+if ((SBRK_ARG_T)bytes < 0){
+result=0;
+goto out;
+}
+if (lsbs!=0){
+if((ptr_t)sbrk((SBRK_ARG_T)GC_page_size - lsbs)==(ptr_t)(-1)){
+result=0;
+goto out;
+}
+}
+#ifdef ADD_HEAP_GUARD_PAGES
+{
+ptr_t guard=(ptr_t)sbrk((SBRK_ARG_T)GC_page_size);
+if (mprotect(guard,GC_page_size,PROT_NONE)!=0)
+ABORT("ADD_HEAP_GUARD_PAGES:mprotect failed");
+}
+#endif
+result=(ptr_t)sbrk((SBRK_ARG_T)bytes);
+if (result==(ptr_t)(-1))result=0;
+}
+out:
+#ifdef IRIX5
+__UNLOCK_MALLOC();
+#endif
+return(result);
+}
+ptr_t GC_unix_get_mem(size_t bytes)
+{
+#if defined(MMAP_SUPPORTED)
+static GC_bool sbrk_failed=FALSE;
+ptr_t result=0;
+if (GC_pages_executable){
+return GC_unix_mmap_get_mem(bytes);
+}
+if (!sbrk_failed)result=GC_unix_sbrk_get_mem(bytes);
+if (0==result){
+sbrk_failed=TRUE;
+result=GC_unix_mmap_get_mem(bytes);
+}
+if (0==result){
+result=GC_unix_sbrk_get_mem(bytes);
+}
+return result;
+#else
+return GC_unix_sbrk_get_mem(bytes);
+#endif
+}
+#endif
+#endif
+#ifdef OS2
+void*os2_alloc(size_t bytes)
+{
+void*result;
+if (DosAllocMem(&result,bytes,(PAG_READ|PAG_WRITE|PAG_COMMIT)
+|(GC_pages_executable?PAG_EXECUTE:0))
+!=NO_ERROR){
+return(0);
+}
+if (result==0)return(os2_alloc(bytes));
+return(result);
+}
+#endif
+#ifdef MSWIN_XBOX1
+ptr_t GC_durango_get_mem(size_t bytes)
+{
+if (0==bytes)return NULL;
+return (ptr_t)VirtualAlloc(NULL,bytes,MEM_COMMIT|MEM_TOP_DOWN,
+PAGE_READWRITE);
+}
+#elif defined(MSWINCE)
+ptr_t GC_wince_get_mem(size_t bytes)
+{
+ptr_t result=0;
+word i;
+GC_ASSERT(GC_page_size!=0);
+bytes=ROUNDUP_PAGESIZE(bytes);
+for (i=0;i < GC_n_heap_bases;i++){
+if (((word)(-(signed_word)GC_heap_lengths[i])
+&(GC_sysinfo.dwAllocationGranularity-1))
+>=bytes){
+result=GC_heap_bases[i]+GC_heap_lengths[i];
+break;
+}
+}
+if (i==GC_n_heap_bases){
+size_t res_bytes=
+SIZET_SAT_ADD(bytes,(size_t)GC_sysinfo.dwAllocationGranularity-1)
+&~((size_t)GC_sysinfo.dwAllocationGranularity-1);
+result=(ptr_t)VirtualAlloc(NULL,res_bytes,
+MEM_RESERVE|MEM_TOP_DOWN,
+GC_pages_executable?PAGE_EXECUTE_READWRITE:
+PAGE_READWRITE);
+if (HBLKDISPL(result)!=0)ABORT("Bad VirtualAlloc result");
+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;
+GC_heap_lengths[GC_n_heap_bases]=0;
+GC_n_heap_bases++;
+}
+result=(ptr_t)VirtualAlloc(result,bytes,MEM_COMMIT,
+GC_pages_executable?PAGE_EXECUTE_READWRITE:
+PAGE_READWRITE);
+#undef IGNORE_PAGES_EXECUTABLE
+if (result!=NULL){
+if (HBLKDISPL(result)!=0)ABORT("Bad VirtualAlloc result");
+GC_heap_lengths[i]+=bytes;
+}
+return(result);
+}
+#elif (defined(USE_WINALLOC)&&!defined(MSWIN_XBOX1))||defined(CYGWIN32)
+#ifdef USE_GLOBAL_ALLOC
+#define GLOBAL_ALLOC_TEST 1
+#else
+#define GLOBAL_ALLOC_TEST GC_no_win32_dlls
+#endif
+#if (defined(GC_USE_MEM_TOP_DOWN)&&defined(USE_WINALLOC))||defined(CPPCHECK)
+DWORD GC_mem_top_down=MEM_TOP_DOWN;
+#else
+#define GC_mem_top_down 0
+#endif
+ptr_t GC_win32_get_mem(size_t bytes)
+{
+ptr_t result;
+#ifndef USE_WINALLOC
+result=GC_unix_get_mem(bytes);
+#else
+#if defined(MSWIN32)&&!defined(MSWINRT_FLAVOR)
+if (GLOBAL_ALLOC_TEST){
+result=(ptr_t)GlobalAlloc(0,SIZET_SAT_ADD(bytes,HBLKSIZE));
+result=(ptr_t)(((word)result+HBLKSIZE - 1)
+&~(word)(HBLKSIZE - 1));
+} else
+#endif
+{
+#ifdef MPROTECT_VDB
+#ifdef GWW_VDB
+#define VIRTUAL_ALLOC_PAD (GC_GWW_AVAILABLE()?0:1)
+#else
+#define VIRTUAL_ALLOC_PAD 1
+#endif
+#else
+#define VIRTUAL_ALLOC_PAD 0
+#endif
+result=(ptr_t)VirtualAlloc(NULL,
+SIZET_SAT_ADD(bytes,VIRTUAL_ALLOC_PAD),
+GetWriteWatch_alloc_flag
+|(MEM_COMMIT|MEM_RESERVE)
+|GC_mem_top_down,
+GC_pages_executable?PAGE_EXECUTE_READWRITE:
+PAGE_READWRITE);
+#undef IGNORE_PAGES_EXECUTABLE
+}
+#endif
+if (HBLKDISPL(result)!=0)ABORT("Bad VirtualAlloc result");
+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
+#if defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32)||defined(MSWIN_XBOX1)
+GC_API void GC_CALL GC_win32_free_heap(void)
+{
+#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
+#else
+GlobalFree(GC_heap_bases[GC_n_heap_bases]);
+#endif
+GC_heap_bases[GC_n_heap_bases]=0;
+}
+return;
+}
+#endif
+#ifndef CYGWIN32
+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
+#ifdef AMIGA
+#define GC_AMIGA_AM
+#undef GC_AMIGA_AM
+#endif
+#if defined(HAIKU)
+#include <stdlib.h>
+ptr_t GC_haiku_get_mem(size_t bytes)
+{
+void*mem;
+GC_ASSERT(GC_page_size!=0);
+if (posix_memalign(&mem,GC_page_size,bytes)==0)
+return mem;
+return NULL;
+}
+#endif
+#ifdef USE_MUNMAP
+#if!defined(NN_PLATFORM_CTR)&&!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(MSWIN_XBOX1)
+#include <unistd.h>
+#ifdef SN_TARGET_PS3
+#include <sys/memory.h>
+#else
+#include <sys/mman.h>
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif
+STATIC ptr_t GC_unmap_start(ptr_t start,size_t bytes)
+{
+ptr_t result=(ptr_t)(((word)start+GC_page_size - 1)
+&~(GC_page_size - 1));
+GC_ASSERT(GC_page_size!=0);
+if ((word)(result+GC_page_size)> (word)(start+bytes))return 0;
+return result;
+}
+GC_INNER void GC_unmap(ptr_t start,size_t bytes)
+{
+ptr_t start_addr=GC_unmap_start(start,bytes);
+ptr_t end_addr=GC_unmap_end(start,bytes);
+word len=end_addr - start_addr;
+if (0==start_addr)return;
+#ifdef USE_WINALLOC
+while (len!=0){
+MEMORY_BASIC_INFORMATION mem_info;
+word free_len;
+if (VirtualQuery(start_addr,&mem_info,sizeof(mem_info))
+!=sizeof(mem_info))
+ABORT("Weird VirtualQuery result");
+free_len=(len < mem_info.RegionSize)?len:mem_info.RegionSize;
+if (!VirtualFree(start_addr,free_len,MEM_DECOMMIT))
+ABORT("VirtualFree failed");
+GC_unmapped_bytes+=free_len;
+start_addr+=free_len;
+len-=free_len;
+}
+#elif defined(SN_TARGET_PS3)
+ps3_free_mem(start_addr,len);
+#else
+{
+#if defined(AIX)||defined(CYGWIN32)||defined(HAIKU)||defined(HPUX)
+if (mprotect(start_addr,len,PROT_NONE))
+ABORT("mprotect(PROT_NONE)failed");
+#elif defined(__EMSCRIPTEN__)
+#else
+void*result=mmap(start_addr,len,PROT_NONE,
+MAP_PRIVATE|MAP_FIXED|OPT_MAP_ANON,
+zero_fd,0);
+if (result!=(void*)start_addr)
+ABORT("mmap(PROT_NONE)failed");
+#if defined(CPPCHECK)||defined(LINT2)
+GC_noop1((word)result);
+#endif
+#endif
+}
+GC_unmapped_bytes+=len;
+#endif
+}
+GC_INNER void GC_remap(ptr_t start,size_t bytes)
+{
+ptr_t start_addr=GC_unmap_start(start,bytes);
+ptr_t end_addr=GC_unmap_end(start,bytes);
+word len=end_addr - start_addr;
+if (0==start_addr)return;
+#ifdef USE_WINALLOC
+while (len!=0){
+MEMORY_BASIC_INFORMATION mem_info;
+word alloc_len;
+ptr_t result;
+if (VirtualQuery(start_addr,&mem_info,sizeof(mem_info))
+!=sizeof(mem_info))
+ABORT("Weird VirtualQuery result");
+alloc_len=(len < mem_info.RegionSize)?len:mem_info.RegionSize;
+result=(ptr_t)VirtualAlloc(start_addr,alloc_len,MEM_COMMIT,
+GC_pages_executable
+?PAGE_EXECUTE_READWRITE
+:PAGE_READWRITE);
+if (result!=start_addr){
+if (GetLastError()==ERROR_NOT_ENOUGH_MEMORY||
+GetLastError()==ERROR_OUTOFMEMORY){
+ABORT("Not enough memory to process remapping");
+} else {
+ABORT("VirtualAlloc remapping failed");
+}
+}
+#ifdef LINT2
+GC_noop1((word)result);
+#endif
+GC_unmapped_bytes-=alloc_len;
+start_addr+=alloc_len;
+len-=alloc_len;
+}
+#else
+{
+#if defined(NACL)||defined(NETBSD)
+void*result=mmap(start_addr,len,(PROT_READ|PROT_WRITE)
+|(GC_pages_executable?PROT_EXEC:0),
+MAP_PRIVATE|MAP_FIXED|OPT_MAP_ANON,
+zero_fd,0);
+if (result!=(void*)start_addr)
+ABORT("mmap as mprotect failed");
+#if defined(CPPCHECK)||defined(LINT2)
+GC_noop1((word)result);
+#endif
+#else
+if (mprotect(start_addr,len,(PROT_READ|PROT_WRITE)
+|(GC_pages_executable?PROT_EXEC:0))!=0){
+ABORT_ARG3("mprotect remapping failed",
+" at %p (length %lu),errcode=%d",
+(void*)start_addr,(unsigned long)len,errno);
+}
+#endif
+}
+#undef IGNORE_PAGES_EXECUTABLE
+GC_unmapped_bytes-=len;
+#endif
+}
+GC_INNER void GC_unmap_gap(ptr_t start1,size_t bytes1,ptr_t start2,
+size_t bytes2)
+{
+ptr_t start1_addr=GC_unmap_start(start1,bytes1);
+ptr_t end1_addr=GC_unmap_end(start1,bytes1);
+ptr_t start2_addr=GC_unmap_start(start2,bytes2);
+ptr_t start_addr=end1_addr;
+ptr_t end_addr=start2_addr;
+size_t len;
+GC_ASSERT(start1+bytes1==start2);
+if (0==start1_addr)start_addr=GC_unmap_start(start1,bytes1+bytes2);
+if (0==start2_addr)end_addr=GC_unmap_end(start1,bytes1+bytes2);
+if (0==start_addr)return;
+len=end_addr - start_addr;
+#ifdef USE_WINALLOC
+while (len!=0){
+MEMORY_BASIC_INFORMATION mem_info;
+word free_len;
+if (VirtualQuery(start_addr,&mem_info,sizeof(mem_info))
+!=sizeof(mem_info))
+ABORT("Weird VirtualQuery result");
+free_len=(len < mem_info.RegionSize)?len:mem_info.RegionSize;
+if (!VirtualFree(start_addr,free_len,MEM_DECOMMIT))
+ABORT("VirtualFree failed");
+GC_unmapped_bytes+=free_len;
+start_addr+=free_len;
+len-=free_len;
+}
+#else
+if (len!=0){
+#if defined(AIX)||defined(CYGWIN32)||defined(HAIKU)||defined(HPUX)
+if (mprotect(start_addr,len,PROT_NONE))
+ABORT("mprotect(PROT_NONE)failed");
+#else
+void*result=mmap(start_addr,len,PROT_NONE,
+MAP_PRIVATE|MAP_FIXED|OPT_MAP_ANON,
+zero_fd,0);
+if (result!=(void*)start_addr)
+ABORT("mmap(PROT_NONE)failed");
+#if defined(CPPCHECK)||defined(LINT2)
+GC_noop1((word)result);
+#endif
+#endif
+GC_unmapped_bytes+=len;
+}
+#endif
+}
+#endif
+#ifndef THREADS
+#if defined(__EMSCRIPTEN__)
+static void scan_regs_cb(void*begin,void*end)
+{
+GC_push_all_stack((ptr_t)begin,(ptr_t)end);
+}
+STATIC void GC_CALLBACK GC_default_push_other_roots(void)
+{
+emscripten_scan_registers(scan_regs_cb);
+}
+#else
+#define GC_default_push_other_roots 0
+#endif
+#else
+#ifdef PCR
+PCR_ERes GC_push_thread_stack(PCR_Th_T*t,PCR_Any dummy)
+{
+struct PCR_ThCtl_TInfoRep info;
+PCR_ERes result;
+info.ti_stkLow=info.ti_stkHi=0;
+result=PCR_ThCtl_GetInfo(t,&info);
+GC_push_all_stack((ptr_t)(info.ti_stkLow),(ptr_t)(info.ti_stkHi));
+return(result);
+}
+PCR_ERes GC_push_old_obj(void*p,size_t size,PCR_Any data)
+{
+GC_push_all_stack((ptr_t)p,(ptr_t)p+size);
+return(PCR_ERes_okay);
+}
+extern struct PCR_MM_ProcsRep*GC_old_allocator;
+STATIC void GC_CALLBACK GC_default_push_other_roots(void)
+{
+if ((*(GC_old_allocator->mmp_enumerate))(PCR_Bool_false,
+GC_push_old_obj,0)
+!=PCR_ERes_okay){
+ABORT("Old object enumeration failed");
+}
+if (PCR_ERes_IsErr(
+PCR_ThCtl_ApplyToAllOtherThreads(GC_push_thread_stack,0))
+||PCR_ERes_IsErr(GC_push_thread_stack(PCR_Th_CurrThread(),0))){
+ABORT("Thread stack marking failed");
+}
+}
+#elif defined(SN_TARGET_PS3)
+STATIC void GC_CALLBACK GC_default_push_other_roots(void)
+{
+ABORT("GC_default_push_other_roots is not implemented");
+}
+void GC_push_thread_structures(void)
+{
+ABORT("GC_push_thread_structures is not implemented");
+}
+#else
+STATIC void GC_CALLBACK GC_default_push_other_roots(void)
+{
+GC_push_all_stacks();
+}
+#endif
+#endif
+GC_push_other_roots_proc GC_push_other_roots=GC_default_push_other_roots;
+GC_API void GC_CALL GC_set_push_other_roots(GC_push_other_roots_proc fn)
+{
+GC_push_other_roots=fn;
+}
+GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void)
+{
+return GC_push_other_roots;
+}
+#if (defined(CHECKSUMS)&&defined(GWW_VDB))||defined(PROC_VDB)
+STATIC void GC_or_pages(page_hash_table pht1,page_hash_table pht2)
+{
+unsigned i;
+for (i=0;i < PHT_SIZE;i++)pht1[i]|=pht2[i];
+}
+#endif
+#ifdef GWW_VDB
+#define GC_GWW_BUF_LEN (MAXHINCR*HBLKSIZE/4096)
+static PVOID gww_buf[GC_GWW_BUF_LEN];
+#ifndef MPROTECT_VDB
+#define GC_gww_dirty_init GC_dirty_init
+#endif
+GC_INNER GC_bool GC_gww_dirty_init(void)
+{
+detect_GetWriteWatch();
+return GC_GWW_AVAILABLE();
+}
+GC_INLINE void GC_gww_read_dirty(GC_bool output_unneeded)
+{
+word i;
+if (!output_unneeded)
+BZERO(GC_grungy_pages,sizeof(GC_grungy_pages));
+for (i=0;i!=GC_n_heap_sects;++i){
+GC_ULONG_PTR count;
+do {
+PVOID*pages=gww_buf;
+DWORD page_size;
+count=GC_GWW_BUF_LEN;
+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;
+size_t nblocks=divHBLKSZ(GC_heap_sects[i].hs_bytes);
+if (i!=0&&last_warned!=start&&warn_count++< 5){
+last_warned=start;
+WARN("GC_gww_read_dirty unexpectedly failed at %p:"
+"Falling back to marking all pages dirty\n",start);
+}
+if (!output_unneeded){
+unsigned j;
+for (j=0;j < nblocks;++j){
+word hash=PHT_HASH(start+j);
+set_pht_entry_from_index(GC_grungy_pages,hash);
+}
+}
+count=1;
+} else if (!output_unneeded){
+PVOID*pages_end=pages+count;
+while (pages!=pages_end){
+struct hblk*h=(struct hblk*)*pages++;
+struct hblk*h_end=(struct hblk*)((char*)h+page_size);
+do {
+set_pht_entry_from_index(GC_grungy_pages,PHT_HASH(h));
+} while ((word)(++h)< (word)h_end);
+}
+}
+} while (count==GC_GWW_BUF_LEN);
+}
+#ifdef CHECKSUMS
+GC_ASSERT(!output_unneeded);
+GC_or_pages(GC_written_pages,GC_grungy_pages);
+#endif
+}
+#else
+#define GC_GWW_AVAILABLE()FALSE
+#endif
+#ifdef DEFAULT_VDB
+GC_INNER GC_bool GC_dirty_init(void)
+{
+GC_VERBOSE_LOG_PRINTF("Initializing DEFAULT_VDB...\n");
+return TRUE;
+}
+#endif
+#ifndef GC_DISABLE_INCREMENTAL
+#if!defined(THREADS)||defined(HAVE_LOCKFREE_AO_OR)
+#define async_set_pht_entry_from_index(db,index)set_pht_entry_from_index_concurrent(db,index)
+#elif defined(AO_HAVE_test_and_set_acquire)
+GC_INNER volatile AO_TS_t GC_fault_handler_lock=AO_TS_INITIALIZER;
+static void async_set_pht_entry_from_index(volatile page_hash_table db,
+size_t index)
+{
+GC_acquire_dirty_lock();
+set_pht_entry_from_index(db,index);
+GC_release_dirty_lock();
+}
+#else
+#error No test_and_set operation:Introduces a race.
+#endif
+#endif
+#ifdef MPROTECT_VDB
+#ifdef DARWIN
+#include <mach/vm_map.h>
+STATIC mach_port_t GC_task_self=0;
+#define PROTECT(addr,len)if (vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len),FALSE,VM_PROT_READ|(GC_pages_executable?VM_PROT_EXECUTE:0))==KERN_SUCCESS){} else ABORT("vm_protect(PROTECT)failed")
+#define UNPROTECT(addr,len)if (vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len),FALSE,(VM_PROT_READ|VM_PROT_WRITE)|(GC_pages_executable?VM_PROT_EXECUTE:0))==KERN_SUCCESS){} else ABORT("vm_protect(UNPROTECT)failed")
+#elif!defined(USE_WINALLOC)
+#include <sys/mman.h>
+#include <signal.h>
+#if!defined(CYGWIN32)&&!defined(HAIKU)
+#include <sys/syscall.h>
+#endif
+#define PROTECT(addr,len)if (mprotect((caddr_t)(addr),(size_t)(len),PROT_READ|(GC_pages_executable?PROT_EXEC:0))>=0){ } else ABORT("mprotect failed")
+#define UNPROTECT(addr,len)if (mprotect((caddr_t)(addr),(size_t)(len),(PROT_READ|PROT_WRITE)|(GC_pages_executable?PROT_EXEC:0))>=0){ } else ABORT(GC_pages_executable?"un-mprotect executable page failed" " (probably disabled by OS)":"un-mprotect failed")
+#undef IGNORE_PAGES_EXECUTABLE
+#else
+#ifndef MSWINCE
+#include <signal.h>
+#endif
+static DWORD protect_junk;
+#define PROTECT(addr,len)if (VirtualProtect((addr),(len),GC_pages_executable?PAGE_EXECUTE_READ:PAGE_READONLY,&protect_junk)){ } else ABORT_ARG1("VirtualProtect failed",":errcode=0x%X",(unsigned)GetLastError())
+#define UNPROTECT(addr,len)if (VirtualProtect((addr),(len),GC_pages_executable?PAGE_EXECUTE_READWRITE:PAGE_READWRITE,&protect_junk)){ } else ABORT("un-VirtualProtect failed")
+#endif
+#if defined(MSWIN32)
+typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_HNDLR_PTR;
+#undef SIG_DFL
+#define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER)((signed_word)-1)
+#elif defined(MSWINCE)
+typedef LONG (WINAPI*SIG_HNDLR_PTR)(struct _EXCEPTION_POINTERS*);
+#undef SIG_DFL
+#define SIG_DFL (SIG_HNDLR_PTR)(-1)
+#elif defined(DARWIN)
+typedef void (*SIG_HNDLR_PTR)();
+#else
+typedef void (*SIG_HNDLR_PTR)(int,siginfo_t*,void*);
+typedef void (*PLAIN_HNDLR_PTR)(int);
+#endif
+#if defined(__GLIBC__)
+#if __GLIBC__ < 2||__GLIBC__==2&&__GLIBC_MINOR__ < 2
+#error glibc too old?
+#endif
+#endif
+#ifndef DARWIN
+STATIC SIG_HNDLR_PTR GC_old_segv_handler=0;
+#if defined(FREEBSD)||defined(HPUX)||defined(HURD)||defined(LINUX)
+STATIC SIG_HNDLR_PTR GC_old_bus_handler=0;
+#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
+#endif
+#ifdef THREADS
+GC_ATTR_NO_SANITIZE_THREAD
+static GC_bool is_header_found_async(void*addr)
+{
+#ifdef HASH_TL
+hdr*result;
+GET_HDR((ptr_t)addr,result);
+return result!=NULL;
+#else
+return HDR_INNER(addr)!=NULL;
+#endif
+}
+#else
+#define is_header_found_async(addr)(HDR(addr)!=NULL)
+#endif
+#ifndef DARWIN
+#if!defined(MSWIN32)&&!defined(MSWINCE)
+#include <errno.h>
+#if defined(FREEBSD)||defined(HURD)||defined(HPUX)
+#define SIG_OK (sig==SIGBUS||sig==SIGSEGV)
+#else
+#define SIG_OK (sig==SIGSEGV)
+#endif
+#if defined(FREEBSD)
+#ifndef SEGV_ACCERR
+#define SEGV_ACCERR 2
+#endif
+#if defined(AARCH64)||defined(ARM32)||defined(MIPS)
+#define CODE_OK (si->si_code==SEGV_ACCERR)
+#elif defined(POWERPC)
+#define AIM
+#include <machine/trap.h>
+#define CODE_OK (si->si_code==EXC_DSI||si->si_code==SEGV_ACCERR)
+#else
+#define CODE_OK (si->si_code==BUS_PAGE_FAULT||si->si_code==SEGV_ACCERR)
+#endif
+#elif defined(OSF1)
+#define CODE_OK (si->si_code==2)
+#elif defined(IRIX5)
+#define CODE_OK (si->si_code==EACCES)
+#elif defined(CYGWIN32)||defined(HAIKU)||defined(HURD)
+#define CODE_OK TRUE
+#elif defined(LINUX)
+#define CODE_OK TRUE
+#elif defined(HPUX)
+#define CODE_OK (si->si_code==SEGV_ACCERR||si->si_code==BUS_ADRERR||si->si_code==BUS_UNKNOWN||si->si_code==SEGV_UNKNOWN||si->si_code==BUS_OBJERR)
+#elif defined(SUNOS5SIGS)
+#define CODE_OK (si->si_code==SEGV_ACCERR)
+#endif
+#ifndef NO_GETCONTEXT
+#include <ucontext.h>
+#endif
+STATIC void GC_write_fault_handler(int sig,siginfo_t*si,void*raw_sc)
+#else
+#define SIG_OK (exc_info->ExceptionRecord->ExceptionCode==STATUS_ACCESS_VIOLATION)
+#define CODE_OK (exc_info->ExceptionRecord->ExceptionInformation[0]==1)
+STATIC LONG WINAPI GC_write_fault_handler(
+struct _EXCEPTION_POINTERS*exc_info)
+#endif
+{
+#if!defined(MSWIN32)&&!defined(MSWINCE)
+char*addr=(char*)si->si_addr;
+#else
+char*addr=(char*)(exc_info->ExceptionRecord
+->ExceptionInformation[1]);
+#endif
+if (SIG_OK&&CODE_OK){
+struct hblk*h=(struct hblk*)((word)addr&~(GC_page_size-1));
+GC_bool in_allocd_block;
+size_t i;
+GC_ASSERT(GC_page_size!=0);
+#ifdef CHECKSUMS
+GC_record_fault(h);
+#endif
+#ifdef SUNOS5SIGS
+in_allocd_block=FALSE;
+for (i=0;i < divHBLKSZ(GC_page_size);i++){
+if (is_header_found_async(&h[i])){
+in_allocd_block=TRUE;
+break;
+}
+}
+#else
+in_allocd_block=is_header_found_async(addr);
+#endif
+if (!in_allocd_block){
+SIG_HNDLR_PTR old_handler;
+#if defined(MSWIN32)||defined(MSWINCE)
+old_handler=GC_old_segv_handler;
+#else
+GC_bool used_si;
+#if defined(FREEBSD)||defined(HURD)||defined(HPUX)
+if (sig==SIGBUS){
+old_handler=GC_old_bus_handler;
+used_si=GC_old_bus_handler_used_si;
+} else
+#endif
+{
+old_handler=GC_old_segv_handler;
+used_si=GC_old_segv_handler_used_si;
+}
+#endif
+if (old_handler==(SIG_HNDLR_PTR)(signed_word)SIG_DFL){
+#if!defined(MSWIN32)&&!defined(MSWINCE)
+ABORT_ARG1("Unexpected bus error or segmentation fault",
+" at %p",(void*)addr);
+#else
+return(EXCEPTION_CONTINUE_SEARCH);
+#endif
+} else {
+#if defined(MSWIN32)||defined(MSWINCE)
+return((*old_handler)(exc_info));
+#else
+if (used_si)
+((SIG_HNDLR_PTR)old_handler)(sig,si,raw_sc);
+else
+((PLAIN_HNDLR_PTR)(signed_word)old_handler)(sig);
+return;
+#endif
+}
+}
+UNPROTECT(h,GC_page_size);
+for (i=0;i < divHBLKSZ(GC_page_size);i++){
+word index=PHT_HASH(h+i);
+async_set_pht_entry_from_index(GC_dirty_pages,index);
+}
+#if defined(MSWIN32)||defined(MSWINCE)
+return(EXCEPTION_CONTINUE_EXECUTION);
+#else
+return;
+#endif
+}
+#if defined(MSWIN32)||defined(MSWINCE)
+return EXCEPTION_CONTINUE_SEARCH;
+#else
+ABORT_ARG1("Unexpected bus error or segmentation fault",
+" at %p",(void*)addr);
+#endif
+}
+#if defined(GC_WIN32_THREADS)&&!defined(CYGWIN32)
+GC_INNER void GC_set_write_fault_handler(void)
+{
+SetUnhandledExceptionFilter(GC_write_fault_handler);
+}
+#endif
+#endif
+#if!defined(DARWIN)
+GC_INNER GC_bool GC_dirty_init(void)
+{
+#if!defined(MSWIN32)&&!defined(MSWINCE)
+struct sigaction act,oldact;
+act.sa_flags=SA_RESTART|SA_SIGINFO;
+act.sa_sigaction=GC_write_fault_handler;
+(void)sigemptyset(&act.sa_mask);
+#if defined(THREADS)&&!defined(GC_OPENBSD_UTHREADS)&&!defined(GC_WIN32_THREADS)&&!defined(NACL)
+(void)sigaddset(&act.sa_mask,GC_get_suspend_signal());
+#endif
+#endif
+GC_VERBOSE_LOG_PRINTF(
+"Initializing mprotect virtual dirty bit implementation\n");
+if (GC_page_size % HBLKSIZE!=0){
+ABORT("Page size not multiple of HBLKSIZE");
+}
+#if!defined(MSWIN32)&&!defined(MSWINCE)
+#if defined(GC_IRIX_THREADS)
+sigaction(SIGSEGV,0,&oldact);
+sigaction(SIGSEGV,&act,0);
+#else
+{
+int res=sigaction(SIGSEGV,&act,&oldact);
+if (res!=0)ABORT("Sigaction failed");
+}
+#endif
+if (oldact.sa_flags&SA_SIGINFO){
+GC_old_segv_handler=oldact.sa_sigaction;
+GC_old_segv_handler_used_si=TRUE;
+} else {
+GC_old_segv_handler=(SIG_HNDLR_PTR)(signed_word)oldact.sa_handler;
+GC_old_segv_handler_used_si=FALSE;
+}
+if (GC_old_segv_handler==(SIG_HNDLR_PTR)(signed_word)SIG_IGN){
+WARN("Previously ignored segmentation violation!?\n",0);
+GC_old_segv_handler=(SIG_HNDLR_PTR)(signed_word)SIG_DFL;
+}
+if (GC_old_segv_handler!=(SIG_HNDLR_PTR)(signed_word)SIG_DFL){
+GC_VERBOSE_LOG_PRINTF("Replaced other SIGSEGV handler\n");
+}
+#if defined(HPUX)||defined(LINUX)||defined(HURD)||(defined(FREEBSD)&&(defined(__GLIBC__)||defined(SUNOS5SIGS)))
+sigaction(SIGBUS,&act,&oldact);
+if ((oldact.sa_flags&SA_SIGINFO)!=0){
+GC_old_bus_handler=oldact.sa_sigaction;
+#if!defined(LINUX)
+GC_old_bus_handler_used_si=TRUE;
+#endif
+} else {
+GC_old_bus_handler=(SIG_HNDLR_PTR)(signed_word)oldact.sa_handler;
+}
+if (GC_old_bus_handler==(SIG_HNDLR_PTR)(signed_word)SIG_IGN){
+WARN("Previously ignored bus error!?\n",0);
+#if!defined(LINUX)
+GC_old_bus_handler=(SIG_HNDLR_PTR)(signed_word)SIG_DFL;
+#else
+#endif
+} else if (GC_old_bus_handler!=(SIG_HNDLR_PTR)(signed_word)SIG_DFL){
+GC_VERBOSE_LOG_PRINTF("Replaced other SIGBUS handler\n");
+}
+#endif
+#endif
+#if defined(GWW_VDB)
+if (GC_gww_dirty_init())
+return TRUE;
+#endif
+#if defined(MSWIN32)
+GC_old_segv_handler=SetUnhandledExceptionFilter(GC_write_fault_handler);
+if (GC_old_segv_handler!=NULL){
+GC_COND_LOG_PRINTF("Replaced other UnhandledExceptionFilter\n");
+} else {
+GC_old_segv_handler=SIG_DFL;
+}
+#elif defined(MSWINCE)
+#endif
+#if defined(CPPCHECK)&&defined(ADDRESS_SANITIZER)
+GC_noop1((word)&__asan_default_options);
+#endif
+return TRUE;
+}
+#endif
+GC_API int GC_CALL GC_incremental_protection_needs(void)
+{
+GC_ASSERT(GC_is_initialized);
+if (GC_page_size==HBLKSIZE){
+return GC_PROTECTS_POINTER_HEAP;
+} else {
+return GC_PROTECTS_POINTER_HEAP|GC_PROTECTS_PTRFREE_HEAP;
+}
+}
+#define HAVE_INCREMENTAL_PROTECTION_NEEDS
+#define IS_PTRFREE(hhdr)((hhdr)->hb_descr==0)
+#define PAGE_ALIGNED(x)!((word)(x)&(GC_page_size - 1))
+STATIC void GC_protect_heap(void)
+{
+unsigned i;
+GC_bool protect_all=
+(0!=(GC_incremental_protection_needs()&GC_PROTECTS_PTRFREE_HEAP));
+GC_ASSERT(GC_page_size!=0);
+for (i=0;i < GC_n_heap_sects;i++){
+ptr_t start=GC_heap_sects[i].hs_start;
+size_t len=GC_heap_sects[i].hs_bytes;
+if (protect_all){
+PROTECT(start,len);
+} else {
+struct hblk*current;
+struct hblk*current_start;
+struct hblk*limit;
+GC_ASSERT(PAGE_ALIGNED(len));
+GC_ASSERT(PAGE_ALIGNED(start));
+current_start=current=(struct hblk*)start;
+limit=(struct hblk*)(start+len);
+while ((word)current < (word)limit){
+hdr*hhdr;
+word nhblks;
+GC_bool is_ptrfree;
+GC_ASSERT(PAGE_ALIGNED(current));
+GET_HDR(current,hhdr);
+if (IS_FORWARDING_ADDR_OR_NIL(hhdr)){
+GC_ASSERT(current_start==current);
+current_start=++current;
+continue;
+}
+if (HBLK_IS_FREE(hhdr)){
+GC_ASSERT(PAGE_ALIGNED(hhdr->hb_sz));
+nhblks=divHBLKSZ(hhdr->hb_sz);
+is_ptrfree=TRUE;
+} else {
+nhblks=OBJ_SZ_TO_BLOCKS(hhdr->hb_sz);
+is_ptrfree=IS_PTRFREE(hhdr);
+}
+if (is_ptrfree){
+if ((word)current_start < (word)current){
+PROTECT(current_start,(ptr_t)current - (ptr_t)current_start);
+}
+current_start=(current+=nhblks);
+} else {
+current+=nhblks;
+}
+}
+if ((word)current_start < (word)current){
+PROTECT(current_start,(ptr_t)current - (ptr_t)current_start);
+}
+}
+}
+}
+#endif
+#ifdef PROC_VDB
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#ifdef GC_NO_SYS_FAULT_H
+#define PG_MODIFIED 1
+struct prpageheader {
+int dummy[2];
+unsigned long pr_nmap;
+unsigned long pr_npage;
+};
+struct prasmap {
+char*pr_vaddr;
+size_t pr_npage;
+char dummy1[64+8];
+unsigned pr_mflags;
+unsigned pr_pagesize;
+int dummy2[2];
+};
+#else
+#include <sys/fault.h>
+#include <sys/procfs.h>
+#endif
+#define INITIAL_BUF_SZ 16384
+STATIC size_t GC_proc_buf_size=INITIAL_BUF_SZ;
+STATIC char*GC_proc_buf=NULL;
+STATIC int GC_proc_fd=0;
+GC_INNER GC_bool GC_dirty_init(void)
+{
+char buf[40];
+if (GC_bytes_allocd!=0||GC_bytes_allocd_before_gc!=0){
+memset(GC_written_pages,0xff,sizeof(page_hash_table));
+GC_VERBOSE_LOG_PRINTF(
+"Allocated %lu bytes:all pages may have been written\n",
+(unsigned long)(GC_bytes_allocd+GC_bytes_allocd_before_gc));
+}
+(void)snprintf(buf,sizeof(buf),"/proc/%ld/pagedata",(long)getpid());
+buf[sizeof(buf)- 1]='\0';
+GC_proc_fd=open(buf,O_RDONLY);
+if (GC_proc_fd < 0){
+WARN("/proc open failed;cannot enable GC incremental mode\n",0);
+return FALSE;
+}
+if (syscall(SYS_fcntl,GC_proc_fd,F_SETFD,FD_CLOEXEC)==-1)
+WARN("Could not set FD_CLOEXEC for/proc\n",0);
+GC_proc_buf=GC_scratch_alloc(GC_proc_buf_size);
+if (GC_proc_buf==NULL)
+ABORT("Insufficient space for/proc read");
+return TRUE;
+}
+GC_INLINE void GC_proc_read_dirty(GC_bool output_unneeded)
+{
+#define READ read
+int nmaps;
+char*bufp=GC_proc_buf;
+int i;
+BZERO(GC_grungy_pages,sizeof(GC_grungy_pages));
+if (READ(GC_proc_fd,bufp,GC_proc_buf_size)<=0){
+size_t new_size=2*GC_proc_buf_size;
+char*new_buf;
+WARN("/proc read failed:GC_proc_buf_size=%" WARN_PRIdPTR "\n",
+(signed_word)GC_proc_buf_size);
+new_buf=GC_scratch_alloc(new_size);
+if (new_buf!=0){
+GC_scratch_recycle_no_gww(bufp,GC_proc_buf_size);
+GC_proc_buf=bufp=new_buf;
+GC_proc_buf_size=new_size;
+}
+if (READ(GC_proc_fd,bufp,GC_proc_buf_size)<=0){
+WARN("Insufficient space for/proc read\n",0);
+if (!output_unneeded)
+memset(GC_grungy_pages,0xff,sizeof (page_hash_table));
+memset(GC_written_pages,0xff,sizeof(page_hash_table));
+return;
+}
+}
+nmaps=((struct prpageheader*)bufp)->pr_nmap;
+#ifdef DEBUG_DIRTY_BITS
+GC_log_printf("Proc VDB read:pr_nmap=%u,pr_npage=%lu\n",
+nmaps,((struct prpageheader*)bufp)->pr_npage);
+#endif
+#if defined(GC_NO_SYS_FAULT_H)&&defined(CPPCHECK)
+GC_noop1(((struct prpageheader*)bufp)->dummy[0]);
+#endif
+bufp+=sizeof(struct prpageheader);
+for (i=0;i < nmaps;i++){
+struct prasmap*map=(struct prasmap*)bufp;
+ptr_t vaddr=(ptr_t)(map->pr_vaddr);
+unsigned long npages=map->pr_npage;
+unsigned pagesize=map->pr_pagesize;
+ptr_t limit;
+#if defined(GC_NO_SYS_FAULT_H)&&defined(CPPCHECK)
+GC_noop1(map->dummy1[0]+map->dummy2[0]);
+#endif
+#ifdef DEBUG_DIRTY_BITS
+GC_log_printf(
+"pr_vaddr=%p,npage=%lu,mflags=0x%x,pagesize=0x%x\n",
+(void*)vaddr,npages,map->pr_mflags,pagesize);
+#endif
+bufp+=sizeof(struct prasmap);
+limit=vaddr+pagesize*npages;
+for (;(word)vaddr < (word)limit;vaddr+=pagesize){
+if ((*bufp++)&PG_MODIFIED){
+struct hblk*h;
+ptr_t next_vaddr=vaddr+pagesize;
+#ifdef DEBUG_DIRTY_BITS
+GC_log_printf("dirty page at:%p\n",(void*)vaddr);
+#endif
+for (h=(struct hblk*)vaddr;
+(word)h < (word)next_vaddr;h++){
+word index=PHT_HASH(h);
+set_pht_entry_from_index(GC_grungy_pages,index);
+}
+}
+}
+bufp=(char*)(((word)bufp+(sizeof(long)-1))
+&~(word)(sizeof(long)-1));
+}
+#ifdef DEBUG_DIRTY_BITS
+GC_log_printf("Proc VDB read done\n");
+#endif
+GC_or_pages(GC_written_pages,GC_grungy_pages);
+#undef READ
+}
+#endif
+#ifdef PCR_VDB
+#include "vd/PCR_VD.h"
+#define NPAGES (32*1024)
+PCR_VD_DB GC_grungy_bits[NPAGES];
+STATIC ptr_t GC_vd_base=NULL;
+GC_INNER GC_bool GC_dirty_init(void)
+{
+GC_vd_base=GC_heap_sects[0].hs_start;
+if (GC_vd_base==0){
+ABORT("Bad initial heap segment");
+}
+if (PCR_VD_Start(HBLKSIZE,GC_vd_base,NPAGES*HBLKSIZE)
+!=PCR_ERes_okay){
+ABORT("Dirty bit initialization failed");
+}
+return TRUE;
+}
+#endif
+#ifndef GC_DISABLE_INCREMENTAL
+GC_INNER GC_bool GC_manual_vdb=FALSE;
+GC_INNER void GC_dirty_inner(const void*p)
+{
+word index=PHT_HASH(p);
+#if defined(MPROTECT_VDB)
+GC_ASSERT(GC_manual_vdb);
+#endif
+async_set_pht_entry_from_index(GC_dirty_pages,index);
+}
+GC_INNER void GC_read_dirty(GC_bool output_unneeded)
+{
+if (GC_manual_vdb
+#if defined(MPROTECT_VDB)
+||!GC_GWW_AVAILABLE()
+#endif
+){
+if (!output_unneeded)
+BCOPY(( void*)GC_dirty_pages,GC_grungy_pages,
+sizeof(GC_dirty_pages));
+BZERO(( void*)GC_dirty_pages,
+sizeof(GC_dirty_pages));
+#ifdef MPROTECT_VDB
+if (!GC_manual_vdb)
+GC_protect_heap();
+#endif
+return;
+}
+#ifdef GWW_VDB
+GC_gww_read_dirty(output_unneeded);
+#elif defined(PROC_VDB)
+GC_proc_read_dirty(output_unneeded);
+#elif defined(PCR_VDB)
+{
+static int onhs=0;
+int nhs=GC_n_heap_sects;
+for (;onhs < nhs;onhs++){
+PCR_VD_WriteProtectEnable(
+GC_heap_sects[onhs].hs_start,
+GC_heap_sects[onhs].hs_bytes);
+}
+}
+if (PCR_VD_Clear(GC_vd_base,NPAGES*HBLKSIZE,GC_grungy_bits)
+!=PCR_ERes_okay){
+ABORT("Dirty bit read failed");
+}
+#endif
+}
+GC_INNER GC_bool GC_page_was_dirty(struct hblk*h)
+{
+#ifdef PCR_VDB
+if (!GC_manual_vdb){
+if ((word)h < (word)GC_vd_base
+||(word)h>=(word)(GC_vd_base+NPAGES*HBLKSIZE)){
+return TRUE;
+}
+return GC_grungy_bits[h-(struct hblk*)GC_vd_base]&PCR_VD_DB_dirtyBit;
+}
+#elif defined(DEFAULT_VDB)
+if (!GC_manual_vdb)
+return TRUE;
+#endif
+return NULL==HDR(h)
+||get_pht_entry_from_index(GC_grungy_pages,PHT_HASH(h));
+}
+#if defined(CHECKSUMS)||defined(PROC_VDB)
+GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk*h)
+{
+#if defined(GWW_VDB)||defined(PROC_VDB)
+#ifdef MPROTECT_VDB
+if (!GC_GWW_AVAILABLE())
+return TRUE;
+#endif
+return NULL==HDR(h)
+||get_pht_entry_from_index(GC_written_pages,PHT_HASH(h));
+#else
+(void)h;
+return TRUE;
+#endif
+}
+#endif
+GC_INNER void GC_remove_protection(struct hblk*h,word nblocks,
+GC_bool is_ptrfree)
+{
+#ifdef PCR_VDB
+(void)is_ptrfree;
+if (!GC_auto_incremental)
+return;
+PCR_VD_WriteProtectDisable(h,nblocks*HBLKSIZE);
+PCR_VD_WriteProtectEnable(h,nblocks*HBLKSIZE);
+#elif defined(MPROTECT_VDB)
+struct hblk*h_trunc;
+struct hblk*h_end;
+struct hblk*current;
+if (!GC_auto_incremental||GC_GWW_AVAILABLE())
+return;
+GC_ASSERT(GC_page_size!=0);
+h_trunc=(struct hblk*)((word)h&~(GC_page_size-1));
+h_end=(struct hblk*)(((word)(h+nblocks)+GC_page_size - 1)
+&~(GC_page_size - 1));
+if (h_end==h_trunc+1&&
+get_pht_entry_from_index(GC_dirty_pages,PHT_HASH(h_trunc))){
+return;
+}
+for (current=h_trunc;(word)current < (word)h_end;++current){
+word index=PHT_HASH(current);
+if (!is_ptrfree||(word)current < (word)h
+||(word)current>=(word)(h+nblocks)){
+async_set_pht_entry_from_index(GC_dirty_pages,index);
+}
+}
+UNPROTECT(h_trunc,(ptr_t)h_end - (ptr_t)h_trunc);
+#else
+(void)h;(void)nblocks;(void)is_ptrfree;
+#endif
+}
+#endif
+#if defined(MPROTECT_VDB)&&defined(DARWIN)
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/exception.h>
+#include <mach/task.h>
+#include <pthread.h>
+EXTERN_C_BEGIN
+extern boolean_t
+exc_server(mach_msg_header_t*,mach_msg_header_t*);
+extern kern_return_t
+exception_raise(mach_port_t,mach_port_t,mach_port_t,exception_type_t,
+exception_data_t,mach_msg_type_number_t);
+extern kern_return_t
+exception_raise_state(mach_port_t,mach_port_t,mach_port_t,exception_type_t,
+exception_data_t,mach_msg_type_number_t,
+thread_state_flavor_t*,thread_state_t,
+mach_msg_type_number_t,thread_state_t,
+mach_msg_type_number_t*);
+extern kern_return_t
+exception_raise_state_identity(mach_port_t,mach_port_t,mach_port_t,
+exception_type_t,exception_data_t,
+mach_msg_type_number_t,thread_state_flavor_t*,
+thread_state_t,mach_msg_type_number_t,
+thread_state_t,mach_msg_type_number_t*);
+GC_API_OSCALL kern_return_t
+catch_exception_raise(mach_port_t exception_port,mach_port_t thread,
+mach_port_t task,exception_type_t exception,
+exception_data_t code,
+mach_msg_type_number_t code_count);
+GC_API_OSCALL kern_return_t
+catch_exception_raise_state(mach_port_name_t exception_port,
+int exception,exception_data_t code,
+mach_msg_type_number_t codeCnt,int flavor,
+thread_state_t old_state,int old_stateCnt,
+thread_state_t new_state,int new_stateCnt);
+GC_API_OSCALL kern_return_t
+catch_exception_raise_state_identity(mach_port_name_t exception_port,
+mach_port_t thread,mach_port_t task,int exception,
+exception_data_t code,mach_msg_type_number_t codeCnt,
+int flavor,thread_state_t old_state,int old_stateCnt,
+thread_state_t new_state,int new_stateCnt);
+EXTERN_C_END
+GC_API_OSCALL kern_return_t
+catch_exception_raise_state(mach_port_name_t exception_port GC_ATTR_UNUSED,
+int exception GC_ATTR_UNUSED,exception_data_t code GC_ATTR_UNUSED,
+mach_msg_type_number_t codeCnt GC_ATTR_UNUSED,int flavor GC_ATTR_UNUSED,
+thread_state_t old_state GC_ATTR_UNUSED,int old_stateCnt GC_ATTR_UNUSED,
+thread_state_t new_state GC_ATTR_UNUSED,int new_stateCnt GC_ATTR_UNUSED)
+{
+ABORT_RET("Unexpected catch_exception_raise_state invocation");
+return(KERN_INVALID_ARGUMENT);
+}
+GC_API_OSCALL kern_return_t
+catch_exception_raise_state_identity(
+mach_port_name_t exception_port GC_ATTR_UNUSED,
+mach_port_t thread GC_ATTR_UNUSED,mach_port_t task GC_ATTR_UNUSED,
+int exception GC_ATTR_UNUSED,exception_data_t code GC_ATTR_UNUSED,
+mach_msg_type_number_t codeCnt GC_ATTR_UNUSED,int flavor GC_ATTR_UNUSED,
+thread_state_t old_state GC_ATTR_UNUSED,int old_stateCnt GC_ATTR_UNUSED,
+thread_state_t new_state GC_ATTR_UNUSED,int new_stateCnt GC_ATTR_UNUSED)
+{
+ABORT_RET("Unexpected catch_exception_raise_state_identity invocation");
+return(KERN_INVALID_ARGUMENT);
+}
+#define MAX_EXCEPTION_PORTS 16
+static struct {
+mach_msg_type_number_t count;
+exception_mask_t masks[MAX_EXCEPTION_PORTS];
+exception_handler_t ports[MAX_EXCEPTION_PORTS];
+exception_behavior_t behaviors[MAX_EXCEPTION_PORTS];
+thread_state_flavor_t flavors[MAX_EXCEPTION_PORTS];
+} GC_old_exc_ports;
+STATIC struct ports_s {
+void (*volatile os_callback[3])(void);
+mach_port_t exception;
+#if defined(THREADS)
+mach_port_t reply;
+#endif
+} GC_ports={
+{
+(void (*)(void))catch_exception_raise,
+(void (*)(void))catch_exception_raise_state,
+(void (*)(void))catch_exception_raise_state_identity
+},
+#ifdef THREADS
+0,
+#endif
+0
+};
+typedef struct {
+mach_msg_header_t head;
+} GC_msg_t;
+typedef enum {
+GC_MP_NORMAL,
+GC_MP_DISCARDING,
+GC_MP_STOPPED
+} GC_mprotect_state_t;
+#ifdef THREADS
+#define ID_STOP 1
+#define ID_RESUME 2
+#define ID_ACK 3
+STATIC GC_mprotect_state_t GC_mprotect_state=GC_MP_NORMAL;
+STATIC void GC_mprotect_thread_notify(mach_msg_id_t id)
+{
+struct buf_s {
+GC_msg_t msg;
+mach_msg_trailer_t trailer;
+} buf;
+mach_msg_return_t r;
+buf.msg.head.msgh_bits=MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
+buf.msg.head.msgh_size=sizeof(buf.msg);
+buf.msg.head.msgh_remote_port=GC_ports.exception;
+buf.msg.head.msgh_local_port=MACH_PORT_NULL;
+buf.msg.head.msgh_id=id;
+r=mach_msg(&buf.msg.head,MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_LARGE,
+sizeof(buf.msg),sizeof(buf),GC_ports.reply,
+MACH_MSG_TIMEOUT_NONE,MACH_PORT_NULL);
+if (r!=MACH_MSG_SUCCESS)
+ABORT("mach_msg failed in GC_mprotect_thread_notify");
+if (buf.msg.head.msgh_id!=ID_ACK)
+ABORT("Invalid ack in GC_mprotect_thread_notify");
+}
+STATIC void GC_mprotect_thread_reply(void)
+{
+GC_msg_t msg;
+mach_msg_return_t r;
+msg.head.msgh_bits=MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
+msg.head.msgh_size=sizeof(msg);
+msg.head.msgh_remote_port=GC_ports.reply;
+msg.head.msgh_local_port=MACH_PORT_NULL;
+msg.head.msgh_id=ID_ACK;
+r=mach_msg(&msg.head,MACH_SEND_MSG,sizeof(msg),0,MACH_PORT_NULL,
+MACH_MSG_TIMEOUT_NONE,MACH_PORT_NULL);
+if (r!=MACH_MSG_SUCCESS)
+ABORT("mach_msg failed in GC_mprotect_thread_reply");
+}
+GC_INNER void GC_mprotect_stop(void)
+{
+GC_mprotect_thread_notify(ID_STOP);
+}
+GC_INNER void GC_mprotect_resume(void)
+{
+GC_mprotect_thread_notify(ID_RESUME);
+}
+#else
+#define GC_mprotect_state GC_MP_NORMAL
+#endif
+struct mp_reply_s {
+mach_msg_header_t head;
+char data[256];
+};
+struct mp_msg_s {
+mach_msg_header_t head;
+mach_msg_body_t msgh_body;
+char data[1024];
+};
+STATIC void*GC_mprotect_thread(void*arg)
+{
+mach_msg_return_t r;
+struct mp_reply_s reply;
+struct mp_msg_s msg;
+mach_msg_id_t id;
+if ((word)arg==GC_WORD_MAX)return 0;
+#if defined(CPPCHECK)
+reply.data[0]=0;
+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
+for(;;){
+r=mach_msg(&msg.head,MACH_RCV_MSG|MACH_RCV_LARGE|
+(GC_mprotect_state==GC_MP_DISCARDING?MACH_RCV_TIMEOUT:0),
+0,sizeof(msg),GC_ports.exception,
+GC_mprotect_state==GC_MP_DISCARDING?0
+:MACH_MSG_TIMEOUT_NONE,MACH_PORT_NULL);
+id=r==MACH_MSG_SUCCESS?msg.head.msgh_id:-1;
+#if defined(THREADS)
+if(GC_mprotect_state==GC_MP_DISCARDING){
+if(r==MACH_RCV_TIMED_OUT){
+GC_mprotect_state=GC_MP_STOPPED;
+GC_mprotect_thread_reply();
+continue;
+}
+if(r==MACH_MSG_SUCCESS&&(id==ID_STOP||id==ID_RESUME))
+ABORT("Out of order mprotect thread request");
+}
+#endif
+if (r!=MACH_MSG_SUCCESS){
+ABORT_ARG2("mach_msg failed",
+":errcode=%d (%s)",(int)r,mach_error_string(r));
+}
+switch(id){
+#if defined(THREADS)
+case ID_STOP:
+if(GC_mprotect_state!=GC_MP_NORMAL)
+ABORT("Called mprotect_stop when state wasn't normal");
+GC_mprotect_state=GC_MP_DISCARDING;
+break;
+case ID_RESUME:
+if(GC_mprotect_state!=GC_MP_STOPPED)
+ABORT("Called mprotect_resume when state wasn't stopped");
+GC_mprotect_state=GC_MP_NORMAL;
+GC_mprotect_thread_reply();
+break;
+#endif
+default:
+if(!exc_server(&msg.head,&reply.head))
+ABORT("exc_server failed");
+r=mach_msg(&reply.head,MACH_SEND_MSG,reply.head.msgh_size,0,
+MACH_PORT_NULL,MACH_MSG_TIMEOUT_NONE,
+MACH_PORT_NULL);
+if(r!=MACH_MSG_SUCCESS){
+#ifdef BROKEN_EXCEPTION_HANDLING
+GC_err_printf("mach_msg failed with %d %s while sending "
+"exc reply\n",(int)r,mach_error_string(r));
+#else
+ABORT("mach_msg failed while sending exception reply");
+#endif
+}
+}
+}
+}
+#ifdef BROKEN_EXCEPTION_HANDLING
+STATIC int GC_sigbus_count=0;
+STATIC void GC_darwin_sigbus(int num,siginfo_t*sip,void*context)
+{
+if (num!=SIGBUS)
+ABORT("Got a non-sigbus signal in the sigbus handler");
+if (GC_sigbus_count>=8){
+ABORT("Got more than 8 SIGBUSs in a row!");
+} else {
+GC_sigbus_count++;
+WARN("Ignoring SIGBUS\n",0);
+}
+}
+#endif
+GC_INNER GC_bool GC_dirty_init(void)
+{
+kern_return_t r;
+mach_port_t me;
+pthread_t thread;
+pthread_attr_t attr;
+exception_mask_t mask;
+#ifdef CAN_HANDLE_FORK
+if (GC_handle_fork){
+WARN("Can't turn on GC incremental mode as fork()"
+" handling requested\n",0);
+return FALSE;
+}
+#endif
+GC_VERBOSE_LOG_PRINTF("Initializing mach/darwin mprotect"
+" virtual dirty bit implementation\n");
+#ifdef BROKEN_EXCEPTION_HANDLING
+WARN("Enabling workarounds for various darwin "
+"exception handling bugs\n",0);
+#endif
+if (GC_page_size % HBLKSIZE!=0){
+ABORT("Page size not multiple of HBLKSIZE");
+}
+GC_task_self=me=mach_task_self();
+r=mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.exception);
+if (r!=KERN_SUCCESS)
+ABORT("mach_port_allocate failed (exception port)");
+r=mach_port_insert_right(me,GC_ports.exception,GC_ports.exception,
+MACH_MSG_TYPE_MAKE_SEND);
+if (r!=KERN_SUCCESS)
+ABORT("mach_port_insert_right failed (exception port)");
+#if defined(THREADS)
+r=mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.reply);
+if(r!=KERN_SUCCESS)
+ABORT("mach_port_allocate failed (reply port)");
+#endif
+mask=EXC_MASK_BAD_ACCESS;
+r=task_get_exception_ports(me,mask,GC_old_exc_ports.masks,
+&GC_old_exc_ports.count,GC_old_exc_ports.ports,
+GC_old_exc_ports.behaviors,
+GC_old_exc_ports.flavors);
+if (r!=KERN_SUCCESS)
+ABORT("task_get_exception_ports failed");
+r=task_set_exception_ports(me,mask,GC_ports.exception,EXCEPTION_DEFAULT,
+GC_MACH_THREAD_STATE);
+if (r!=KERN_SUCCESS)
+ABORT("task_set_exception_ports failed");
+if (pthread_attr_init(&attr)!=0)
+ABORT("pthread_attr_init failed");
+if (pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED)!=0)
+ABORT("pthread_attr_setdetachedstate failed");
+#undef pthread_create
+if (pthread_create(&thread,&attr,GC_mprotect_thread,NULL)!=0)
+ABORT("pthread_create failed");
+(void)pthread_attr_destroy(&attr);
+#ifdef BROKEN_EXCEPTION_HANDLING
+{
+struct sigaction sa,oldsa;
+sa.sa_handler=(SIG_HNDLR_PTR)GC_darwin_sigbus;
+sigemptyset(&sa.sa_mask);
+sa.sa_flags=SA_RESTART|SA_SIGINFO;
+if (sigaction(SIGBUS,&sa,&oldsa)< 0)
+ABORT("sigaction failed");
+if (oldsa.sa_handler!=(SIG_HNDLR_PTR)(signed_word)SIG_DFL){
+GC_VERBOSE_LOG_PRINTF("Replaced other SIGBUS handler\n");
+}
+}
+#endif
+#if defined(CPPCHECK)
+GC_noop1((word)GC_ports.os_callback[0]);
+#endif
+return TRUE;
+}
+STATIC kern_return_t GC_forward_exception(mach_port_t thread,mach_port_t task,
+exception_type_t exception,
+exception_data_t data,
+mach_msg_type_number_t data_count)
+{
+unsigned int i;
+kern_return_t r;
+mach_port_t port;
+exception_behavior_t behavior;
+thread_state_flavor_t flavor;
+thread_state_data_t thread_state;
+mach_msg_type_number_t thread_state_count=THREAD_STATE_MAX;
+for (i=0;i < GC_old_exc_ports.count;i++)
+if (GC_old_exc_ports.masks[i]&(1<<exception))
+break;
+if (i==GC_old_exc_ports.count)
+ABORT("No handler for exception!");
+port=GC_old_exc_ports.ports[i];
+behavior=GC_old_exc_ports.behaviors[i];
+flavor=GC_old_exc_ports.flavors[i];
+if (behavior==EXCEPTION_STATE||behavior==EXCEPTION_STATE_IDENTITY){
+r=thread_get_state(thread,flavor,thread_state,&thread_state_count);
+if(r!=KERN_SUCCESS)
+ABORT("thread_get_state failed in forward_exception");
+}
+switch(behavior){
+case EXCEPTION_STATE:
+r=exception_raise_state(port,thread,task,exception,data,data_count,
+&flavor,thread_state,thread_state_count,
+thread_state,&thread_state_count);
+break;
+case EXCEPTION_STATE_IDENTITY:
+r=exception_raise_state_identity(port,thread,task,exception,data,
+data_count,&flavor,thread_state,
+thread_state_count,thread_state,
+&thread_state_count);
+break;
+default:
+r=exception_raise(port,thread,task,exception,data,data_count);
+}
+if (behavior==EXCEPTION_STATE||behavior==EXCEPTION_STATE_IDENTITY){
+r=thread_set_state(thread,flavor,thread_state,thread_state_count);
+if (r!=KERN_SUCCESS)
+ABORT("thread_set_state failed in forward_exception");
+}
+return r;
+}
+#define FWD()GC_forward_exception(thread,task,exception,code,code_count)
+#ifdef ARM32
+#define DARWIN_EXC_STATE ARM_EXCEPTION_STATE
+#define DARWIN_EXC_STATE_COUNT ARM_EXCEPTION_STATE_COUNT
+#define DARWIN_EXC_STATE_T arm_exception_state_t
+#define DARWIN_EXC_STATE_DAR THREAD_FLD_NAME(far)
+#elif defined(AARCH64)
+#define DARWIN_EXC_STATE ARM_EXCEPTION_STATE64
+#define DARWIN_EXC_STATE_COUNT ARM_EXCEPTION_STATE64_COUNT
+#define DARWIN_EXC_STATE_T arm_exception_state64_t
+#define DARWIN_EXC_STATE_DAR THREAD_FLD_NAME(far)
+#elif defined(POWERPC)
+#if CPP_WORDSZ==32
+#define DARWIN_EXC_STATE PPC_EXCEPTION_STATE
+#define DARWIN_EXC_STATE_COUNT PPC_EXCEPTION_STATE_COUNT
+#define DARWIN_EXC_STATE_T ppc_exception_state_t
+#else
+#define DARWIN_EXC_STATE PPC_EXCEPTION_STATE64
+#define DARWIN_EXC_STATE_COUNT PPC_EXCEPTION_STATE64_COUNT
+#define DARWIN_EXC_STATE_T ppc_exception_state64_t
+#endif
+#define DARWIN_EXC_STATE_DAR THREAD_FLD_NAME(dar)
+#elif defined(I386)||defined(X86_64)
+#if CPP_WORDSZ==32
+#if defined(i386_EXCEPTION_STATE_COUNT)&&!defined(x86_EXCEPTION_STATE32_COUNT)
+#define DARWIN_EXC_STATE i386_EXCEPTION_STATE
+#define DARWIN_EXC_STATE_COUNT i386_EXCEPTION_STATE_COUNT
+#define DARWIN_EXC_STATE_T i386_exception_state_t
+#else
+#define DARWIN_EXC_STATE x86_EXCEPTION_STATE32
+#define DARWIN_EXC_STATE_COUNT x86_EXCEPTION_STATE32_COUNT
+#define DARWIN_EXC_STATE_T x86_exception_state32_t
+#endif
+#else
+#define DARWIN_EXC_STATE x86_EXCEPTION_STATE64
+#define DARWIN_EXC_STATE_COUNT x86_EXCEPTION_STATE64_COUNT
+#define DARWIN_EXC_STATE_T x86_exception_state64_t
+#endif
+#define DARWIN_EXC_STATE_DAR THREAD_FLD_NAME(faultvaddr)
+#elif!defined(CPPCHECK)
+#error FIXME for non-arm/ppc/x86 darwin
+#endif
+GC_API_OSCALL kern_return_t
+catch_exception_raise(mach_port_t exception_port GC_ATTR_UNUSED,
+mach_port_t thread,mach_port_t task GC_ATTR_UNUSED,
+exception_type_t exception,exception_data_t code,
+mach_msg_type_number_t code_count GC_ATTR_UNUSED)
+{
+kern_return_t r;
+char*addr;
+thread_state_flavor_t flavor=DARWIN_EXC_STATE;
+mach_msg_type_number_t exc_state_count=DARWIN_EXC_STATE_COUNT;
+DARWIN_EXC_STATE_T exc_state;
+if (exception!=EXC_BAD_ACCESS||code[0]!=KERN_PROTECTION_FAILURE){
+#ifdef DEBUG_EXCEPTION_HANDLING
+GC_log_printf("Exception:0x%x Code:0x%x 0x%x in catch...\n",
+exception,code_count > 0?code[0]:-1,
+code_count > 1?code[1]:-1);
+#endif
+return FWD();
+}
+r=thread_get_state(thread,flavor,(natural_t*)&exc_state,
+&exc_state_count);
+if(r!=KERN_SUCCESS){
+#ifdef BROKEN_EXCEPTION_HANDLING
+GC_err_printf("thread_get_state failed in catch_exception_raise\n");
+return KERN_SUCCESS;
+#else
+ABORT("thread_get_state failed in catch_exception_raise");
+#endif
+}
+addr=(char*)exc_state.DARWIN_EXC_STATE_DAR;
+if (!is_header_found_async(addr)){
+#ifdef BROKEN_EXCEPTION_HANDLING
+static char*last_fault;
+static int last_fault_count;
+if(addr!=last_fault){
+last_fault=addr;
+last_fault_count=0;
+}
+if(++last_fault_count < 32){
+if(last_fault_count==1)
+WARN("Ignoring KERN_PROTECTION_FAILURE at %p\n",addr);
+return KERN_SUCCESS;
+}
+GC_err_printf("Unexpected KERN_PROTECTION_FAILURE at %p;aborting...\n",
+(void*)addr);
+EXIT();
+#else
+return FWD();
+#endif
+}
+#ifdef BROKEN_EXCEPTION_HANDLING
+GC_sigbus_count=0;
+#endif
+GC_ASSERT(GC_page_size!=0);
+if (GC_mprotect_state==GC_MP_NORMAL){
+struct hblk*h=(struct hblk*)((word)addr&~(GC_page_size-1));
+size_t i;
+UNPROTECT(h,GC_page_size);
+for (i=0;i < divHBLKSZ(GC_page_size);i++){
+word index=PHT_HASH(h+i);
+async_set_pht_entry_from_index(GC_dirty_pages,index);
+}
+} else if (GC_mprotect_state==GC_MP_DISCARDING){
+} else {
+GC_err_printf("KERN_PROTECTION_FAILURE while world is stopped\n");
+return FWD();
+}
+return KERN_SUCCESS;
+}
+#undef FWD
+#ifndef NO_DESC_CATCH_EXCEPTION_RAISE
+__asm__(".desc _catch_exception_raise,0x10");
+__asm__(".desc _catch_exception_raise_state,0x10");
+__asm__(".desc _catch_exception_raise_state_identity,0x10");
+#endif
+#endif
+#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
+#ifdef ECOS
+#undef sbrk
+#endif
+GC_API void GC_CALL GC_set_pages_executable(int value)
+{
+GC_ASSERT(!GC_is_initialized);
+GC_pages_executable=(GC_bool)(value!=0);
+}
+GC_API int GC_CALL GC_get_pages_executable(void)
+{
+#ifdef IGNORE_PAGES_EXECUTABLE
+return 1;
+#else
+return (int)GC_pages_executable;
+#endif
+}
+#if defined(I386)&&defined(LINUX)&&defined(SAVE_CALL_CHAIN)
+#include <features.h>
+struct frame {
+struct frame*fr_savfp;
+long fr_savpc;
+#if NARGS > 0
+long fr_arg[NARGS];
+#endif
+};
+#endif
+#if defined(SPARC)
+#if defined(LINUX)
+#include <features.h>
+#if defined(SAVE_CALL_CHAIN)
+struct frame {
+long fr_local[8];
+long fr_arg[6];
+struct frame*fr_savfp;
+long fr_savpc;
+#ifndef __arch64__
+char*fr_stret;
+#endif
+long fr_argd[6];
+long fr_argx[0];
+};
+#endif
+#elif defined (DRSNX)
+#include <sys/sparc/frame.h>
+#elif defined(OPENBSD)
+#include <frame.h>
+#elif defined(FREEBSD)||defined(NETBSD)
+#include <machine/frame.h>
+#else
+#include <sys/frame.h>
+#endif
+#if NARGS > 6
+#error We only know how to get the first 6 arguments
+#endif
+#endif
+#ifdef NEED_CALLINFO
+#ifdef LINUX
+#include <unistd.h>
+#endif
+#endif
+#if defined(GC_HAVE_BUILTIN_BACKTRACE)
+#ifdef _MSC_VER
+#ifndef GC_MSVC_DBG_H
+#define GC_MSVC_DBG_H
+#include <stdlib.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if!MSVC_DBG_DLL
+#define MSVC_DBG_EXPORT
+#elif MSVC_DBG_BUILD
+#define MSVC_DBG_EXPORT __declspec(dllexport)
+#else
+#define MSVC_DBG_EXPORT __declspec(dllimport)
+#endif
+#ifndef MAX_SYM_NAME
+#define MAX_SYM_NAME 2000
+#endif
+typedef void*HANDLE;
+typedef struct _CONTEXT CONTEXT;
+MSVC_DBG_EXPORT size_t GetStackFrames(size_t skip,void*frames[],size_t maxFrames);
+MSVC_DBG_EXPORT size_t GetStackFramesFromContext(HANDLE hProcess,HANDLE hThread,CONTEXT*context,size_t skip,void*frames[],size_t maxFrames);
+MSVC_DBG_EXPORT size_t GetModuleNameFromAddress(void*address,char*moduleName,size_t size);
+MSVC_DBG_EXPORT size_t GetModuleNameFromStack(size_t skip,char*moduleName,size_t size);
+MSVC_DBG_EXPORT size_t GetSymbolNameFromAddress(void*address,char*symbolName,size_t size,size_t*offsetBytes);
+MSVC_DBG_EXPORT size_t GetSymbolNameFromStack(size_t skip,char*symbolName,size_t size,size_t*offsetBytes);
+MSVC_DBG_EXPORT size_t GetFileLineFromAddress(void*address,char*fileName,size_t size,size_t*lineNumber,size_t*offsetBytes);
+MSVC_DBG_EXPORT size_t GetFileLineFromStack(size_t skip,char*fileName,size_t size,size_t*lineNumber,size_t*offsetBytes);
+MSVC_DBG_EXPORT size_t GetDescriptionFromAddress(void*address,const char*format,char*description,size_t size);
+MSVC_DBG_EXPORT size_t GetDescriptionFromStack(void*const frames[],size_t count,const char*format,char*description[],size_t size);
+MSVC_DBG_EXPORT int backtrace(void*addresses[],int count);
+MSVC_DBG_EXPORT char**backtrace_symbols(void*const addresses[],int count);
+#ifdef __cplusplus
+}
+#endif
+#endif
+#else
+#include <execinfo.h>
+#endif
+#endif
+#ifdef SAVE_CALL_CHAIN
+#if NARGS==0&&NFRAMES % 2==0&&defined(GC_HAVE_BUILTIN_BACKTRACE)
+#ifdef REDIRECT_MALLOC
+#ifdef THREADS
+__thread
+#endif
+GC_bool GC_in_save_callers=FALSE;
+#endif
+GC_INNER void GC_save_callers(struct callinfo info[NFRAMES])
+{
+void*tmp_info[NFRAMES+1];
+int npcs,i;
+#define IGNORE_FRAMES 1
+#ifdef REDIRECT_MALLOC
+if (GC_in_save_callers){
+info[0].ci_pc=(word)(&GC_save_callers);
+for (i=1;i < NFRAMES;++i)info[i].ci_pc=0;
+return;
+}
+GC_in_save_callers=TRUE;
+#endif
+GC_ASSERT(I_HOLD_LOCK());
+GC_STATIC_ASSERT(sizeof(struct callinfo)==sizeof(void*));
+npcs=backtrace((void**)tmp_info,NFRAMES+IGNORE_FRAMES);
+if (npcs > IGNORE_FRAMES)
+BCOPY(&tmp_info[IGNORE_FRAMES],info,
+(npcs - IGNORE_FRAMES)*sizeof(void*));
+for (i=npcs - IGNORE_FRAMES;i < NFRAMES;++i)info[i].ci_pc=0;
+#ifdef REDIRECT_MALLOC
+GC_in_save_callers=FALSE;
+#endif
+}
+#else
+#if (defined(OPENBSD)||defined(NETBSD)||defined(FREEBSD))&&defined(SPARC)
+#define FR_SAVFP fr_fp
+#define FR_SAVPC fr_pc
+#else
+#define FR_SAVFP fr_savfp
+#define FR_SAVPC fr_savpc
+#endif
+#if defined(SPARC)&&(defined(__arch64__)||defined(__sparcv9))
+#define BIAS 2047
+#else
+#define BIAS 0
+#endif
+GC_INNER void GC_save_callers(struct callinfo info[NFRAMES])
+{
+struct frame*frame;
+struct frame*fp;
+int nframes=0;
+#ifdef I386
+asm("movl %%ebp,%0":"=r"(frame));
+fp=frame;
+#else
+frame=(struct frame*)GC_save_regs_in_stack();
+fp=(struct frame*)((long)frame->FR_SAVFP+BIAS);
+#endif
+for (;!((word)fp HOTTER_THAN (word)frame)
+#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
+int i;
+#endif
+info[nframes].ci_pc=fp->FR_SAVPC;
+#if NARGS > 0
+for (i=0;i < NARGS;i++){
+info[nframes].ci_arg[i]=~(fp->fr_arg[i]);
+}
+#endif
+}
+if (nframes < NFRAMES)info[nframes].ci_pc=0;
+}
+#endif
+#endif
+#ifdef NEED_CALLINFO
+GC_INNER void GC_print_callers(struct callinfo info[NFRAMES])
+{
+int i;
+static int reentry_count=0;
+DCL_LOCK_STATE;
+LOCK();
+++reentry_count;
+UNLOCK();
+#if NFRAMES==1
+GC_err_printf("\tCaller at allocation:\n");
+#else
+GC_err_printf("\tCall chain at allocation:\n");
+#endif
+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;
+GC_err_printf("\t\targs:");
+for (j=0;j < NARGS;j++){
+if (j!=0)GC_err_printf(",");
+GC_err_printf("%d (0x%X)",~(info[i].ci_arg[j]),
+~(info[i].ci_arg[j]));
+}
+GC_err_printf("\n");
+}
+#endif
+if (reentry_count > 1){
+GC_err_printf("\t\t##PC##=0x%lx\n",
+(unsigned long)info[i].ci_pc);
+continue;
+}
+{
+char buf[40];
+char*name;
+#if defined(GC_HAVE_BUILTIN_BACKTRACE)&&!defined(GC_BACKTRACE_SYMBOLS_BROKEN)
+char**sym_name=
+backtrace_symbols((void**)(&(info[i].ci_pc)),1);
+if (sym_name!=NULL){
+name=sym_name[0];
+} else
+#endif
+{
+(void)snprintf(buf,sizeof(buf),"##PC##=0x%lx",
+(unsigned long)info[i].ci_pc);
+buf[sizeof(buf)- 1]='\0';
+name=buf;
+}
+#if defined(LINUX)&&!defined(SMALL_CONFIG)
+do {
+FILE*pipe;
+#define EXE_SZ 100
+static char exe_name[EXE_SZ];
+#define CMD_SZ 200
+char cmd_buf[CMD_SZ];
+#define RESULT_SZ 200
+static char result_buf[RESULT_SZ];
+size_t result_len;
+char*old_preload;
+#define PRELOAD_SZ 200
+char preload_buf[PRELOAD_SZ];
+static GC_bool found_exe_name=FALSE;
+static GC_bool will_fail=FALSE;
+if (will_fail)
+break;
+if (!found_exe_name){
+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;
+break;
+}
+exe_name[ret_code]='\0';
+found_exe_name=TRUE;
+}
+(void)snprintf(cmd_buf,sizeof(cmd_buf),
+"/usr/bin/addr2line -f -e %s 0x%lx",
+exe_name,(unsigned long)info[i].ci_pc);
+cmd_buf[sizeof(cmd_buf)- 1]='\0';
+old_preload=GETENV("LD_PRELOAD");
+if (0!=old_preload){
+size_t old_len=strlen(old_preload);
+if (old_len>=PRELOAD_SZ){
+will_fail=TRUE;
+break;
+}
+BCOPY(old_preload,preload_buf,old_len+1);
+unsetenv ("LD_PRELOAD");
+}
+pipe=popen(cmd_buf,"r");
+if (0!=old_preload
+&&0!=setenv ("LD_PRELOAD",preload_buf,0)){
+WARN("Failed to reset LD_PRELOAD\n",0);
+}
+if (NULL==pipe){
+will_fail=TRUE;
+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'))
+break;
+{
+char*nl=strchr(result_buf,'\n');
+if (nl!=NULL
+&&(word)nl < (word)(result_buf+result_len)){
+*nl=':';
+}
+if (strncmp(result_buf,"main",
+nl!=NULL
+?(size_t)((word)nl
+- COVERT_DATAFLOW(result_buf))
+:result_len)==0){
+stop=TRUE;
+}
+}
+if (result_len < RESULT_SZ - 25){
+(void)snprintf(&result_buf[result_len],
+sizeof(result_buf)- result_len,
+" [0x%lx]",(unsigned long)info[i].ci_pc);
+result_buf[sizeof(result_buf)- 1]='\0';
+}
+#if defined(CPPCHECK)
+GC_noop1((unsigned char)name[0]);
+#endif
+name=result_buf;
+} while (0);
+#endif
+GC_err_printf("\t\t%s\n",name);
+#if defined(GC_HAVE_BUILTIN_BACKTRACE)&&!defined(GC_BACKTRACE_SYMBOLS_BROKEN)
+if (sym_name!=NULL)
+free(sym_name);
+#endif
+}
+#if defined(LINUX)&&!defined(SMALL_CONFIG)
+if (stop)
+break;
+#endif
+}
+LOCK();
+--reentry_count;
+UNLOCK();
+}
+#endif
+#if defined(LINUX)&&defined(__ELF__)&&!defined(SMALL_CONFIG)
+void GC_print_address_map(void)
+{
+char*maps;
+GC_err_printf("----------Begin address map----------\n");
+maps=GC_get_maps();
+GC_err_puts(maps!=NULL?maps:"Failed to get map!\n");
+GC_err_printf("----------End address map----------\n");
+}
+#endif
+#if defined(THREAD_LOCAL_ALLOC)
+#ifndef THREADS
+#error "invalid config - THREAD_LOCAL_ALLOC requires GC_THREADS"
+#endif
+#ifndef GC_THREAD_LOCAL_ALLOC_H
+#define GC_THREAD_LOCAL_ALLOC_H
+#ifdef THREAD_LOCAL_ALLOC
+#if defined(USE_HPUX_TLS)
+#error USE_HPUX_TLS macro was replaced by USE_COMPILER_TLS
+#endif
+#include <stdlib.h>
+EXTERN_C_BEGIN
+#if!defined(USE_PTHREAD_SPECIFIC)&&!defined(USE_WIN32_SPECIFIC)&&!defined(USE_WIN32_COMPILER_TLS)&&!defined(USE_COMPILER_TLS)&&!defined(USE_CUSTOM_SPECIFIC)
+#if defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32)
+#if defined(CYGWIN32)&&GC_GNUC_PREREQ(4,0)
+#if defined(__clang__)
+#define USE_PTHREAD_SPECIFIC
+#else
+#define USE_COMPILER_TLS
+#endif
+#elif defined(__GNUC__)||defined(MSWINCE)
+#define USE_WIN32_SPECIFIC
+#else
+#define USE_WIN32_COMPILER_TLS
+#endif
+#elif (defined(LINUX)&&!defined(ARM32)&&!defined(AVR32)&&GC_GNUC_PREREQ(3,3)&&!(defined(__clang__)&&defined(HOST_ANDROID)))||(defined(FREEBSD)||(defined(NETBSD)&&__NetBSD_Version__>=600000000)&&(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
+#elif defined(GC_DGUX386_THREADS)||defined(GC_OSF1_THREADS)||defined(GC_AIX_THREADS)||defined(GC_DARWIN_THREADS)||defined(GC_FREEBSD_THREADS)||defined(GC_NETBSD_THREADS)||defined(GC_LINUX_THREADS)||defined(GC_HAIKU_THREADS)||defined(GC_RTEMS_PTHREADS)
+#define USE_PTHREAD_SPECIFIC
+#elif defined(GC_HPUX_THREADS)
+#ifdef __GNUC__
+#define USE_PTHREAD_SPECIFIC
+#else
+#define USE_COMPILER_TLS
+#endif
+#else
+#define USE_CUSTOM_SPECIFIC
+#endif
+#endif
+#ifndef THREAD_FREELISTS_KINDS
+#ifdef ENABLE_DISCLAIM
+#define THREAD_FREELISTS_KINDS (NORMAL+2)
+#else
+#define THREAD_FREELISTS_KINDS (NORMAL+1)
+#endif
+#endif
+typedef struct thread_local_freelists {
+void*_freelists[THREAD_FREELISTS_KINDS][TINY_FREELISTS];
+#define ptrfree_freelists _freelists[PTRFREE]
+#define normal_freelists _freelists[NORMAL]
+#ifdef GC_GCJ_SUPPORT
+void*gcj_freelists[TINY_FREELISTS];
+#define ERROR_FL ((void*)GC_WORD_MAX)
+#endif
+#define DIRECT_GRANULES (HBLKSIZE/GRANULE_BYTES)
+}*GC_tlfs;
+#if defined(USE_PTHREAD_SPECIFIC)
+#define GC_getspecific pthread_getspecific
+#define GC_setspecific pthread_setspecific
+#define GC_key_create pthread_key_create
+#define GC_remove_specific(key)pthread_setspecific(key,NULL)
+#define GC_remove_specific_after_fork(key,t)(void)0
+typedef pthread_key_t GC_key_t;
+#elif defined(USE_COMPILER_TLS)||defined(USE_WIN32_COMPILER_TLS)
+#define GC_getspecific(x)(x)
+#define GC_setspecific(key,v)((key)=(v),0)
+#define GC_key_create(key,d)0
+#define GC_remove_specific(key)
+#define GC_remove_specific_after_fork(key,t)(void)0
+typedef void*GC_key_t;
+#elif defined(USE_WIN32_SPECIFIC)
+#define GC_getspecific TlsGetValue
+#define GC_setspecific(key,v)!TlsSetValue(key,v)
+#ifndef TLS_OUT_OF_INDEXES
+#define TLS_OUT_OF_INDEXES (DWORD)0xFFFFFFFF
+#endif
+#define GC_key_create(key,d)((d)!=0||(*(key)=TlsAlloc())==TLS_OUT_OF_INDEXES?-1:0)
+#define GC_remove_specific(key)
+#define GC_remove_specific_after_fork(key,t)(void)0
+typedef DWORD GC_key_t;
+#elif defined(USE_CUSTOM_SPECIFIC)
+EXTERN_C_END
+#ifndef GC_SPECIFIC_H
+#define GC_SPECIFIC_H
+#include <errno.h>
+EXTERN_C_BEGIN
+#define MALLOC_CLEAR(n)GC_INTERNAL_MALLOC(n,NORMAL)
+#define TS_CACHE_SIZE 1024
+#define CACHE_HASH(n)((((n)>>8)^(n))&(TS_CACHE_SIZE - 1))
+#define TS_HASH_SIZE 1024
+#define HASH(p)((unsigned)((((word)(p))>>8)^(word)(p))&(TS_HASH_SIZE - 1))
+#ifdef GC_ASSERTIONS
+typedef GC_hidden_pointer ts_entry_value_t;
+#define TS_HIDE_VALUE(p)GC_HIDE_POINTER(p)
+#define TS_REVEAL_PTR(p)GC_REVEAL_POINTER(p)
+#else
+typedef void*ts_entry_value_t;
+#define TS_HIDE_VALUE(p)(p)
+#define TS_REVEAL_PTR(p)(p)
+#endif
+typedef struct thread_specific_entry {
+volatile AO_t qtid;
+ts_entry_value_t value;
+struct thread_specific_entry*next;
+pthread_t thread;
+} tse;
+#define quick_thread_id()(((word)GC_approx_sp())>>12)
+#define INVALID_QTID ((word)0)
+#define INVALID_THREADID ((pthread_t)0)
+union ptse_ao_u {
+tse*p;
+volatile AO_t ao;
+};
+typedef struct thread_specific_data {
+tse*volatile cache[TS_CACHE_SIZE];
+union ptse_ao_u hash[TS_HASH_SIZE];
+pthread_mutex_t lock;
+} tsd;
+typedef tsd*GC_key_t;
+#define GC_key_create(key,d)GC_key_create_inner(key)
+GC_INNER int GC_key_create_inner(tsd**key_ptr);
+GC_INNER int GC_setspecific(tsd*key,void*value);
+#define GC_remove_specific(key)GC_remove_specific_after_fork(key,pthread_self())
+GC_INNER void GC_remove_specific_after_fork(tsd*key,pthread_t t);
+GC_INNER void*GC_slow_getspecific(tsd*key,word qtid,
+tse*volatile*cache_entry);
+GC_INLINE void*GC_getspecific(tsd*key)
+{
+word qtid=quick_thread_id();
+tse*volatile*entry_ptr=&key->cache[CACHE_HASH(qtid)];
+tse*entry=*entry_ptr;
+GC_ASSERT(qtid!=INVALID_QTID);
+if (EXPECT(entry->qtid==qtid,TRUE)){
+GC_ASSERT(entry->thread==pthread_self());
+return TS_REVEAL_PTR(entry->value);
+}
+return GC_slow_getspecific(key,qtid,entry_ptr);
+}
+EXTERN_C_END
+#endif
+EXTERN_C_BEGIN
+#else
+#error implement me
+#endif
+GC_INNER void GC_init_thread_local(GC_tlfs p);
+GC_INNER void GC_destroy_thread_local(GC_tlfs p);
+GC_INNER void GC_mark_thread_local_fls_for(GC_tlfs p);
+#ifdef GC_ASSERTIONS
+GC_bool GC_is_thread_tsd_valid(void*tsd);
+void GC_check_tls_for(GC_tlfs p);
+#if defined(USE_CUSTOM_SPECIFIC)
+void GC_check_tsd_marks(tsd*key);
+#endif
+#endif
+#ifndef GC_ATTR_TLS_FAST
+#define GC_ATTR_TLS_FAST
+#endif
+extern
+#if defined(USE_COMPILER_TLS)
+__thread GC_ATTR_TLS_FAST
+#elif defined(USE_WIN32_COMPILER_TLS)
+__declspec(thread)GC_ATTR_TLS_FAST
+#endif
+GC_key_t GC_thread_key;
+EXTERN_C_END
+#endif
+#endif
+#include <stdlib.h>
+#if defined(USE_COMPILER_TLS)
+__thread GC_ATTR_TLS_FAST
+#elif defined(USE_WIN32_COMPILER_TLS)
+__declspec(thread)GC_ATTR_TLS_FAST
+#endif
+GC_key_t GC_thread_key;
+static GC_bool keys_initialized;
+static void return_single_freelist(void*fl,void**gfl)
+{
+if (*gfl==0){
+*gfl=fl;
+} else {
+void*q,**qptr;
+GC_ASSERT(GC_size(fl)==GC_size(*gfl));
+qptr=&(obj_link(fl));
+while ((word)(q=*qptr)>=HBLKSIZE)
+qptr=&(obj_link(q));
+GC_ASSERT(0==q);
+*qptr=*gfl;
+*gfl=fl;
+}
+}
+static void return_freelists(void**fl,void**gfl)
+{
+int i;
+for (i=1;i < TINY_FREELISTS;++i){
+if ((word)(fl[i])>=HBLKSIZE){
+return_single_freelist(fl[i],&gfl[i]);
+}
+fl[i]=(ptr_t)HBLKSIZE;
+}
+#ifdef GC_GCJ_SUPPORT
+if (fl[0]==ERROR_FL)return;
+#endif
+if ((word)(fl[0])>=HBLKSIZE){
+return_single_freelist(fl[0],&gfl[1]);
+}
+}
+#ifdef USE_PTHREAD_SPECIFIC
+static void reset_thread_key(void*v){
+pthread_setspecific(GC_thread_key,v);
+}
+#else
+#define reset_thread_key 0
+#endif
+GC_INNER void GC_init_thread_local(GC_tlfs p)
+{
+int i,j,res;
+GC_ASSERT(I_HOLD_LOCK());
+if (!EXPECT(keys_initialized,TRUE)){
+GC_ASSERT((word)&GC_thread_key % sizeof(word)==0);
+res=GC_key_create(&GC_thread_key,reset_thread_key);
+if (COVERT_DATAFLOW(res)!=0){
+ABORT("Failed to create key for local allocator");
+}
+keys_initialized=TRUE;
+}
+res=GC_setspecific(GC_thread_key,p);
+if (COVERT_DATAFLOW(res)!=0){
+ABORT("Failed to set thread specific allocation pointers");
+}
+for (j=0;j < TINY_FREELISTS;++j){
+for (i=0;i < THREAD_FREELISTS_KINDS;++i){
+p->_freelists[i][j]=(void*)(word)1;
+}
+#ifdef GC_GCJ_SUPPORT
+p->gcj_freelists[j]=(void*)(word)1;
+#endif
+}
+#ifdef GC_GCJ_SUPPORT
+p->gcj_freelists[0]=ERROR_FL;
+#endif
+}
+GC_INNER void GC_destroy_thread_local(GC_tlfs p)
+{
+int k;
+GC_STATIC_ASSERT(THREAD_FREELISTS_KINDS<=MAXOBJKINDS);
+for (k=0;k < THREAD_FREELISTS_KINDS;++k){
+if (k==(int)GC_n_kinds)
+break;
+return_freelists(p->_freelists[k],GC_obj_kinds[k].ok_freelist);
+}
+#ifdef GC_GCJ_SUPPORT
+return_freelists(p->gcj_freelists,(void**)GC_gcjobjfreelist);
+#endif
+}
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_malloc_kind(size_t bytes,int kind)
+{
+size_t granules;
+void*tsd;
+void*result;
+#if MAXOBJKINDS > THREAD_FREELISTS_KINDS
+if (EXPECT(kind>=THREAD_FREELISTS_KINDS,FALSE)){
+return GC_malloc_kind_global(bytes,kind);
+}
+#endif
+#if!defined(USE_PTHREAD_SPECIFIC)&&!defined(USE_WIN32_SPECIFIC)
+{
+GC_key_t k=GC_thread_key;
+if (EXPECT(0==k,FALSE)){
+return GC_malloc_kind_global(bytes,kind);
+}
+tsd=GC_getspecific(k);
+}
+#else
+if (!EXPECT(keys_initialized,TRUE))
+return GC_malloc_kind_global(bytes,kind);
+tsd=GC_getspecific(GC_thread_key);
+#endif
+#if!defined(USE_COMPILER_TLS)&&!defined(USE_WIN32_COMPILER_TLS)
+if (EXPECT(0==tsd,FALSE)){
+return GC_malloc_kind_global(bytes,kind);
+}
+#endif
+GC_ASSERT(GC_is_initialized);
+GC_ASSERT(GC_is_thread_tsd_valid(tsd));
+granules=ROUNDED_UP_GRANULES(bytes);
+#if defined(CPPCHECK)
+#define MALLOC_KIND_PTRFREE_INIT (void*)1
+#else
+#define MALLOC_KIND_PTRFREE_INIT NULL
+#endif
+GC_FAST_MALLOC_GRANS(result,granules,
+((GC_tlfs)tsd)->_freelists[kind],DIRECT_GRANULES,
+kind,GC_malloc_kind_global(bytes,kind),
+(void)(kind==PTRFREE?MALLOC_KIND_PTRFREE_INIT
+:(obj_link(result)=0)));
+#ifdef LOG_ALLOCS
+GC_log_printf("GC_malloc_kind(%lu,%d)returned %p,recent GC #%lu\n",
+(unsigned long)bytes,kind,result,
+(unsigned long)GC_gc_no);
+#endif
+return result;
+}
+#ifdef GC_GCJ_SUPPORT
+GC_API GC_ATTR_MALLOC void*GC_CALL GC_gcj_malloc(size_t bytes,
+void*ptr_to_struct_containing_descr)
+{
+if (EXPECT(GC_incremental,FALSE)){
+return GC_core_gcj_malloc(bytes,ptr_to_struct_containing_descr);
+} else {
+size_t granules=ROUNDED_UP_GRANULES(bytes);
+void*result;
+void**tiny_fl;
+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,
+GC_core_gcj_malloc(bytes,
+ptr_to_struct_containing_descr),
+{AO_compiler_barrier();
+*(void**)result=ptr_to_struct_containing_descr;});
+return result;
+}
+}
+#endif
+GC_INNER void GC_mark_thread_local_fls_for(GC_tlfs p)
+{
+ptr_t q;
+int i,j;
+for (j=0;j < TINY_FREELISTS;++j){
+for (i=0;i < THREAD_FREELISTS_KINDS;++i){
+q=(ptr_t)AO_load((volatile AO_t*)&p->_freelists[i][j]);
+if ((word)q > HBLKSIZE)
+GC_set_fl_marks(q);
+}
+#ifdef GC_GCJ_SUPPORT
+if (EXPECT(j > 0,TRUE)){
+q=(ptr_t)AO_load((volatile AO_t*)&p->gcj_freelists[j]);
+if ((word)q > HBLKSIZE)
+GC_set_fl_marks(q);
+}
+#endif
+}
+}
+#if defined(GC_ASSERTIONS)
+void GC_check_tls_for(GC_tlfs p)
+{
+int i,j;
+for (j=1;j < TINY_FREELISTS;++j){
+for (i=0;i < THREAD_FREELISTS_KINDS;++i){
+GC_check_fl_marks(&p->_freelists[i][j]);
+}
+#ifdef GC_GCJ_SUPPORT
+GC_check_fl_marks(&p->gcj_freelists[j]);
+#endif
+}
+}
+#endif
+#endif
+#ifndef GC_PTHREAD_SUPPORT_H
+#define GC_PTHREAD_SUPPORT_H
+#if defined(GC_PTHREADS)&&!defined(GC_WIN32_THREADS)
+#if defined(GC_DARWIN_THREADS)
+#else
+#ifndef GC_PTHREAD_STOP_WORLD_H
+#define GC_PTHREAD_STOP_WORLD_H
+EXTERN_C_BEGIN
+struct thread_stop_info {
+#if!defined(GC_OPENBSD_UTHREADS)&&!defined(NACL)&&!defined(SN_TARGET_ORBIS)&&!defined(SN_TARGET_PSP2)
+volatile AO_t last_stop_count;
+#endif
+ptr_t stack_ptr;
+#ifdef NACL
+#ifdef ARM32
+#define NACL_GC_REG_STORAGE_SIZE 9
+#else
+#define NACL_GC_REG_STORAGE_SIZE 20
+#endif
+ptr_t reg_storage[NACL_GC_REG_STORAGE_SIZE];
+#elif defined(SN_TARGET_ORBIS)
+#define ORBIS_GC_REG_STORAGE_SIZE 27
+word registers[ORBIS_GC_REG_STORAGE_SIZE];
+#endif
+};
+GC_INNER void GC_stop_init(void);
+EXTERN_C_END
+#endif
+#endif
+#ifdef THREAD_LOCAL_ALLOC
+#endif
+#ifdef THREAD_SANITIZER
+#endif
+EXTERN_C_BEGIN
+typedef struct GC_Thread_Rep {
+#ifdef THREAD_SANITIZER
+char dummy[sizeof(oh)];
+#endif
+struct GC_Thread_Rep*next;
+pthread_t id;
+#ifdef USE_TKILL_ON_ANDROID
+pid_t kernel_id;
+#endif
+struct thread_stop_info stop_info;
+#if defined(GC_ENABLE_SUSPEND_THREAD)&&!defined(GC_DARWIN_THREADS)&&!defined(GC_OPENBSD_UTHREADS)&&!defined(NACL)
+volatile AO_t suspended_ext;
+#endif
+unsigned char flags;
+#define FINISHED 1
+#define DETACHED 2
+#define MAIN_THREAD 4
+#define DISABLED_GC 0x10
+unsigned char thread_blocked;
+unsigned short finalizer_skipped;
+unsigned char finalizer_nested;
+ptr_t stack_end;
+ptr_t altstack;
+word altstack_size;
+ptr_t stack;
+word stack_size;
+#if defined(GC_DARWIN_THREADS)&&!defined(DARWIN_DONT_PARSE_STACK)
+ptr_t topOfStack;
+#endif
+#ifdef IA64
+ptr_t backing_store_end;
+ptr_t backing_store_ptr;
+#endif
+struct GC_traced_stack_sect_s*traced_stack_sect;
+void*status;
+#ifdef THREAD_LOCAL_ALLOC
+struct thread_local_freelists tlfs GC_ATTR_WORD_ALIGNED;
+#endif
+}*GC_thread;
+#ifndef THREAD_TABLE_SZ
+#define THREAD_TABLE_SZ 256
+#endif
+#if CPP_WORDSZ==64
+#define THREAD_TABLE_INDEX(id)(int)(((((NUMERIC_THREAD_ID(id)>>8)^NUMERIC_THREAD_ID(id))>>16)^((NUMERIC_THREAD_ID(id)>>8)^NUMERIC_THREAD_ID(id)))% THREAD_TABLE_SZ)
+#else
+#define THREAD_TABLE_INDEX(id)(int)(((NUMERIC_THREAD_ID(id)>>16)^(NUMERIC_THREAD_ID(id)>>8)^NUMERIC_THREAD_ID(id))% THREAD_TABLE_SZ)
+#endif
+GC_EXTERN volatile GC_thread GC_threads[THREAD_TABLE_SZ];
+GC_EXTERN GC_bool GC_thr_initialized;
+GC_INNER GC_thread GC_lookup_thread(pthread_t id);
+#ifdef NACL
+GC_EXTERN __thread GC_thread GC_nacl_gc_thread_self;
+GC_INNER void GC_nacl_initialize_gc_thread(void);
+GC_INNER void GC_nacl_shutdown_gc_thread(void);
+#endif
+#ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
+GC_INNER void GC_unblock_gc_signals(void);
+#endif
+#ifdef GC_PTHREAD_START_STANDALONE
+#define GC_INNER_PTHRSTART
+#else
+#define GC_INNER_PTHRSTART GC_INNER
+#endif
+GC_INNER_PTHRSTART void*GC_CALLBACK GC_inner_start_routine(
+struct GC_stack_base*sb,void*arg);
+GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread(
+void*(**pstart)(void*),
+void**pstart_arg,
+struct GC_stack_base*sb,void*arg);
+GC_INNER_PTHRSTART void GC_thread_exit_proc(void*);
+EXTERN_C_END
+#endif
+#endif
+#if defined(GC_DARWIN_THREADS)
+#include <sys/sysctl.h>
+#include <mach/machine.h>
+#include <CoreFoundation/CoreFoundation.h>
+#ifdef POWERPC
+#if CPP_WORDSZ==32
+#define PPC_RED_ZONE_SIZE 224
+#elif CPP_WORDSZ==64
+#define PPC_RED_ZONE_SIZE 320
+#endif
+#endif
+#ifndef DARWIN_DONT_PARSE_STACK
+typedef struct StackFrame {
+unsigned long savedSP;
+unsigned long savedCR;
+unsigned long savedLR;
+unsigned long reserved[2];
+unsigned long savedRTOC;
+} StackFrame;
+GC_INNER ptr_t GC_FindTopOfStack(unsigned long stack_start)
+{
+StackFrame*frame=(StackFrame*)stack_start;
+if (stack_start==0){
+#ifdef POWERPC
+#if CPP_WORDSZ==32
+__asm__ __volatile__ ("lwz %0,0(r1)":"=r" (frame));
+#else
+__asm__ __volatile__ ("ld %0,0(r1)":"=r" (frame));
+#endif
+#elif defined(ARM32)
+volatile ptr_t sp_reg;
+__asm__ __volatile__ ("mov %0,r7\n":"=r" (sp_reg));
+frame=(StackFrame*)sp_reg;
+#elif defined(AARCH64)
+volatile ptr_t sp_reg;
+__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
+}
+#ifdef DEBUG_THREADS_EXTRA
+GC_log_printf("FindTopOfStack start at sp=%p\n",(void*)frame);
+#endif
+while (frame->savedSP!=0){
+frame=(StackFrame*)frame->savedSP;
+if ((frame->savedLR&~0x3)==0||(frame->savedLR&~0x3)==~0x3UL)
+break;
+}
+#ifdef DEBUG_THREADS_EXTRA
+GC_log_printf("FindTopOfStack finish at sp=%p\n",(void*)frame);
+#endif
+return (ptr_t)frame;
+}
+#endif
+#ifdef GC_NO_THREADS_DISCOVERY
+#define GC_query_task_threads FALSE
+#elif defined(GC_DISCOVER_TASK_THREADS)
+#define GC_query_task_threads TRUE
+#else
+STATIC GC_bool GC_query_task_threads=FALSE;
+#endif
+GC_API void GC_CALL GC_use_threads_discovery(void)
+{
+#if defined(GC_NO_THREADS_DISCOVERY)||defined(DARWIN_DONT_PARSE_STACK)
+ABORT("Darwin task-threads-based stop and push unsupported");
+#else
+#ifndef GC_ALWAYS_MULTITHREADED
+GC_ASSERT(!GC_need_to_lock);
+#endif
+#ifndef GC_DISCOVER_TASK_THREADS
+GC_query_task_threads=TRUE;
+#endif
+GC_init_parallel();
+#endif
+}
+#ifndef kCFCoreFoundationVersionNumber_iOS_8_0
+#define kCFCoreFoundationVersionNumber_iOS_8_0 1140.1
+#endif
+STATIC ptr_t GC_stack_range_for(ptr_t*phi,thread_act_t thread,GC_thread p,
+GC_bool thread_blocked,mach_port_t my_thread,
+ptr_t*paltstack_lo,
+ptr_t*paltstack_hi GC_ATTR_UNUSED)
+{
+ptr_t lo;
+if (thread==my_thread){
+GC_ASSERT(!thread_blocked);
+lo=GC_approx_sp();
+#ifndef DARWIN_DONT_PARSE_STACK
+*phi=GC_FindTopOfStack(0);
+#endif
+} else if (thread_blocked){
+#if defined(CPPCHECK)
+if (NULL==p)ABORT("Invalid GC_thread passed to GC_stack_range_for");
+#endif
+lo=p->stop_info.stack_ptr;
+#ifndef DARWIN_DONT_PARSE_STACK
+*phi=p->topOfStack;
+#endif
+} else {
+kern_return_t kern_result;
+GC_THREAD_STATE_T state;
+#if defined(ARM32)&&defined(ARM_THREAD_STATE32)
+size_t size;
+static cpu_type_t cputype=0;
+if (cputype==0){
+sysctlbyname("hw.cputype",&cputype,&size,NULL,0);
+}
+if (cputype==CPU_TYPE_ARM64
+||kCFCoreFoundationVersionNumber
+>=kCFCoreFoundationVersionNumber_iOS_8_0){
+arm_unified_thread_state_t unified_state;
+mach_msg_type_number_t unified_thread_state_count
+=ARM_UNIFIED_THREAD_STATE_COUNT;
+#if defined(CPPCHECK)
+#define GC_ARM_UNIFIED_THREAD_STATE 1
+#else
+#define GC_ARM_UNIFIED_THREAD_STATE ARM_UNIFIED_THREAD_STATE
+#endif
+kern_result=thread_get_state(thread,GC_ARM_UNIFIED_THREAD_STATE,
+(natural_t*)&unified_state,
+&unified_thread_state_count);
+#if!defined(CPPCHECK)
+if (unified_state.ash.flavor!=ARM_THREAD_STATE32){
+ABORT("unified_state flavor should be ARM_THREAD_STATE32");
+}
+#endif
+state=unified_state;
+} else
+#endif
+{
+mach_msg_type_number_t thread_state_count=GC_MACH_THREAD_STATE_COUNT;
+kern_result=thread_get_state(thread,GC_MACH_THREAD_STATE,
+(natural_t*)&state,
+&thread_state_count);
+}
+#ifdef DEBUG_THREADS
+GC_log_printf("thread_get_state returns value=%d\n",kern_result);
+#endif
+if (kern_result!=KERN_SUCCESS)
+ABORT("thread_get_state failed");
+#if defined(I386)
+lo=(ptr_t)state.THREAD_FLD(esp);
+#ifndef DARWIN_DONT_PARSE_STACK
+*phi=GC_FindTopOfStack(state.THREAD_FLD(esp));
+#endif
+GC_push_one(state.THREAD_FLD(eax));
+GC_push_one(state.THREAD_FLD(ebx));
+GC_push_one(state.THREAD_FLD(ecx));
+GC_push_one(state.THREAD_FLD(edx));
+GC_push_one(state.THREAD_FLD(edi));
+GC_push_one(state.THREAD_FLD(esi));
+GC_push_one(state.THREAD_FLD(ebp));
+#elif defined(X86_64)
+lo=(ptr_t)state.THREAD_FLD(rsp);
+#ifndef DARWIN_DONT_PARSE_STACK
+*phi=GC_FindTopOfStack(state.THREAD_FLD(rsp));
+#endif
+GC_push_one(state.THREAD_FLD(rax));
+GC_push_one(state.THREAD_FLD(rbx));
+GC_push_one(state.THREAD_FLD(rcx));
+GC_push_one(state.THREAD_FLD(rdx));
+GC_push_one(state.THREAD_FLD(rdi));
+GC_push_one(state.THREAD_FLD(rsi));
+GC_push_one(state.THREAD_FLD(rbp));
+GC_push_one(state.THREAD_FLD(r8));
+GC_push_one(state.THREAD_FLD(r9));
+GC_push_one(state.THREAD_FLD(r10));
+GC_push_one(state.THREAD_FLD(r11));
+GC_push_one(state.THREAD_FLD(r12));
+GC_push_one(state.THREAD_FLD(r13));
+GC_push_one(state.THREAD_FLD(r14));
+GC_push_one(state.THREAD_FLD(r15));
+#elif defined(POWERPC)
+lo=(ptr_t)(state.THREAD_FLD(r1)- PPC_RED_ZONE_SIZE);
+#ifndef DARWIN_DONT_PARSE_STACK
+*phi=GC_FindTopOfStack(state.THREAD_FLD(r1));
+#endif
+GC_push_one(state.THREAD_FLD(r0));
+GC_push_one(state.THREAD_FLD(r2));
+GC_push_one(state.THREAD_FLD(r3));
+GC_push_one(state.THREAD_FLD(r4));
+GC_push_one(state.THREAD_FLD(r5));
+GC_push_one(state.THREAD_FLD(r6));
+GC_push_one(state.THREAD_FLD(r7));
+GC_push_one(state.THREAD_FLD(r8));
+GC_push_one(state.THREAD_FLD(r9));
+GC_push_one(state.THREAD_FLD(r10));
+GC_push_one(state.THREAD_FLD(r11));
+GC_push_one(state.THREAD_FLD(r12));
+GC_push_one(state.THREAD_FLD(r13));
+GC_push_one(state.THREAD_FLD(r14));
+GC_push_one(state.THREAD_FLD(r15));
+GC_push_one(state.THREAD_FLD(r16));
+GC_push_one(state.THREAD_FLD(r17));
+GC_push_one(state.THREAD_FLD(r18));
+GC_push_one(state.THREAD_FLD(r19));
+GC_push_one(state.THREAD_FLD(r20));
+GC_push_one(state.THREAD_FLD(r21));
+GC_push_one(state.THREAD_FLD(r22));
+GC_push_one(state.THREAD_FLD(r23));
+GC_push_one(state.THREAD_FLD(r24));
+GC_push_one(state.THREAD_FLD(r25));
+GC_push_one(state.THREAD_FLD(r26));
+GC_push_one(state.THREAD_FLD(r27));
+GC_push_one(state.THREAD_FLD(r28));
+GC_push_one(state.THREAD_FLD(r29));
+GC_push_one(state.THREAD_FLD(r30));
+GC_push_one(state.THREAD_FLD(r31));
+#elif defined(ARM32)
+lo=(ptr_t)state.THREAD_FLD(sp);
+#ifndef DARWIN_DONT_PARSE_STACK
+*phi=GC_FindTopOfStack(state.THREAD_FLD(r[7]));
+#endif
+{
+int j;
+for (j=0;j < 7;j++)
+GC_push_one(state.THREAD_FLD(r[j]));
+j++;
+for (;j<=12;j++)
+GC_push_one(state.THREAD_FLD(r[j]));
+}
+GC_push_one(state.THREAD_FLD(lr));
+#elif defined(AARCH64)
+lo=(ptr_t)state.THREAD_FLD(sp);
+#ifndef DARWIN_DONT_PARSE_STACK
+*phi=GC_FindTopOfStack(state.THREAD_FLD(fp));
+#endif
+{
+int j;
+for (j=0;j<=28;j++){
+GC_push_one(state.THREAD_FLD(x[j]));
+}
+}
+GC_push_one(state.THREAD_FLD(lr));
+#elif defined(CPPCHECK)
+lo=NULL;
+#else
+#error FIXME for non-arm/ppc/x86 architectures
+#endif
+}
+#ifdef DARWIN_DONT_PARSE_STACK
+*phi=(p->flags&MAIN_THREAD)!=0?GC_stackbottom:p->stack_end;
+#endif
+#ifdef DARWIN_DONT_PARSE_STACK
+if (p->altstack!=NULL&&(word)p->altstack<=(word)lo
+&&(word)lo<=(word)p->altstack+p->altstack_size){
+*paltstack_lo=lo;
+*paltstack_hi=p->altstack+p->altstack_size;
+lo=p->stack;
+*phi=p->stack+p->stack_size;
+} else
+#endif
+{
+*paltstack_lo=NULL;
+}
+#ifdef DEBUG_THREADS
+GC_log_printf("Darwin:Stack for thread %p=[%p,%p)\n",
+(void*)(word)thread,(void*)lo,(void*)(*phi));
+#endif
+return lo;
+}
+GC_INNER void GC_push_all_stacks(void)
+{
+ptr_t hi,altstack_lo,altstack_hi;
+task_t my_task=current_task();
+mach_port_t my_thread=mach_thread_self();
+GC_bool found_me=FALSE;
+int nthreads=0;
+word total_size=0;
+mach_msg_type_number_t listcount=(mach_msg_type_number_t)THREAD_TABLE_SZ;
+if (!EXPECT(GC_thr_initialized,TRUE))
+GC_thr_init();
+#ifndef DARWIN_DONT_PARSE_STACK
+if (GC_query_task_threads){
+int i;
+kern_return_t kern_result;
+thread_act_array_t act_list=0;
+kern_result=task_threads(my_task,&act_list,&listcount);
+if (kern_result!=KERN_SUCCESS)
+ABORT("task_threads failed");
+for (i=0;i < (int)listcount;i++){
+thread_act_t thread=act_list[i];
+ptr_t lo=GC_stack_range_for(&hi,thread,NULL,FALSE,my_thread,
+&altstack_lo,&altstack_hi);
+if (lo){
+GC_ASSERT((word)lo<=(word)hi);
+total_size+=hi - lo;
+GC_push_all_stack(lo,hi);
+}
+nthreads++;
+if (thread==my_thread)
+found_me=TRUE;
+mach_port_deallocate(my_task,thread);
+}
+vm_deallocate(my_task,(vm_address_t)act_list,
+sizeof(thread_t)*listcount);
+} else
+#endif
+{
+int i;
+for (i=0;i < (int)listcount;i++){
+GC_thread p;
+for (p=GC_threads[i];p!=NULL;p=p->next)
+if ((p->flags&FINISHED)==0){
+thread_act_t thread=(thread_act_t)p->stop_info.mach_thread;
+ptr_t lo=GC_stack_range_for(&hi,thread,p,
+(GC_bool)p->thread_blocked,
+my_thread,&altstack_lo,
+&altstack_hi);
+if (lo){
+GC_ASSERT((word)lo<=(word)hi);
+total_size+=hi - lo;
+GC_push_all_stack_sections(lo,hi,p->traced_stack_sect);
+}
+if (altstack_lo){
+total_size+=altstack_hi - altstack_lo;
+GC_push_all_stack(altstack_lo,altstack_hi);
+}
+nthreads++;
+if (thread==my_thread)
+found_me=TRUE;
+}
+}
+}
+mach_port_deallocate(my_task,my_thread);
+GC_VERBOSE_LOG_PRINTF("Pushed %d thread stacks\n",nthreads);
+if (!found_me&&!GC_in_thread_creation)
+ABORT("Collecting from unknown thread");
+GC_total_stacksize=total_size;
+}
+#ifndef GC_NO_THREADS_DISCOVERY
+#ifdef MPROTECT_VDB
+STATIC mach_port_t GC_mach_handler_thread=0;
+STATIC GC_bool GC_use_mach_handler_thread=FALSE;
+GC_INNER void GC_darwin_register_mach_handler_thread(mach_port_t thread)
+{
+GC_mach_handler_thread=thread;
+GC_use_mach_handler_thread=TRUE;
+}
+#endif
+#ifndef GC_MAX_MACH_THREADS
+#define GC_MAX_MACH_THREADS THREAD_TABLE_SZ
+#endif
+struct GC_mach_thread {
+thread_act_t thread;
+GC_bool suspended;
+};
+struct GC_mach_thread GC_mach_threads[GC_MAX_MACH_THREADS];
+STATIC int GC_mach_threads_count=0;
+STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list,int count,
+thread_act_array_t old_list,
+int old_count,task_t my_task,
+mach_port_t my_thread)
+{
+int i;
+int j=-1;
+GC_bool changed=FALSE;
+for (i=0;i < count;i++){
+thread_act_t thread=act_list[i];
+GC_bool found;
+kern_return_t kern_result;
+if (thread==my_thread
+#ifdef MPROTECT_VDB
+||(GC_mach_handler_thread==thread&&GC_use_mach_handler_thread)
+#endif
+#ifdef PARALLEL_MARK
+||GC_is_mach_marker(thread)
+#endif
+){
+mach_port_deallocate(my_task,thread);
+continue;
+}
+found=FALSE;
+{
+int last_found=j;
+while (++j < old_count)
+if (old_list[j]==thread){
+found=TRUE;
+break;
+}
+if (!found){
+for (j=0;j < last_found;j++)
+if (old_list[j]==thread){
+found=TRUE;
+break;
+}
+}
+}
+if (found){
+mach_port_deallocate(my_task,thread);
+continue;
+}
+if (GC_mach_threads_count==GC_MAX_MACH_THREADS)
+ABORT("Too many threads");
+GC_mach_threads[GC_mach_threads_count].thread=thread;
+GC_mach_threads[GC_mach_threads_count].suspended=FALSE;
+changed=TRUE;
+#ifdef DEBUG_THREADS
+GC_log_printf("Suspending %p\n",(void*)(word)thread);
+#endif
+GC_acquire_dirty_lock();
+do {
+kern_result=thread_suspend(thread);
+} while (kern_result==KERN_ABORTED);
+GC_release_dirty_lock();
+if (kern_result!=KERN_SUCCESS){
+GC_mach_threads[GC_mach_threads_count].suspended=FALSE;
+} else {
+GC_mach_threads[GC_mach_threads_count].suspended=TRUE;
+if (GC_on_thread_event)
+GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED,(void*)(word)thread);
+}
+GC_mach_threads_count++;
+}
+return changed;
+}
+#endif
+GC_INNER void GC_stop_world(void)
+{
+task_t my_task=current_task();
+mach_port_t my_thread=mach_thread_self();
+kern_return_t kern_result;
+#ifdef DEBUG_THREADS
+GC_log_printf("Stopping the world from thread %p\n",
+(void*)(word)my_thread);
+#endif
+#ifdef PARALLEL_MARK
+if (GC_parallel){
+GC_acquire_mark_lock();
+GC_ASSERT(GC_fl_builder_count==0);
+}
+#endif
+if (GC_query_task_threads){
+#ifndef GC_NO_THREADS_DISCOVERY
+GC_bool changed;
+thread_act_array_t act_list,prev_list;
+mach_msg_type_number_t listcount,prevcount;
+GC_mach_threads_count=0;
+changed=TRUE;
+prev_list=NULL;
+prevcount=0;
+do {
+kern_result=task_threads(my_task,&act_list,&listcount);
+if (kern_result==KERN_SUCCESS){
+changed=GC_suspend_thread_list(act_list,listcount,prev_list,
+prevcount,my_task,my_thread);
+if (prev_list!=NULL){
+vm_deallocate(my_task,(vm_address_t)prev_list,
+sizeof(thread_t)*prevcount);
+}
+prev_list=act_list;
+prevcount=listcount;
+}
+} while (changed);
+GC_ASSERT(prev_list!=0);
+vm_deallocate(my_task,(vm_address_t)act_list,
+sizeof(thread_t)*listcount);
+#endif
+} else {
+unsigned i;
+for (i=0;i < THREAD_TABLE_SZ;i++){
+GC_thread p;
+for (p=GC_threads[i];p!=NULL;p=p->next){
+if ((p->flags&FINISHED)==0&&!p->thread_blocked&&
+p->stop_info.mach_thread!=my_thread){
+GC_acquire_dirty_lock();
+do {
+kern_result=thread_suspend(p->stop_info.mach_thread);
+} while (kern_result==KERN_ABORTED);
+GC_release_dirty_lock();
+if (kern_result!=KERN_SUCCESS)
+ABORT("thread_suspend failed");
+if (GC_on_thread_event)
+GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED,
+(void*)(word)p->stop_info.mach_thread);
+}
+}
+}
+}
+#ifdef MPROTECT_VDB
+if (GC_auto_incremental){
+GC_mprotect_stop();
+}
+#endif
+#ifdef PARALLEL_MARK
+if (GC_parallel)
+GC_release_mark_lock();
+#endif
+#ifdef DEBUG_THREADS
+GC_log_printf("World stopped from %p\n",(void*)(word)my_thread);
+#endif
+mach_port_deallocate(my_task,my_thread);
+}
+GC_INLINE void GC_thread_resume(thread_act_t thread)
+{
+kern_return_t kern_result;
+#if defined(DEBUG_THREADS)||defined(GC_ASSERTIONS)
+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)
+ABORT("thread_info failed");
+#endif
+#ifdef DEBUG_THREADS
+GC_log_printf("Resuming thread %p with state %d\n",(void*)(word)thread,
+info.run_state);
+#endif
+kern_result=thread_resume(thread);
+if (kern_result!=KERN_SUCCESS){
+WARN("thread_resume(%p)failed:mach port invalid\n",thread);
+} else if (GC_on_thread_event){
+GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED,(void*)(word)thread);
+}
+}
+GC_INNER void GC_start_world(void)
+{
+task_t my_task=current_task();
+#ifdef DEBUG_THREADS
+GC_log_printf("World starting\n");
+#endif
+#ifdef MPROTECT_VDB
+if (GC_auto_incremental){
+GC_mprotect_resume();
+}
+#endif
+if (GC_query_task_threads){
+#ifndef GC_NO_THREADS_DISCOVERY
+int i,j;
+kern_return_t kern_result;
+thread_act_array_t act_list;
+mach_msg_type_number_t listcount;
+kern_result=task_threads(my_task,&act_list,&listcount);
+if (kern_result!=KERN_SUCCESS)
+ABORT("task_threads failed");
+j=(int)listcount;
+for (i=0;i < GC_mach_threads_count;i++){
+thread_act_t thread=GC_mach_threads[i].thread;
+if (GC_mach_threads[i].suspended){
+int last_found=j;
+while (++j < (int)listcount){
+if (act_list[j]==thread)
+break;
+}
+if (j>=(int)listcount){
+for (j=0;j < last_found;j++){
+if (act_list[j]==thread)
+break;
+}
+}
+if (j!=last_found){
+GC_thread_resume(thread);
+}
+} else {
+#ifdef DEBUG_THREADS
+GC_log_printf("Not resuming thread %p as it is not suspended\n",
+(void*)(word)thread);
+#endif
+}
+mach_port_deallocate(my_task,thread);
+}
+for (i=0;i < (int)listcount;i++)
+mach_port_deallocate(my_task,act_list[i]);
+vm_deallocate(my_task,(vm_address_t)act_list,
+sizeof(thread_t)*listcount);
+#endif
+} else {
+int i;
+mach_port_t my_thread=mach_thread_self();
+for (i=0;i < THREAD_TABLE_SZ;i++){
+GC_thread p;
+for (p=GC_threads[i];p!=NULL;p=p->next){
+if ((p->flags&FINISHED)==0&&!p->thread_blocked&&
+p->stop_info.mach_thread!=my_thread)
+GC_thread_resume(p->stop_info.mach_thread);
+}
+}
+mach_port_deallocate(my_task,my_thread);
+}
+#ifdef DEBUG_THREADS
+GC_log_printf("World started\n");
+#endif
+}
+#endif
+#if!defined(MACOS)&&!defined(SN_TARGET_ORBIS)&&!defined(SN_TARGET_PSP2)&&!defined(_WIN32_WCE)&&!defined(__CC_ARM)
+#include <sys/types.h>
+#endif
+#undef GC_MUST_RESTORE_REDEFINED_DLOPEN
+#if defined(GC_PTHREADS)&&!defined(GC_NO_DLOPEN)&&!defined(GC_NO_THREAD_REDIRECTS)&&!defined(GC_USE_LD_WRAP)
+#undef dlopen
+#define GC_MUST_RESTORE_REDEFINED_DLOPEN
+#endif
+STATIC GC_has_static_roots_func GC_has_static_roots=0;
+#if (defined(DYNAMIC_LOADING)||defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32))&&!defined(PCR)
+#if!defined(DARWIN)&&!defined(SCO_ELF)&&!defined(SOLARISDL)&&!defined(AIX)&&!defined(DGUX)&&!defined(IRIX5)&&!defined(HPUX)&&!defined(CYGWIN32)&&!defined(MSWIN32)&&!defined(MSWINCE)&&!(defined(ALPHA)&&defined(OSF1))&&!(defined(FREEBSD)&&defined(__ELF__))&&!(defined(LINUX)&&defined(__ELF__))&&!(defined(NETBSD)&&defined(__ELF__))&&!(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.
+#endif
+#include <stdio.h>
+#ifdef SOLARISDL
+#include <sys/elf.h>
+#include <dlfcn.h>
+#include <link.h>
+#endif
+#if defined(NETBSD)
+#include <sys/param.h>
+#include <dlfcn.h>
+#include <machine/elf_machdep.h>
+#define ELFSIZE ARCH_ELFSIZE
+#endif
+#if defined(OPENBSD)
+#include <sys/param.h>
+#if (OpenBSD>=200519)&&!defined(HAVE_DL_ITERATE_PHDR)
+#define HAVE_DL_ITERATE_PHDR
+#endif
+#endif
+#if defined(SCO_ELF)||defined(DGUX)||defined(HURD)||defined(NACL)||(defined(__ELF__)&&(defined(LINUX)||defined(FREEBSD)||defined(NETBSD)||defined(OPENBSD)))
+#include <stddef.h>
+#if!defined(OPENBSD)&&!defined(HOST_ANDROID)
+#include <elf.h>
+#endif
+#ifdef HOST_ANDROID
+#ifdef BIONIC_ELFDATA_REDEF_BUG
+#include <asm/elf.h>
+#include <linux/elf-em.h>
+#undef ELF_DATA
+#undef EM_ALPHA
+#endif
+#include <link.h>
+#if!defined(GC_DONT_DEFINE_LINK_MAP)&&!(__ANDROID_API__>=21)
+struct link_map {
+uintptr_t l_addr;
+char*l_name;
+uintptr_t l_ld;
+struct link_map*l_next;
+struct link_map*l_prev;
+};
+struct r_debug {
+int32_t r_version;
+struct link_map*r_map;
+void (*r_brk)(void);
+int32_t r_state;
+uintptr_t r_ldbase;
+};
+#endif
+#else
+EXTERN_C_BEGIN
+#include <link.h>
+EXTERN_C_END
+#endif
+#endif
+#ifndef ElfW
+#if defined(FREEBSD)
+#if __ELF_WORD_SIZE==32
+#define ElfW(type)Elf32_##type
+#else
+#define ElfW(type)Elf64_##type
+#endif
+#elif defined(NETBSD)||defined(OPENBSD)
+#if ELFSIZE==32
+#define ElfW(type)Elf32_##type
+#elif ELFSIZE==64
+#define ElfW(type)Elf64_##type
+#else
+#error Missing ELFSIZE define
+#endif
+#else
+#if!defined(ELF_CLASS)||ELF_CLASS==ELFCLASS32
+#define ElfW(type)Elf32_##type
+#else
+#define ElfW(type)Elf64_##type
+#endif
+#endif
+#endif
+#if defined(SOLARISDL)&&!defined(USE_PROC_FOR_LIBRARIES)
+EXTERN_C_BEGIN
+extern ElfW(Dyn)_DYNAMIC;
+EXTERN_C_END
+STATIC struct link_map*
+GC_FirstDLOpenedLinkMap(void)
+{
+ElfW(Dyn)*dp;
+static struct link_map*cachedResult=0;
+static ElfW(Dyn)*dynStructureAddr=0;
+#ifdef SUNOS53_SHARED_LIB
+if( dynStructureAddr==0){
+void*startupSyms=dlopen(0,RTLD_LAZY);
+dynStructureAddr=(ElfW(Dyn)*)(word)dlsym(startupSyms,"_DYNAMIC");
+}
+#else
+dynStructureAddr=&_DYNAMIC;
+#endif
+if (0==COVERT_DATAFLOW(dynStructureAddr)){
+return(0);
+}
+if (cachedResult==0){
+int tag;
+for( dp=((ElfW(Dyn)*)(&_DYNAMIC));(tag=dp->d_tag)!=0;dp++){
+if (tag==DT_DEBUG){
+struct r_debug*rd=(struct r_debug*)dp->d_un.d_ptr;
+if (rd!=NULL){
+struct link_map*lm=rd->r_map;
+if (lm!=NULL)
+cachedResult=lm->l_next;
+}
+break;
+}
+}
+}
+return cachedResult;
+}
+#endif
+#ifdef GC_MUST_RESTORE_REDEFINED_DLOPEN
+#define dlopen GC_dlopen
+#endif
+#if defined(SOLARISDL)
+#if!defined(PCR)&&!defined(GC_SOLARIS_THREADS)&&defined(THREADS)&&!defined(CPPCHECK)
+#error Fix mutual exclusion with dlopen
+#endif
+#ifndef USE_PROC_FOR_LIBRARIES
+GC_INNER void GC_register_dynamic_libraries(void)
+{
+struct link_map*lm;
+for (lm=GC_FirstDLOpenedLinkMap();lm!=0;lm=lm->l_next){
+ElfW(Ehdr)*e;
+ElfW(Phdr)*p;
+unsigned long offset;
+char*start;
+int i;
+e=(ElfW(Ehdr)*)lm->l_addr;
+p=((ElfW(Phdr)*)(((char*)(e))+e->e_phoff));
+offset=((unsigned long)(lm->l_addr));
+for( i=0;i < (int)e->e_phnum;i++,p++){
+switch( p->p_type){
+case PT_LOAD:
+{
+if(!(p->p_flags&PF_W))break;
+start=((char*)(p->p_vaddr))+offset;
+GC_add_roots_inner(start,start+p->p_memsz,TRUE);
+}
+break;
+default:
+break;
+}
+}
+}
+}
+#endif
+#endif
+#if defined(SCO_ELF)||defined(DGUX)||defined(HURD)||defined(NACL)||(defined(__ELF__)&&(defined(LINUX)||defined(FREEBSD)||defined(NETBSD)||defined(OPENBSD)))
+#ifdef USE_PROC_FOR_LIBRARIES
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#define MAPS_BUF_SIZE (32*1024)
+static void sort_heap_sects(struct HeapSect*base,size_t number_of_elements)
+{
+signed_word n=(signed_word)number_of_elements;
+signed_word nsorted=1;
+while (nsorted < n){
+signed_word i;
+while (nsorted < n&&
+(word)base[nsorted-1].hs_start < (word)base[nsorted].hs_start)
+++nsorted;
+if (nsorted==n)break;
+GC_ASSERT((word)base[nsorted-1].hs_start > (word)base[nsorted].hs_start);
+i=nsorted - 1;
+while (i>=0&&(word)base[i].hs_start > (word)base[i+1].hs_start){
+struct HeapSect tmp=base[i];
+base[i]=base[i+1];
+base[i+1]=tmp;
+--i;
+}
+GC_ASSERT((word)base[nsorted-1].hs_start < (word)base[nsorted].hs_start);
+++nsorted;
+}
+}
+STATIC void GC_register_map_entries(char*maps)
+{
+char*prot;
+char*buf_ptr=maps;
+ptr_t start,end;
+unsigned int maj_dev;
+ptr_t least_ha,greatest_ha;
+unsigned i;
+GC_ASSERT(I_HOLD_LOCK());
+sort_heap_sects(GC_our_memory,GC_n_memory);
+least_ha=GC_our_memory[0].hs_start;
+greatest_ha=GC_our_memory[GC_n_memory-1].hs_start
++GC_our_memory[GC_n_memory-1].hs_bytes;
+for (;;){
+buf_ptr=GC_parse_map_entry(buf_ptr,&start,&end,&prot,
+&maj_dev,0);
+if (NULL==buf_ptr)
+break;
+if (prot[1]=='w'){
+if ((word)start<=(word)GC_stackbottom
+&&(word)end>=(word)GC_stackbottom){
+continue;
+}
+#ifdef THREADS
+if (GC_segment_is_thread_stack(start,end))continue;
+#endif
+if ((word)end<=(word)least_ha
+||(word)start>=(word)greatest_ha){
+GC_add_roots_inner(start,end,TRUE);
+continue;
+}
+i=0;
+while ((word)(GC_our_memory[i].hs_start
++GC_our_memory[i].hs_bytes)< (word)start)
+++i;
+GC_ASSERT(i < GC_n_memory);
+if ((word)GC_our_memory[i].hs_start<=(word)start){
+start=GC_our_memory[i].hs_start
++GC_our_memory[i].hs_bytes;
+++i;
+}
+while (i < GC_n_memory
+&&(word)GC_our_memory[i].hs_start < (word)end
+&&(word)start < (word)end){
+if ((word)start < (word)GC_our_memory[i].hs_start)
+GC_add_roots_inner(start,
+GC_our_memory[i].hs_start,TRUE);
+start=GC_our_memory[i].hs_start
++GC_our_memory[i].hs_bytes;
+++i;
+}
+if ((word)start < (word)end)
+GC_add_roots_inner(start,end,TRUE);
+} else if (prot[0]=='-'&&prot[1]=='-'&&prot[2]=='-'){
+GC_remove_roots_subregion(start,end);
+}
+}
+}
+GC_INNER void GC_register_dynamic_libraries(void)
+{
+char*maps=GC_get_maps();
+if (NULL==maps)
+ABORT("Failed to read/proc for library registration");
+GC_register_map_entries(maps);
+}
+GC_INNER GC_bool GC_register_main_static_data(void)
+{
+return FALSE;
+}
+#define HAVE_REGISTER_MAIN_STATIC_DATA
+#else
+#if __GLIBC__ > 2||(__GLIBC__==2&&__GLIBC_MINOR__ > 2)||(__GLIBC__==2&&__GLIBC_MINOR__==2&&defined(DT_CONFIG))||defined(HOST_ANDROID)
+#ifndef HAVE_DL_ITERATE_PHDR
+#define HAVE_DL_ITERATE_PHDR
+#endif
+#ifdef HOST_ANDROID
+EXTERN_C_BEGIN
+extern int dl_iterate_phdr(int (*cb)(struct dl_phdr_info*,
+size_t,void*),
+void*data);
+EXTERN_C_END
+#endif
+#endif
+#if defined(__DragonFly__)||defined(__FreeBSD_kernel__)||(defined(FREEBSD)&&__FreeBSD__>=7)
+#ifndef HAVE_DL_ITERATE_PHDR
+#define HAVE_DL_ITERATE_PHDR
+#endif
+#define DL_ITERATE_PHDR_STRONG
+#elif defined(HAVE_DL_ITERATE_PHDR)
+EXTERN_C_BEGIN
+#pragma weak dl_iterate_phdr
+EXTERN_C_END
+#endif
+#if defined(HAVE_DL_ITERATE_PHDR)
+#ifdef PT_GNU_RELRO
+#define MAX_LOAD_SEGS MAX_ROOT_SETS
+static struct load_segment {
+ptr_t start;
+ptr_t end;
+ptr_t start2;
+ptr_t end2;
+} load_segs[MAX_LOAD_SEGS];
+static int n_load_segs;
+static GC_bool load_segs_overflow;
+#endif
+STATIC int GC_register_dynlib_callback(struct dl_phdr_info*info,
+size_t size,void*ptr)
+{
+const ElfW(Phdr)*p;
+ptr_t start,end;
+int i;
+if (size < offsetof (struct dl_phdr_info,dlpi_phnum)
++sizeof (info->dlpi_phnum))
+return -1;
+p=info->dlpi_phdr;
+for (i=0;i < (int)info->dlpi_phnum;i++,p++){
+if (p->p_type==PT_LOAD){
+GC_has_static_roots_func callback=GC_has_static_roots;
+if ((p->p_flags&PF_W)==0)continue;
+start=(ptr_t)p->p_vaddr+info->dlpi_addr;
+end=start+p->p_memsz;
+if (callback!=0&&!callback(info->dlpi_name,start,p->p_memsz))
+continue;
+#ifdef PT_GNU_RELRO
+#if CPP_WORDSZ==64
+start=(ptr_t)((word)start&~(word)(sizeof(word)- 1));
+#endif
+if (n_load_segs>=MAX_LOAD_SEGS){
+if (!load_segs_overflow){
+WARN("Too many PT_LOAD segments;"
+" registering as roots directly...\n",0);
+load_segs_overflow=TRUE;
+}
+GC_add_roots_inner(start,end,TRUE);
+} else {
+load_segs[n_load_segs].start=start;
+load_segs[n_load_segs].end=end;
+load_segs[n_load_segs].start2=0;
+load_segs[n_load_segs].end2=0;
+++n_load_segs;
+}
+#else
+GC_add_roots_inner(start,end,TRUE);
+#endif
+}
+}
+#ifdef PT_GNU_RELRO
+p=info->dlpi_phdr;
+for (i=0;i < (int)info->dlpi_phnum;i++,p++){
+if (p->p_type==PT_GNU_RELRO){
+int j;
+start=(ptr_t)p->p_vaddr+info->dlpi_addr;
+end=start+p->p_memsz;
+for (j=n_load_segs;--j>=0;){
+if ((word)start>=(word)load_segs[j].start
+&&(word)start < (word)load_segs[j].end){
+if (load_segs[j].start2!=0){
+WARN("More than one GNU_RELRO segment per load one\n",0);
+} else {
+GC_ASSERT((word)end<=(word)load_segs[j].end);
+load_segs[j].end2=load_segs[j].end;
+load_segs[j].end=start;
+load_segs[j].start2=end;
+}
+break;
+}
+if (0==j&&0==GC_has_static_roots)
+WARN("Failed to find PT_GNU_RELRO segment"
+" inside PT_LOAD region\n",0);
+}
+}
+}
+#endif
+*(int*)ptr=1;
+return 0;
+}
+GC_INNER GC_bool GC_register_main_static_data(void)
+{
+#ifdef DL_ITERATE_PHDR_STRONG
+return FALSE;
+#else
+return 0==COVERT_DATAFLOW(dl_iterate_phdr);
+#endif
+}
+STATIC GC_bool GC_register_dynamic_libraries_dl_iterate_phdr(void)
+{
+int did_something;
+if (GC_register_main_static_data())
+return FALSE;
+#ifdef PT_GNU_RELRO
+{
+static GC_bool excluded_segs=FALSE;
+n_load_segs=0;
+load_segs_overflow=FALSE;
+if (!EXPECT(excluded_segs,TRUE)){
+GC_exclude_static_roots_inner((ptr_t)load_segs,
+(ptr_t)load_segs+sizeof(load_segs));
+excluded_segs=TRUE;
+}
+}
+#endif
+did_something=0;
+dl_iterate_phdr(GC_register_dynlib_callback,&did_something);
+if (did_something){
+#ifdef PT_GNU_RELRO
+int i;
+for (i=0;i < n_load_segs;++i){
+if ((word)load_segs[i].end > (word)load_segs[i].start){
+GC_add_roots_inner(load_segs[i].start,load_segs[i].end,TRUE);
+}
+if ((word)load_segs[i].end2 > (word)load_segs[i].start2){
+GC_add_roots_inner(load_segs[i].start2,load_segs[i].end2,TRUE);
+}
+}
+#endif
+} else {
+ptr_t datastart,dataend;
+#ifdef DATASTART_IS_FUNC
+static ptr_t datastart_cached=(ptr_t)GC_WORD_MAX;
+if (datastart_cached==(ptr_t)GC_WORD_MAX){
+datastart_cached=DATASTART;
+}
+datastart=datastart_cached;
+#else
+datastart=DATASTART;
+#endif
+#ifdef DATAEND_IS_FUNC
+{
+static ptr_t dataend_cached=0;
+if (dataend_cached==0){
+dataend_cached=DATAEND;
+}
+dataend=dataend_cached;
+}
+#else
+dataend=DATAEND;
+#endif
+if (NULL==*(char*volatile*)&datastart
+||(word)datastart > (word)dataend)
+ABORT_ARG2("Wrong DATASTART/END pair",
+":%p .. %p",(void*)datastart,(void*)dataend);
+GC_add_roots_inner(datastart,dataend,TRUE);
+#ifdef GC_HAVE_DATAREGION2
+if ((word)DATASTART2 - 1U>=(word)DATAEND2){
+ABORT_ARG2("Wrong DATASTART/END2 pair",
+":%p .. %p",(void*)DATASTART2,(void*)DATAEND2);
+}
+GC_add_roots_inner(DATASTART2,DATAEND2,TRUE);
+#endif
+}
+return TRUE;
+}
+#define HAVE_REGISTER_MAIN_STATIC_DATA
+#else
+#if defined(NETBSD)||defined(OPENBSD)
+#include <sys/exec_elf.h>
+#ifndef DT_DEBUG
+#define DT_DEBUG 21
+#endif
+#ifndef PT_LOAD
+#define PT_LOAD 1
+#endif
+#ifndef PF_W
+#define PF_W 2
+#endif
+#elif!defined(HOST_ANDROID)
+#include <elf.h>
+#endif
+#ifndef HOST_ANDROID
+#include <link.h>
+#endif
+#endif
+EXTERN_C_BEGIN
+#ifdef __GNUC__
+#pragma weak _DYNAMIC
+#endif
+extern ElfW(Dyn)_DYNAMIC[];
+EXTERN_C_END
+STATIC struct link_map*
+GC_FirstDLOpenedLinkMap(void)
+{
+static struct link_map*cachedResult=0;
+if (0==COVERT_DATAFLOW(_DYNAMIC)){
+return(0);
+}
+if( cachedResult==0){
+#if defined(NETBSD)&&defined(RTLD_DI_LINKMAP)
+#if defined(CPPCHECK)
+#define GC_RTLD_DI_LINKMAP 2
+#else
+#define GC_RTLD_DI_LINKMAP RTLD_DI_LINKMAP
+#endif
+struct link_map*lm=NULL;
+if (!dlinfo(RTLD_SELF,GC_RTLD_DI_LINKMAP,&lm)&&lm!=NULL){
+while (lm->l_prev!=NULL){
+lm=lm->l_prev;
+}
+cachedResult=lm->l_next;
+}
+#else
+ElfW(Dyn)*dp;
+int tag;
+for( dp=_DYNAMIC;(tag=dp->d_tag)!=0;dp++){
+if (tag==DT_DEBUG){
+struct r_debug*rd=(struct r_debug*)dp->d_un.d_ptr;
+if (rd!=NULL){
+struct link_map*lm=rd->r_map;
+if (lm!=NULL)
+cachedResult=lm->l_next;
+}
+break;
+}
+}
+#endif
+}
+return cachedResult;
+}
+GC_INNER void GC_register_dynamic_libraries(void)
+{
+struct link_map*lm;
+#ifdef HAVE_DL_ITERATE_PHDR
+if (GC_register_dynamic_libraries_dl_iterate_phdr()){
+return;
+}
+#endif
+for (lm=GC_FirstDLOpenedLinkMap();lm!=0;lm=lm->l_next)
+{
+ElfW(Ehdr)*e;
+ElfW(Phdr)*p;
+unsigned long offset;
+char*start;
+int i;
+e=(ElfW(Ehdr)*)lm->l_addr;
+#ifdef HOST_ANDROID
+if (e==NULL)
+continue;
+#endif
+p=((ElfW(Phdr)*)(((char*)(e))+e->e_phoff));
+offset=((unsigned long)(lm->l_addr));
+for( i=0;i < (int)e->e_phnum;i++,p++){
+switch( p->p_type){
+case PT_LOAD:
+{
+if(!(p->p_flags&PF_W))break;
+start=((char*)(p->p_vaddr))+offset;
+GC_add_roots_inner(start,start+p->p_memsz,TRUE);
+}
+break;
+default:
+break;
+}
+}
+}
+}
+#endif
+#endif
+#if defined(IRIX5)||(defined(USE_PROC_FOR_LIBRARIES)&&!defined(LINUX))
+#include <sys/procfs.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <elf.h>
+#include <errno.h>
+#include <signal.h>
+#ifndef _sigargs
+#define IRIX6
+#endif
+GC_INNER void GC_register_dynamic_libraries(void)
+{
+static int fd=-1;
+char buf[30];
+static prmap_t*addr_map=0;
+static int current_sz=0;
+int needed_sz=0;
+int i;
+long flags;
+ptr_t start;
+ptr_t limit;
+ptr_t heap_start=HEAP_START;
+ptr_t heap_end=heap_start;
+#ifdef SOLARISDL
+#define MA_PHYS 0
+#endif
+if (fd < 0){
+(void)snprintf(buf,sizeof(buf),"/proc/%ld",(long)getpid());
+buf[sizeof(buf)- 1]='\0';
+fd=open(buf,O_RDONLY);
+if (fd < 0){
+ABORT("/proc open failed");
+}
+}
+if (ioctl(fd,PIOCNMAP,&needed_sz)< 0){
+ABORT_ARG2("/proc PIOCNMAP ioctl failed",
+":fd=%d,errno=%d",fd,errno);
+}
+if (needed_sz>=current_sz){
+GC_scratch_recycle_no_gww(addr_map,
+(size_t)current_sz*sizeof(prmap_t));
+current_sz=needed_sz*2+1;
+addr_map=(prmap_t*)GC_scratch_alloc(
+(size_t)current_sz*sizeof(prmap_t));
+if (addr_map==NULL)
+ABORT("Insufficient memory for address map");
+}
+if (ioctl(fd,PIOCMAP,addr_map)< 0){
+ABORT_ARG3("/proc PIOCMAP ioctl failed",
+":errcode=%d,needed_sz=%d,addr_map=%p",
+errno,needed_sz,(void*)addr_map);
+};
+if (GC_n_heap_sects > 0){
+heap_end=GC_heap_sects[GC_n_heap_sects-1].hs_start
++GC_heap_sects[GC_n_heap_sects-1].hs_bytes;
+if ((word)heap_end < (word)GC_scratch_last_end_ptr)
+heap_end=GC_scratch_last_end_ptr;
+}
+for (i=0;i < needed_sz;i++){
+flags=addr_map[i].pr_mflags;
+if ((flags&(MA_BREAK|MA_STACK|MA_PHYS
+|MA_FETCHOP|MA_NOTCACHED))!=0)goto irrelevant;
+if ((flags&(MA_READ|MA_WRITE))!=(MA_READ|MA_WRITE))
+goto irrelevant;
+start=(ptr_t)(addr_map[i].pr_vaddr);
+if (GC_roots_present(start))goto irrelevant;
+if ((word)start < (word)heap_end&&(word)start>=(word)heap_start)
+goto irrelevant;
+limit=start+addr_map[i].pr_size;
+#ifndef IRIX6
+if (addr_map[i].pr_off==0&&strncmp(start,ELFMAG,4)==0){
+caddr_t arg;
+int obj;
+#define MAP_IRR_SZ 10
+static ptr_t map_irr[MAP_IRR_SZ];
+static int n_irr=0;
+struct stat buf;
+int j;
+for (j=0;j < n_irr;j++){
+if (map_irr[j]==start)goto irrelevant;
+}
+arg=(caddr_t)start;
+obj=ioctl(fd,PIOCOPENM,&arg);
+if (obj>=0){
+fstat(obj,&buf);
+close(obj);
+if ((buf.st_mode&0111)!=0){
+if (n_irr < MAP_IRR_SZ){
+map_irr[n_irr++]=start;
+}
+goto irrelevant;
+}
+}
+}
+#endif
+GC_add_roots_inner(start,limit,TRUE);
+irrelevant:;
+}
+if (close(fd)< 0)ABORT("Couldn't close/proc file");
+fd=-1;
+}
+#endif
+#if defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32)
+#include <stdlib.h>
+STATIC void GC_cond_add_roots(char*base,char*limit)
+{
+#ifdef GC_WIN32_THREADS
+char*curr_base=base;
+char*next_stack_lo;
+char*next_stack_hi;
+if (base==limit)return;
+for(;;){
+GC_get_next_stack(curr_base,limit,&next_stack_lo,&next_stack_hi);
+if ((word)next_stack_lo>=(word)limit)break;
+if ((word)next_stack_lo > (word)curr_base)
+GC_add_roots_inner(curr_base,next_stack_lo,TRUE);
+curr_base=next_stack_hi;
+}
+if ((word)curr_base < (word)limit)
+GC_add_roots_inner(curr_base,limit,TRUE);
+#else
+char*stack_top
+=(char*)((word)GC_approx_sp()&
+~(word)(GC_sysinfo.dwAllocationGranularity - 1));
+if (base==limit)return;
+if ((word)limit > (word)stack_top
+&&(word)base < (word)GC_stackbottom){
+return;
+}
+GC_add_roots_inner(base,limit,TRUE);
+#endif
+}
+#ifdef DYNAMIC_LOADING
+GC_INNER GC_bool GC_register_main_static_data(void)
+{
+#if defined(MSWINCE)||defined(CYGWIN32)
+return FALSE;
+#else
+return GC_no_win32_dlls;
+#endif
+}
+#define HAVE_REGISTER_MAIN_STATIC_DATA
+#endif
+#ifdef DEBUG_VIRTUALQUERY
+void GC_dump_meminfo(MEMORY_BASIC_INFORMATION*buf)
+{
+GC_printf("BaseAddress=0x%lx,AllocationBase=0x%lx,"
+" RegionSize=0x%lx(%lu)\n",buf->BaseAddress,
+buf->AllocationBase,buf->RegionSize,buf->RegionSize);
+GC_printf("\tAllocationProtect=0x%lx,State=0x%lx,Protect=0x%lx,"
+"Type=0x%lx\n",buf->AllocationProtect,buf->State,
+buf->Protect,buf->Type);
+}
+#endif
+#if defined(MSWINCE)||defined(CYGWIN32)
+#define GC_wnt TRUE
+#endif
+GC_INNER void GC_register_dynamic_libraries(void)
+{
+MEMORY_BASIC_INFORMATION buf;
+DWORD protect;
+LPVOID p;
+char*base;
+char*limit,*new_limit;
+#ifdef MSWIN32
+if (GC_no_win32_dlls)return;
+#endif
+p=GC_sysinfo.lpMinimumApplicationAddress;
+base=limit=(char*)p;
+while ((word)p < (word)GC_sysinfo.lpMaximumApplicationAddress){
+size_t result=VirtualQuery(p,&buf,sizeof(buf));
+#ifdef MSWINCE
+if (result==0){
+new_limit=(char*)
+(((DWORD)p+GC_sysinfo.dwAllocationGranularity)
+&~(GC_sysinfo.dwAllocationGranularity-1));
+} else
+#endif
+{
+if (result!=sizeof(buf)){
+ABORT("Weird VirtualQuery result");
+}
+new_limit=(char*)p+buf.RegionSize;
+protect=buf.Protect;
+if (buf.State==MEM_COMMIT
+&&(protect==PAGE_EXECUTE_READWRITE
+||protect==PAGE_EXECUTE_WRITECOPY
+||protect==PAGE_READWRITE
+||protect==PAGE_WRITECOPY)
+&&(buf.Type==MEM_IMAGE
+#ifdef GC_REGISTER_MEM_PRIVATE
+||(protect==PAGE_READWRITE&&buf.Type==MEM_PRIVATE)
+#else
+||(!GC_wnt&&buf.Type==MEM_PRIVATE)
+#endif
+)
+&&!GC_is_heap_base(buf.AllocationBase)){
+#ifdef DEBUG_VIRTUALQUERY
+GC_dump_meminfo(&buf);
+#endif
+if ((char*)p!=limit){
+GC_cond_add_roots(base,limit);
+base=(char*)p;
+}
+limit=new_limit;
+}
+}
+if ((word)p > (word)new_limit)break;
+p=(LPVOID)new_limit;
+}
+GC_cond_add_roots(base,limit);
+}
+#endif
+#if defined(ALPHA)&&defined(OSF1)
+#include <loader.h>
+EXTERN_C_BEGIN
+extern char*sys_errlist[];
+extern int sys_nerr;
+extern int errno;
+EXTERN_C_END
+GC_INNER void GC_register_dynamic_libraries(void)
+{
+ldr_module_t moduleid=LDR_NULL_MODULE;
+ldr_process_t mypid=ldr_my_process();
+while (TRUE){
+ldr_module_info_t moduleinfo;
+size_t modulereturnsize;
+ldr_region_t region;
+ldr_region_info_t regioninfo;
+size_t regionreturnsize;
+int status=ldr_next_module(mypid,&moduleid);
+if (moduleid==LDR_NULL_MODULE)
+break;
+if (status!=0){
+ABORT_ARG3("ldr_next_module failed",
+":status=%d,errcode=%d (%s)",status,errno,
+errno < sys_nerr?sys_errlist[errno]:"");
+}
+status=ldr_inq_module(mypid,moduleid,&moduleinfo,
+sizeof(moduleinfo),&modulereturnsize);
+if (status!=0)
+ABORT("ldr_inq_module failed");
+if (moduleinfo.lmi_flags&LDR_MAIN)
+continue;
+#ifdef DL_VERBOSE
+GC_log_printf("---Module---\n");
+GC_log_printf("Module ID\t=%16ld\n",moduleinfo.lmi_modid);
+GC_log_printf("Count of regions=%16d\n",moduleinfo.lmi_nregion);
+GC_log_printf("flags for module=%16lx\n",moduleinfo.lmi_flags);
+GC_log_printf("module pathname\t=\"%s\"\n",moduleinfo.lmi_name);
+#endif
+for (region=0;region < moduleinfo.lmi_nregion;region++){
+status=ldr_inq_region(mypid,moduleid,region,&regioninfo,
+sizeof(regioninfo),&regionreturnsize);
+if (status!=0)
+ABORT("ldr_inq_region failed");
+if (!(regioninfo.lri_prot&LDR_W))
+continue;
+#ifdef DL_VERBOSE
+GC_log_printf("--- Region---\n");
+GC_log_printf("Region number\t=%16ld\n",
+regioninfo.lri_region_no);
+GC_log_printf("Protection flags=%016x\n",regioninfo.lri_prot);
+GC_log_printf("Virtual address\t=%16p\n",regioninfo.lri_vaddr);
+GC_log_printf("Mapped address\t=%16p\n",
+regioninfo.lri_mapaddr);
+GC_log_printf("Region size\t=%16ld\n",regioninfo.lri_size);
+GC_log_printf("Region name\t=\"%s\"\n",regioninfo.lri_name);
+#endif
+GC_add_roots_inner((char*)regioninfo.lri_mapaddr,
+(char*)regioninfo.lri_mapaddr+regioninfo.lri_size,
+TRUE);
+}
+}
+}
+#endif
+#if defined(HPUX)
+#include <errno.h>
+#include <dl.h>
+EXTERN_C_BEGIN
+extern char*sys_errlist[];
+extern int sys_nerr;
+EXTERN_C_END
+GC_INNER void GC_register_dynamic_libraries(void)
+{
+int index=1;
+while (TRUE){
+struct shl_descriptor*shl_desc;
+int status=shl_get(index,&shl_desc);
+if (status!=0){
+#ifdef GC_HPUX_THREADS
+break;
+#else
+if (errno==EINVAL){
+break;
+} else {
+ABORT_ARG3("shl_get failed",
+":status=%d,errcode=%d (%s)",status,errno,
+errno < sys_nerr?sys_errlist[errno]:"");
+}
+#endif
+}
+#ifdef DL_VERBOSE
+GC_log_printf("---Shared library---\n");
+GC_log_printf("\tfilename\t=\"%s\"\n",shl_desc->filename);
+GC_log_printf("\tindex\t\t=%d\n",index);
+GC_log_printf("\thandle\t\t=%08x\n",
+(unsigned long)shl_desc->handle);
+GC_log_printf("\ttext seg.start\t=%08x\n",shl_desc->tstart);
+GC_log_printf("\ttext seg.end\t=%08x\n",shl_desc->tend);
+GC_log_printf("\tdata seg.start\t=%08x\n",shl_desc->dstart);
+GC_log_printf("\tdata seg.end\t=%08x\n",shl_desc->dend);
+GC_log_printf("\tref.count\t=%lu\n",shl_desc->ref_count);
+#endif
+GC_add_roots_inner((char*)shl_desc->dstart,
+(char*)shl_desc->dend,TRUE);
+index++;
+}
+}
+#endif
+#ifdef AIX
+#include <alloca.h>
+#include <sys/ldr.h>
+#include <sys/errno.h>
+GC_INNER void GC_register_dynamic_libraries(void)
+{
+int ldibuflen=8192;
+for (;;){
+int len;
+struct ld_info*ldi;
+#if defined(CPPCHECK)
+char ldibuf[ldibuflen];
+#else
+char*ldibuf=alloca(ldibuflen);
+#endif
+len=loadquery(L_GETINFO,ldibuf,ldibuflen);
+if (len < 0){
+if (errno!=ENOMEM){
+ABORT("loadquery failed");
+}
+ldibuflen*=2;
+continue;
+}
+ldi=(struct ld_info*)ldibuf;
+while (ldi){
+len=ldi->ldinfo_next;
+GC_add_roots_inner(
+ldi->ldinfo_dataorg,
+(ptr_t)(unsigned long)ldi->ldinfo_dataorg
++ldi->ldinfo_datasize,
+TRUE);
+ldi=len?(struct ld_info*)((char*)ldi+len):0;
+}
+break;
+}
+}
+#endif
+#ifdef DARWIN
+#ifndef __private_extern__
+#define __private_extern__ extern
+#include <mach-o/dyld.h>
+#undef __private_extern__
+#else
+#include <mach-o/dyld.h>
+#endif
+#include <mach-o/getsect.h>
+STATIC const struct dyld_sections_s {
+const char*seg;
+const char*sect;
+} GC_dyld_sections[]={
+{ SEG_DATA,SECT_DATA },
+{ SEG_DATA,"__static_data" },
+{ SEG_DATA,SECT_BSS },
+{ SEG_DATA,SECT_COMMON },
+{ SEG_DATA,"__zobj_data" },
+{ SEG_DATA,"__zobj_bss" }
+};
+STATIC const char*const GC_dyld_add_sect_fmts[]={
+"__bss%u",
+"__pu_bss%u",
+"__zo_bss%u",
+"__zo_pu_bss%u"
+};
+#ifndef L2_MAX_OFILE_ALIGNMENT
+#define L2_MAX_OFILE_ALIGNMENT 15
+#endif
+STATIC const char*GC_dyld_name_for_hdr(const struct GC_MACH_HEADER*hdr)
+{
+unsigned long i,c;
+c=_dyld_image_count();
+for (i=0;i < c;i++)
+if ((const struct GC_MACH_HEADER*)_dyld_get_image_header(i)==hdr)
+return _dyld_get_image_name(i);
+return NULL;
+}
+STATIC void GC_dyld_image_add(const struct GC_MACH_HEADER*hdr,
+intptr_t slide)
+{
+unsigned long start,end;
+unsigned i,j;
+const struct GC_MACH_SECTION*sec;
+const char*name;
+GC_has_static_roots_func callback=GC_has_static_roots;
+DCL_LOCK_STATE;
+if (GC_no_dls)return;
+#ifdef DARWIN_DEBUG
+name=GC_dyld_name_for_hdr(hdr);
+#else
+name=callback!=0?GC_dyld_name_for_hdr(hdr):NULL;
+#endif
+for (i=0;i < sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++){
+sec=GC_GETSECTBYNAME(hdr,GC_dyld_sections[i].seg,
+GC_dyld_sections[i].sect);
+if (sec==NULL||sec->size < sizeof(word))
+continue;
+start=slide+sec->addr;
+end=start+sec->size;
+LOCK();
+if (callback==0||callback(name,(void*)start,(size_t)sec->size)){
+#ifdef DARWIN_DEBUG
+GC_log_printf(
+"Adding section __DATA,%s at %p-%p (%lu bytes)from image %s\n",
+GC_dyld_sections[i].sect,(void*)start,(void*)end,
+(unsigned long)sec->size,name);
+#endif
+GC_add_roots_inner((ptr_t)start,(ptr_t)end,FALSE);
+}
+UNLOCK();
+}
+for (j=0;j < sizeof(GC_dyld_add_sect_fmts)/sizeof(char*);j++){
+const char*fmt=GC_dyld_add_sect_fmts[j];
+for (i=0;i<=L2_MAX_OFILE_ALIGNMENT;i++){
+char secnam[16];
+(void)snprintf(secnam,sizeof(secnam),fmt,(unsigned)i);
+secnam[sizeof(secnam)- 1]='\0';
+sec=GC_GETSECTBYNAME(hdr,SEG_DATA,secnam);
+if (sec==NULL||sec->size==0)
+continue;
+start=slide+sec->addr;
+end=start+sec->size;
+#ifdef DARWIN_DEBUG
+GC_log_printf("Adding on-demand section __DATA,%s at"
+" %p-%p (%lu bytes)from image %s\n",
+secnam,(void*)start,(void*)end,
+(unsigned long)sec->size,name);
+#endif
+GC_add_roots((char*)start,(char*)end);
+}
+}
+#if defined(DARWIN_DEBUG)&&!defined(NO_DEBUGGING)
+LOCK();
+GC_print_static_roots();
+UNLOCK();
+#endif
+}
+STATIC void GC_dyld_image_remove(const struct GC_MACH_HEADER*hdr,
+intptr_t slide)
+{
+unsigned long start,end;
+unsigned i,j;
+const struct GC_MACH_SECTION*sec;
+#if defined(DARWIN_DEBUG)&&!defined(NO_DEBUGGING)
+DCL_LOCK_STATE;
+#endif
+for (i=0;i < sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++){
+sec=GC_GETSECTBYNAME(hdr,GC_dyld_sections[i].seg,
+GC_dyld_sections[i].sect);
+if (sec==NULL||sec->size==0)
+continue;
+start=slide+sec->addr;
+end=start+sec->size;
+#ifdef DARWIN_DEBUG
+GC_log_printf(
+"Removing section __DATA,%s at %p-%p (%lu bytes)from image %s\n",
+GC_dyld_sections[i].sect,(void*)start,(void*)end,
+(unsigned long)sec->size,GC_dyld_name_for_hdr(hdr));
+#endif
+GC_remove_roots((char*)start,(char*)end);
+}
+for (j=0;j < sizeof(GC_dyld_add_sect_fmts)/sizeof(char*);j++){
+const char*fmt=GC_dyld_add_sect_fmts[j];
+for (i=0;i<=L2_MAX_OFILE_ALIGNMENT;i++){
+char secnam[16];
+(void)snprintf(secnam,sizeof(secnam),fmt,(unsigned)i);
+secnam[sizeof(secnam)- 1]='\0';
+sec=GC_GETSECTBYNAME(hdr,SEG_DATA,secnam);
+if (sec==NULL||sec->size==0)
+continue;
+start=slide+sec->addr;
+end=start+sec->size;
+#ifdef DARWIN_DEBUG
+GC_log_printf("Removing on-demand section __DATA,%s at"
+" %p-%p (%lu bytes)from image %s\n",secnam,
+(void*)start,(void*)end,(unsigned long)sec->size,
+GC_dyld_name_for_hdr(hdr));
+#endif
+GC_remove_roots((char*)start,(char*)end);
+}
+}
+#if defined(DARWIN_DEBUG)&&!defined(NO_DEBUGGING)
+LOCK();
+GC_print_static_roots();
+UNLOCK();
+#endif
+}
+GC_INNER void GC_register_dynamic_libraries(void)
+{
+}
+GC_INNER void GC_init_dyld(void)
+{
+static GC_bool initialized=FALSE;
+if (initialized)return;
+#ifdef DARWIN_DEBUG
+GC_log_printf("Registering dyld callbacks...\n");
+#endif
+_dyld_register_func_for_add_image(
+(void (*)(const struct mach_header*,intptr_t))GC_dyld_image_add);
+_dyld_register_func_for_remove_image(
+(void (*)(const struct mach_header*,intptr_t))GC_dyld_image_remove);
+initialized=TRUE;
+#ifdef NO_DYLD_BIND_FULLY_IMAGE
+#else
+if (GC_no_dls)return;
+if (GETENV("DYLD_BIND_AT_LAUNCH")==0){
+#ifdef DARWIN_DEBUG
+GC_log_printf("Forcing full bind of GC code...\n");
+#endif
+if (!_dyld_bind_fully_image_containing_address(
+(unsigned long*)GC_malloc))
+ABORT("_dyld_bind_fully_image_containing_address failed");
+}
+#endif
+}
+#define HAVE_REGISTER_MAIN_STATIC_DATA
+GC_INNER GC_bool GC_register_main_static_data(void)
+{
+return FALSE;
+}
+#endif
+#if defined(HAIKU)
+#include <kernel/image.h>
+GC_INNER void GC_register_dynamic_libraries(void)
+{
+image_info info;
+int32 cookie=0;
+while (get_next_image_info(0,&cookie,&info)==B_OK){
+ptr_t data=(ptr_t)info.data;
+GC_add_roots_inner(data,data+info.data_size,TRUE);
+}
+}
+#endif
+#elif defined(PCR)
+GC_INNER void GC_register_dynamic_libraries(void)
+{
+PCR_IL_LoadedFile*p=PCR_IL_GetLastLoadedFile();
+PCR_IL_LoadedSegment*q;
+while (p!=NIL&&!(p->lf_commitPoint)){
+p=p->lf_prev;
+}
+for (;p!=NIL;p=p->lf_prev){
+for (q=p->lf_ls;q!=NIL;q=q->ls_next){
+if ((q->ls_flags&PCR_IL_SegFlags_Traced_MASK)
+==PCR_IL_SegFlags_Traced_on){
+GC_add_roots_inner((ptr_t)q->ls_addr,
+(ptr_t)q->ls_addr+q->ls_bytes,TRUE);
+}
+}
+}
+}
+#endif
+#if!defined(HAVE_REGISTER_MAIN_STATIC_DATA)&&defined(DYNAMIC_LOADING)
+GC_INNER GC_bool GC_register_main_static_data(void)
+{
+return TRUE;
+}
+#endif
+GC_API void GC_CALL GC_register_has_static_roots_callback(
+GC_has_static_roots_func callback)
+{
+GC_has_static_roots=callback;
+}
+#if defined(GC_PTHREADS)&&!defined(GC_NO_DLOPEN)
+#undef GC_MUST_RESTORE_REDEFINED_DLOPEN
+#if defined(dlopen)&&!defined(GC_USE_LD_WRAP)
+#undef dlopen
+#define GC_MUST_RESTORE_REDEFINED_DLOPEN
+#endif
+#ifndef USE_PROC_FOR_LIBRARIES
+static void disable_gc_for_dlopen(void)
+{
+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();
+}
+#endif
+#ifdef GC_USE_LD_WRAP
+#define WRAP_DLFUNC(f)__wrap_##f
+#define REAL_DLFUNC(f)__real_##f
+void*REAL_DLFUNC(dlopen)(const char*,int);
+#else
+#define WRAP_DLFUNC(f)GC_##f
+#define REAL_DLFUNC(f)f
+#endif
+GC_API void*WRAP_DLFUNC(dlopen)(const char*path,int mode)
+{
+void*result;
+#ifndef USE_PROC_FOR_LIBRARIES
+disable_gc_for_dlopen();
+#endif
+result=REAL_DLFUNC(dlopen)(path,mode);
+#ifndef USE_PROC_FOR_LIBRARIES
+GC_enable();
+#endif
+return(result);
+}
+#ifdef GC_USE_LD_WRAP
+GC_API void*GC_dlopen(const char*path,int mode)
+{
+return dlopen(path,mode);
+}
+#endif
+#ifdef GC_MUST_RESTORE_REDEFINED_DLOPEN
+#define dlopen GC_dlopen
+#endif
+#endif
+#if!defined(SN_TARGET_ORBIS)&&!defined(SN_TARGET_PSP2)
+#include <stdio.h>
+#ifdef AMIGA
+#ifndef __GNUC__
+#include <dos.h>
+#else
+#include <machine/reg.h>
+#endif
+#endif
+#if defined(MACOS)&&defined(__MWERKS__)
+#if defined(POWERPC)
+#define NONVOLATILE_GPR_COUNT 19
+struct ppc_registers {
+unsigned long gprs[NONVOLATILE_GPR_COUNT];
+};
+typedef struct ppc_registers ppc_registers;
+#if defined(CPPCHECK)
+void getRegisters(ppc_registers*regs);
+#else
+asm static void getRegisters(register ppc_registers*regs)
+{
+stmw r13,regs->gprs
+blr
+}
+#endif
+static void PushMacRegisters(void)
+{
+ppc_registers regs;
+int i;
+getRegisters(&regs);
+for (i=0;i < NONVOLATILE_GPR_COUNT;i++)
+GC_push_one(regs.gprs[i]);
+}
+#else
+asm static void PushMacRegisters(void)
+{
+sub.w #4,sp
+move.l a2,(sp)
+jsr GC_push_one
+move.l a3,(sp)
+jsr GC_push_one
+move.l a4,(sp)
+jsr GC_push_one
+#if!__option(a6frames)
+move.l a6,(sp)
+jsr GC_push_one
+#endif
+move.l d2,(sp)
+jsr GC_push_one
+move.l d3,(sp)
+jsr GC_push_one
+move.l d4,(sp)
+jsr GC_push_one
+move.l d5,(sp)
+jsr GC_push_one
+move.l d6,(sp)
+jsr GC_push_one
+move.l d7,(sp)
+jsr GC_push_one
+add.w #4,sp
+rts
+}
+#endif
+#endif
+#if defined(SPARC)||defined(IA64)
+GC_INNER ptr_t GC_save_regs_ret_val=NULL;
+#endif
+#undef HAVE_PUSH_REGS
+#if defined(USE_ASM_PUSH_REGS)
+#define HAVE_PUSH_REGS
+#else
+#ifdef STACK_NOT_SCANNED
+void GC_push_regs(void)
+{
+}
+#define HAVE_PUSH_REGS
+#elif defined(M68K)&&defined(AMIGA)
+void GC_push_regs(void)
+{
+#ifdef __GNUC__
+asm("subq.w&0x4,%sp");
+asm("mov.l %a2,(%sp)");asm("jsr _GC_push_one");
+asm("mov.l %a3,(%sp)");asm("jsr _GC_push_one");
+asm("mov.l %a4,(%sp)");asm("jsr _GC_push_one");
+asm("mov.l %a5,(%sp)");asm("jsr _GC_push_one");
+asm("mov.l %a6,(%sp)");asm("jsr _GC_push_one");
+asm("mov.l %d2,(%sp)");asm("jsr _GC_push_one");
+asm("mov.l %d3,(%sp)");asm("jsr _GC_push_one");
+asm("mov.l %d4,(%sp)");asm("jsr _GC_push_one");
+asm("mov.l %d5,(%sp)");asm("jsr _GC_push_one");
+asm("mov.l %d6,(%sp)");asm("jsr _GC_push_one");
+asm("mov.l %d7,(%sp)");asm("jsr _GC_push_one");
+asm("addq.w&0x4,%sp");
+#else
+GC_push_one(getreg(REG_A2));
+GC_push_one(getreg(REG_A3));
+#ifndef __SASC
+GC_push_one(getreg(REG_A4));
+#endif
+GC_push_one(getreg(REG_A5));
+GC_push_one(getreg(REG_A6));
+GC_push_one(getreg(REG_D2));
+GC_push_one(getreg(REG_D3));
+GC_push_one(getreg(REG_D4));
+GC_push_one(getreg(REG_D5));
+GC_push_one(getreg(REG_D6));
+GC_push_one(getreg(REG_D7));
+#endif
+}
+#define HAVE_PUSH_REGS
+#elif defined(MACOS)
+#if defined(M68K)&&defined(THINK_C)&&!defined(CPPCHECK)
+#define PushMacReg(reg)move.l reg,(sp)jsr GC_push_one
+void GC_push_regs(void)
+{
+asm {
+sub.w #4,sp;reserve space for one parameter.
+PushMacReg(a2);
+PushMacReg(a3);
+PushMacReg(a4);
+;skip a5 (globals),a6 (frame pointer),and a7 (stack pointer)
+PushMacReg(d2);
+PushMacReg(d3);
+PushMacReg(d4);
+PushMacReg(d5);
+PushMacReg(d6);
+PushMacReg(d7);
+add.w #4,sp;fix stack.
+}
+}
+#define HAVE_PUSH_REGS
+#undef PushMacReg
+#elif defined(__MWERKS__)
+void GC_push_regs(void)
+{
+PushMacRegisters();
+}
+#define HAVE_PUSH_REGS
+#endif
+#endif
+#endif
+#if defined(HAVE_PUSH_REGS)&&defined(THREADS)
+#error GC_push_regs cannot be used with threads
+#undef HAVE_PUSH_REGS
+#endif
+#if!defined(HAVE_PUSH_REGS)&&defined(UNIX_LIKE)
+#include <signal.h>
+#ifndef NO_GETCONTEXT
+#if defined(DARWIN)&&(MAC_OS_X_VERSION_MAX_ALLOWED>=1060)
+#include <sys/ucontext.h>
+#else
+#include <ucontext.h>
+#endif
+#ifdef GETCONTEXT_FPU_EXCMASK_BUG
+#include <fenv.h>
+#endif
+#endif
+#endif
+GC_ATTR_NO_SANITIZE_ADDR
+GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t,void*),
+volatile ptr_t arg)
+{
+volatile int dummy;
+volatile ptr_t context=0;
+#if defined(HAVE_PUSH_REGS)
+GC_push_regs();
+#elif defined(__EMSCRIPTEN__)
+#else
+#if defined(UNIX_LIKE)&&!defined(NO_GETCONTEXT)
+static signed char getcontext_works=0;
+ucontext_t ctxt;
+#ifdef GETCONTEXT_FPU_EXCMASK_BUG
+#ifdef X86_64
+unsigned short old_fcw;
+#if defined(CPPCHECK)
+GC_noop1((word)&old_fcw);
+#endif
+__asm__ __volatile__ ("fstcw %0":"=m" (*&old_fcw));
+#else
+int except_mask=fegetexcept();
+#endif
+#endif
+if (getcontext_works>=0){
+if (getcontext(&ctxt)< 0){
+WARN("getcontext failed:"
+" using another register retrieval method...\n",0);
+} else {
+context=(ptr_t)&ctxt;
+}
+if (EXPECT(0==getcontext_works,FALSE))
+getcontext_works=context!=NULL?1:-1;
+}
+#ifdef GETCONTEXT_FPU_EXCMASK_BUG
+#ifdef X86_64
+__asm__ __volatile__ ("fldcw %0"::"m" (*&old_fcw));
+{
+unsigned mxcsr;
+__asm__ __volatile__ ("stmxcsr %0":"=m" (*&mxcsr));
+mxcsr=(mxcsr&~(FE_ALL_EXCEPT<<7))|
+((old_fcw&FE_ALL_EXCEPT)<<7);
+__asm__ __volatile__ ("ldmxcsr %0"::"m" (*&mxcsr));
+}
+#else
+if (feenableexcept(except_mask)< 0)
+ABORT("feenableexcept failed");
+#endif
+#endif
+#if defined(SPARC)||defined(IA64)
+GC_save_regs_ret_val=GC_save_regs_in_stack();
+#endif
+if (NULL==context)
+#endif
+{
+#if defined(HAVE_BUILTIN_UNWIND_INIT)
+__builtin_unwind_init();
+#elif defined(NO_CRT)&&defined(MSWIN32)
+CONTEXT ctx;
+RtlCaptureContext(&ctx);
+#else
+jmp_buf regs;
+word*i=(word*)&regs;
+ptr_t lim=(ptr_t)(&regs)+sizeof(regs);
+for (;(word)i < (word)lim;i++){
+*i=0;
+}
+#if defined(MSWIN32)||defined(MSWINCE)||defined(UTS4)||defined(OS2)||defined(CX_UX)||defined(__CC_ARM)||defined(LINUX)||defined(EWS4800)||defined(RTEMS)
+(void)setjmp(regs);
+#else
+(void)_setjmp(regs);
+#endif
+#endif
+}
+#endif
+fn(arg,( void*)context);
+GC_noop1(COVERT_DATAFLOW(&dummy));
+}
+#endif
+#if defined(GC_PTHREADS)&&!defined(GC_WIN32_THREADS)&&!defined(GC_DARWIN_THREADS)&&!defined(SN_TARGET_ORBIS)&&!defined(SN_TARGET_PSP2)
+#ifdef NACL
+#include <unistd.h>
+#include <sys/time.h>
+STATIC int GC_nacl_num_gc_threads=0;
+STATIC __thread int GC_nacl_thread_idx=-1;
+STATIC volatile int GC_nacl_park_threads_now=0;
+STATIC volatile pthread_t GC_nacl_thread_parker=-1;
+GC_INNER __thread GC_thread GC_nacl_gc_thread_self=NULL;
+volatile int GC_nacl_thread_parked[MAX_NACL_GC_THREADS];
+int GC_nacl_thread_used[MAX_NACL_GC_THREADS];
+#elif defined(GC_OPENBSD_UTHREADS)
+#include <pthread_np.h>
+#else
+#include <signal.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+#if (!defined(AO_HAVE_load_acquire)||!defined(AO_HAVE_store_release))&&!defined(CPPCHECK)
+#error AO_load_acquire and/or AO_store_release are missing;
+#error please define AO_REQUIRE_CAS manually
+#endif
+#undef pthread_sigmask
+#ifdef GC_ENABLE_SUSPEND_THREAD
+static void*GC_CALLBACK suspend_self_inner(void*client_data);
+#endif
+#ifdef DEBUG_THREADS
+#ifndef NSIG
+#if defined(MAXSIG)
+#define NSIG (MAXSIG+1)
+#elif defined(_NSIG)
+#define NSIG _NSIG
+#elif defined(__SIGRTMAX)
+#define NSIG (__SIGRTMAX+1)
+#else
+#error define NSIG
+#endif
+#endif
+void GC_print_sig_mask(void)
+{
+sigset_t blocked;
+int i;
+if (pthread_sigmask(SIG_BLOCK,NULL,&blocked)!=0)
+ABORT("pthread_sigmask failed");
+for (i=1;i < NSIG;i++){
+if (sigismember(&blocked,i))
+GC_printf("Signal blocked:%d\n",i);
+}
+}
+#endif
+STATIC void GC_remove_allowed_signals(sigset_t*set)
+{
+if (sigdelset(set,SIGINT)!=0
+||sigdelset(set,SIGQUIT)!=0
+||sigdelset(set,SIGABRT)!=0
+||sigdelset(set,SIGTERM)!=0){
+ABORT("sigdelset failed");
+}
+#ifdef MPROTECT_VDB
+if (sigdelset(set,SIGSEGV)!=0
+#ifdef HAVE_SIGBUS
+||sigdelset(set,SIGBUS)!=0
+#endif
+){
+ABORT("sigdelset failed");
+}
+#endif
+}
+static sigset_t suspend_handler_mask;
+#define THREAD_RESTARTED 0x1
+STATIC volatile AO_t GC_stop_count=0;
+STATIC volatile AO_t GC_world_is_stopped=FALSE;
+#if defined(GC_OSF1_THREADS)||defined(THREAD_SANITIZER)||defined(ADDRESS_SANITIZER)||defined(MEMORY_SANITIZER)
+STATIC GC_bool GC_retry_signals=TRUE;
+#else
+STATIC GC_bool GC_retry_signals=FALSE;
+#endif
+#ifndef SIG_THR_RESTART
+#if defined(GC_HPUX_THREADS)||defined(GC_OSF1_THREADS)||defined(GC_NETBSD_THREADS)||defined(GC_USESIGRT_SIGNALS)
+#if defined(_SIGRTMIN)&&!defined(CPPCHECK)
+#define SIG_THR_RESTART _SIGRTMIN+5
+#else
+#define SIG_THR_RESTART SIGRTMIN+5
+#endif
+#else
+#define SIG_THR_RESTART SIGXCPU
+#endif
+#endif
+#define SIGNAL_UNSET (-1)
+STATIC int GC_sig_suspend=SIGNAL_UNSET;
+STATIC int GC_sig_thr_restart=SIGNAL_UNSET;
+GC_API void GC_CALL GC_set_suspend_signal(int sig)
+{
+if (GC_is_initialized)return;
+GC_sig_suspend=sig;
+}
+GC_API void GC_CALL GC_set_thr_restart_signal(int sig)
+{
+if (GC_is_initialized)return;
+GC_sig_thr_restart=sig;
+}
+GC_API int GC_CALL GC_get_suspend_signal(void)
+{
+return GC_sig_suspend!=SIGNAL_UNSET?GC_sig_suspend:SIG_SUSPEND;
+}
+GC_API int GC_CALL GC_get_thr_restart_signal(void)
+{
+return GC_sig_thr_restart!=SIGNAL_UNSET
+?GC_sig_thr_restart:SIG_THR_RESTART;
+}
+#if defined(GC_EXPLICIT_SIGNALS_UNBLOCK)||!defined(NO_SIGNALS_UNBLOCK_IN_MAIN)
+GC_INNER void GC_unblock_gc_signals(void)
+{
+sigset_t set;
+sigemptyset(&set);
+GC_ASSERT(GC_sig_suspend!=SIGNAL_UNSET);
+GC_ASSERT(GC_sig_thr_restart!=SIGNAL_UNSET);
+sigaddset(&set,GC_sig_suspend);
+sigaddset(&set,GC_sig_thr_restart);
+if (pthread_sigmask(SIG_UNBLOCK,&set,NULL)!=0)
+ABORT("pthread_sigmask failed");
+}
+#endif
+STATIC sem_t GC_suspend_ack_sem;
+STATIC void GC_suspend_handler_inner(ptr_t dummy,void*context);
+#ifndef NO_SA_SIGACTION
+STATIC void GC_suspend_handler(int sig,siginfo_t*info GC_ATTR_UNUSED,
+void*context GC_ATTR_UNUSED)
+#else
+STATIC void GC_suspend_handler(int sig)
+#endif
+{
+int old_errno=errno;
+if (sig!=GC_sig_suspend){
+#if defined(GC_FREEBSD_THREADS)
+if (0==sig)return;
+#endif
+ABORT("Bad signal in suspend_handler");
+}
+#if defined(IA64)||defined(HP_PA)||defined(M68K)
+GC_with_callee_saves_pushed(GC_suspend_handler_inner,NULL);
+#else
+{
+#ifdef NO_SA_SIGACTION
+void*context=0;
+#endif
+GC_suspend_handler_inner(NULL,context);
+}
+#endif
+errno=old_errno;
+}
+#ifdef BASE_ATOMIC_OPS_EMULATED
+#define ao_load_acquire_async(p)(*(p))
+#define ao_load_async(p)ao_load_acquire_async(p)
+#define ao_store_release_async(p,v)(void)(*(p)=(v))
+#define ao_store_async(p,v)ao_store_release_async(p,v)
+#else
+#define ao_load_acquire_async(p)AO_load_acquire(p)
+#define ao_load_async(p)AO_load(p)
+#define ao_store_release_async(p,v)AO_store_release(p,v)
+#define ao_store_async(p,v)AO_store(p,v)
+#endif
+#ifdef THREAD_SANITIZER
+GC_ATTR_NO_SANITIZE_THREAD
+static GC_thread GC_lookup_thread_async(pthread_t id)
+{
+GC_thread p=GC_threads[THREAD_TABLE_INDEX(id)];
+while (p!=NULL&&!THREAD_EQUAL(p->id,id))
+p=p->next;
+return p;
+}
+#else
+#define GC_lookup_thread_async GC_lookup_thread
+#endif
+GC_INLINE void GC_store_stack_ptr(GC_thread me)
+{
+#ifdef SPARC
+ao_store_async((volatile AO_t*)&me->stop_info.stack_ptr,
+(AO_t)GC_save_regs_in_stack());
+#else
+#ifdef IA64
+me->backing_store_ptr=GC_save_regs_in_stack();
+#endif
+ao_store_async((volatile AO_t*)&me->stop_info.stack_ptr,
+(AO_t)GC_approx_sp());
+#endif
+}
+STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED,
+void*context GC_ATTR_UNUSED)
+{
+pthread_t self=pthread_self();
+GC_thread me;
+IF_CANCEL(int cancel_state;)
+AO_t my_stop_count=ao_load_acquire_async(&GC_stop_count);
+DISABLE_CANCEL(cancel_state);
+#ifdef DEBUG_THREADS
+GC_log_printf("Suspending %p\n",(void*)self);
+#endif
+GC_ASSERT(((word)my_stop_count&THREAD_RESTARTED)==0);
+me=GC_lookup_thread_async(self);
+#ifdef GC_ENABLE_SUSPEND_THREAD
+if (ao_load_async(&me->suspended_ext)){
+GC_store_stack_ptr(me);
+sem_post(&GC_suspend_ack_sem);
+suspend_self_inner(me);
+#ifdef DEBUG_THREADS
+GC_log_printf("Continuing %p on GC_resume_thread\n",(void*)self);
+#endif
+RESTORE_CANCEL(cancel_state);
+return;
+}
+#endif
+if (((word)me->stop_info.last_stop_count&~(word)THREAD_RESTARTED)
+==(word)my_stop_count){
+if (!GC_retry_signals){
+WARN("Duplicate suspend signal in thread %p\n",self);
+}
+RESTORE_CANCEL(cancel_state);
+return;
+}
+GC_store_stack_ptr(me);
+#ifdef THREAD_SANITIZER
+{
+sigset_t set;
+sigemptyset(&set);
+GC_ASSERT(GC_sig_suspend!=SIGNAL_UNSET);
+GC_ASSERT(GC_sig_thr_restart!=SIGNAL_UNSET);
+sigaddset(&set,GC_sig_suspend);
+sigaddset(&set,GC_sig_thr_restart);
+if (pthread_sigmask(SIG_UNBLOCK,&set,NULL)!=0)
+ABORT("pthread_sigmask failed in suspend handler");
+}
+#endif
+sem_post(&GC_suspend_ack_sem);
+ao_store_release_async(&me->stop_info.last_stop_count,my_stop_count);
+do {
+sigsuspend (&suspend_handler_mask);
+} while (ao_load_acquire_async(&GC_world_is_stopped)
+&&ao_load_async(&GC_stop_count)==my_stop_count);
+#ifdef DEBUG_THREADS
+GC_log_printf("Continuing %p\n",(void*)self);
+#endif
+#ifndef GC_NETBSD_THREADS_WORKAROUND
+if (GC_retry_signals)
+#endif
+{
+sem_post(&GC_suspend_ack_sem);
+#ifdef GC_NETBSD_THREADS_WORKAROUND
+if (GC_retry_signals)
+#endif
+{
+ao_store_release_async(&me->stop_info.last_stop_count,
+(AO_t)((word)my_stop_count|THREAD_RESTARTED));
+}
+}
+RESTORE_CANCEL(cancel_state);
+}
+static void suspend_restart_barrier(int n_live_threads)
+{
+int i;
+for (i=0;i < n_live_threads;i++){
+while (0!=sem_wait(&GC_suspend_ack_sem)){
+if (errno!=EINTR)
+ABORT("sem_wait failed");
+}
+}
+#ifdef GC_ASSERTIONS
+sem_getvalue(&GC_suspend_ack_sem,&i);
+GC_ASSERT(0==i);
+#endif
+}
+static int resend_lost_signals(int n_live_threads,
+int (*suspend_restart_all)(void))
+{
+#define WAIT_UNIT 3000
+#define RETRY_INTERVAL 100000
+if (n_live_threads > 0){
+unsigned long wait_usecs=0;
+for (;;){
+int ack_count;
+sem_getvalue(&GC_suspend_ack_sem,&ack_count);
+if (ack_count==n_live_threads)
+break;
+if (wait_usecs > RETRY_INTERVAL){
+int newly_sent=suspend_restart_all();
+GC_COND_LOG_PRINTF("Resent %d signals after timeout\n",newly_sent);
+sem_getvalue(&GC_suspend_ack_sem,&ack_count);
+if (newly_sent < n_live_threads - ack_count){
+WARN("Lost some threads while stopping or starting world?!\n",0);
+n_live_threads=ack_count+newly_sent;
+}
+wait_usecs=0;
+}
+#ifdef LINT2
+#undef WAIT_UNIT
+#define WAIT_UNIT 1
+sched_yield();
+#elif defined(CPPCHECK)
+{
+struct timespec ts;
+ts.tv_sec=0;
+ts.tv_nsec=WAIT_UNIT*1000;
+(void)nanosleep(&ts,NULL);
+}
+#else
+usleep(WAIT_UNIT);
+#endif
+wait_usecs+=WAIT_UNIT;
+}
+}
+return n_live_threads;
+}
+STATIC void GC_restart_handler(int sig)
+{
+#if defined(DEBUG_THREADS)
+int old_errno=errno;
+#endif
+if (sig!=GC_sig_thr_restart)
+ABORT("Bad signal in restart handler");
+#ifdef DEBUG_THREADS
+GC_log_printf("In GC_restart_handler for %p\n",(void*)pthread_self());
+errno=old_errno;
+#endif
+}
+#ifdef USE_TKILL_ON_ANDROID
+EXTERN_C_BEGIN
+extern int tkill(pid_t tid,int sig);
+EXTERN_C_END
+static int android_thread_kill(pid_t tid,int sig)
+{
+int ret;
+int old_errno=errno;
+ret=tkill(tid,sig);
+if (ret < 0){
+ret=errno;
+errno=old_errno;
+}
+return ret;
+}
+#define THREAD_SYSTEM_ID(t)(t)->kernel_id
+#define RAISE_SIGNAL(t,sig)android_thread_kill(THREAD_SYSTEM_ID(t),sig)
+#else
+#define THREAD_SYSTEM_ID(t)(t)->id
+#define RAISE_SIGNAL(t,sig)pthread_kill(THREAD_SYSTEM_ID(t),sig)
+#endif
+#ifdef GC_ENABLE_SUSPEND_THREAD
+#include <sys/time.h>
+STATIC void GC_brief_async_signal_safe_sleep(void)
+{
+struct timeval tv;
+tv.tv_sec=0;
+#if defined(GC_TIME_LIMIT)&&!defined(CPPCHECK)
+tv.tv_usec=1000*GC_TIME_LIMIT/2;
+#else
+tv.tv_usec=1000*50/2;
+#endif
+(void)select(0,0,0,0,&tv);
+}
+static void*GC_CALLBACK suspend_self_inner(void*client_data){
+GC_thread me=(GC_thread)client_data;
+while (ao_load_acquire_async(&me->suspended_ext)){
+GC_brief_async_signal_safe_sleep();
+}
+return NULL;
+}
+GC_API void GC_CALL GC_suspend_thread(GC_SUSPEND_THREAD_ID thread){
+GC_thread t;
+IF_CANCEL(int cancel_state;)
+DCL_LOCK_STATE;
+LOCK();
+t=GC_lookup_thread((pthread_t)thread);
+if (t==NULL||t->suspended_ext){
+UNLOCK();
+return;
+}
+AO_store_release(&t->suspended_ext,TRUE);
+if (THREAD_EQUAL((pthread_t)thread,pthread_self())){
+UNLOCK();
+(void)GC_do_blocking(suspend_self_inner,t);
+return;
+}
+if ((t->flags&FINISHED)!=0){
+UNLOCK();
+return;
+}
+DISABLE_CANCEL(cancel_state);
+#ifdef PARALLEL_MARK
+if (GC_parallel)
+GC_wait_for_reclaim();
+#endif
+if (GC_manual_vdb){
+GC_acquire_dirty_lock();
+}
+switch (RAISE_SIGNAL(t,GC_sig_suspend)){
+case 0:
+break;
+default:
+ABORT("pthread_kill failed");
+}
+GC_ASSERT(GC_thr_initialized);
+while (sem_wait(&GC_suspend_ack_sem)!=0){
+if (errno!=EINTR)
+ABORT("sem_wait for handler failed (suspend_self)");
+}
+if (GC_manual_vdb)
+GC_release_dirty_lock();
+RESTORE_CANCEL(cancel_state);
+UNLOCK();
+}
+GC_API void GC_CALL GC_resume_thread(GC_SUSPEND_THREAD_ID thread){
+GC_thread t;
+DCL_LOCK_STATE;
+LOCK();
+t=GC_lookup_thread((pthread_t)thread);
+if (t!=NULL)
+AO_store(&t->suspended_ext,FALSE);
+UNLOCK();
+}
+GC_API int GC_CALL GC_is_thread_suspended(GC_SUSPEND_THREAD_ID thread){
+GC_thread t;
+int is_suspended=0;
+DCL_LOCK_STATE;
+LOCK();
+t=GC_lookup_thread((pthread_t)thread);
+if (t!=NULL&&t->suspended_ext)
+is_suspended=(int)TRUE;
+UNLOCK();
+return is_suspended;
+}
+#endif
+#undef ao_load_acquire_async
+#undef ao_load_async
+#undef ao_store_async
+#undef ao_store_release_async
+#endif
+#ifdef IA64
+#define IF_IA64(x)x
+#else
+#define IF_IA64(x)
+#endif
+GC_INNER void GC_push_all_stacks(void)
+{
+GC_bool found_me=FALSE;
+size_t nthreads=0;
+int i;
+GC_thread p;
+ptr_t lo,hi;
+IF_IA64(ptr_t bs_lo;ptr_t bs_hi;)
+struct GC_traced_stack_sect_s*traced_stack_sect;
+pthread_t self=pthread_self();
+word total_size=0;
+if (!EXPECT(GC_thr_initialized,TRUE))
+GC_thr_init();
+#ifdef DEBUG_THREADS
+GC_log_printf("Pushing stacks from thread %p\n",(void*)self);
+#endif
+for (i=0;i < THREAD_TABLE_SZ;i++){
+for (p=GC_threads[i];p!=0;p=p->next){
+if (p->flags&FINISHED)continue;
+++nthreads;
+traced_stack_sect=p->traced_stack_sect;
+if (THREAD_EQUAL(p->id,self)){
+GC_ASSERT(!p->thread_blocked);
+#ifdef SPARC
+lo=(ptr_t)GC_save_regs_in_stack();
+#else
+lo=GC_approx_sp();
+#endif
+found_me=TRUE;
+IF_IA64(bs_hi=(ptr_t)GC_save_regs_in_stack();)
+} else {
+lo=(ptr_t)AO_load((volatile AO_t*)&p->stop_info.stack_ptr);
+IF_IA64(bs_hi=p->backing_store_ptr;)
+if (traced_stack_sect!=NULL
+&&traced_stack_sect->saved_stack_ptr==lo){
+traced_stack_sect=traced_stack_sect->prev;
+}
+}
+if ((p->flags&MAIN_THREAD)==0){
+hi=p->stack_end;
+IF_IA64(bs_lo=p->backing_store_end);
+} else {
+hi=GC_stackbottom;
+IF_IA64(bs_lo=BACKING_STORE_BASE;)
+}
+#ifdef DEBUG_THREADS
+GC_log_printf("Stack for thread %p=[%p,%p)\n",
+(void*)p->id,(void*)lo,(void*)hi);
+#endif
+if (0==lo)ABORT("GC_push_all_stacks:sp not set!");
+if (p->altstack!=NULL&&(word)p->altstack<=(word)lo
+&&(word)lo<=(word)p->altstack+p->altstack_size){
+hi=p->altstack+p->altstack_size;
+}
+GC_push_all_stack_sections(lo,hi,traced_stack_sect);
+#ifdef STACK_GROWS_UP
+total_size+=lo - hi;
+#else
+total_size+=hi - lo;
+#endif
+#ifdef NACL
+GC_push_all_stack((ptr_t)p->stop_info.reg_storage,
+(ptr_t)(p->stop_info.reg_storage+NACL_GC_REG_STORAGE_SIZE));
+total_size+=NACL_GC_REG_STORAGE_SIZE*sizeof(ptr_t);
+#endif
+#ifdef IA64
+#ifdef DEBUG_THREADS
+GC_log_printf("Reg stack for thread %p=[%p,%p)\n",
+(void*)p->id,(void*)bs_lo,(void*)bs_hi);
+#endif
+GC_push_all_register_sections(bs_lo,bs_hi,
+THREAD_EQUAL(p->id,self),
+traced_stack_sect);
+total_size+=bs_hi - bs_lo;
+#endif
+}
+}
+GC_VERBOSE_LOG_PRINTF("Pushed %d thread stacks\n",(int)nthreads);
+if (!found_me&&!GC_in_thread_creation)
+ABORT("Collecting from unknown thread");
+GC_total_stacksize=total_size;
+}
+#ifdef DEBUG_THREADS
+pthread_t GC_stopping_thread;
+int GC_stopping_pid=0;
+#endif
+STATIC int GC_suspend_all(void)
+{
+int n_live_threads=0;
+int i;
+#ifndef NACL
+GC_thread p;
+#ifndef GC_OPENBSD_UTHREADS
+int result;
+#endif
+pthread_t self=pthread_self();
+for (i=0;i < THREAD_TABLE_SZ;i++){
+for (p=GC_threads[i];p!=0;p=p->next){
+if (!THREAD_EQUAL(p->id,self)){
+if ((p->flags&FINISHED)!=0)continue;
+if (p->thread_blocked)continue;
+#ifndef GC_OPENBSD_UTHREADS
+#ifdef GC_ENABLE_SUSPEND_THREAD
+if (p->suspended_ext)continue;
+#endif
+if (AO_load(&p->stop_info.last_stop_count)==GC_stop_count)
+continue;
+n_live_threads++;
+#endif
+#ifdef DEBUG_THREADS
+GC_log_printf("Sending suspend signal to %p\n",(void*)p->id);
+#endif
+#ifdef GC_OPENBSD_UTHREADS
+{
+stack_t stack;
+GC_acquire_dirty_lock();
+if (pthread_suspend_np(p->id)!=0)
+ABORT("pthread_suspend_np failed");
+GC_release_dirty_lock();
+if (pthread_stackseg_np(p->id,&stack))
+ABORT("pthread_stackseg_np failed");
+p->stop_info.stack_ptr=(ptr_t)stack.ss_sp - stack.ss_size;
+if (GC_on_thread_event)
+GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED,
+(void*)p->id);
+}
+#else
+result=RAISE_SIGNAL(p,GC_sig_suspend);
+switch(result){
+case ESRCH:
+n_live_threads--;
+break;
+case 0:
+if (GC_on_thread_event)
+GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED,
+(void*)(word)THREAD_SYSTEM_ID(p));
+break;
+default:
+ABORT_ARG1("pthread_kill failed at suspend",
+":errcode=%d",result);
+}
+#endif
+}
+}
+}
+#else
+#ifndef NACL_PARK_WAIT_NANOSECONDS
+#define NACL_PARK_WAIT_NANOSECONDS (100*1000)
+#endif
+#define NANOS_PER_SECOND (1000UL*1000*1000)
+unsigned long num_sleeps=0;
+#ifdef DEBUG_THREADS
+GC_log_printf("pthread_stop_world:num_threads=%d\n",
+GC_nacl_num_gc_threads - 1);
+#endif
+GC_nacl_thread_parker=pthread_self();
+GC_nacl_park_threads_now=1;
+if (GC_manual_vdb)
+GC_acquire_dirty_lock();
+while (1){
+int num_threads_parked=0;
+struct timespec ts;
+int num_used=0;
+for (i=0;i < MAX_NACL_GC_THREADS
+&&num_used < GC_nacl_num_gc_threads;i++){
+if (GC_nacl_thread_used[i]==1){
+num_used++;
+if (GC_nacl_thread_parked[i]==1){
+num_threads_parked++;
+if (GC_on_thread_event)
+GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED,(void*)(word)i);
+}
+}
+}
+if (num_threads_parked>=GC_nacl_num_gc_threads - 1)
+break;
+ts.tv_sec=0;
+ts.tv_nsec=NACL_PARK_WAIT_NANOSECONDS;
+#ifdef DEBUG_THREADS
+GC_log_printf("Sleep waiting for %d threads to park...\n",
+GC_nacl_num_gc_threads - num_threads_parked - 1);
+#endif
+nanosleep(&ts,0);
+if (++num_sleeps > NANOS_PER_SECOND/NACL_PARK_WAIT_NANOSECONDS){
+WARN("GC appears stalled waiting for %" WARN_PRIdPTR
+" threads to park...\n",
+GC_nacl_num_gc_threads - num_threads_parked - 1);
+num_sleeps=0;
+}
+}
+if (GC_manual_vdb)
+GC_release_dirty_lock();
+#endif
+return n_live_threads;
+}
+GC_INNER void GC_stop_world(void)
+{
+#if!defined(GC_OPENBSD_UTHREADS)&&!defined(NACL)
+int n_live_threads;
+#endif
+GC_ASSERT(I_HOLD_LOCK());
+#ifdef DEBUG_THREADS
+GC_stopping_thread=pthread_self();
+GC_stopping_pid=getpid();
+GC_log_printf("Stopping the world from %p\n",(void*)GC_stopping_thread);
+#endif
+#ifdef PARALLEL_MARK
+if (GC_parallel){
+GC_acquire_mark_lock();
+GC_ASSERT(GC_fl_builder_count==0);
+}
+#endif
+#if defined(GC_OPENBSD_UTHREADS)||defined(NACL)
+(void)GC_suspend_all();
+#else
+AO_store(&GC_stop_count,
+(AO_t)((word)GC_stop_count+(THREAD_RESTARTED+1)));
+if (GC_manual_vdb){
+GC_acquire_dirty_lock();
+}
+AO_store_release(&GC_world_is_stopped,TRUE);
+n_live_threads=GC_suspend_all();
+if (GC_retry_signals)
+n_live_threads=resend_lost_signals(n_live_threads,GC_suspend_all);
+suspend_restart_barrier(n_live_threads);
+if (GC_manual_vdb)
+GC_release_dirty_lock();
+#endif
+#ifdef PARALLEL_MARK
+if (GC_parallel)
+GC_release_mark_lock();
+#endif
+#ifdef DEBUG_THREADS
+GC_log_printf("World stopped from %p\n",(void*)pthread_self());
+GC_stopping_thread=0;
+#endif
+}
+#ifdef NACL
+#if defined(__x86_64__)
+#define NACL_STORE_REGS()do { __asm__ __volatile__ ("push %rbx");__asm__ __volatile__ ("push %rbp");__asm__ __volatile__ ("push %r12");__asm__ __volatile__ ("push %r13");__asm__ __volatile__ ("push %r14");__asm__ __volatile__ ("push %r15");__asm__ __volatile__ ("mov %%esp,%0":"=m" (GC_nacl_gc_thread_self->stop_info.stack_ptr));BCOPY(GC_nacl_gc_thread_self->stop_info.stack_ptr,GC_nacl_gc_thread_self->stop_info.reg_storage,NACL_GC_REG_STORAGE_SIZE*sizeof(ptr_t));__asm__ __volatile__ ("naclasp $48,%r15");} while (0)
+#elif defined(__i386__)
+#define NACL_STORE_REGS()do { __asm__ __volatile__ ("push %ebx");__asm__ __volatile__ ("push %ebp");__asm__ __volatile__ ("push %esi");__asm__ __volatile__ ("push %edi");__asm__ __volatile__ ("mov %%esp,%0":"=m" (GC_nacl_gc_thread_self->stop_info.stack_ptr));BCOPY(GC_nacl_gc_thread_self->stop_info.stack_ptr,GC_nacl_gc_thread_self->stop_info.reg_storage,NACL_GC_REG_STORAGE_SIZE*sizeof(ptr_t));__asm__ __volatile__ ("add $16,%esp");} while (0)
+#elif defined(__arm__)
+#define NACL_STORE_REGS()do { __asm__ __volatile__ ("push {r4-r8,r10-r12,lr}");__asm__ __volatile__ ("mov r0,%0"::"r" (&GC_nacl_gc_thread_self->stop_info.stack_ptr));__asm__ __volatile__ ("bic r0,r0,#0xc0000000");__asm__ __volatile__ ("str sp,[r0]");BCOPY(GC_nacl_gc_thread_self->stop_info.stack_ptr,GC_nacl_gc_thread_self->stop_info.reg_storage,NACL_GC_REG_STORAGE_SIZE*sizeof(ptr_t));__asm__ __volatile__ ("add sp,sp,#40");__asm__ __volatile__ ("bic sp,sp,#0xc0000000");} while (0)
+#else
+#error TODO Please port NACL_STORE_REGS
+#endif
+GC_API_OSCALL void nacl_pre_syscall_hook(void)
+{
+if (GC_nacl_thread_idx!=-1){
+NACL_STORE_REGS();
+GC_nacl_gc_thread_self->stop_info.stack_ptr=GC_approx_sp();
+GC_nacl_thread_parked[GC_nacl_thread_idx]=1;
+}
+}
+GC_API_OSCALL void __nacl_suspend_thread_if_needed(void)
+{
+if (GC_nacl_park_threads_now){
+pthread_t self=pthread_self();
+if (GC_nacl_thread_parker==self)
+return;
+if (GC_nacl_thread_idx < 0)
+return;
+if (!GC_nacl_thread_parked[GC_nacl_thread_idx]){
+NACL_STORE_REGS();
+GC_nacl_gc_thread_self->stop_info.stack_ptr=GC_approx_sp();
+}
+GC_nacl_thread_parked[GC_nacl_thread_idx]=1;
+while (GC_nacl_park_threads_now){
+}
+GC_nacl_thread_parked[GC_nacl_thread_idx]=0;
+BZERO(GC_nacl_gc_thread_self->stop_info.reg_storage,
+NACL_GC_REG_STORAGE_SIZE*sizeof(ptr_t));
+}
+}
+GC_API_OSCALL void nacl_post_syscall_hook(void)
+{
+__nacl_suspend_thread_if_needed();
+if (GC_nacl_thread_idx!=-1){
+GC_nacl_thread_parked[GC_nacl_thread_idx]=0;
+}
+}
+STATIC GC_bool GC_nacl_thread_parking_inited=FALSE;
+STATIC pthread_mutex_t GC_nacl_thread_alloc_lock=PTHREAD_MUTEX_INITIALIZER;
+struct nacl_irt_blockhook {
+int (*register_block_hooks)(void (*pre)(void),void (*post)(void));
+};
+EXTERN_C_BEGIN
+extern size_t nacl_interface_query(const char*interface_ident,
+void*table,size_t tablesize);
+EXTERN_C_END
+GC_INNER void GC_nacl_initialize_gc_thread(void)
+{
+int i;
+static struct nacl_irt_blockhook gc_hook;
+pthread_mutex_lock(&GC_nacl_thread_alloc_lock);
+if (!EXPECT(GC_nacl_thread_parking_inited,TRUE)){
+BZERO(GC_nacl_thread_parked,sizeof(GC_nacl_thread_parked));
+BZERO(GC_nacl_thread_used,sizeof(GC_nacl_thread_used));
+nacl_interface_query("nacl-irt-blockhook-0.1",
+&gc_hook,sizeof(gc_hook));
+gc_hook.register_block_hooks(nacl_pre_syscall_hook,
+nacl_post_syscall_hook);
+GC_nacl_thread_parking_inited=TRUE;
+}
+GC_ASSERT(GC_nacl_num_gc_threads<=MAX_NACL_GC_THREADS);
+for (i=0;i < MAX_NACL_GC_THREADS;i++){
+if (GC_nacl_thread_used[i]==0){
+GC_nacl_thread_used[i]=1;
+GC_nacl_thread_idx=i;
+GC_nacl_num_gc_threads++;
+break;
+}
+}
+pthread_mutex_unlock(&GC_nacl_thread_alloc_lock);
+}
+GC_INNER void GC_nacl_shutdown_gc_thread(void)
+{
+pthread_mutex_lock(&GC_nacl_thread_alloc_lock);
+GC_ASSERT(GC_nacl_thread_idx>=0);
+GC_ASSERT(GC_nacl_thread_idx < MAX_NACL_GC_THREADS);
+GC_ASSERT(GC_nacl_thread_used[GC_nacl_thread_idx]!=0);
+GC_nacl_thread_used[GC_nacl_thread_idx]=0;
+GC_nacl_thread_idx=-1;
+GC_nacl_num_gc_threads--;
+pthread_mutex_unlock(&GC_nacl_thread_alloc_lock);
+}
+#else
+STATIC int GC_restart_all(void)
+{
+int n_live_threads=0;
+int i;
+pthread_t self=pthread_self();
+GC_thread p;
+#ifndef GC_OPENBSD_UTHREADS
+int result;
+#endif
+for (i=0;i < THREAD_TABLE_SZ;i++){
+for (p=GC_threads[i];p!=NULL;p=p->next){
+if (!THREAD_EQUAL(p->id,self)){
+if ((p->flags&FINISHED)!=0)continue;
+if (p->thread_blocked)continue;
+#ifndef GC_OPENBSD_UTHREADS
+#ifdef GC_ENABLE_SUSPEND_THREAD
+if (p->suspended_ext)continue;
+#endif
+if (GC_retry_signals
+&&AO_load(&p->stop_info.last_stop_count)
+==(AO_t)((word)GC_stop_count|THREAD_RESTARTED))
+continue;
+n_live_threads++;
+#endif
+#ifdef DEBUG_THREADS
+GC_log_printf("Sending restart signal to %p\n",(void*)p->id);
+#endif
+#ifdef GC_OPENBSD_UTHREADS
+if (pthread_resume_np(p->id)!=0)
+ABORT("pthread_resume_np failed");
+if (GC_on_thread_event)
+GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED,(void*)p->id);
+#else
+result=RAISE_SIGNAL(p,GC_sig_thr_restart);
+switch(result){
+case ESRCH:
+n_live_threads--;
+break;
+case 0:
+if (GC_on_thread_event)
+GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED,
+(void*)(word)THREAD_SYSTEM_ID(p));
+break;
+default:
+ABORT_ARG1("pthread_kill failed at resume",
+":errcode=%d",result);
+}
+#endif
+}
+}
+}
+return n_live_threads;
+}
+#endif
+GC_INNER void GC_start_world(void)
+{
+#ifndef NACL
+int n_live_threads;
+GC_ASSERT(I_HOLD_LOCK());
+#ifdef DEBUG_THREADS
+GC_log_printf("World starting\n");
+#endif
+#ifndef GC_OPENBSD_UTHREADS
+AO_store_release(&GC_world_is_stopped,FALSE);
+#endif
+n_live_threads=GC_restart_all();
+#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);
+suspend_restart_barrier(n_live_threads);
+#else
+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");
+#endif
+#else
+#ifdef DEBUG_THREADS
+GC_log_printf("World starting...\n");
+#endif
+GC_nacl_park_threads_now=0;
+if (GC_on_thread_event)
+GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED,NULL);
+#endif
+}
+GC_INNER void GC_stop_init(void)
+{
+#if!defined(GC_OPENBSD_UTHREADS)&&!defined(NACL)
+struct sigaction act;
+char*str;
+if (SIGNAL_UNSET==GC_sig_suspend)
+GC_sig_suspend=SIG_SUSPEND;
+if (SIGNAL_UNSET==GC_sig_thr_restart)
+GC_sig_thr_restart=SIG_THR_RESTART;
+if (GC_sig_suspend==GC_sig_thr_restart)
+ABORT("Cannot use same signal for thread suspend and resume");
+if (sem_init(&GC_suspend_ack_sem,GC_SEM_INIT_PSHARED,0)!=0)
+ABORT("sem_init failed");
+#ifdef SA_RESTART
+act.sa_flags=SA_RESTART
+#else
+act.sa_flags=0
+#endif
+#ifndef NO_SA_SIGACTION
+|SA_SIGINFO
+#endif
+;
+if (sigfillset(&act.sa_mask)!=0){
+ABORT("sigfillset failed");
+}
+#ifdef GC_RTEMS_PTHREADS
+if(sigprocmask(SIG_UNBLOCK,&act.sa_mask,NULL)!=0){
+ABORT("sigprocmask failed");
+}
+#endif
+GC_remove_allowed_signals(&act.sa_mask);
+#ifndef NO_SA_SIGACTION
+act.sa_sigaction=GC_suspend_handler;
+#else
+act.sa_handler=GC_suspend_handler;
+#endif
+if (sigaction(GC_sig_suspend,&act,NULL)!=0){
+ABORT("Cannot set SIG_SUSPEND handler");
+}
+#ifndef NO_SA_SIGACTION
+act.sa_flags&=~SA_SIGINFO;
+#endif
+act.sa_handler=GC_restart_handler;
+if (sigaction(GC_sig_thr_restart,&act,NULL)!=0){
+ABORT("Cannot set SIG_THR_RESTART handler");
+}
+if (sigfillset(&suspend_handler_mask)!=0)ABORT("sigfillset failed");
+GC_remove_allowed_signals(&suspend_handler_mask);
+if (sigdelset(&suspend_handler_mask,GC_sig_thr_restart)!=0)
+ABORT("sigdelset failed");
+str=GETENV("GC_RETRY_SIGNALS");
+if (str!=NULL){
+if (*str=='0'&&*(str+1)=='\0'){
+GC_retry_signals=FALSE;
+} else {
+GC_retry_signals=TRUE;
+}
+}
+if (GC_retry_signals){
+GC_COND_LOG_PRINTF(
+"Will retry suspend and restart signals if necessary\n");
+}
+#ifndef NO_SIGNALS_UNBLOCK_IN_MAIN
+GC_unblock_gc_signals();
+#endif
+#endif
+}
+#endif
+#if defined(GC_PTHREADS)&&!defined(GC_WIN32_THREADS)
+#include <stdlib.h>
+#include <pthread.h>
+#include <sched.h>
+#include <time.h>
+#include <errno.h>
+#include <unistd.h>
+#if!defined(SN_TARGET_ORBIS)&&!defined(SN_TARGET_PSP2)
+#if!defined(GC_RTEMS_PTHREADS)
+#include <sys/mman.h>
+#endif
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#endif
+#include <signal.h>
+#if defined(GC_DARWIN_THREADS)
+#ifndef GC_DARWIN_SEMAPHORE_H
+#define GC_DARWIN_SEMAPHORE_H
+#if!defined(GC_DARWIN_THREADS)
+#error darwin_semaphore.h included with GC_DARWIN_THREADS not defined
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef struct {
+pthread_mutex_t mutex;
+pthread_cond_t cond;
+int value;
+} sem_t;
+GC_INLINE int sem_init(sem_t*sem,int pshared,int value){
+if (pshared!=0){
+errno=EPERM;
+return -1;
+}
+sem->value=value;
+if (pthread_mutex_init(&sem->mutex,NULL)!=0)
+return -1;
+if (pthread_cond_init(&sem->cond,NULL)!=0){
+(void)pthread_mutex_destroy(&sem->mutex);
+return -1;
+}
+return 0;
+}
+GC_INLINE int sem_post(sem_t*sem){
+if (pthread_mutex_lock(&sem->mutex)!=0)
+return -1;
+sem->value++;
+if (pthread_cond_signal(&sem->cond)!=0){
+(void)pthread_mutex_unlock(&sem->mutex);
+return -1;
+}
+return pthread_mutex_unlock(&sem->mutex)!=0?-1:0;
+}
+GC_INLINE int sem_wait(sem_t*sem){
+if (pthread_mutex_lock(&sem->mutex)!=0)
+return -1;
+while (sem->value==0){
+if (pthread_cond_wait(&sem->cond,&sem->mutex)!=0){
+(void)pthread_mutex_unlock(&sem->mutex);
+return -1;
+}
+}
+sem->value--;
+return pthread_mutex_unlock(&sem->mutex)!=0?-1:0;
+}
+GC_INLINE int sem_destroy(sem_t*sem){
+return pthread_cond_destroy(&sem->cond)!=0
+||pthread_mutex_destroy(&sem->mutex)!=0?-1:0;
+}
+#ifdef __cplusplus
+}
+#endif
+#endif
+#else
+#include <semaphore.h>
+#endif
+#if defined(GC_DARWIN_THREADS)||defined(GC_FREEBSD_THREADS)
+#include <sys/sysctl.h>
+#endif
+#if defined(GC_NETBSD_THREADS)||defined(GC_OPENBSD_THREADS)
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#endif
+#if!defined(USE_SPIN_LOCK)
+GC_INNER pthread_mutex_t GC_allocate_ml=PTHREAD_MUTEX_INITIALIZER;
+#endif
+#ifdef GC_ASSERTIONS
+GC_INNER unsigned long GC_lock_holder=NO_THREAD;
+#endif
+#if defined(GC_DGUX386_THREADS)
+#include <sys/dg_sys_info.h>
+#include <sys/_int_psem.h>
+typedef unsigned int sem_t;
+#endif
+#undef pthread_create
+#ifndef GC_NO_PTHREAD_SIGMASK
+#undef pthread_sigmask
+#endif
+#ifndef GC_NO_PTHREAD_CANCEL
+#undef pthread_cancel
+#endif
+#ifdef GC_HAVE_PTHREAD_EXIT
+#undef pthread_exit
+#endif
+#undef pthread_join
+#undef pthread_detach
+#if defined(GC_OSF1_THREADS)&&defined(_PTHREAD_USE_MANGLED_NAMES_)&&!defined(_PTHREAD_USE_PTDNAM_)
+#define pthread_create __pthread_create
+#define pthread_join __pthread_join
+#define pthread_detach __pthread_detach
+#ifndef GC_NO_PTHREAD_CANCEL
+#define pthread_cancel __pthread_cancel
+#endif
+#ifdef GC_HAVE_PTHREAD_EXIT
+#define pthread_exit __pthread_exit
+#endif
+#endif
+#ifdef GC_USE_LD_WRAP
+#define WRAP_FUNC(f)__wrap_##f
+#define REAL_FUNC(f)__real_##f
+int REAL_FUNC(pthread_create)(pthread_t*,
+GC_PTHREAD_CREATE_CONST pthread_attr_t*,
+void*(*start_routine)(void*),void*);
+int REAL_FUNC(pthread_join)(pthread_t,void**);
+int REAL_FUNC(pthread_detach)(pthread_t);
+#ifndef GC_NO_PTHREAD_SIGMASK
+int REAL_FUNC(pthread_sigmask)(int,const sigset_t*,sigset_t*);
+#endif
+#ifndef GC_NO_PTHREAD_CANCEL
+int REAL_FUNC(pthread_cancel)(pthread_t);
+#endif
+#ifdef GC_HAVE_PTHREAD_EXIT
+void REAL_FUNC(pthread_exit)(void*)GC_PTHREAD_EXIT_ATTRIBUTE;
+#endif
+#else
+#ifdef GC_USE_DLOPEN_WRAP
+#include <dlfcn.h>
+#define WRAP_FUNC(f)f
+#define REAL_FUNC(f)GC_real_##f
+typedef int (*GC_pthread_create_t)(pthread_t*,
+GC_PTHREAD_CREATE_CONST pthread_attr_t*,
+void*(*)(void*),void*);
+static GC_pthread_create_t REAL_FUNC(pthread_create);
+#ifndef GC_NO_PTHREAD_SIGMASK
+typedef int (*GC_pthread_sigmask_t)(int,const sigset_t*,
+sigset_t*);
+static GC_pthread_sigmask_t REAL_FUNC(pthread_sigmask);
+#endif
+typedef int (*GC_pthread_join_t)(pthread_t,void**);
+static GC_pthread_join_t REAL_FUNC(pthread_join);
+typedef int (*GC_pthread_detach_t)(pthread_t);
+static GC_pthread_detach_t REAL_FUNC(pthread_detach);
+#ifndef GC_NO_PTHREAD_CANCEL
+typedef int (*GC_pthread_cancel_t)(pthread_t);
+static GC_pthread_cancel_t REAL_FUNC(pthread_cancel);
+#endif
+#ifdef GC_HAVE_PTHREAD_EXIT
+typedef void (*GC_pthread_exit_t)(void*)GC_PTHREAD_EXIT_ATTRIBUTE;
+static GC_pthread_exit_t REAL_FUNC(pthread_exit);
+#endif
+#else
+#define WRAP_FUNC(f)GC_##f
+#if!defined(GC_DGUX386_THREADS)
+#define REAL_FUNC(f)f
+#else
+#define REAL_FUNC(f)__d10_##f
+#endif
+#endif
+#endif
+#if defined(GC_USE_LD_WRAP)||defined(GC_USE_DLOPEN_WRAP)
+GC_API int GC_pthread_create(pthread_t*t,
+GC_PTHREAD_CREATE_CONST pthread_attr_t*a,
+void*(*fn)(void*),void*arg)
+{
+return pthread_create(t,a,fn,arg);
+}
+#ifndef GC_NO_PTHREAD_SIGMASK
+GC_API int GC_pthread_sigmask(int how,const sigset_t*mask,
+sigset_t*old)
+{
+return pthread_sigmask(how,mask,old);
+}
+#endif
+GC_API int GC_pthread_join(pthread_t t,void**res)
+{
+return pthread_join(t,res);
+}
+GC_API int GC_pthread_detach(pthread_t t)
+{
+return pthread_detach(t);
+}
+#ifndef GC_NO_PTHREAD_CANCEL
+GC_API int GC_pthread_cancel(pthread_t t)
+{
+return pthread_cancel(t);
+}
+#endif
+#ifdef GC_HAVE_PTHREAD_EXIT
+GC_API GC_PTHREAD_EXIT_ATTRIBUTE void GC_pthread_exit(void*retval)
+{
+pthread_exit(retval);
+}
+#endif
+#endif
+#ifdef GC_USE_DLOPEN_WRAP
+STATIC GC_bool GC_syms_initialized=FALSE;
+STATIC void GC_init_real_syms(void)
+{
+void*dl_handle;
+if (GC_syms_initialized)return;
+#ifdef RTLD_NEXT
+dl_handle=RTLD_NEXT;
+#else
+dl_handle=dlopen("libpthread.so.0",RTLD_LAZY);
+if (NULL==dl_handle){
+dl_handle=dlopen("libpthread.so",RTLD_LAZY);
+}
+if (NULL==dl_handle)ABORT("Couldn't open libpthread");
+#endif
+REAL_FUNC(pthread_create)=(GC_pthread_create_t)(word)
+dlsym(dl_handle,"pthread_create");
+#ifdef RTLD_NEXT
+if (REAL_FUNC(pthread_create)==0)
+ABORT("pthread_create not found"
+" (probably -lgc is specified after -lpthread)");
+#endif
+#ifndef GC_NO_PTHREAD_SIGMASK
+REAL_FUNC(pthread_sigmask)=(GC_pthread_sigmask_t)(word)
+dlsym(dl_handle,"pthread_sigmask");
+#endif
+REAL_FUNC(pthread_join)=(GC_pthread_join_t)(word)
+dlsym(dl_handle,"pthread_join");
+REAL_FUNC(pthread_detach)=(GC_pthread_detach_t)(word)
+dlsym(dl_handle,"pthread_detach");
+#ifndef GC_NO_PTHREAD_CANCEL
+REAL_FUNC(pthread_cancel)=(GC_pthread_cancel_t)(word)
+dlsym(dl_handle,"pthread_cancel");
+#endif
+#ifdef GC_HAVE_PTHREAD_EXIT
+REAL_FUNC(pthread_exit)=(GC_pthread_exit_t)(word)
+dlsym(dl_handle,"pthread_exit");
+#endif
+GC_syms_initialized=TRUE;
+}
+#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;
+#ifndef GC_ALWAYS_MULTITHREADED
+GC_INNER GC_bool GC_need_to_lock=FALSE;
+#endif
+STATIC int GC_nprocs=1;
+#ifdef THREAD_LOCAL_ALLOC
+GC_INNER void GC_mark_thread_local_free_lists(void)
+{
+int i;
+GC_thread p;
+for (i=0;i < THREAD_TABLE_SZ;++i){
+for (p=GC_threads[i];0!=p;p=p->next){
+if (!(p->flags&FINISHED))
+GC_mark_thread_local_fls_for(&(p->tlfs));
+}
+}
+}
+#if defined(GC_ASSERTIONS)
+void GC_check_tls(void)
+{
+int i;
+GC_thread p;
+for (i=0;i < THREAD_TABLE_SZ;++i){
+for (p=GC_threads[i];0!=p;p=p->next){
+if (!(p->flags&FINISHED))
+GC_check_tls_for(&(p->tlfs));
+}
+}
+#if defined(USE_CUSTOM_SPECIFIC)
+if (GC_thread_key!=0)
+GC_check_tsd_marks(GC_thread_key);
+#endif
+}
+#endif
+#endif
+#ifdef PARALLEL_MARK
+#ifndef MAX_MARKERS
+#define MAX_MARKERS 16
+#endif
+static ptr_t marker_sp[MAX_MARKERS - 1]={0};
+#ifdef IA64
+static ptr_t marker_bsp[MAX_MARKERS - 1]={0};
+#endif
+#if defined(GC_DARWIN_THREADS)&&!defined(GC_NO_THREADS_DISCOVERY)
+static mach_port_t marker_mach_threads[MAX_MARKERS - 1]={0};
+GC_INNER GC_bool GC_is_mach_marker(thread_act_t thread)
+{
+int i;
+for (i=0;i < GC_markers_m1;i++){
+if (marker_mach_threads[i]==thread)
+return TRUE;
+}
+return FALSE;
+}
+#endif
+#ifdef HAVE_PTHREAD_SETNAME_NP_WITH_TID_AND_ARG
+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];
+int len=sizeof("GC-marker-")- 1;
+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
+(void)pthread_setname_np(name_buf);
+#else
+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;
+IF_CANCEL(int cancel_state;)
+if ((word)id==GC_WORD_MAX)return 0;
+DISABLE_CANCEL(cancel_state);
+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();
+#endif
+#if defined(GC_DARWIN_THREADS)&&!defined(GC_NO_THREADS_DISCOVERY)
+marker_mach_threads[(word)id]=mach_thread_self();
+#endif
+GC_acquire_mark_lock();
+if (0==--GC_fl_builder_count)
+GC_notify_all_builder();
+for (;;++my_mark_no){
+if (my_mark_no < GC_mark_no||my_mark_no > GC_mark_no+2){
+my_mark_no=GC_mark_no;
+}
+#ifdef DEBUG_THREADS
+GC_log_printf("Starting mark helper for mark number %lu\n",
+(unsigned long)my_mark_no);
+#endif
+GC_help_marker(my_mark_no);
+}
+}
+STATIC pthread_t GC_mark_threads[MAX_MARKERS];
+#ifdef CAN_HANDLE_FORK
+static int available_markers_m1=0;
+static pthread_cond_t mark_cv;
+#else
+#define available_markers_m1 GC_markers_m1
+static pthread_cond_t mark_cv=PTHREAD_COND_INITIALIZER;
+#endif
+GC_INNER void GC_start_mark_threads_inner(void)
+{
+int i;
+pthread_attr_t attr;
+#ifndef NO_MARKER_SPECIAL_SIGMASK
+sigset_t set,oldset;
+#endif
+GC_ASSERT(I_DONT_HOLD_LOCK());
+if (available_markers_m1<=0)return;
+#ifdef CAN_HANDLE_FORK
+if (GC_parallel)return;
+{
+pthread_cond_t mark_cv_local=PTHREAD_COND_INITIALIZER;
+BCOPY(&mark_cv_local,&mark_cv,sizeof(mark_cv));
+}
+#endif
+GC_ASSERT(GC_fl_builder_count==0);
+INIT_REAL_SYMS();
+if (0!=pthread_attr_init(&attr))ABORT("pthread_attr_init failed");
+if (0!=pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED))
+ABORT("pthread_attr_setdetachstate failed");
+#ifdef DEFAULT_STACK_MAYBE_SMALL
+{
+size_t old_size;
+if (pthread_attr_getstacksize(&attr,&old_size)!=0)
+ABORT("pthread_attr_getstacksize failed");
+if (old_size < MIN_STACK_SIZE
+&&old_size!=0){
+if (pthread_attr_setstacksize(&attr,MIN_STACK_SIZE)!=0)
+ABORT("pthread_attr_setstacksize failed");
+}
+}
+#endif
+#ifndef NO_MARKER_SPECIAL_SIGMASK
+if (sigfillset(&set)!=0)
+ABORT("sigfillset failed");
+#if!defined(GC_DARWIN_THREADS)&&!defined(GC_OPENBSD_UTHREADS)&&!defined(NACL)
+if (sigdelset(&set,GC_get_suspend_signal())!=0
+||sigdelset(&set,GC_get_thr_restart_signal())!=0)
+ABORT("sigdelset failed");
+#endif
+if (REAL_FUNC(pthread_sigmask)(SIG_BLOCK,&set,&oldset)< 0){
+WARN("pthread_sigmask set failed,no markers started,"
+" errno=%" WARN_PRIdPTR "\n",errno);
+GC_markers_m1=0;
+(void)pthread_attr_destroy(&attr);
+return;
+}
+#endif
+#ifdef CAN_HANDLE_FORK
+GC_markers_m1=available_markers_m1;
+#endif
+for (i=0;i < available_markers_m1;++i){
+if (0!=REAL_FUNC(pthread_create)(GC_mark_threads+i,&attr,
+GC_mark_thread,(void*)(word)i)){
+WARN("Marker thread creation failed,errno=%" WARN_PRIdPTR "\n",
+errno);
+GC_markers_m1=i;
+break;
+}
+}
+#ifndef NO_MARKER_SPECIAL_SIGMASK
+if (REAL_FUNC(pthread_sigmask)(SIG_SETMASK,&oldset,NULL)< 0){
+WARN("pthread_sigmask restore failed,errno=%" WARN_PRIdPTR "\n",
+errno);
+}
+#endif
+(void)pthread_attr_destroy(&attr);
+GC_wait_for_markers_init();
+GC_COND_LOG_PRINTF("Started %d mark helper threads\n",GC_markers_m1);
+}
+#endif
+GC_INNER GC_bool GC_thr_initialized=FALSE;
+GC_INNER volatile GC_thread GC_threads[THREAD_TABLE_SZ]={0};
+void GC_push_thread_structures(void)
+{
+GC_ASSERT(I_HOLD_LOCK());
+GC_PUSH_ALL_SYM(GC_threads);
+#if defined(THREAD_LOCAL_ALLOC)
+GC_PUSH_ALL_SYM(GC_thread_key);
+#endif
+}
+#ifdef DEBUG_THREADS
+STATIC int GC_count_threads(void)
+{
+int i;
+int count=0;
+GC_ASSERT(I_HOLD_LOCK());
+for (i=0;i < THREAD_TABLE_SZ;++i){
+GC_thread th=GC_threads[i];
+while (th){
+if (!(th->flags&FINISHED))
+++count;
+th=th->next;
+}
+}
+return count;
+}
+#endif
+static struct GC_Thread_Rep first_thread;
+STATIC GC_thread GC_new_thread(pthread_t id)
+{
+int hv=THREAD_TABLE_INDEX(id);
+GC_thread result;
+static GC_bool first_thread_used=FALSE;
+#ifdef DEBUG_THREADS
+GC_log_printf("Creating thread %p\n",(void*)id);
+for (result=GC_threads[hv];result!=NULL;result=result->next)
+if (!THREAD_EQUAL(result->id,id)){
+GC_log_printf("Hash collision at GC_threads[%d]\n",hv);
+break;
+}
+#endif
+GC_ASSERT(I_HOLD_LOCK());
+if (!EXPECT(first_thread_used,TRUE)){
+result=&first_thread;
+first_thread_used=TRUE;
+GC_ASSERT(NULL==GC_threads[hv]);
+#if defined(THREAD_SANITIZER)&&defined(CPPCHECK)
+GC_noop1(result->dummy[0]);
+#endif
+} else {
+result=(struct GC_Thread_Rep*)
+GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep),NORMAL);
+if (result==0)return(0);
+}
+result->id=id;
+#ifdef USE_TKILL_ON_ANDROID
+result->kernel_id=gettid();
+#endif
+result->next=GC_threads[hv];
+GC_threads[hv]=result;
+#ifdef NACL
+GC_nacl_gc_thread_self=result;
+GC_nacl_initialize_gc_thread();
+#endif
+GC_ASSERT(result->flags==0&&result->thread_blocked==0);
+if (EXPECT(result!=&first_thread,TRUE))
+GC_dirty(result);
+return(result);
+}
+STATIC void GC_delete_thread(pthread_t id)
+{
+int hv=THREAD_TABLE_INDEX(id);
+GC_thread p=GC_threads[hv];
+GC_thread prev=NULL;
+#ifdef DEBUG_THREADS
+GC_log_printf("Deleting thread %p,n_threads=%d\n",
+(void*)id,GC_count_threads());
+#endif
+#ifdef NACL
+GC_nacl_shutdown_gc_thread();
+GC_nacl_gc_thread_self=NULL;
+#endif
+GC_ASSERT(I_HOLD_LOCK());
+while (!THREAD_EQUAL(p->id,id)){
+prev=p;
+p=p->next;
+}
+if (prev==0){
+GC_threads[hv]=p->next;
+} else {
+GC_ASSERT(prev!=&first_thread);
+prev->next=p->next;
+GC_dirty(prev);
+}
+if (p!=&first_thread){
+#ifdef GC_DARWIN_THREADS
+mach_port_deallocate(mach_task_self(),p->stop_info.mach_thread);
+#endif
+GC_INTERNAL_FREE(p);
+}
+}
+STATIC void GC_delete_gc_thread(GC_thread t)
+{
+pthread_t id=t->id;
+int hv=THREAD_TABLE_INDEX(id);
+GC_thread p=GC_threads[hv];
+GC_thread prev=NULL;
+GC_ASSERT(I_HOLD_LOCK());
+while (p!=t){
+prev=p;
+p=p->next;
+}
+if (prev==0){
+GC_threads[hv]=p->next;
+} else {
+GC_ASSERT(prev!=&first_thread);
+prev->next=p->next;
+GC_dirty(prev);
+}
+#ifdef GC_DARWIN_THREADS
+mach_port_deallocate(mach_task_self(),p->stop_info.mach_thread);
+#endif
+GC_INTERNAL_FREE(p);
+#ifdef DEBUG_THREADS
+GC_log_printf("Deleted thread %p,n_threads=%d\n",
+(void*)id,GC_count_threads());
+#endif
+}
+GC_INNER GC_thread GC_lookup_thread(pthread_t id)
+{
+GC_thread p=GC_threads[THREAD_TABLE_INDEX(id)];
+while (p!=0&&!THREAD_EQUAL(p->id,id))p=p->next;
+return(p);
+}
+GC_INNER void GC_reset_finalizer_nested(void)
+{
+GC_thread me=GC_lookup_thread(pthread_self());
+me->finalizer_nested=0;
+}
+GC_INNER unsigned char*GC_check_finalizer_nested(void)
+{
+GC_thread me=GC_lookup_thread(pthread_self());
+unsigned nesting_level=me->finalizer_nested;
+if (nesting_level){
+if (++me->finalizer_skipped < (1U<<nesting_level))return NULL;
+me->finalizer_skipped=0;
+}
+me->finalizer_nested=(unsigned char)(nesting_level+1);
+return&me->finalizer_nested;
+}
+#if defined(GC_ASSERTIONS)&&defined(THREAD_LOCAL_ALLOC)
+GC_bool GC_is_thread_tsd_valid(void*tsd)
+{
+GC_thread me;
+DCL_LOCK_STATE;
+LOCK();
+me=GC_lookup_thread(pthread_self());
+UNLOCK();
+return (word)tsd>=(word)(&me->tlfs)
+&&(word)tsd < (word)(&me->tlfs)+sizeof(me->tlfs);
+}
+#endif
+GC_API int GC_CALL GC_thread_is_registered(void)
+{
+pthread_t self=pthread_self();
+GC_thread me;
+DCL_LOCK_STATE;
+LOCK();
+me=GC_lookup_thread(self);
+UNLOCK();
+return me!=NULL;
+}
+static pthread_t main_pthread_id;
+static void*main_stack,*main_altstack;
+static word main_stack_size,main_altstack_size;
+GC_API void GC_CALL GC_register_altstack(void*stack,GC_word stack_size,
+void*altstack,
+GC_word altstack_size)
+{
+GC_thread me;
+pthread_t self=pthread_self();
+DCL_LOCK_STATE;
+LOCK();
+me=GC_lookup_thread(self);
+if (me!=NULL){
+me->stack=(ptr_t)stack;
+me->stack_size=stack_size;
+me->altstack=(ptr_t)altstack;
+me->altstack_size=altstack_size;
+} else {
+main_pthread_id=self;
+main_stack=stack;
+main_stack_size=stack_size;
+main_altstack=altstack;
+main_altstack_size=altstack_size;
+}
+UNLOCK();
+}
+#ifdef CAN_HANDLE_FORK
+#ifdef CAN_CALL_ATFORK
+GC_ATTR_NO_SANITIZE_THREAD
+#endif
+static void store_to_threads_table(int hv,GC_thread me)
+{
+GC_threads[hv]=me;
+}
+STATIC void GC_remove_all_threads_but_me(void)
+{
+pthread_t self=pthread_self();
+int hv;
+for (hv=0;hv < THREAD_TABLE_SZ;++hv){
+GC_thread p,next;
+GC_thread me=NULL;
+for (p=GC_threads[hv];0!=p;p=next){
+next=p->next;
+if (THREAD_EQUAL(p->id,self)
+&&me==NULL){
+me=p;
+p->next=0;
+#ifdef GC_DARWIN_THREADS
+me->stop_info.mach_thread=mach_thread_self();
+#endif
+#ifdef USE_TKILL_ON_ANDROID
+me->kernel_id=gettid();
+#endif
+#if defined(THREAD_LOCAL_ALLOC)&&!defined(USE_CUSTOM_SPECIFIC)
+{
+int res;
+res=GC_setspecific(GC_thread_key,&me->tlfs);
+if (COVERT_DATAFLOW(res)!=0)
+ABORT("GC_setspecific failed (in child)");
+}
+#endif
+} else {
+#ifdef THREAD_LOCAL_ALLOC
+if (!(p->flags&FINISHED)){
+GC_remove_specific_after_fork(GC_thread_key,p->id);
+}
+#endif
+#if!defined(THREAD_SANITIZER)||!defined(CAN_CALL_ATFORK)
+if (p!=&first_thread)GC_INTERNAL_FREE(p);
+#endif
+}
+}
+store_to_threads_table(hv,me);
+}
+}
+#endif
+#ifdef USE_PROC_FOR_LIBRARIES
+GC_INNER GC_bool GC_segment_is_thread_stack(ptr_t lo,ptr_t hi)
+{
+int i;
+GC_thread p;
+GC_ASSERT(I_HOLD_LOCK());
+#ifdef PARALLEL_MARK
+for (i=0;i < GC_markers_m1;++i){
+if ((word)marker_sp[i] > (word)lo&&(word)marker_sp[i] < (word)hi)
+return TRUE;
+#ifdef IA64
+if ((word)marker_bsp[i] > (word)lo
+&&(word)marker_bsp[i] < (word)hi)
+return TRUE;
+#endif
+}
+#endif
+for (i=0;i < THREAD_TABLE_SZ;i++){
+for (p=GC_threads[i];p!=0;p=p->next){
+if (0!=p->stack_end){
+#ifdef STACK_GROWS_UP
+if ((word)p->stack_end>=(word)lo
+&&(word)p->stack_end < (word)hi)
+return TRUE;
+#else
+if ((word)p->stack_end > (word)lo
+&&(word)p->stack_end<=(word)hi)
+return TRUE;
+#endif
+}
+}
+}
+return FALSE;
+}
+#endif
+#ifdef IA64
+GC_INNER ptr_t GC_greatest_stack_base_below(ptr_t bound)
+{
+int i;
+GC_thread p;
+ptr_t result=0;
+GC_ASSERT(I_HOLD_LOCK());
+#ifdef PARALLEL_MARK
+for (i=0;i < GC_markers_m1;++i){
+if ((word)marker_sp[i] > (word)result
+&&(word)marker_sp[i] < (word)bound)
+result=marker_sp[i];
+}
+#endif
+for (i=0;i < THREAD_TABLE_SZ;i++){
+for (p=GC_threads[i];p!=0;p=p->next){
+if ((word)p->stack_end > (word)result
+&&(word)p->stack_end < (word)bound){
+result=p->stack_end;
+}
+}
+}
+return result;
+}
+#endif
+#ifndef STAT_READ
+#define STAT_BUF_SIZE 4096
+#define STAT_READ read
+#endif
+#ifdef GC_HPUX_THREADS
+#define GC_get_nprocs()pthread_num_processors_np()
+#elif defined(GC_OSF1_THREADS)||defined(GC_AIX_THREADS)||defined(GC_HAIKU_THREADS)||defined(GC_SOLARIS_THREADS)||defined(HURD)||defined(HOST_ANDROID)||defined(NACL)
+GC_INLINE int GC_get_nprocs(void)
+{
+int nprocs=(int)sysconf(_SC_NPROCESSORS_ONLN);
+return nprocs > 0?nprocs:1;
+}
+#elif defined(GC_IRIX_THREADS)
+GC_INLINE int GC_get_nprocs(void)
+{
+int nprocs=(int)sysconf(_SC_NPROC_ONLN);
+return nprocs > 0?nprocs:1;
+}
+#elif defined(GC_LINUX_THREADS)
+STATIC int GC_get_nprocs(void)
+{
+char stat_buf[STAT_BUF_SIZE];
+int f;
+int result,i,len;
+f=open("/proc/stat",O_RDONLY);
+if (f < 0){
+WARN("Couldn't read/proc/stat\n",0);
+return 1;
+}
+len=STAT_READ(f,stat_buf,STAT_BUF_SIZE);
+close(f);
+result=1;
+for (i=0;i < len - 100;++i){
+if (stat_buf[i]=='\n'&&stat_buf[i+1]=='c'
+&&stat_buf[i+2]=='p'&&stat_buf[i+3]=='u'){
+int cpu_no=atoi(&stat_buf[i+4]);
+if (cpu_no>=result)
+result=cpu_no+1;
+}
+}
+return result;
+}
+#elif defined(GC_DGUX386_THREADS)
+STATIC int GC_get_nprocs(void)
+{
+int numCpus;
+struct dg_sys_info_pm_info pm_sysinfo;
+int status=0;
+status=dg_sys_info((long int*)&pm_sysinfo,
+DG_SYS_INFO_PM_INFO_TYPE,DG_SYS_INFO_PM_CURRENT_VERSION);
+if (status < 0)
+numCpus=-1;
+else
+numCpus=pm_sysinfo.idle_vp_count;
+return(numCpus);
+}
+#elif defined(GC_DARWIN_THREADS)||defined(GC_FREEBSD_THREADS)||defined(GC_NETBSD_THREADS)||defined(GC_OPENBSD_THREADS)
+STATIC int GC_get_nprocs(void)
+{
+int mib[]={CTL_HW,HW_NCPU};
+int res;
+size_t len=sizeof(res);
+sysctl(mib,sizeof(mib)/sizeof(int),&res,&len,NULL,0);
+return res;
+}
+#else
+#define GC_get_nprocs()1
+#endif
+#if defined(ARM32)&&defined(GC_LINUX_THREADS)&&!defined(NACL)
+STATIC int GC_get_nprocs_present(void)
+{
+char stat_buf[16];
+int f;
+int len;
+f=open("/sys/devices/system/cpu/present",O_RDONLY);
+if (f < 0)
+return -1;
+len=STAT_READ(f,stat_buf,sizeof(stat_buf));
+close(f);
+if (len < 2||stat_buf[0]!='0'||stat_buf[len - 1]!='\n'){
+return 0;
+} else if (len==2){
+return 1;
+} else if (stat_buf[1]!='-'){
+return 0;
+}
+stat_buf[len - 1]='\0';
+return atoi(&stat_buf[2])+1;
+}
+#endif
+STATIC void GC_wait_for_gc_completion(GC_bool wait_for_all)
+{
+DCL_LOCK_STATE;
+#if!defined(THREAD_SANITIZER)||!defined(CAN_CALL_ATFORK)
+GC_ASSERT(I_HOLD_LOCK());
+#endif
+ASSERT_CANCEL_DISABLED();
+if (GC_incremental&&GC_collection_in_progress()){
+word old_gc_no=GC_gc_no;
+while (GC_incremental&&GC_collection_in_progress()
+&&(wait_for_all||old_gc_no==GC_gc_no)){
+ENTER_GC();
+GC_in_thread_creation=TRUE;
+GC_collect_a_little_inner(1);
+GC_in_thread_creation=FALSE;
+EXIT_GC();
+UNLOCK();
+sched_yield();
+LOCK();
+}
+}
+}
+#ifdef CAN_HANDLE_FORK
+IF_CANCEL(static int fork_cancel_state;)
+#if defined(GC_ASSERTIONS)&&defined(CAN_CALL_ATFORK)
+GC_ATTR_NO_SANITIZE_THREAD
+#endif
+static void fork_prepare_proc(void)
+{
+LOCK();
+DISABLE_CANCEL(fork_cancel_state);
+#if defined(PARALLEL_MARK)
+if (GC_parallel)
+GC_wait_for_reclaim();
+#endif
+GC_wait_for_gc_completion(TRUE);
+#if defined(PARALLEL_MARK)
+if (GC_parallel)
+GC_acquire_mark_lock();
+#endif
+GC_acquire_dirty_lock();
+}
+#if defined(GC_ASSERTIONS)&&defined(CAN_CALL_ATFORK)
+GC_ATTR_NO_SANITIZE_THREAD
+#endif
+static void fork_parent_proc(void)
+{
+GC_release_dirty_lock();
+#if defined(PARALLEL_MARK)
+if (GC_parallel)
+GC_release_mark_lock();
+#endif
+RESTORE_CANCEL(fork_cancel_state);
+UNLOCK();
+}
+#if defined(GC_ASSERTIONS)&&defined(CAN_CALL_ATFORK)
+GC_ATTR_NO_SANITIZE_THREAD
+#endif
+static void fork_child_proc(void)
+{
+GC_release_dirty_lock();
+#if defined(PARALLEL_MARK)
+if (GC_parallel)
+GC_release_mark_lock();
+#endif
+GC_remove_all_threads_but_me();
+#ifdef PARALLEL_MARK
+GC_parallel=FALSE;
+#endif
+RESTORE_CANCEL(fork_cancel_state);
+UNLOCK();
+#ifdef USE_PTHREAD_LOCKS
+GC_ASSERT(I_DONT_HOLD_LOCK());
+(void)pthread_mutex_destroy(&GC_allocate_ml);
+if (0!=pthread_mutex_init(&GC_allocate_ml,NULL))
+ABORT("pthread_mutex_init failed (in child)");
+#endif
+}
+GC_API void GC_CALL GC_atfork_prepare(void)
+{
+if (!EXPECT(GC_is_initialized,TRUE))GC_init();
+#if defined(GC_DARWIN_THREADS)&&defined(MPROTECT_VDB)
+if (GC_auto_incremental){
+GC_ASSERT(0==GC_handle_fork);
+ABORT("Unable to fork while mprotect_thread is running");
+}
+#endif
+if (GC_handle_fork<=0)
+fork_prepare_proc();
+}
+GC_API void GC_CALL GC_atfork_parent(void)
+{
+if (GC_handle_fork<=0)
+fork_parent_proc();
+}
+GC_API void GC_CALL GC_atfork_child(void)
+{
+if (GC_handle_fork<=0)
+fork_child_proc();
+}
+#endif
+#ifdef INCLUDE_LINUX_THREAD_DESCR
+__thread int GC_dummy_thread_local;
+#endif
+#ifdef PARALLEL_MARK
+static void setup_mark_lock(void);
+static unsigned required_markers_cnt=0;
+#endif
+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)
+{
+GC_ASSERT(I_HOLD_LOCK());
+if (GC_thr_initialized)return;
+GC_thr_initialized=TRUE;
+GC_ASSERT((word)&GC_threads % sizeof(word)==0);
+#ifdef CAN_HANDLE_FORK
+if (GC_handle_fork){
+#ifdef CAN_CALL_ATFORK
+if (pthread_atfork(fork_prepare_proc,fork_parent_proc,
+fork_child_proc)==0){
+GC_handle_fork=1;
+} else
+#endif
+if (GC_handle_fork!=-1)
+ABORT("pthread_atfork failed");
+}
+#endif
+#ifdef INCLUDE_LINUX_THREAD_DESCR
+{
+ptr_t thread_local_addr=(ptr_t)(&GC_dummy_thread_local);
+ptr_t main_thread_start,main_thread_end;
+if (!GC_enclosing_mapping(thread_local_addr,&main_thread_start,
+&main_thread_end)){
+ABORT("Failed to find mapping for main thread thread locals");
+} else {
+GC_add_roots_inner(main_thread_start,main_thread_end,FALSE);
+}
+}
+#endif
+{
+pthread_t self=pthread_self();
+GC_thread t=GC_new_thread(self);
+if (t==NULL)
+ABORT("Failed to allocate memory for the initial thread");
+#ifdef GC_DARWIN_THREADS
+t->stop_info.mach_thread=mach_thread_self();
+#else
+t->stop_info.stack_ptr=GC_approx_sp();
+#endif
+t->flags=DETACHED|MAIN_THREAD;
+if (THREAD_EQUAL(self,main_pthread_id)){
+t->stack=(ptr_t)main_stack;
+t->stack_size=main_stack_size;
+t->altstack=(ptr_t)main_altstack;
+t->altstack_size=main_altstack_size;
+}
+}
+#ifndef GC_DARWIN_THREADS
+GC_stop_init();
+#endif
+{
+char*nprocs_string=GETENV("GC_NPROCS");
+GC_nprocs=-1;
+if (nprocs_string!=NULL)GC_nprocs=atoi(nprocs_string);
+}
+if (GC_nprocs<=0
+#if defined(ARM32)&&defined(GC_LINUX_THREADS)&&!defined(NACL)
+&&(GC_nprocs=GC_get_nprocs_present())<=1
+#endif
+)
+{
+GC_nprocs=GC_get_nprocs();
+}
+if (GC_nprocs<=0){
+WARN("GC_get_nprocs()returned %" WARN_PRIdPTR "\n",GC_nprocs);
+GC_nprocs=2;
+#ifdef PARALLEL_MARK
+available_markers_m1=0;
+#endif
+} else {
+#ifdef PARALLEL_MARK
+{
+char*markers_string=GETENV("GC_MARKERS");
+int markers=required_markers_cnt;
+if (markers_string!=NULL){
+markers=atoi(markers_string);
+if (markers<=0||markers > MAX_MARKERS){
+WARN("Too big or invalid number of mark threads:%" WARN_PRIdPTR
+";using maximum threads\n",(signed_word)markers);
+markers=MAX_MARKERS;
+}
+} else if (0==markers){
+markers=GC_nprocs;
+#if defined(GC_MIN_MARKERS)&&!defined(CPPCHECK)
+if (markers < GC_MIN_MARKERS)
+markers=GC_MIN_MARKERS;
+#endif
+if (markers > MAX_MARKERS)
+markers=MAX_MARKERS;
+}
+available_markers_m1=markers - 1;
+}
+#endif
+}
+GC_COND_LOG_PRINTF("Number of processors=%d\n",GC_nprocs);
+#ifdef PARALLEL_MARK
+if (available_markers_m1<=0){
+GC_parallel=FALSE;
+GC_COND_LOG_PRINTF(
+"Single marker thread,turning off parallel marking\n");
+} else {
+setup_mark_lock();
+}
+#endif
+}
+GC_INNER void GC_init_parallel(void)
+{
+#if defined(THREAD_LOCAL_ALLOC)
+DCL_LOCK_STATE;
+#endif
+if (parallel_initialized)return;
+parallel_initialized=TRUE;
+if (!GC_is_initialized)GC_init();
+#if defined(THREAD_LOCAL_ALLOC)
+LOCK();
+GC_init_thread_local(&(GC_lookup_thread(pthread_self())->tlfs));
+UNLOCK();
+#endif
+}
+#ifndef GC_NO_PTHREAD_SIGMASK
+GC_API int WRAP_FUNC(pthread_sigmask)(int how,const sigset_t*set,
+sigset_t*oset)
+{
+sigset_t fudged_set;
+INIT_REAL_SYMS();
+if (set!=NULL&&(how==SIG_BLOCK||how==SIG_SETMASK)){
+int sig_suspend=GC_get_suspend_signal();
+fudged_set=*set;
+GC_ASSERT(sig_suspend>=0);
+if (sigdelset(&fudged_set,sig_suspend)!=0)
+ABORT("sigdelset failed");
+set=&fudged_set;
+}
+return(REAL_FUNC(pthread_sigmask)(how,set,oset));
+}
+#endif
+GC_INNER void GC_do_blocking_inner(ptr_t data,void*context GC_ATTR_UNUSED)
+{
+struct blocking_data*d=(struct blocking_data*)data;
+pthread_t self=pthread_self();
+GC_thread me;
+#if defined(SPARC)||defined(IA64)
+ptr_t stack_ptr=GC_save_regs_in_stack();
+#endif
+#if defined(GC_DARWIN_THREADS)&&!defined(DARWIN_DONT_PARSE_STACK)
+GC_bool topOfStackUnset=FALSE;
+#endif
+DCL_LOCK_STATE;
+LOCK();
+me=GC_lookup_thread(self);
+GC_ASSERT(!(me->thread_blocked));
+#ifdef SPARC
+me->stop_info.stack_ptr=stack_ptr;
+#else
+me->stop_info.stack_ptr=GC_approx_sp();
+#endif
+#if defined(GC_DARWIN_THREADS)&&!defined(DARWIN_DONT_PARSE_STACK)
+if (me->topOfStack==NULL){
+topOfStackUnset=TRUE;
+me->topOfStack=GC_FindTopOfStack(0);
+}
+#endif
+#ifdef IA64
+me->backing_store_ptr=stack_ptr;
+#endif
+me->thread_blocked=(unsigned char)TRUE;
+UNLOCK();
+d->client_data=(d->fn)(d->client_data);
+LOCK();
+#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)
+me->topOfStack=NULL;
+#endif
+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)
+t=GC_lookup_thread(pthread_self());
+GC_ASSERT((t->flags&FINISHED)==0);
+GC_ASSERT(!(t->thread_blocked)
+&&NULL==t->traced_stack_sect);
+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;
+}
+}
+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);
+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_API void*GC_CALL GC_call_with_gc_active(GC_fn_type fn,
+void*client_data)
+{
+struct GC_traced_stack_sect_s stacksect;
+pthread_t self=pthread_self();
+GC_thread me;
+DCL_LOCK_STATE;
+LOCK();
+me=GC_lookup_thread(self);
+if ((me->flags&MAIN_THREAD)==0){
+GC_ASSERT(me->stack_end!=NULL);
+if ((word)me->stack_end HOTTER_THAN (word)(&stacksect))
+me->stack_end=(ptr_t)(&stacksect);
+} else {
+if ((word)GC_stackbottom HOTTER_THAN (word)(&stacksect))
+GC_stackbottom=(ptr_t)COVERT_DATAFLOW(&stacksect);
+}
+if (!me->thread_blocked){
+UNLOCK();
+client_data=fn(client_data);
+GC_noop1(COVERT_DATAFLOW(&stacksect));
+return client_data;
+}
+stacksect.saved_stack_ptr=me->stop_info.stack_ptr;
+#ifdef IA64
+stacksect.backing_store_end=GC_save_regs_in_stack();
+stacksect.saved_backing_store_ptr=me->backing_store_ptr;
+#endif
+stacksect.prev=me->traced_stack_sect;
+me->thread_blocked=FALSE;
+me->traced_stack_sect=&stacksect;
+UNLOCK();
+client_data=fn(client_data);
+GC_ASSERT(me->thread_blocked==FALSE);
+GC_ASSERT(me->traced_stack_sect==&stacksect);
+#if defined(CPPCHECK)
+GC_noop1((word)me->traced_stack_sect);
+#endif
+LOCK();
+me->traced_stack_sect=stacksect.prev;
+#ifdef IA64
+me->backing_store_ptr=stacksect.saved_backing_store_ptr;
+#endif
+me->thread_blocked=(unsigned char)TRUE;
+me->stop_info.stack_ptr=stacksect.saved_stack_ptr;
+UNLOCK();
+return client_data;
+}
+STATIC void GC_unregister_my_thread_inner(GC_thread me)
+{
+#ifdef DEBUG_THREADS
+GC_log_printf(
+"Unregistering thread %p,gc_thread=%p,n_threads=%d\n",
+(void*)me->id,(void*)me,GC_count_threads());
+#endif
+GC_ASSERT(!(me->flags&FINISHED));
+#if defined(THREAD_LOCAL_ALLOC)
+GC_ASSERT(GC_getspecific(GC_thread_key)==&me->tlfs);
+GC_destroy_thread_local(&(me->tlfs));
+#endif
+#if defined(GC_HAVE_PTHREAD_EXIT)||!defined(GC_NO_PTHREAD_CANCEL)
+if ((me->flags&DISABLED_GC)!=0){
+GC_dont_gc--;
+}
+#endif
+if (me->flags&DETACHED){
+GC_delete_thread(pthread_self());
+} else {
+me->flags|=FINISHED;
+}
+#if defined(THREAD_LOCAL_ALLOC)
+GC_remove_specific(GC_thread_key);
+#endif
+}
+GC_API int GC_CALL GC_unregister_my_thread(void)
+{
+pthread_t self=pthread_self();
+GC_thread me;
+IF_CANCEL(int cancel_state;)
+DCL_LOCK_STATE;
+LOCK();
+DISABLE_CANCEL(cancel_state);
+GC_wait_for_gc_completion(FALSE);
+me=GC_lookup_thread(self);
+#ifdef DEBUG_THREADS
+GC_log_printf(
+"Called GC_unregister_my_thread on %p,gc_thread=%p\n",
+(void*)self,(void*)me);
+#endif
+GC_ASSERT(THREAD_EQUAL(me->id,self));
+GC_unregister_my_thread_inner(me);
+RESTORE_CANCEL(cancel_state);
+UNLOCK();
+return GC_SUCCESS;
+}
+GC_INNER_PTHRSTART void GC_thread_exit_proc(void*arg)
+{
+IF_CANCEL(int cancel_state;)
+DCL_LOCK_STATE;
+#ifdef DEBUG_THREADS
+GC_log_printf("Called GC_thread_exit_proc on %p,gc_thread=%p\n",
+(void*)((GC_thread)arg)->id,arg);
+#endif
+LOCK();
+DISABLE_CANCEL(cancel_state);
+GC_wait_for_gc_completion(FALSE);
+GC_unregister_my_thread_inner((GC_thread)arg);
+RESTORE_CANCEL(cancel_state);
+UNLOCK();
+}
+#if!defined(SN_TARGET_ORBIS)&&!defined(SN_TARGET_PSP2)
+GC_API int WRAP_FUNC(pthread_join)(pthread_t thread,void**retval)
+{
+int result;
+GC_thread t;
+DCL_LOCK_STATE;
+ASSERT_SYMS_INITIALIZED();
+LOCK();
+t=GC_lookup_thread(thread);
+UNLOCK();
+result=REAL_FUNC(pthread_join)(thread,retval);
+#if defined(GC_FREEBSD_THREADS)
+if (result==EINTR)result=0;
+#endif
+if (result==0){
+LOCK();
+if ((t->flags&FINISHED)!=0)
+GC_delete_gc_thread(t);
+UNLOCK();
+}
+return result;
+}
+GC_API int WRAP_FUNC(pthread_detach)(pthread_t thread)
+{
+int result;
+GC_thread t;
+DCL_LOCK_STATE;
+ASSERT_SYMS_INITIALIZED();
+LOCK();
+t=GC_lookup_thread(thread);
+UNLOCK();
+result=REAL_FUNC(pthread_detach)(thread);
+if (result==0){
+LOCK();
+t->flags|=DETACHED;
+if ((t->flags&FINISHED)!=0){
+GC_delete_gc_thread(t);
+}
+UNLOCK();
+}
+return result;
+}
+#endif
+#ifndef GC_NO_PTHREAD_CANCEL
+GC_API int WRAP_FUNC(pthread_cancel)(pthread_t thread)
+{
+#ifdef CANCEL_SAFE
+GC_thread t;
+DCL_LOCK_STATE;
+#endif
+INIT_REAL_SYMS();
+#ifdef CANCEL_SAFE
+LOCK();
+t=GC_lookup_thread(thread);
+if (t!=NULL&&(t->flags&DISABLED_GC)==0){
+t->flags|=DISABLED_GC;
+GC_dont_gc++;
+}
+UNLOCK();
+#endif
+return REAL_FUNC(pthread_cancel)(thread);
+}
+#endif
+#ifdef GC_HAVE_PTHREAD_EXIT
+GC_API GC_PTHREAD_EXIT_ATTRIBUTE void WRAP_FUNC(pthread_exit)(void*retval)
+{
+pthread_t self=pthread_self();
+GC_thread me;
+DCL_LOCK_STATE;
+INIT_REAL_SYMS();
+LOCK();
+me=GC_lookup_thread(self);
+if (me!=0&&(me->flags&DISABLED_GC)==0){
+me->flags|=DISABLED_GC;
+GC_dont_gc++;
+}
+UNLOCK();
+REAL_FUNC(pthread_exit)(retval);
+}
+#endif
+GC_INNER GC_bool GC_in_thread_creation=FALSE;
+GC_INLINE void GC_record_stack_base(GC_thread me,
+const struct GC_stack_base*sb)
+{
+#ifndef GC_DARWIN_THREADS
+me->stop_info.stack_ptr=(ptr_t)sb->mem_base;
+#endif
+me->stack_end=(ptr_t)sb->mem_base;
+if (me->stack_end==NULL)
+ABORT("Bad stack base in GC_register_my_thread");
+#ifdef IA64
+me->backing_store_end=(ptr_t)sb->reg_base;
+#endif
+}
+STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base*sb,
+pthread_t my_pthread)
+{
+GC_thread me;
+GC_in_thread_creation=TRUE;
+me=GC_new_thread(my_pthread);
+GC_in_thread_creation=FALSE;
+if (me==0)
+ABORT("Failed to allocate memory for thread registering");
+#ifdef GC_DARWIN_THREADS
+me->stop_info.mach_thread=mach_thread_self();
+#endif
+GC_record_stack_base(me,sb);
+#ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
+GC_unblock_gc_signals();
+#endif
+return me;
+}
+GC_API void GC_CALL GC_allow_register_threads(void)
+{
+GC_ASSERT(GC_lookup_thread(pthread_self())!=0);
+set_need_to_lock();
+}
+GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base*sb)
+{
+pthread_t self=pthread_self();
+GC_thread me;
+DCL_LOCK_STATE;
+if (GC_need_to_lock==FALSE)
+ABORT("Threads explicit registering is not previously enabled");
+LOCK();
+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;
+#if defined(THREAD_LOCAL_ALLOC)
+GC_init_thread_local(&(me->tlfs));
+#endif
+UNLOCK();
+return GC_SUCCESS;
+} else if ((me->flags&FINISHED)!=0){
+#ifdef GC_DARWIN_THREADS
+me->stop_info.mach_thread=mach_thread_self();
+#endif
+GC_record_stack_base(me,sb);
+me->flags&=~FINISHED;
+#ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
+GC_unblock_gc_signals();
+#endif
+#if defined(THREAD_LOCAL_ALLOC)
+GC_init_thread_local(&(me->tlfs));
+#endif
+UNLOCK();
+return GC_SUCCESS;
+} else {
+UNLOCK();
+return GC_DUPLICATE;
+}
+}
+struct start_info {
+void*(*start_routine)(void*);
+void*arg;
+word flags;
+sem_t registered;
+};
+GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread(
+void*(**pstart)(void*),
+void**pstart_arg,
+struct GC_stack_base*sb,void*arg)
+{
+struct start_info*si=(struct start_info*)arg;
+pthread_t self=pthread_self();
+GC_thread me;
+DCL_LOCK_STATE;
+#ifdef DEBUG_THREADS
+GC_log_printf("Starting thread %p,pid=%ld,sp=%p\n",
+(void*)self,(long)getpid(),(void*)&arg);
+#endif
+LOCK();
+me=GC_register_my_thread_inner(sb,self);
+me->flags=si->flags;
+#if defined(THREAD_LOCAL_ALLOC)
+GC_init_thread_local(&(me->tlfs));
+#endif
+UNLOCK();
+*pstart=si->start_routine;
+#ifdef DEBUG_THREADS
+GC_log_printf("start_routine=%p\n",(void*)(signed_word)(*pstart));
+#endif
+*pstart_arg=si->arg;
+sem_post(&(si->registered));
+return me;
+}
+#if!defined(SN_TARGET_ORBIS)&&!defined(SN_TARGET_PSP2)
+STATIC void*GC_start_routine(void*arg)
+{
+#ifdef INCLUDE_LINUX_THREAD_DESCR
+struct GC_stack_base sb;
+#ifdef REDIRECT_MALLOC
+GC_disable();
+#endif
+if (GC_get_stack_base(&sb)!=GC_SUCCESS)
+ABORT("Failed to get thread stack base");
+#ifdef REDIRECT_MALLOC
+GC_enable();
+#endif
+return GC_inner_start_routine(&sb,arg);
+#else
+return GC_call_with_stack_base(GC_inner_start_routine,arg);
+#endif
+}
+GC_API int WRAP_FUNC(pthread_create)(pthread_t*new_thread,
+GC_PTHREAD_CREATE_CONST pthread_attr_t*attr,
+void*(*start_routine)(void*),void*arg)
+{
+int result;
+int detachstate;
+word my_flags=0;
+struct start_info si;
+DCL_LOCK_STATE;
+INIT_REAL_SYMS();
+if (!EXPECT(parallel_initialized,TRUE))
+GC_init_parallel();
+if (sem_init(&si.registered,GC_SEM_INIT_PSHARED,0)!=0)
+ABORT("sem_init failed");
+si.start_routine=start_routine;
+si.arg=arg;
+LOCK();
+if (!EXPECT(GC_thr_initialized,TRUE))
+GC_thr_init();
+#ifdef GC_ASSERTIONS
+{
+size_t stack_size=0;
+if (NULL!=attr){
+if (pthread_attr_getstacksize(attr,&stack_size)!=0)
+ABORT("pthread_attr_getstacksize failed");
+}
+if (0==stack_size){
+pthread_attr_t my_attr;
+if (pthread_attr_init(&my_attr)!=0)
+ABORT("pthread_attr_init failed");
+if (pthread_attr_getstacksize(&my_attr,&stack_size)!=0)
+ABORT("pthread_attr_getstacksize failed");
+(void)pthread_attr_destroy(&my_attr);
+}
+if (0==stack_size){
+#ifndef SOLARIS
+WARN("Failed to get stack size for assertion checking\n",0);
+#endif
+stack_size=1000000;
+}
+GC_ASSERT(stack_size>=65536);
+}
+#endif
+if (NULL==attr){
+detachstate=PTHREAD_CREATE_JOINABLE;
+} else {
+pthread_attr_getdetachstate(attr,&detachstate);
+}
+if (PTHREAD_CREATE_DETACHED==detachstate)my_flags|=DETACHED;
+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);
+if (0==result){
+IF_CANCEL(int cancel_state;)
+#ifdef DEBUG_THREADS
+GC_log_printf("Started thread %p\n",(void*)(*new_thread));
+#endif
+DISABLE_CANCEL(cancel_state);
+while (0!=sem_wait(&si.registered)){
+#if defined(GC_HAIKU_THREADS)
+if (EACCES==errno)continue;
+#endif
+if (EINTR!=errno)ABORT("sem_wait failed");
+}
+RESTORE_CANCEL(cancel_state);
+}
+sem_destroy(&si.registered);
+return(result);
+}
+#endif
+#if defined(USE_SPIN_LOCK)||!defined(NO_PTHREAD_TRYLOCK)
+#define GC_PAUSE_SPIN_CYCLES 10
+STATIC void GC_pause(void)
+{
+int i;
+for (i=0;i < GC_PAUSE_SPIN_CYCLES;++i){
+#if defined(AO_HAVE_compiler_barrier)&&!defined(BASE_ATOMIC_OPS_EMULATED)
+AO_compiler_barrier();
+#else
+GC_noop1(i);
+#endif
+}
+}
+#endif
+#ifndef SPIN_MAX
+#define SPIN_MAX 128
+#endif
+GC_INNER volatile GC_bool GC_collecting=FALSE;
+#if (!defined(USE_SPIN_LOCK)&&!defined(NO_PTHREAD_TRYLOCK))||defined(PARALLEL_MARK)
+#ifdef LOCK_STATS
+volatile AO_t GC_spin_count=0;
+volatile AO_t GC_block_count=0;
+volatile AO_t GC_unlocked_count=0;
+#endif
+STATIC void GC_generic_lock(pthread_mutex_t*lock)
+{
+#ifndef NO_PTHREAD_TRYLOCK
+unsigned pause_length=1;
+unsigned i;
+if (0==pthread_mutex_trylock(lock)){
+#ifdef LOCK_STATS
+(void)AO_fetch_and_add1(&GC_unlocked_count);
+#endif
+return;
+}
+for (;pause_length<=SPIN_MAX;pause_length<<=1){
+for (i=0;i < pause_length;++i){
+GC_pause();
+}
+switch(pthread_mutex_trylock(lock)){
+case 0:
+#ifdef LOCK_STATS
+(void)AO_fetch_and_add1(&GC_spin_count);
+#endif
+return;
+case EBUSY:
+break;
+default:
+ABORT("Unexpected error from pthread_mutex_trylock");
+}
+}
+#endif
+#ifdef LOCK_STATS
+(void)AO_fetch_and_add1(&GC_block_count);
+#endif
+pthread_mutex_lock(lock);
+}
+#endif
+#if defined(AO_HAVE_char_load)&&!defined(BASE_ATOMIC_OPS_EMULATED)
+#define is_collecting()((GC_bool)AO_char_load((unsigned char*)&GC_collecting))
+#else
+#define is_collecting()GC_collecting
+#endif
+#if defined(USE_SPIN_LOCK)
+GC_INNER volatile AO_TS_t GC_allocate_lock=AO_TS_INITIALIZER;
+#define low_spin_max 30
+#define high_spin_max SPIN_MAX
+static volatile AO_t spin_max=low_spin_max;
+static volatile AO_t last_spins=0;
+GC_INNER void GC_lock(void)
+{
+unsigned my_spin_max;
+unsigned my_last_spins;
+unsigned i;
+if (AO_test_and_set_acquire(&GC_allocate_lock)==AO_TS_CLEAR){
+return;
+}
+my_spin_max=(unsigned)AO_load(&spin_max);
+my_last_spins=(unsigned)AO_load(&last_spins);
+for (i=0;i < my_spin_max;i++){
+if (is_collecting()||GC_nprocs==1)
+goto yield;
+if (i < my_last_spins/2){
+GC_pause();
+continue;
+}
+if (AO_test_and_set_acquire(&GC_allocate_lock)==AO_TS_CLEAR){
+AO_store(&last_spins,(AO_t)i);
+AO_store(&spin_max,(AO_t)high_spin_max);
+return;
+}
+}
+AO_store(&spin_max,(AO_t)low_spin_max);
+yield:
+for (i=0;;++i){
+if (AO_test_and_set_acquire(&GC_allocate_lock)==AO_TS_CLEAR){
+return;
+}
+#define SLEEP_THRESHOLD 12
+if (i < SLEEP_THRESHOLD){
+sched_yield();
+} else {
+struct timespec ts;
+if (i > 24)i=24;
+ts.tv_sec=0;
+ts.tv_nsec=1<<i;
+nanosleep(&ts,0);
+}
+}
+}
+#elif defined(USE_PTHREAD_LOCKS)
+#ifndef NO_PTHREAD_TRYLOCK
+GC_INNER void GC_lock(void)
+{
+if (1==GC_nprocs||is_collecting()){
+pthread_mutex_lock(&GC_allocate_ml);
+} else {
+GC_generic_lock(&GC_allocate_ml);
+}
+}
+#elif defined(GC_ASSERTIONS)
+GC_INNER void GC_lock(void)
+{
+pthread_mutex_lock(&GC_allocate_ml);
+}
+#endif
+#endif
+#ifdef PARALLEL_MARK
+#ifdef GC_ASSERTIONS
+STATIC unsigned long GC_mark_lock_holder=NO_THREAD;
+#define SET_MARK_LOCK_HOLDER (void)(GC_mark_lock_holder=NUMERIC_THREAD_ID(pthread_self()))
+#define UNSET_MARK_LOCK_HOLDER do { GC_ASSERT(GC_mark_lock_holder==NUMERIC_THREAD_ID(pthread_self()));GC_mark_lock_holder=NO_THREAD;} while (0)
+#else
+#define SET_MARK_LOCK_HOLDER (void)0
+#define UNSET_MARK_LOCK_HOLDER (void)0
+#endif
+#ifdef GLIBC_2_1_MUTEX_HACK
+static pthread_mutex_t mark_mutex=
+{0,0,0,PTHREAD_MUTEX_ERRORCHECK_NP,{0,0}};
+#else
+static pthread_mutex_t mark_mutex=PTHREAD_MUTEX_INITIALIZER;
+#endif
+static pthread_cond_t builder_cv=PTHREAD_COND_INITIALIZER;
+#ifdef GLIBC_2_19_TSX_BUG
+static int parse_version(int*pminor,const char*pverstr){
+char*endp;
+unsigned long value=strtoul(pverstr,&endp,10);
+int major=(int)value;
+if (major < 0||(char*)pverstr==endp||(unsigned)major!=value){
+return -1;
+}
+if (*endp!='.'){
+*pminor=-1;
+} else {
+value=strtoul(endp+1,&endp,10);
+*pminor=(int)value;
+if (*pminor < 0||(unsigned)(*pminor)!=value){
+return -1;
+}
+}
+return major;
+}
+#endif
+static void setup_mark_lock(void)
+{
+#ifdef GLIBC_2_19_TSX_BUG
+pthread_mutexattr_t mattr;
+int glibc_minor=-1;
+int glibc_major=parse_version(&glibc_minor,gnu_get_libc_version());
+if (glibc_major > 2||(glibc_major==2&&glibc_minor>=19)){
+if (0!=pthread_mutexattr_init(&mattr)){
+ABORT("pthread_mutexattr_init failed");
+}
+if (0!=pthread_mutexattr_settype(&mattr,PTHREAD_MUTEX_NORMAL)){
+ABORT("pthread_mutexattr_settype failed");
+}
+if (0!=pthread_mutex_init(&mark_mutex,&mattr)){
+ABORT("pthread_mutex_init failed");
+}
+(void)pthread_mutexattr_destroy(&mattr);
+}
+#endif
+}
+GC_INNER void GC_acquire_mark_lock(void)
+{
+#if defined(NUMERIC_THREAD_ID_UNIQUE)&&!defined(THREAD_SANITIZER)
+GC_ASSERT(GC_mark_lock_holder!=NUMERIC_THREAD_ID(pthread_self()));
+#endif
+GC_generic_lock(&mark_mutex);
+SET_MARK_LOCK_HOLDER;
+}
+GC_INNER void GC_release_mark_lock(void)
+{
+UNSET_MARK_LOCK_HOLDER;
+if (pthread_mutex_unlock(&mark_mutex)!=0){
+ABORT("pthread_mutex_unlock failed");
+}
+}
+STATIC void GC_wait_builder(void)
+{
+ASSERT_CANCEL_DISABLED();
+UNSET_MARK_LOCK_HOLDER;
+if (pthread_cond_wait(&builder_cv,&mark_mutex)!=0){
+ABORT("pthread_cond_wait failed");
+}
+GC_ASSERT(GC_mark_lock_holder==NO_THREAD);
+SET_MARK_LOCK_HOLDER;
+}
+GC_INNER void GC_wait_for_reclaim(void)
+{
+GC_acquire_mark_lock();
+while (GC_fl_builder_count > 0){
+GC_wait_builder();
+}
+GC_release_mark_lock();
+}
+GC_INNER void GC_notify_all_builder(void)
+{
+GC_ASSERT(GC_mark_lock_holder==NUMERIC_THREAD_ID(pthread_self()));
+if (pthread_cond_broadcast(&builder_cv)!=0){
+ABORT("pthread_cond_broadcast failed");
+}
+}
+GC_INNER void GC_wait_marker(void)
+{
+ASSERT_CANCEL_DISABLED();
+GC_ASSERT(GC_parallel);
+UNSET_MARK_LOCK_HOLDER;
+if (pthread_cond_wait(&mark_cv,&mark_mutex)!=0){
+ABORT("pthread_cond_wait failed");
+}
+GC_ASSERT(GC_mark_lock_holder==NO_THREAD);
+SET_MARK_LOCK_HOLDER;
+}
+GC_INNER void GC_notify_all_marker(void)
+{
+GC_ASSERT(GC_parallel);
+if (pthread_cond_broadcast(&mark_cv)!=0){
+ABORT("pthread_cond_broadcast failed");
+}
+}
+#endif
+#ifdef PTHREAD_REGISTER_CANCEL_WEAK_STUBS
+EXTERN_C_BEGIN
+extern void __pthread_register_cancel(void)__attribute__((__weak__));
+extern void __pthread_unregister_cancel(void)__attribute__((__weak__));
+EXTERN_C_END
+void __pthread_register_cancel(void){}
+void __pthread_unregister_cancel(void){}
+#endif
+#endif
+#if defined(USE_CUSTOM_SPECIFIC)
+static const tse invalid_tse={INVALID_QTID,0,0,INVALID_THREADID};
+GC_INNER int GC_key_create_inner(tsd**key_ptr)
+{
+int i;
+int ret;
+tsd*result;
+GC_ASSERT(I_HOLD_LOCK());
+GC_ASSERT((word)(&invalid_tse.next)% sizeof(tse*)==0);
+result=(tsd*)MALLOC_CLEAR(sizeof(tsd));
+if (NULL==result)return ENOMEM;
+ret=pthread_mutex_init(&result->lock,NULL);
+if (ret!=0)return ret;
+for (i=0;i < TS_CACHE_SIZE;++i){
+result->cache[i]=( tse*)&invalid_tse;
+}
+#ifdef GC_ASSERTIONS
+for (i=0;i < TS_HASH_SIZE;++i){
+GC_ASSERT(result->hash[i].p==0);
+}
+#endif
+*key_ptr=result;
+return 0;
+}
+GC_INNER int GC_setspecific(tsd*key,void*value)
+{
+pthread_t self=pthread_self();
+unsigned hash_val=HASH(self);
+volatile tse*entry;
+GC_ASSERT(I_HOLD_LOCK());
+GC_ASSERT(self!=INVALID_THREADID);
+GC_dont_gc++;
+entry=(volatile tse*)MALLOC_CLEAR(sizeof(tse));
+GC_dont_gc--;
+if (0==entry)return ENOMEM;
+pthread_mutex_lock(&(key->lock));
+entry->next=key->hash[hash_val].p;
+entry->thread=self;
+entry->value=TS_HIDE_VALUE(value);
+GC_ASSERT(entry->qtid==INVALID_QTID);
+AO_store_release(&key->hash[hash_val].ao,(AO_t)entry);
+GC_dirty(( void*)entry);
+GC_dirty(key->hash+hash_val);
+if (pthread_mutex_unlock(&key->lock)!=0)
+ABORT("pthread_mutex_unlock failed (setspecific)");
+return 0;
+}
+GC_INNER void GC_remove_specific_after_fork(tsd*key,pthread_t t)
+{
+unsigned hash_val=HASH(t);
+tse*entry;
+tse*prev=NULL;
+#ifdef CAN_HANDLE_FORK
+GC_ASSERT(I_HOLD_LOCK());
+#endif
+pthread_mutex_lock(&(key->lock));
+entry=key->hash[hash_val].p;
+while (entry!=NULL&&!THREAD_EQUAL(entry->thread,t)){
+prev=entry;
+entry=entry->next;
+}
+if (entry!=NULL){
+entry->qtid=INVALID_QTID;
+if (NULL==prev){
+key->hash[hash_val].p=entry->next;
+GC_dirty(key->hash+hash_val);
+} else {
+prev->next=entry->next;
+GC_dirty(prev);
+}
+}
+#ifdef LINT2
+GC_noop1((word)entry);
+#endif
+if (pthread_mutex_unlock(&key->lock)!=0)
+ABORT("pthread_mutex_unlock failed (remove_specific after fork)");
+}
+GC_INNER void*GC_slow_getspecific(tsd*key,word qtid,
+tse*volatile*cache_ptr)
+{
+pthread_t self=pthread_self();
+tse*entry=key->hash[HASH(self)].p;
+GC_ASSERT(qtid!=INVALID_QTID);
+while (entry!=NULL&&!THREAD_EQUAL(entry->thread,self)){
+entry=entry->next;
+}
+if (entry==NULL)return NULL;
+entry->qtid=(AO_t)qtid;
+*cache_ptr=entry;
+return TS_REVEAL_PTR(entry->value);
+}
+#ifdef GC_ASSERTIONS
+void GC_check_tsd_marks(tsd*key)
+{
+int i;
+tse*p;
+if (!GC_is_marked(GC_base(key))){
+ABORT("Unmarked thread-specific-data table");
+}
+for (i=0;i < TS_HASH_SIZE;++i){
+for (p=key->hash[i].p;p!=0;p=p->next){
+if (!GC_is_marked(GC_base(p))){
+ABORT_ARG1("Unmarked thread-specific-data entry",
+" at %p",(void*)p);
+}
+}
+}
+for (i=0;i < TS_CACHE_SIZE;++i){
+p=key->cache[i];
+if (p!=&invalid_tse&&!GC_is_marked(GC_base(p))){
+ABORT_ARG1("Unmarked cached thread-specific-data entry",
+" at %p",(void*)p);
+}
+}
+}
+#endif
+#endif
+#if defined(GC_WIN32_THREADS)
+#ifdef THREAD_LOCAL_ALLOC
+#endif
+#if!defined(USE_PTHREAD_LOCKS)
+GC_INNER CRITICAL_SECTION GC_allocate_ml;
+#ifdef GC_ASSERTIONS
+GC_INNER DWORD GC_lock_holder=NO_THREAD;
+#endif
+#else
+GC_INNER pthread_mutex_t GC_allocate_ml=PTHREAD_MUTEX_INITIALIZER;
+#ifdef GC_ASSERTIONS
+GC_INNER unsigned long GC_lock_holder=NO_THREAD;
+#endif
+#endif
+#undef CreateThread
+#undef ExitThread
+#undef _beginthreadex
+#undef _endthreadex
+#ifdef GC_PTHREADS
+#include <errno.h>
+#undef pthread_create
+#undef pthread_join
+#undef pthread_detach
+#ifndef GC_NO_PTHREAD_SIGMASK
+#undef pthread_sigmask
+#endif
+STATIC void*GC_pthread_start(void*arg);
+STATIC void GC_thread_exit_proc(void*arg);
+#include <pthread.h>
+#ifdef CAN_CALL_ATFORK
+#include <unistd.h>
+#endif
+#elif!defined(MSWINCE)
+#include <process.h>
+#include <errno.h>
+#endif
+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
+#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)
+#ifdef GC_DISCOVER_TASK_THREADS
+#define GC_win32_dll_threads TRUE
+#else
+STATIC GC_bool GC_win32_dll_threads=FALSE;
+#endif
+#else
+#ifndef GC_NO_THREADS_DISCOVERY
+#define GC_NO_THREADS_DISCOVERY
+#endif
+#define GC_win32_dll_threads FALSE
+#undef MAX_THREADS
+#define MAX_THREADS 1
+#endif
+typedef LONG*IE_t;
+STATIC GC_bool GC_thr_initialized=FALSE;
+#ifndef GC_ALWAYS_MULTITHREADED
+GC_INNER GC_bool GC_need_to_lock=FALSE;
+#endif
+static GC_bool parallel_initialized=FALSE;
+GC_API void GC_CALL GC_use_threads_discovery(void)
+{
+#ifdef GC_NO_THREADS_DISCOVERY
+ABORT("GC DllMain-based thread registration unsupported");
+#else
+GC_ASSERT(!parallel_initialized);
+#ifndef GC_DISCOVER_TASK_THREADS
+GC_win32_dll_threads=TRUE;
+#endif
+GC_init_parallel();
+#endif
+}
+#define ADDR_LIMIT ((ptr_t)GC_WORD_MAX)
+struct GC_Thread_Rep {
+union {
+#ifndef GC_NO_THREADS_DISCOVERY
+volatile AO_t in_use;
+LONG long_in_use;
+#endif
+struct GC_Thread_Rep*next;
+} tm;
+DWORD id;
+#ifdef MSWINCE
+#define THREAD_HANDLE(t)(HANDLE)(word)(t)->id
+#else
+HANDLE handle;
+#define THREAD_HANDLE(t)(t)->handle
+#endif
+ptr_t stack_base;
+ptr_t last_stack_min;
+#ifdef IA64
+ptr_t backing_store_end;
+ptr_t backing_store_ptr;
+#elif defined(I386)
+ptr_t initial_stack_base;
+#endif
+ptr_t thread_blocked_sp;
+struct GC_traced_stack_sect_s*traced_stack_sect;
+unsigned short finalizer_skipped;
+unsigned char finalizer_nested;
+unsigned char suspended;
+#ifdef GC_PTHREADS
+unsigned char flags;
+#define FINISHED 1
+#define DETACHED 2
+#define KNOWN_FINISHED(t)(((t)->flags)&FINISHED)
+pthread_t pthread_id;
+void*status;
+#else
+#define KNOWN_FINISHED(t)0
+#endif
+#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];
+#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;
+STATIC volatile AO_t GC_attached_thread=FALSE;
+STATIC volatile GC_bool GC_please_stop=FALSE;
+#elif defined(GC_ASSERTIONS)
+STATIC GC_bool GC_please_stop=FALSE;
+#endif
+#if defined(WRAP_MARK_SOME)&&!defined(GC_PTHREADS)
+GC_INNER GC_bool GC_started_thread_while_stopped(void)
+{
+#ifndef GC_NO_THREADS_DISCOVERY
+if (GC_win32_dll_threads){
+#ifdef AO_HAVE_compare_and_swap_release
+if (AO_compare_and_swap_release(&GC_attached_thread,TRUE,
+FALSE))
+return TRUE;
+#else
+AO_nop_full();
+if (AO_load(&GC_attached_thread)){
+AO_store(&GC_attached_thread,FALSE);
+return TRUE;
+}
+#endif
+}
+#endif
+return FALSE;
+}
+#endif
+#ifndef MAX_THREADS
+#define MAX_THREADS 512
+#endif
+volatile struct GC_Thread_Rep dll_thread_table[MAX_THREADS];
+STATIC volatile LONG GC_max_thread_index=0;
+#ifndef THREAD_TABLE_SZ
+#define THREAD_TABLE_SZ 256
+#endif
+#define THREAD_TABLE_INDEX(id)(int)((((id)>>8)^(id))% THREAD_TABLE_SZ)
+STATIC GC_thread GC_threads[THREAD_TABLE_SZ];
+static struct GC_Thread_Rep first_thread;
+static GC_bool first_thread_used=FALSE;
+STATIC GC_thread GC_new_thread(DWORD id)
+{
+int hv=THREAD_TABLE_INDEX(id);
+GC_thread result;
+#ifdef DEBUG_THREADS
+GC_log_printf("Creating thread 0x%lx\n",(long)id);
+if (GC_threads[hv]!=NULL)
+GC_log_printf("Hash collision at GC_threads[%d]\n",hv);
+#endif
+GC_ASSERT(I_HOLD_LOCK());
+if (!EXPECT(first_thread_used,TRUE)){
+result=&first_thread;
+first_thread_used=TRUE;
+GC_ASSERT(NULL==GC_threads[hv]);
+} else {
+GC_ASSERT(!GC_win32_dll_threads);
+result=(struct GC_Thread_Rep*)
+GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep),NORMAL);
+if (result==0)return(0);
+}
+result->tm.next=GC_threads[hv];
+GC_threads[hv]=result;
+#ifdef GC_PTHREADS
+GC_ASSERT(result->flags==0);
+#endif
+GC_ASSERT(result->thread_blocked_sp==NULL);
+if (EXPECT(result!=&first_thread,TRUE))
+GC_dirty(result);
+return(result);
+}
+GC_INNER GC_bool GC_in_thread_creation=FALSE;
+GC_INLINE void GC_record_stack_base(GC_vthread me,
+const struct GC_stack_base*sb)
+{
+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");
+}
+STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base*sb,
+DWORD thread_id)
+{
+GC_vthread me;
+#if defined(MPROTECT_VDB)&&!defined(CYGWIN32)
+if (GC_auto_incremental
+#ifdef GWW_VDB
+&&!GC_gww_dirty_init()
+#endif
+)
+GC_set_write_fault_handler();
+#endif
+#ifndef GC_NO_THREADS_DISCOVERY
+if (GC_win32_dll_threads){
+int i;
+for (i=0;
+InterlockedExchange(&dll_thread_table[i].tm.long_in_use,1)!=0;
+i++){
+if (i==MAX_THREADS - 1)
+ABORT("Too many threads");
+}
+while (i > GC_max_thread_index){
+InterlockedIncrement((IE_t)&GC_max_thread_index);
+}
+if (GC_max_thread_index>=MAX_THREADS){
+GC_max_thread_index=MAX_THREADS - 1;
+}
+me=dll_thread_table+i;
+} else
+#endif
+{
+GC_ASSERT(I_HOLD_LOCK());
+GC_in_thread_creation=TRUE;
+me=GC_new_thread(thread_id);
+GC_in_thread_creation=FALSE;
+if (me==0)
+ABORT("Failed to allocate memory for thread registering");
+}
+#ifdef GC_PTHREADS
+me->pthread_id=pthread_self();
+#endif
+#ifndef MSWINCE
+if (!DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),
+GetCurrentProcess(),
+(HANDLE*)&(me->handle),
+0,FALSE,
+DUPLICATE_SAME_ACCESS)){
+ABORT_ARG1("DuplicateHandle failed",
+":errcode=0x%X",(unsigned)GetLastError());
+}
+#endif
+me->last_stack_min=ADDR_LIMIT;
+GC_record_stack_base(me,sb);
+me->id=thread_id;
+#if defined(THREAD_LOCAL_ALLOC)
+GC_init_thread_local((GC_tlfs)(&(me->tlfs)));
+#endif
+#ifndef GC_NO_THREADS_DISCOVERY
+if (GC_win32_dll_threads){
+if (GC_please_stop){
+AO_store(&GC_attached_thread,TRUE);
+AO_nop_full();
+}
+} else
+#endif
+{
+GC_ASSERT(!GC_please_stop);
+}
+return (GC_thread)(me);
+}
+GC_INLINE LONG GC_get_max_thread_index(void)
+{
+LONG my_max=GC_max_thread_index;
+if (my_max>=MAX_THREADS)return MAX_THREADS - 1;
+return my_max;
+}
+STATIC GC_thread GC_lookup_thread_inner(DWORD thread_id)
+{
+#ifndef GC_NO_THREADS_DISCOVERY
+if (GC_win32_dll_threads){
+int i;
+LONG my_max=GC_get_max_thread_index();
+for (i=0;i<=my_max&&
+(!AO_load_acquire(&dll_thread_table[i].tm.in_use)
+||dll_thread_table[i].id!=thread_id);
+i++){
+}
+return i<=my_max?(GC_thread)(dll_thread_table+i):NULL;
+} else
+#endif
+{
+GC_thread p=GC_threads[THREAD_TABLE_INDEX(thread_id)];
+GC_ASSERT(I_HOLD_LOCK());
+while (p!=0&&p->id!=thread_id)p=p->tm.next;
+return(p);
+}
+}
+#ifdef LINT2
+#define CHECK_LOOKUP_MY_THREAD(me)if (!(me))ABORT("GC_lookup_thread_inner(GetCurrentThreadId)failed")
+#else
+#define CHECK_LOOKUP_MY_THREAD(me)
+#endif
+GC_INNER void GC_reset_finalizer_nested(void)
+{
+GC_thread me=GC_lookup_thread_inner(GetCurrentThreadId());
+CHECK_LOOKUP_MY_THREAD(me);
+me->finalizer_nested=0;
+}
+GC_INNER unsigned char*GC_check_finalizer_nested(void)
+{
+GC_thread me=GC_lookup_thread_inner(GetCurrentThreadId());
+unsigned nesting_level;
+CHECK_LOOKUP_MY_THREAD(me);
+nesting_level=me->finalizer_nested;
+if (nesting_level){
+if (++me->finalizer_skipped < (1U<<nesting_level))return NULL;
+me->finalizer_skipped=0;
+}
+me->finalizer_nested=(unsigned char)(nesting_level+1);
+return&me->finalizer_nested;
+}
+#if defined(GC_ASSERTIONS)&&defined(THREAD_LOCAL_ALLOC)
+GC_bool GC_is_thread_tsd_valid(void*tsd)
+{
+GC_thread me;
+DCL_LOCK_STATE;
+LOCK();
+me=GC_lookup_thread_inner(GetCurrentThreadId());
+UNLOCK();
+return (word)tsd>=(word)(&me->tlfs)
+&&(word)tsd < (word)(&me->tlfs)+sizeof(me->tlfs);
+}
+#endif
+GC_API int GC_CALL GC_thread_is_registered(void)
+{
+DWORD thread_id=GetCurrentThreadId();
+GC_thread me;
+DCL_LOCK_STATE;
+LOCK();
+me=GC_lookup_thread_inner(thread_id);
+UNLOCK();
+return me!=NULL;
+}
+GC_API void GC_CALL GC_register_altstack(void*stack GC_ATTR_UNUSED,
+GC_word stack_size GC_ATTR_UNUSED,
+void*altstack GC_ATTR_UNUSED,
+GC_word altstack_size GC_ATTR_UNUSED)
+{
+}
+#if defined(MPROTECT_VDB)
+#define UNPROTECT_THREAD(t)if (!GC_win32_dll_threads&&GC_auto_incremental&&t!=&first_thread){ GC_ASSERT(SMALL_OBJ(GC_size(t)));GC_remove_protection(HBLKPTR(t),1,FALSE);} else (void)0
+#else
+#define UNPROTECT_THREAD(t)(void)0
+#endif
+#ifdef CYGWIN32
+#define GC_PTHREAD_PTRVAL(pthread_id)pthread_id
+#elif defined(GC_WIN32_PTHREADS)||defined(GC_PTHREADS_PARAMARK)
+#include <pthread.h>
+#if defined(__WINPTHREADS_VERSION_MAJOR)
+#define GC_PTHREAD_PTRVAL(pthread_id)pthread_id
+#else
+#define GC_PTHREAD_PTRVAL(pthread_id)pthread_id.p
+#endif
+#endif
+STATIC void GC_delete_gc_thread_no_free(GC_vthread t)
+{
+#ifndef MSWINCE
+CloseHandle(t->handle);
+#endif
+#ifndef GC_NO_THREADS_DISCOVERY
+if (GC_win32_dll_threads){
+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
+{
+DWORD id=((GC_thread)t)->id;
+int hv=THREAD_TABLE_INDEX(id);
+GC_thread p=GC_threads[hv];
+GC_thread prev=NULL;
+GC_ASSERT(I_HOLD_LOCK());
+while (p!=(GC_thread)t){
+prev=p;
+p=p->tm.next;
+}
+if (prev==0){
+GC_threads[hv]=p->tm.next;
+} else {
+GC_ASSERT(prev!=&first_thread);
+prev->tm.next=p->tm.next;
+GC_dirty(prev);
+}
+}
+}
+STATIC void GC_delete_thread(DWORD id)
+{
+if (GC_win32_dll_threads){
+GC_vthread t=GC_lookup_thread_inner(id);
+if (0==t){
+WARN("Removing nonexistent thread,id=%" WARN_PRIdPTR "\n",id);
+} else {
+GC_delete_gc_thread_no_free(t);
+}
+} else {
+int hv=THREAD_TABLE_INDEX(id);
+GC_thread p=GC_threads[hv];
+GC_thread prev=NULL;
+GC_ASSERT(I_HOLD_LOCK());
+while (p->id!=id){
+prev=p;
+p=p->tm.next;
+}
+#ifndef MSWINCE
+CloseHandle(p->handle);
+#endif
+if (prev==0){
+GC_threads[hv]=p->tm.next;
+} else {
+GC_ASSERT(prev!=&first_thread);
+prev->tm.next=p->tm.next;
+GC_dirty(prev);
+}
+if (EXPECT(p!=&first_thread,TRUE)){
+GC_INTERNAL_FREE(p);
+}
+}
+}
+GC_API void GC_CALL GC_allow_register_threads(void)
+{
+GC_ASSERT(GC_lookup_thread_inner(GetCurrentThreadId())!=0);
+#if!defined(GC_ALWAYS_MULTITHREADED)&&!defined(PARALLEL_MARK)&&!defined(GC_NO_THREADS_DISCOVERY)
+parallel_initialized=TRUE;
+#endif
+set_need_to_lock();
+}
+GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base*sb)
+{
+GC_thread me;
+DWORD thread_id=GetCurrentThreadId();
+DCL_LOCK_STATE;
+if (GC_need_to_lock==FALSE)
+ABORT("Threads explicit registering is not previously enabled");
+LOCK();
+me=GC_lookup_thread_inner(thread_id);
+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;
+#else
+GC_register_my_thread_inner(sb,thread_id);
+#endif
+UNLOCK();
+return GC_SUCCESS;
+} else
+#ifdef GC_PTHREADS
+if ((me->flags&FINISHED)!=0){
+GC_record_stack_base(me,sb);
+me->flags&=~FINISHED;
+#ifdef THREAD_LOCAL_ALLOC
+GC_init_thread_local((GC_tlfs)(&me->tlfs));
+#endif
+UNLOCK();
+return GC_SUCCESS;
+} else
+#endif
+{
+UNLOCK();
+return GC_DUPLICATE;
+}
+}
+STATIC void GC_wait_for_gc_completion(GC_bool wait_for_all)
+{
+GC_ASSERT(I_HOLD_LOCK());
+if (GC_incremental&&GC_collection_in_progress()){
+word old_gc_no=GC_gc_no;
+do {
+ENTER_GC();
+GC_in_thread_creation=TRUE;
+GC_collect_a_little_inner(1);
+GC_in_thread_creation=FALSE;
+EXIT_GC();
+UNLOCK();
+Sleep(0);
+LOCK();
+} while (GC_incremental&&GC_collection_in_progress()
+&&(wait_for_all||old_gc_no==GC_gc_no));
+}
+}
+GC_API int GC_CALL GC_unregister_my_thread(void)
+{
+DCL_LOCK_STATE;
+#ifdef DEBUG_THREADS
+GC_log_printf("Unregistering thread 0x%lx\n",(long)GetCurrentThreadId());
+#endif
+if (GC_win32_dll_threads){
+#if defined(THREAD_LOCAL_ALLOC)
+GC_ASSERT(FALSE);
+#else
+GC_delete_thread(GetCurrentThreadId());
+#endif
+} else {
+#if defined(THREAD_LOCAL_ALLOC)||defined(GC_PTHREADS)
+GC_thread me;
+#endif
+DWORD thread_id=GetCurrentThreadId();
+LOCK();
+GC_wait_for_gc_completion(FALSE);
+#if defined(THREAD_LOCAL_ALLOC)||defined(GC_PTHREADS)
+me=GC_lookup_thread_inner(thread_id);
+CHECK_LOOKUP_MY_THREAD(me);
+GC_ASSERT(!KNOWN_FINISHED(me));
+#endif
+#if defined(THREAD_LOCAL_ALLOC)
+GC_ASSERT(GC_getspecific(GC_thread_key)==&me->tlfs);
+GC_destroy_thread_local(&(me->tlfs));
+#endif
+#ifdef GC_PTHREADS
+if ((me->flags&DETACHED)==0){
+me->flags|=FINISHED;
+} else
+#endif
+{
+GC_delete_thread(thread_id);
+}
+#if defined(THREAD_LOCAL_ALLOC)
+GC_remove_specific(GC_thread_key);
+#endif
+UNLOCK();
+}
+return GC_SUCCESS;
+}
+GC_INNER void GC_do_blocking_inner(ptr_t data,void*context GC_ATTR_UNUSED)
+{
+struct blocking_data*d=(struct blocking_data*)data;
+DWORD thread_id=GetCurrentThreadId();
+GC_thread me;
+#ifdef IA64
+ptr_t stack_ptr=GC_save_regs_in_stack();
+#endif
+DCL_LOCK_STATE;
+LOCK();
+me=GC_lookup_thread_inner(thread_id);
+CHECK_LOOKUP_MY_THREAD(me);
+GC_ASSERT(me->thread_blocked_sp==NULL);
+#ifdef IA64
+me->backing_store_ptr=stack_ptr;
+#endif
+me->thread_blocked_sp=(ptr_t)&d;
+UNLOCK();
+d->client_data=(d->fn)(d->client_data);
+LOCK();
+#if defined(CPPCHECK)
+GC_noop1((word)me->thread_blocked_sp);
+#endif
+me->thread_blocked_sp=NULL;
+UNLOCK();
+}
+GC_API void*GC_CALL GC_call_with_gc_active(GC_fn_type fn,
+void*client_data)
+{
+struct GC_traced_stack_sect_s stacksect;
+DWORD thread_id=GetCurrentThreadId();
+GC_thread me;
+DCL_LOCK_STATE;
+LOCK();
+me=GC_lookup_thread_inner(thread_id);
+CHECK_LOOKUP_MY_THREAD(me);
+GC_ASSERT(me->stack_base!=NULL);
+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){
+UNLOCK();
+client_data=fn(client_data);
+GC_noop1(COVERT_DATAFLOW(&stacksect));
+return client_data;
+}
+stacksect.saved_stack_ptr=me->thread_blocked_sp;
+#ifdef IA64
+stacksect.backing_store_end=GC_save_regs_in_stack();
+stacksect.saved_backing_store_ptr=me->backing_store_ptr;
+#endif
+stacksect.prev=me->traced_stack_sect;
+me->thread_blocked_sp=NULL;
+me->traced_stack_sect=&stacksect;
+UNLOCK();
+client_data=fn(client_data);
+GC_ASSERT(me->thread_blocked_sp==NULL);
+GC_ASSERT(me->traced_stack_sect==&stacksect);
+LOCK();
+#if defined(CPPCHECK)
+GC_noop1((word)me->traced_stack_sect);
+#endif
+me->traced_stack_sect=stacksect.prev;
+#ifdef IA64
+me->backing_store_ptr=stacksect.saved_backing_store_ptr;
+#endif
+me->thread_blocked_sp=stacksect.saved_stack_ptr;
+UNLOCK();
+return client_data;
+}
+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){
+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);
+t->stack_base=(ptr_t)sb->mem_base;
+t->last_stack_min=ADDR_LIMIT;
+#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);
+sb->mem_base=me->stack_base;
+#ifdef IA64
+sb->reg_base=me->backing_store_end;
+#endif
+UNLOCK();
+return (void*)me;
+}
+#ifdef GC_PTHREADS
+#define PTHREAD_MAP_SIZE 512
+DWORD GC_pthread_map_cache[PTHREAD_MAP_SIZE]={0};
+#define PTHREAD_MAP_INDEX(pthread_id)((NUMERIC_THREAD_ID(pthread_id)>>5)% PTHREAD_MAP_SIZE)
+#define SET_PTHREAD_MAP_CACHE(pthread_id,win32_id)(void)(GC_pthread_map_cache[PTHREAD_MAP_INDEX(pthread_id)]=(win32_id))
+#define GET_PTHREAD_MAP_CACHE(pthread_id)GC_pthread_map_cache[PTHREAD_MAP_INDEX(pthread_id)]
+STATIC GC_thread GC_lookup_pthread(pthread_t id)
+{
+#ifndef GC_NO_THREADS_DISCOVERY
+if (GC_win32_dll_threads){
+int i;
+LONG my_max=GC_get_max_thread_index();
+for (i=0;i<=my_max&&
+(!AO_load_acquire(&dll_thread_table[i].tm.in_use)
+||THREAD_EQUAL(dll_thread_table[i].pthread_id,id));
+i++){
+}
+return i<=my_max?(GC_thread)(dll_thread_table+i):NULL;
+} else
+#endif
+{
+DWORD win32_id=GET_PTHREAD_MAP_CACHE(id);
+int hv_guess=THREAD_TABLE_INDEX(win32_id);
+int hv;
+GC_thread p;
+DCL_LOCK_STATE;
+LOCK();
+for (p=GC_threads[hv_guess];0!=p;p=p->tm.next){
+if (THREAD_EQUAL(p->pthread_id,id))
+goto foundit;
+}
+for (hv=0;hv < THREAD_TABLE_SZ;++hv){
+for (p=GC_threads[hv];0!=p;p=p->tm.next){
+if (THREAD_EQUAL(p->pthread_id,id))
+goto foundit;
+}
+}
+p=0;
+foundit:
+UNLOCK();
+return p;
+}
+}
+#endif
+#ifdef CAN_HANDLE_FORK
+STATIC void GC_remove_all_threads_but_me(void)
+{
+int hv;
+GC_thread me=NULL;
+DWORD thread_id;
+pthread_t pthread_id=pthread_self();
+GC_ASSERT(!GC_win32_dll_threads);
+for (hv=0;hv < THREAD_TABLE_SZ;++hv){
+GC_thread p,next;
+for (p=GC_threads[hv];0!=p;p=next){
+next=p->tm.next;
+if (THREAD_EQUAL(p->pthread_id,pthread_id)
+&&me==NULL){
+me=p;
+p->tm.next=0;
+} else {
+#ifdef THREAD_LOCAL_ALLOC
+if ((p->flags&FINISHED)==0){
+GC_remove_specific_after_fork(GC_thread_key,p->pthread_id);
+}
+#endif
+if (&first_thread!=p)
+GC_INTERNAL_FREE(p);
+}
+}
+GC_threads[hv]=NULL;
+}
+GC_ASSERT(me!=NULL);
+thread_id=GetCurrentThreadId();
+GC_threads[THREAD_TABLE_INDEX(thread_id)]=me;
+me->id=thread_id;
+#ifndef MSWINCE
+if (!DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),
+GetCurrentProcess(),(HANDLE*)&me->handle,
+0,FALSE,
+DUPLICATE_SAME_ACCESS))
+ABORT("DuplicateHandle failed");
+#endif
+#if defined(THREAD_LOCAL_ALLOC)&&!defined(USE_CUSTOM_SPECIFIC)
+if (GC_setspecific(GC_thread_key,&me->tlfs)!=0)
+ABORT("GC_setspecific failed (in child)");
+#endif
+}
+static void fork_prepare_proc(void)
+{
+LOCK();
+#ifdef PARALLEL_MARK
+if (GC_parallel)
+GC_wait_for_reclaim();
+#endif
+GC_wait_for_gc_completion(TRUE);
+#ifdef PARALLEL_MARK
+if (GC_parallel)
+GC_acquire_mark_lock();
+#endif
+}
+static void fork_parent_proc(void)
+{
+#ifdef PARALLEL_MARK
+if (GC_parallel)
+GC_release_mark_lock();
+#endif
+UNLOCK();
+}
+static void fork_child_proc(void)
+{
+#ifdef PARALLEL_MARK
+if (GC_parallel){
+GC_release_mark_lock();
+GC_parallel=FALSE;
+}
+#endif
+GC_remove_all_threads_but_me();
+UNLOCK();
+}
+GC_API void GC_CALL GC_atfork_prepare(void)
+{
+if (!EXPECT(GC_is_initialized,TRUE))GC_init();
+if (GC_handle_fork<=0)
+fork_prepare_proc();
+}
+GC_API void GC_CALL GC_atfork_parent(void)
+{
+if (GC_handle_fork<=0)
+fork_parent_proc();
+}
+GC_API void GC_CALL GC_atfork_child(void)
+{
+if (GC_handle_fork<=0)
+fork_child_proc();
+}
+#endif
+void GC_push_thread_structures(void)
+{
+GC_ASSERT(I_HOLD_LOCK());
+#ifndef GC_NO_THREADS_DISCOVERY
+if (GC_win32_dll_threads){
+} else
+#endif
+{
+GC_PUSH_ALL_SYM(GC_threads);
+}
+#if defined(THREAD_LOCAL_ALLOC)
+GC_PUSH_ALL_SYM(GC_thread_key);
+#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;
+#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
+STATIC void GC_suspend(GC_thread t)
+{
+#ifndef MSWINCE
+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);
+GC_acquire_dirty_lock();
+#ifdef MSWINCE
+while (SuspendThread(THREAD_HANDLE(t))==(DWORD)-1){
+GC_release_dirty_lock();
+Sleep(10);
+GC_acquire_dirty_lock();
+}
+#elif defined(RETRY_GET_THREAD_CONTEXT)
+for (;;){
+if (GetExitCodeThread(t->handle,&exitCode)
+&&exitCode!=STILL_ACTIVE){
+GC_release_dirty_lock();
+#ifdef GC_PTHREADS
+t->stack_base=0;
+#else
+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)){
+t->context_sp=copy_ptr_regs(t->context_regs,&context);
+break;
+}
+if (ResumeThread(t->handle)==(DWORD)-1)
+ABORT("ResumeThread failed in suspend loop");
+}
+if (retry_cnt > 1){
+GC_release_dirty_lock();
+Sleep(0);
+GC_acquire_dirty_lock();
+}
+if (++retry_cnt>=MAX_SUSPEND_THREAD_RETRIES)
+ABORT("SuspendThread loop failed");
+}
+#else
+if (GetExitCodeThread(t->handle,&exitCode)
+&&exitCode!=STILL_ACTIVE){
+GC_release_dirty_lock();
+#ifdef GC_PTHREADS
+t->stack_base=0;
+#else
+GC_ASSERT(GC_win32_dll_threads);
+GC_delete_gc_thread_no_free(t);
+#endif
+return;
+}
+if (SuspendThread(t->handle)==(DWORD)-1)
+ABORT("SuspendThread failed");
+#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(CONSOLE_LOG))||defined(MSWINCE))
+GC_INNER GC_bool GC_write_disabled=FALSE;
+#endif
+GC_INNER void GC_stop_world(void)
+{
+DWORD thread_id=GetCurrentThreadId();
+if (!GC_thr_initialized)
+ABORT("GC_stop_world()called before GC_thr_init()");
+GC_ASSERT(I_HOLD_LOCK());
+#ifdef PARALLEL_MARK
+if (GC_parallel){
+GC_acquire_mark_lock();
+GC_ASSERT(GC_fl_builder_count==0);
+}
+#endif
+#if!defined(GC_NO_THREADS_DISCOVERY)||defined(GC_ASSERTIONS)
+GC_please_stop=TRUE;
+#endif
+#if (defined(MSWIN32)&&!defined(CONSOLE_LOG))||defined(MSWINCE)
+GC_ASSERT(!GC_write_disabled);
+EnterCriticalSection(&GC_write_cs);
+#ifdef GC_ASSERTIONS
+GC_write_disabled=TRUE;
+#endif
+#endif
+#ifndef GC_NO_THREADS_DISCOVERY
+if (GC_win32_dll_threads){
+int i;
+int my_max;
+AO_store(&GC_attached_thread,FALSE);
+my_max=(int)GC_get_max_thread_index();
+for (i=0;i<=my_max;i++){
+GC_vthread t=dll_thread_table+i;
+if (t->stack_base!=0&&t->thread_blocked_sp==NULL
+&&t->id!=thread_id){
+GC_suspend((GC_thread)t);
+}
+}
+} else
+#endif
+{
+GC_thread t;
+int i;
+for (i=0;i < THREAD_TABLE_SZ;i++){
+for (t=GC_threads[i];t!=0;t=t->tm.next){
+if (t->stack_base!=0&&t->thread_blocked_sp==NULL
+&&!KNOWN_FINISHED(t)&&t->id!=thread_id){
+GC_suspend(t);
+}
+}
+}
+}
+#if (defined(MSWIN32)&&!defined(CONSOLE_LOG))||defined(MSWINCE)
+#ifdef GC_ASSERTIONS
+GC_write_disabled=FALSE;
+#endif
+LeaveCriticalSection(&GC_write_cs);
+#endif
+#ifdef PARALLEL_MARK
+if (GC_parallel)
+GC_release_mark_lock();
+#endif
+}
+GC_INNER void GC_start_world(void)
+{
+#ifdef GC_ASSERTIONS
+DWORD thread_id=GetCurrentThreadId();
+#endif
+GC_ASSERT(I_HOLD_LOCK());
+if (GC_win32_dll_threads){
+LONG my_max=GC_get_max_thread_index();
+int i;
+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");
+t->suspended=FALSE;
+if (GC_on_thread_event)
+GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED,THREAD_HANDLE(t));
+}
+}
+} else {
+GC_thread t;
+int i;
+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");
+UNPROTECT_THREAD(t);
+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
+}
+}
+}
+}
+#if!defined(GC_NO_THREADS_DISCOVERY)||defined(GC_ASSERTIONS)
+GC_please_stop=FALSE;
+#endif
+}
+#ifdef MSWINCE
+#define GC_wince_evaluate_stack_min(s)(ptr_t)(((word)(s)- 1)&~(word)0xFFFF)
+#elif defined(GC_ASSERTIONS)
+#define GC_dont_query_stack_min FALSE
+#endif
+static ptr_t last_address=0;
+static MEMORY_BASIC_INFORMATION last_info;
+STATIC ptr_t GC_get_stack_min(ptr_t s)
+{
+ptr_t bottom;
+GC_ASSERT(I_HOLD_LOCK());
+if (s!=last_address){
+VirtualQuery(s,&last_info,sizeof(last_info));
+last_address=s;
+}
+do {
+bottom=(ptr_t)last_info.BaseAddress;
+VirtualQuery(bottom - 1,&last_info,sizeof(last_info));
+last_address=bottom - 1;
+} while ((last_info.Protect&PAGE_READWRITE)
+&&!(last_info.Protect&PAGE_GUARD));
+return(bottom);
+}
+static GC_bool may_be_in_stack(ptr_t s)
+{
+GC_ASSERT(I_HOLD_LOCK());
+if (s!=last_address){
+VirtualQuery(s,&last_info,sizeof(last_info));
+last_address=s;
+}
+return (last_info.Protect&PAGE_READWRITE)
+&&!(last_info.Protect&PAGE_GUARD);
+}
+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);
+#endif
+PUSH4(Edi,Esi,Ebx,Edx),PUSH2(Ecx,Eax),PUSH1(Ebp);
+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);
+sp=(ptr_t)context.Rsp;
+#elif defined(ARM32)
+PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11);
+PUSH1(R12);
+sp=(ptr_t)context.Sp;
+#elif defined(AARCH64)
+PUSH4(X0,X1,X2,X3),PUSH4(X4,X5,X6,X7),PUSH4(X8,X9,X10,X11);
+PUSH4(X12,X13,X14,X15),PUSH4(X16,X17,X18,X19),PUSH4(X20,X21,X22,X23);
+PUSH4(X24,X25,X26,X27),PUSH1(X28);
+PUSH1(Lr);
+sp=(ptr_t)context.Sp;
+#elif defined(SHx)
+PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11);
+PUSH2(R12,R13),PUSH1(R14);
+sp=(ptr_t)context.R15;
+#elif defined(MIPS)
+PUSH4(IntAt,IntV0,IntV1,IntA0),PUSH4(IntA1,IntA2,IntA3,IntT0);
+PUSH4(IntT1,IntT2,IntT3,IntT4),PUSH4(IntT5,IntT6,IntT7,IntS0);
+PUSH4(IntS1,IntS2,IntS3,IntS4),PUSH4(IntS5,IntS6,IntS7,IntT8);
+PUSH4(IntT9,IntK0,IntK1,IntS8);
+sp=(ptr_t)context.IntSp;
+#elif defined(PPC)
+PUSH4(Gpr0,Gpr3,Gpr4,Gpr5),PUSH4(Gpr6,Gpr7,Gpr8,Gpr9);
+PUSH4(Gpr10,Gpr11,Gpr12,Gpr14),PUSH4(Gpr15,Gpr16,Gpr17,Gpr18);
+PUSH4(Gpr19,Gpr20,Gpr21,Gpr22),PUSH4(Gpr23,Gpr24,Gpr25,Gpr26);
+PUSH4(Gpr27,Gpr28,Gpr29,Gpr30),PUSH1(Gpr31);
+sp=(ptr_t)context.Gpr1;
+#elif defined(ALPHA)
+PUSH4(IntV0,IntT0,IntT1,IntT2),PUSH4(IntT3,IntT4,IntT5,IntT6);
+PUSH4(IntT7,IntS0,IntS1,IntS2),PUSH4(IntS3,IntS4,IntS5,IntFp);
+PUSH4(IntA0,IntA1,IntA2,IntA3),PUSH4(IntA4,IntA5,IntT8,IntT9);
+PUSH4(IntT10,IntT11,IntT12,IntAt);
+sp=(ptr_t)context.IntSp;
+#elif defined(CPPCHECK)
+sp=(ptr_t)(word)cnt;
+#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){
+#ifdef RETRY_GET_THREAD_CONTEXT
+word*regs=thread->context_regs;
+if (thread->suspended){
+sp=thread->context_sp;
+} else
+#else
+word regs[PUSHED_REGS_COUNT];
+#endif
+{
+CONTEXT context;
+context.ContextFlags=GET_THREAD_CONTEXT_FLAGS;
+if (GetThreadContext(THREAD_HANDLE(thread),&context)){
+sp=copy_ptr_regs(regs,&context);
+} else {
+#ifdef RETRY_GET_THREAD_CONTEXT
+sp=thread->context_sp;
+if (NULL==sp){
+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);
+if (isWow64){
+DWORD ContextFlags=(DWORD)regs[0];
+WORD SegFs=(WORD)regs[1];
+if ((ContextFlags&CONTEXT_EXCEPTION_REPORTING)!=0
+&&(ContextFlags&(CONTEXT_EXCEPTION_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
+&&((word)thread->stack_base<=(word)tib->StackLimit
+||(word)tib->StackBase < (word)thread->stack_base)){
+WARN("GetThreadContext might return stale register values"
+" including ESP=%p\n",sp);
+} else {
+sp=(ptr_t)tib->StackLimit;
+}
+}
+#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
+}
+if (thread->last_stack_min==ADDR_LIMIT){
+#ifdef MSWINCE
+if (GC_dont_query_stack_min){
+stack_min=GC_wince_evaluate_stack_min(traced_stack_sect!=NULL?
+(ptr_t)traced_stack_sect:thread->stack_base);
+} else
+#endif
+{
+stack_min=GC_get_stack_min(traced_stack_sect!=NULL?
+(ptr_t)traced_stack_sect:thread->stack_base);
+UNPROTECT_THREAD(thread);
+thread->last_stack_min=stack_min;
+}
+} else {
+if (traced_stack_sect!=NULL&&
+(word)thread->last_stack_min > (word)traced_stack_sect){
+UNPROTECT_THREAD(thread);
+thread->last_stack_min=(ptr_t)traced_stack_sect;
+}
+if ((word)sp < (word)thread->stack_base
+&&(word)sp>=(word)thread->last_stack_min){
+stack_min=sp;
+} else {
+if (may_be_in_stack(thread->id==me&&
+(word)sp < (word)thread->last_stack_min?
+sp:thread->last_stack_min)){
+stack_min=(ptr_t)last_info.BaseAddress;
+if ((word)sp < (word)stack_min
+||(word)sp>=(word)thread->stack_base)
+stack_min=GC_get_stack_min(thread->last_stack_min);
+} else {
+stack_min=GC_get_stack_min(thread->stack_base);
+}
+UNPROTECT_THREAD(thread);
+thread->last_stack_min=stack_min;
+}
+}
+GC_ASSERT(GC_dont_query_stack_min
+||stack_min==GC_get_stack_min(thread->stack_base)
+||((word)sp>=(word)stack_min
+&&(word)stack_min < (word)thread->stack_base
+&&(word)stack_min
+> (word)GC_get_stack_min(thread->stack_base)));
+if ((word)sp>=(word)stack_min&&(word)sp < (word)thread->stack_base){
+#ifdef DEBUG_THREADS
+GC_log_printf("Pushing stack for 0x%x from sp %p to %p from 0x%x\n",
+(int)thread->id,(void*)sp,(void*)thread->stack_base,
+(int)me);
+#endif
+GC_push_all_stack_sections(sp,thread->stack_base,traced_stack_sect);
+} else {
+if (thread->id==me||(word)sp>=(word)thread->stack_base
+||(word)(sp+GC_page_size)< (word)stack_min)
+WARN("Thread stack pointer %p out of range,pushing everything\n",
+sp);
+#ifdef DEBUG_THREADS
+GC_log_printf("Pushing stack for 0x%x from (min)%p to %p from 0x%x\n",
+(int)thread->id,(void*)stack_min,
+(void*)thread->stack_base,(int)me);
+#endif
+GC_push_all_stack(stack_min,thread->stack_base);
+}
+return thread->stack_base - sp;
+}
+GC_INNER void GC_push_all_stacks(void)
+{
+DWORD thread_id=GetCurrentThreadId();
+GC_bool found_me=FALSE;
+#ifndef SMALL_CONFIG
+unsigned nthreads=0;
+#endif
+word total_size=0;
+#ifndef GC_NO_THREADS_DISCOVERY
+if (GC_win32_dll_threads){
+int i;
+LONG my_max=GC_get_max_thread_index();
+for (i=0;i<=my_max;i++){
+GC_thread t=(GC_thread)(dll_thread_table+i);
+if (t->tm.in_use&&t->stack_base){
+#ifndef SMALL_CONFIG
+++nthreads;
+#endif
+total_size+=GC_push_stack_for(t,thread_id);
+if (t->id==thread_id)found_me=TRUE;
+}
+}
+} else
+#endif
+{
+int i;
+for (i=0;i < THREAD_TABLE_SZ;i++){
+GC_thread t;
+for (t=GC_threads[i];t!=0;t=t->tm.next){
+if (!KNOWN_FINISHED(t)&&t->stack_base){
+#ifndef SMALL_CONFIG
+++nthreads;
+#endif
+total_size+=GC_push_stack_for(t,thread_id);
+if (t->id==thread_id)found_me=TRUE;
+}
+}
+}
+}
+#ifndef SMALL_CONFIG
+GC_VERBOSE_LOG_PRINTF("Pushed %d thread stacks%s\n",nthreads,
+GC_win32_dll_threads?
+" based on DllMain thread tracking":"");
+#endif
+if (!found_me&&!GC_in_thread_creation)
+ABORT("Collecting from unknown thread");
+GC_total_stacksize=total_size;
+}
+#ifdef PARALLEL_MARK
+#ifndef MAX_MARKERS
+#define MAX_MARKERS 16
+#endif
+static ptr_t marker_sp[MAX_MARKERS - 1];
+#ifdef IA64
+static ptr_t marker_bsp[MAX_MARKERS - 1];
+#endif
+static ptr_t marker_last_stack_min[MAX_MARKERS - 1];
+#endif
+GC_INNER void GC_get_next_stack(char*start,char*limit,
+char**lo,char**hi)
+{
+int i;
+char*current_min=ADDR_LIMIT;
+ptr_t*plast_stack_min=NULL;
+GC_thread thread=NULL;
+if (GC_win32_dll_threads){
+LONG my_max=GC_get_max_thread_index();
+for (i=0;i<=my_max;i++){
+ptr_t s=(ptr_t)(dll_thread_table[i].stack_base);
+if ((word)s > (word)start&&(word)s < (word)current_min){
+plast_stack_min=(ptr_t*)
+&dll_thread_table[i].last_stack_min;
+current_min=s;
+#if defined(CPPCHECK)
+thread=(GC_thread)&dll_thread_table[i];
+#endif
+}
+}
+} else {
+for (i=0;i < THREAD_TABLE_SZ;i++){
+GC_thread t;
+for (t=GC_threads[i];t!=0;t=t->tm.next){
+ptr_t s=t->stack_base;
+if ((word)s > (word)start&&(word)s < (word)current_min){
+plast_stack_min=&t->last_stack_min;
+thread=t;
+current_min=s;
+}
+}
+}
+#ifdef PARALLEL_MARK
+for (i=0;i < GC_markers_m1;++i){
+ptr_t s=marker_sp[i];
+#ifdef IA64
+#endif
+if ((word)s > (word)start&&(word)s < (word)current_min){
+GC_ASSERT(marker_last_stack_min[i]!=NULL);
+plast_stack_min=&marker_last_stack_min[i];
+current_min=s;
+thread=NULL;
+}
+}
+#endif
+}
+*hi=current_min;
+if (current_min==ADDR_LIMIT){
+*lo=ADDR_LIMIT;
+return;
+}
+GC_ASSERT((word)current_min > (word)start&&plast_stack_min!=NULL);
+#ifdef MSWINCE
+if (GC_dont_query_stack_min){
+*lo=GC_wince_evaluate_stack_min(current_min);
+return;
+}
+#endif
+if ((word)current_min > (word)limit&&!may_be_in_stack(limit)){
+*lo=ADDR_LIMIT;
+return;
+}
+if (*plast_stack_min==ADDR_LIMIT
+||!may_be_in_stack(*plast_stack_min)){
+*lo=GC_get_stack_min(current_min);
+} else {
+*lo=GC_get_stack_min(*plast_stack_min);
+}
+if (thread!=NULL){
+UNPROTECT_THREAD(thread);
+}
+*plast_stack_min=*lo;
+}
+#ifdef PARALLEL_MARK
+#if defined(GC_PTHREADS)&&!defined(GC_PTHREADS_PARAMARK)
+#if!defined(__MINGW32__)
+#define GC_PTHREADS_PARAMARK
+#endif
+#endif
+#if!defined(GC_PTHREADS_PARAMARK)
+STATIC HANDLE GC_marker_cv[MAX_MARKERS - 1]={0};
+STATIC DWORD GC_marker_Id[MAX_MARKERS - 1]={0};
+#endif
+#if defined(GC_PTHREADS)&&defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID)
+static void set_marker_thread_name(unsigned id)
+{
+char name_buf[16];
+int len=sizeof("GC-marker-")- 1;
+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)
+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;
+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;
+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
+#ifdef GC_PTHREADS_PARAMARK
+STATIC void*GC_mark_thread(void*id)
+#elif defined(MSWINCE)
+STATIC DWORD WINAPI GC_mark_thread(LPVOID id)
+#else
+STATIC unsigned __stdcall GC_mark_thread(void*id)
+#endif
+{
+word my_mark_no=0;
+if ((word)id==GC_WORD_MAX)return 0;
+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();
+#endif
+#if!defined(GC_PTHREADS_PARAMARK)
+GC_marker_Id[(word)id]=GetCurrentThreadId();
+#endif
+GC_acquire_mark_lock();
+if (0==--GC_fl_builder_count)
+GC_notify_all_builder();
+for (;;++my_mark_no){
+if (my_mark_no - GC_mark_no > (word)2){
+my_mark_no=GC_mark_no;
+}
+#ifdef DEBUG_THREADS
+GC_log_printf("Starting mark helper for mark number %lu\n",
+(unsigned long)my_mark_no);
+#endif
+GC_help_marker(my_mark_no);
+}
+}
+#ifndef GC_ASSERTIONS
+#define SET_MARK_LOCK_HOLDER (void)0
+#define UNSET_MARK_LOCK_HOLDER (void)0
+#endif
+#ifdef CAN_HANDLE_FORK
+static int available_markers_m1=0;
+#else
+#define available_markers_m1 GC_markers_m1
+#endif
+#ifdef GC_PTHREADS_PARAMARK
+#include <pthread.h>
+#if defined(GC_ASSERTIONS)&&!defined(NUMERIC_THREAD_ID)
+#define NUMERIC_THREAD_ID(id)(unsigned long)(word)GC_PTHREAD_PTRVAL(id)
+#endif
+#ifdef CAN_HANDLE_FORK
+static pthread_cond_t mark_cv;
+#else
+static pthread_cond_t mark_cv=PTHREAD_COND_INITIALIZER;
+#endif
+GC_INNER void GC_start_mark_threads_inner(void)
+{
+int i;
+pthread_attr_t attr;
+pthread_t new_thread;
+#ifndef NO_MARKER_SPECIAL_SIGMASK
+sigset_t set,oldset;
+#endif
+GC_ASSERT(I_DONT_HOLD_LOCK());
+if (available_markers_m1<=0)return;
+#ifdef CAN_HANDLE_FORK
+if (GC_parallel)return;
+{
+pthread_cond_t mark_cv_local=PTHREAD_COND_INITIALIZER;
+BCOPY(&mark_cv_local,&mark_cv,sizeof(mark_cv));
+}
+#endif
+GC_ASSERT(GC_fl_builder_count==0);
+if (0!=pthread_attr_init(&attr))ABORT("pthread_attr_init failed");
+if (0!=pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED))
+ABORT("pthread_attr_setdetachstate failed");
+#ifndef NO_MARKER_SPECIAL_SIGMASK
+if (sigfillset(&set)!=0)
+ABORT("sigfillset failed");
+if (pthread_sigmask(SIG_BLOCK,&set,&oldset)< 0){
+WARN("pthread_sigmask set failed,no markers started,"
+" errno=%" WARN_PRIdPTR "\n",errno);
+GC_markers_m1=0;
+(void)pthread_attr_destroy(&attr);
+return;
+}
+#endif
+#ifdef CAN_HANDLE_FORK
+GC_markers_m1=available_markers_m1;
+#endif
+for (i=0;i < available_markers_m1;++i){
+marker_last_stack_min[i]=ADDR_LIMIT;
+if (0!=pthread_create(&new_thread,&attr,
+GC_mark_thread,(void*)(word)i)){
+WARN("Marker thread creation failed\n",0);
+GC_markers_m1=i;
+break;
+}
+}
+#ifndef NO_MARKER_SPECIAL_SIGMASK
+if (pthread_sigmask(SIG_SETMASK,&oldset,NULL)< 0){
+WARN("pthread_sigmask restore failed,errno=%" WARN_PRIdPTR "\n",
+errno);
+}
+#endif
+(void)pthread_attr_destroy(&attr);
+GC_wait_for_markers_init();
+GC_COND_LOG_PRINTF("Started %d mark helper threads\n",GC_markers_m1);
+}
+#ifdef GC_ASSERTIONS
+STATIC unsigned long GC_mark_lock_holder=NO_THREAD;
+#define SET_MARK_LOCK_HOLDER (void)(GC_mark_lock_holder=NUMERIC_THREAD_ID(pthread_self()))
+#define UNSET_MARK_LOCK_HOLDER do { GC_ASSERT(GC_mark_lock_holder==NUMERIC_THREAD_ID(pthread_self()));GC_mark_lock_holder=NO_THREAD;} while (0)
+#endif
+static pthread_mutex_t mark_mutex=PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t builder_cv=PTHREAD_COND_INITIALIZER;
+#ifdef LOCK_STATS
+volatile AO_t GC_block_count=0;
+#endif
+GC_INNER void GC_acquire_mark_lock(void)
+{
+#if defined(NUMERIC_THREAD_ID_UNIQUE)&&!defined(THREAD_SANITIZER)
+GC_ASSERT(GC_mark_lock_holder!=NUMERIC_THREAD_ID(pthread_self()));
+#endif
+if (pthread_mutex_lock(&mark_mutex)!=0){
+ABORT("pthread_mutex_lock failed");
+}
+#ifdef LOCK_STATS
+(void)AO_fetch_and_add1(&GC_block_count);
+#endif
+SET_MARK_LOCK_HOLDER;
+}
+GC_INNER void GC_release_mark_lock(void)
+{
+UNSET_MARK_LOCK_HOLDER;
+if (pthread_mutex_unlock(&mark_mutex)!=0){
+ABORT("pthread_mutex_unlock failed");
+}
+}
+STATIC void GC_wait_builder(void)
+{
+UNSET_MARK_LOCK_HOLDER;
+if (pthread_cond_wait(&builder_cv,&mark_mutex)!=0){
+ABORT("pthread_cond_wait failed");
+}
+GC_ASSERT(GC_mark_lock_holder==NO_THREAD);
+SET_MARK_LOCK_HOLDER;
+}
+GC_INNER void GC_wait_for_reclaim(void)
+{
+GC_acquire_mark_lock();
+while (GC_fl_builder_count > 0){
+GC_wait_builder();
+}
+GC_release_mark_lock();
+}
+GC_INNER void GC_notify_all_builder(void)
+{
+GC_ASSERT(GC_mark_lock_holder==NUMERIC_THREAD_ID(pthread_self()));
+if (pthread_cond_broadcast(&builder_cv)!=0){
+ABORT("pthread_cond_broadcast failed");
+}
+}
+GC_INNER void GC_wait_marker(void)
+{
+GC_ASSERT(GC_parallel);
+UNSET_MARK_LOCK_HOLDER;
+if (pthread_cond_wait(&mark_cv,&mark_mutex)!=0){
+ABORT("pthread_cond_wait failed");
+}
+GC_ASSERT(GC_mark_lock_holder==NO_THREAD);
+SET_MARK_LOCK_HOLDER;
+}
+GC_INNER void GC_notify_all_marker(void)
+{
+GC_ASSERT(GC_parallel);
+if (pthread_cond_broadcast(&mark_cv)!=0){
+ABORT("pthread_cond_broadcast failed");
+}
+}
+#else
+#ifndef MARK_THREAD_STACK_SIZE
+#define MARK_THREAD_STACK_SIZE 0
+#endif
+static HANDLE mark_mutex_event=(HANDLE)0;
+static HANDLE builder_cv=(HANDLE)0;
+static HANDLE mark_cv=(HANDLE)0;
+GC_INNER void GC_start_mark_threads_inner(void)
+{
+int i;
+GC_ASSERT(I_DONT_HOLD_LOCK());
+if (available_markers_m1<=0)return;
+GC_ASSERT(GC_fl_builder_count==0);
+for (i=0;i < GC_markers_m1;++i){
+if ((GC_marker_cv[i]=CreateEvent(NULL,
+TRUE,
+FALSE,
+NULL))==(HANDLE)0)
+ABORT("CreateEvent failed");
+}
+for (i=0;i < GC_markers_m1;++i){
+#if defined(MSWINCE)||defined(MSWIN_XBOX1)
+HANDLE handle;
+DWORD thread_id;
+marker_last_stack_min[i]=ADDR_LIMIT;
+handle=CreateThread(NULL,
+MARK_THREAD_STACK_SIZE,
+GC_mark_thread,(LPVOID)(word)i,
+0,&thread_id);
+if (handle==NULL){
+WARN("Marker thread creation failed\n",0);
+break;
+} else {
+CloseHandle(handle);
+}
+#else
+GC_uintptr_t handle;
+unsigned thread_id;
+marker_last_stack_min[i]=ADDR_LIMIT;
+handle=_beginthreadex(NULL,
+MARK_THREAD_STACK_SIZE,GC_mark_thread,
+(void*)(word)i,0,&thread_id);
+if (!handle||handle==(GC_uintptr_t)-1L){
+WARN("Marker thread creation failed\n",0);
+break;
+} else {
+}
+#endif
+}
+while (GC_markers_m1 > i){
+GC_markers_m1--;
+CloseHandle(GC_marker_cv[GC_markers_m1]);
+}
+GC_wait_for_markers_init();
+GC_COND_LOG_PRINTF("Started %d mark helper threads\n",GC_markers_m1);
+if (i==0){
+CloseHandle(mark_cv);
+CloseHandle(builder_cv);
+CloseHandle(mark_mutex_event);
+}
+}
+#ifdef GC_ASSERTIONS
+STATIC DWORD GC_mark_lock_holder=NO_THREAD;
+#define SET_MARK_LOCK_HOLDER (void)(GC_mark_lock_holder=GetCurrentThreadId())
+#define UNSET_MARK_LOCK_HOLDER do { GC_ASSERT(GC_mark_lock_holder==GetCurrentThreadId());GC_mark_lock_holder=NO_THREAD;} while (0)
+#endif
+STATIC LONG GC_mark_mutex_state=0;
+#ifdef LOCK_STATS
+volatile AO_t GC_block_count=0;
+volatile AO_t GC_unlocked_count=0;
+#endif
+GC_INNER void GC_acquire_mark_lock(void)
+{
+#ifndef THREAD_SANITIZER
+GC_ASSERT(GC_mark_lock_holder!=GetCurrentThreadId());
+#endif
+if (InterlockedExchange(&GC_mark_mutex_state,1)!=0){
+#ifdef LOCK_STATS
+(void)AO_fetch_and_add1(&GC_block_count);
+#endif
+while (InterlockedExchange(&GC_mark_mutex_state,
+-1)!=0){
+if (WaitForSingleObject(mark_mutex_event,INFINITE)==WAIT_FAILED)
+ABORT("WaitForSingleObject failed");
+}
+}
+#ifdef LOCK_STATS
+else {
+(void)AO_fetch_and_add1(&GC_unlocked_count);
+}
+#endif
+GC_ASSERT(GC_mark_lock_holder==NO_THREAD);
+SET_MARK_LOCK_HOLDER;
+}
+GC_INNER void GC_release_mark_lock(void)
+{
+UNSET_MARK_LOCK_HOLDER;
+if (InterlockedExchange(&GC_mark_mutex_state,0)< 0){
+if (SetEvent(mark_mutex_event)==FALSE)
+ABORT("SetEvent failed");
+}
+}
+GC_INNER void GC_wait_for_reclaim(void)
+{
+GC_ASSERT(builder_cv!=0);
+for (;;){
+GC_acquire_mark_lock();
+if (GC_fl_builder_count==0)
+break;
+if (ResetEvent(builder_cv)==FALSE)
+ABORT("ResetEvent failed");
+GC_release_mark_lock();
+if (WaitForSingleObject(builder_cv,INFINITE)==WAIT_FAILED)
+ABORT("WaitForSingleObject failed");
+}
+GC_release_mark_lock();
+}
+GC_INNER void GC_notify_all_builder(void)
+{
+GC_ASSERT(GC_mark_lock_holder==GetCurrentThreadId());
+GC_ASSERT(builder_cv!=0);
+GC_ASSERT(GC_fl_builder_count==0);
+if (SetEvent(builder_cv)==FALSE)
+ABORT("SetEvent failed");
+}
+GC_INNER void GC_wait_marker(void)
+{
+HANDLE event=mark_cv;
+DWORD thread_id=GetCurrentThreadId();
+int i=GC_markers_m1;
+while (i--> 0){
+if (GC_marker_Id[i]==thread_id){
+event=GC_marker_cv[i];
+break;
+}
+}
+if (ResetEvent(event)==FALSE)
+ABORT("ResetEvent failed");
+GC_release_mark_lock();
+if (WaitForSingleObject(event,INFINITE)==WAIT_FAILED)
+ABORT("WaitForSingleObject failed");
+GC_acquire_mark_lock();
+}
+GC_INNER void GC_notify_all_marker(void)
+{
+DWORD thread_id=GetCurrentThreadId();
+int i=GC_markers_m1;
+while (i--> 0){
+if (SetEvent(GC_marker_Id[i]!=thread_id?GC_marker_cv[i]:
+mark_cv)==FALSE)
+ABORT("SetEvent failed");
+}
+}
+#endif
+static unsigned required_markers_cnt=0;
+#endif
+typedef struct {
+LPTHREAD_START_ROUTINE start;
+LPVOID param;
+} thread_args;
+STATIC void*GC_CALLBACK GC_win32_start_inner(struct GC_stack_base*sb,
+void*arg)
+{
+void*ret;
+LPTHREAD_START_ROUTINE start=((thread_args*)arg)->start;
+LPVOID param=((thread_args*)arg)->param;
+GC_register_my_thread(sb);
+#ifdef DEBUG_THREADS
+GC_log_printf("thread 0x%lx starting...\n",(long)GetCurrentThreadId());
+#endif
+GC_free(arg);
+#if!defined(__GNUC__)&&!defined(NO_CRT)
+ret=NULL;
+__try
+#endif
+{
+ret=(void*)(word)(*start)(param);
+}
+#if!defined(__GNUC__)&&!defined(NO_CRT)
+__finally
+#endif
+{
+GC_unregister_my_thread();
+}
+#ifdef DEBUG_THREADS
+GC_log_printf("thread 0x%lx returned from start routine\n",
+(long)GetCurrentThreadId());
+#endif
+return ret;
+}
+STATIC DWORD WINAPI GC_win32_start(LPVOID arg)
+{
+return (DWORD)(word)GC_call_with_stack_base(GC_win32_start_inner,arg);
+}
+GC_API HANDLE WINAPI GC_CreateThread(
+LPSECURITY_ATTRIBUTES lpThreadAttributes,
+GC_WIN32_SIZE_T dwStackSize,
+LPTHREAD_START_ROUTINE lpStartAddress,
+LPVOID lpParameter,DWORD dwCreationFlags,
+LPDWORD lpThreadId)
+{
+if (!EXPECT(parallel_initialized,TRUE))
+GC_init_parallel();
+#ifdef DEBUG_THREADS
+GC_log_printf("About to create a thread from 0x%lx\n",
+(long)GetCurrentThreadId());
+#endif
+if (GC_win32_dll_threads){
+return CreateThread(lpThreadAttributes,dwStackSize,lpStartAddress,
+lpParameter,dwCreationFlags,lpThreadId);
+} else {
+thread_args*args=
+(thread_args*)GC_malloc_uncollectable(sizeof(thread_args));
+HANDLE thread_h;
+if (NULL==args){
+SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+return NULL;
+}
+args->start=lpStartAddress;
+args->param=lpParameter;
+GC_dirty(args);
+REACHABLE_AFTER_DIRTY(lpParameter);
+set_need_to_lock();
+thread_h=CreateThread(lpThreadAttributes,dwStackSize,GC_win32_start,
+args,dwCreationFlags,lpThreadId);
+if (thread_h==0)GC_free(args);
+return thread_h;
+}
+}
+GC_API DECLSPEC_NORETURN void WINAPI GC_ExitThread(DWORD dwExitCode)
+{
+GC_unregister_my_thread();
+ExitThread(dwExitCode);
+}
+#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*),
+void*arglist,unsigned initflag,
+unsigned*thrdaddr)
+{
+if (!EXPECT(parallel_initialized,TRUE))
+GC_init_parallel();
+#ifdef DEBUG_THREADS
+GC_log_printf("About to create a thread from 0x%lx\n",
+(long)GetCurrentThreadId());
+#endif
+if (GC_win32_dll_threads){
+return _beginthreadex(security,stack_size,start_address,
+arglist,initflag,thrdaddr);
+} else {
+GC_uintptr_t thread_h;
+thread_args*args=
+(thread_args*)GC_malloc_uncollectable(sizeof(thread_args));
+if (NULL==args){
+errno=EAGAIN;
+return 0;
+}
+args->start=(LPTHREAD_START_ROUTINE)start_address;
+args->param=arglist;
+GC_dirty(args);
+REACHABLE_AFTER_DIRTY(arglist);
+set_need_to_lock();
+thread_h=_beginthreadex(security,stack_size,
+(unsigned (__stdcall*)(void*))GC_win32_start,
+args,initflag,thrdaddr);
+if (thread_h==0)GC_free(args);
+return thread_h;
+}
+}
+GC_API void GC_CALL GC_endthreadex(unsigned retval)
+{
+GC_unregister_my_thread();
+_endthreadex(retval);
+}
+#endif
+#ifdef GC_WINMAIN_REDIRECT
+#if defined(MSWINCE)&&defined(UNDER_CE)
+#define WINMAIN_LPTSTR LPWSTR
+#else
+#define WINMAIN_LPTSTR LPSTR
+#endif
+#undef WinMain
+int WINAPI GC_WinMain(HINSTANCE,HINSTANCE,WINMAIN_LPTSTR,int);
+typedef struct {
+HINSTANCE hInstance;
+HINSTANCE hPrevInstance;
+WINMAIN_LPTSTR lpCmdLine;
+int nShowCmd;
+} main_thread_args;
+static DWORD WINAPI main_thread_start(LPVOID arg)
+{
+main_thread_args*args=(main_thread_args*)arg;
+return (DWORD)GC_WinMain(args->hInstance,args->hPrevInstance,
+args->lpCmdLine,args->nShowCmd);
+}
+STATIC void*GC_waitForSingleObjectInfinite(void*handle)
+{
+return (void*)(word)WaitForSingleObject((HANDLE)handle,INFINITE);
+}
+#ifndef WINMAIN_THREAD_STACK_SIZE
+#define WINMAIN_THREAD_STACK_SIZE 0
+#endif
+int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
+WINMAIN_LPTSTR lpCmdLine,int nShowCmd)
+{
+DWORD exit_code=1;
+main_thread_args args={
+hInstance,hPrevInstance,lpCmdLine,nShowCmd
+};
+HANDLE thread_h;
+DWORD thread_id;
+GC_INIT();
+thread_h=GC_CreateThread(NULL,
+WINMAIN_THREAD_STACK_SIZE,
+main_thread_start,&args,0,
+&thread_id);
+if (thread_h!=NULL){
+if ((DWORD)(word)GC_do_blocking(GC_waitForSingleObjectInfinite,
+(void*)thread_h)==WAIT_FAILED)
+ABORT("WaitForSingleObject(main_thread)failed");
+GetExitCodeThread (thread_h,&exit_code);
+CloseHandle (thread_h);
+} else {
+ABORT("GC_CreateThread(main_thread)failed");
+}
+#ifdef MSWINCE
+GC_deinit();
+#endif
+return (int)exit_code;
+}
+#endif
+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)
+{
+struct GC_stack_base sb;
+#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);
+#ifdef GC_NO_THREADS_DISCOVERY
+#define GC_main_thread GetCurrentThreadId()
+#else
+GC_main_thread=GetCurrentThreadId();
+#endif
+GC_thr_initialized=TRUE;
+#ifdef CAN_HANDLE_FORK
+if (GC_handle_fork){
+#ifdef CAN_CALL_ATFORK
+if (pthread_atfork(fork_prepare_proc,fork_parent_proc,
+fork_child_proc)==0){
+GC_handle_fork=1;
+} else
+#endif
+if (GC_handle_fork!=-1)
+ABORT("pthread_atfork failed");
+}
+#endif
+#ifdef WOW64_THREAD_CONTEXT_WORKAROUND
+if (hK32){
+FARPROC pfn=GetProcAddress(hK32,"IsWow64Process");
+if (pfn
+&&!(*(BOOL (WINAPI*)(HANDLE,BOOL*))(word)pfn)(
+GetCurrentProcess(),&isWow64))
+isWow64=FALSE;
+}
+#endif
+sb.mem_base=GC_stackbottom;
+GC_ASSERT(sb.mem_base!=NULL);
+#ifdef IA64
+sb.reg_base=GC_register_stackbottom;
+#endif
+#if defined(PARALLEL_MARK)
+{
+char*markers_string=GETENV("GC_MARKERS");
+int markers=required_markers_cnt;
+if (markers_string!=NULL){
+markers=atoi(markers_string);
+if (markers<=0||markers > MAX_MARKERS){
+WARN("Too big or invalid number of mark threads:%" WARN_PRIdPTR
+";using maximum threads\n",(signed_word)markers);
+markers=MAX_MARKERS;
+}
+} else if (0==markers){
+#ifdef MSWINCE
+markers=(int)GC_sysinfo.dwNumberOfProcessors;
+#else
+#ifdef _WIN64
+DWORD_PTR procMask=0;
+DWORD_PTR sysMask;
+#else
+DWORD procMask=0;
+DWORD sysMask;
+#endif
+int ncpu=0;
+if (
+#ifdef __cplusplus
+GetProcessAffinityMask(GetCurrentProcess(),&procMask,&sysMask)
+#else
+GetProcessAffinityMask(GetCurrentProcess(),
+(void*)&procMask,(void*)&sysMask)
+#endif
+&&procMask){
+do {
+ncpu++;
+} while ((procMask&=procMask - 1)!=0);
+}
+markers=ncpu;
+#endif
+#if defined(GC_MIN_MARKERS)&&!defined(CPPCHECK)
+if (markers < GC_MIN_MARKERS)
+markers=GC_MIN_MARKERS;
+#endif
+if (markers > MAX_MARKERS)
+markers=MAX_MARKERS;
+}
+available_markers_m1=markers - 1;
+}
+if (GC_win32_dll_threads||available_markers_m1<=0){
+GC_parallel=FALSE;
+GC_COND_LOG_PRINTF(
+"Single marker thread,turning off parallel marking\n");
+} else {
+#ifndef GC_PTHREADS_PARAMARK
+mark_mutex_event=CreateEvent(NULL,
+FALSE,
+FALSE,NULL);
+builder_cv=CreateEvent(NULL,
+TRUE,
+FALSE,NULL);
+mark_cv=CreateEvent(NULL,TRUE,
+FALSE,NULL);
+if (mark_mutex_event==(HANDLE)0||builder_cv==(HANDLE)0
+||mark_cv==(HANDLE)0)
+ABORT("CreateEvent failed");
+#endif
+#if!defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID)&&!defined(MSWINCE)
+if (hK32)
+setThreadDescription_fn=GetProcAddress(hK32,
+"SetThreadDescription");
+#endif
+}
+#endif
+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
+struct start_info {
+void*(*start_routine)(void*);
+void*arg;
+GC_bool detached;
+};
+GC_API int GC_pthread_join(pthread_t pthread_id,void**retval)
+{
+int result;
+#ifndef GC_WIN32_PTHREADS
+GC_thread t;
+#endif
+DCL_LOCK_STATE;
+GC_ASSERT(!GC_win32_dll_threads);
+#ifdef DEBUG_THREADS
+GC_log_printf("thread %p(0x%lx)is joining thread %p\n",
+(void*)GC_PTHREAD_PTRVAL(pthread_self()),
+(long)GetCurrentThreadId(),
+(void*)GC_PTHREAD_PTRVAL(pthread_id));
+#endif
+#ifndef GC_WIN32_PTHREADS
+while ((t=GC_lookup_pthread(pthread_id))==0)
+Sleep(10);
+#endif
+result=pthread_join(pthread_id,retval);
+if (0==result){
+#ifdef GC_WIN32_PTHREADS
+GC_thread t=GC_lookup_pthread(pthread_id);
+if (NULL==t)ABORT("Thread not registered");
+#endif
+LOCK();
+if ((t->flags&FINISHED)!=0){
+GC_delete_gc_thread_no_free(t);
+GC_INTERNAL_FREE(t);
+}
+UNLOCK();
+}
+#ifdef DEBUG_THREADS
+GC_log_printf("thread %p(0x%lx)join with thread %p %s\n",
+(void*)GC_PTHREAD_PTRVAL(pthread_self()),
+(long)GetCurrentThreadId(),
+(void*)GC_PTHREAD_PTRVAL(pthread_id),
+result!=0?"failed":"succeeded");
+#endif
+return result;
+}
+GC_API int GC_pthread_create(pthread_t*new_thread,
+GC_PTHREAD_CREATE_CONST pthread_attr_t*attr,
+void*(*start_routine)(void*),void*arg)
+{
+int result;
+struct start_info*si;
+if (!EXPECT(parallel_initialized,TRUE))
+GC_init_parallel();
+GC_ASSERT(!GC_win32_dll_threads);
+si=(struct start_info*)GC_malloc_uncollectable(
+sizeof(struct start_info));
+if (NULL==si)
+return EAGAIN;
+si->start_routine=start_routine;
+si->arg=arg;
+GC_dirty(si);
+REACHABLE_AFTER_DIRTY(arg);
+if (attr!=0&&
+pthread_attr_getdetachstate(attr,&si->detached)
+==PTHREAD_CREATE_DETACHED){
+si->detached=TRUE;
+}
+#ifdef DEBUG_THREADS
+GC_log_printf("About to create a thread from %p(0x%lx)\n",
+(void*)GC_PTHREAD_PTRVAL(pthread_self()),
+(long)GetCurrentThreadId());
+#endif
+set_need_to_lock();
+result=pthread_create(new_thread,attr,GC_pthread_start,si);
+if (result){
+GC_free(si);
+}
+return(result);
+}
+STATIC void*GC_CALLBACK GC_pthread_start_inner(struct GC_stack_base*sb,
+void*arg)
+{
+struct start_info*si=(struct start_info*)arg;
+void*result;
+void*(*start)(void*);
+void*start_arg;
+DWORD thread_id=GetCurrentThreadId();
+pthread_t pthread_id=pthread_self();
+GC_thread me;
+DCL_LOCK_STATE;
+#ifdef DEBUG_THREADS
+GC_log_printf("thread %p(0x%x)starting...\n",
+(void*)GC_PTHREAD_PTRVAL(pthread_id),(int)thread_id);
+#endif
+GC_ASSERT(!GC_win32_dll_threads);
+LOCK();
+me=GC_register_my_thread_inner(sb,thread_id);
+SET_PTHREAD_MAP_CACHE(pthread_id,thread_id);
+GC_ASSERT(me!=&first_thread);
+me->pthread_id=pthread_id;
+if (si->detached)me->flags|=DETACHED;
+UNLOCK();
+start=si->start_routine;
+start_arg=si->arg;
+GC_free(si);
+pthread_cleanup_push(GC_thread_exit_proc,(void*)me);
+result=(*start)(start_arg);
+me->status=result;
+GC_dirty(me);
+pthread_cleanup_pop(1);
+#ifdef DEBUG_THREADS
+GC_log_printf("thread %p(0x%x)returned from start routine\n",
+(void*)GC_PTHREAD_PTRVAL(pthread_id),(int)thread_id);
+#endif
+return(result);
+}
+STATIC void*GC_pthread_start(void*arg)
+{
+return GC_call_with_stack_base(GC_pthread_start_inner,arg);
+}
+STATIC void GC_thread_exit_proc(void*arg)
+{
+GC_thread me=(GC_thread)arg;
+DCL_LOCK_STATE;
+GC_ASSERT(!GC_win32_dll_threads);
+#ifdef DEBUG_THREADS
+GC_log_printf("thread %p(0x%lx)called pthread_exit()\n",
+(void*)GC_PTHREAD_PTRVAL(pthread_self()),
+(long)GetCurrentThreadId());
+#endif
+LOCK();
+GC_wait_for_gc_completion(FALSE);
+#if defined(THREAD_LOCAL_ALLOC)
+GC_ASSERT(GC_getspecific(GC_thread_key)==&me->tlfs);
+GC_destroy_thread_local(&(me->tlfs));
+#endif
+if (me->flags&DETACHED){
+GC_delete_thread(GetCurrentThreadId());
+} else {
+me->flags|=FINISHED;
+}
+#if defined(THREAD_LOCAL_ALLOC)
+GC_remove_specific(GC_thread_key);
+#endif
+UNLOCK();
+}
+#ifndef GC_NO_PTHREAD_SIGMASK
+GC_API int GC_pthread_sigmask(int how,const sigset_t*set,
+sigset_t*oset)
+{
+return pthread_sigmask(how,set,oset);
+}
+#endif
+GC_API int GC_pthread_detach(pthread_t thread)
+{
+int result;
+GC_thread t;
+DCL_LOCK_STATE;
+GC_ASSERT(!GC_win32_dll_threads);
+while ((t=GC_lookup_pthread(thread))==NULL)
+Sleep(10);
+result=pthread_detach(thread);
+if (result==0){
+LOCK();
+t->flags|=DETACHED;
+if ((t->flags&FINISHED)!=0){
+GC_delete_gc_thread_no_free(t);
+GC_INTERNAL_FREE(t);
+}
+UNLOCK();
+}
+return result;
+}
+#elif!defined(GC_NO_THREADS_DISCOVERY)
+#ifdef GC_INSIDE_DLL
+GC_API
+#else
+#define GC_DllMain DllMain
+#endif
+BOOL WINAPI GC_DllMain(HINSTANCE inst GC_ATTR_UNUSED,ULONG reason,
+LPVOID reserved GC_ATTR_UNUSED)
+{
+DWORD thread_id;
+if (!GC_win32_dll_threads&&parallel_initialized)return TRUE;
+switch (reason){
+case DLL_THREAD_ATTACH:
+#ifdef PARALLEL_MARK
+if (GC_parallel){
+break;
+}
+#endif
+case DLL_PROCESS_ATTACH:
+thread_id=GetCurrentThreadId();
+if (parallel_initialized&&GC_main_thread!=thread_id){
+#ifdef PARALLEL_MARK
+ABORT("Cannot initialize parallel marker from DllMain");
+#else
+struct GC_stack_base sb;
+#ifdef GC_ASSERTIONS
+int sb_result=
+#endif
+GC_get_stack_base(&sb);
+GC_ASSERT(sb_result==GC_SUCCESS);
+GC_register_my_thread_inner(&sb,thread_id);
+#endif
+}
+break;
+case DLL_THREAD_DETACH:
+GC_ASSERT(parallel_initialized);
+if (GC_win32_dll_threads){
+GC_delete_thread(GetCurrentThreadId());
+}
+break;
+case DLL_PROCESS_DETACH:
+if (GC_win32_dll_threads){
+int i;
+int my_max=(int)GC_get_max_thread_index();
+for (i=0;i<=my_max;++i){
+if (AO_load(&(dll_thread_table[i].tm.in_use)))
+GC_delete_gc_thread_no_free(&dll_thread_table[i]);
+}
+GC_deinit();
+}
+break;
+}
+return TRUE;
+}
+#endif
+GC_INNER void GC_init_parallel(void)
+{
+#if defined(THREAD_LOCAL_ALLOC)
+GC_thread me;
+DCL_LOCK_STATE;
+#endif
+if (parallel_initialized)return;
+parallel_initialized=TRUE;
+if (!GC_is_initialized)GC_init();
+#if defined(CPPCHECK)&&!defined(GC_NO_THREADS_DISCOVERY)
+GC_noop1((word)&GC_DllMain);
+#endif
+if (GC_win32_dll_threads){
+set_need_to_lock();
+}
+#if defined(THREAD_LOCAL_ALLOC)
+LOCK();
+me=GC_lookup_thread_inner(GetCurrentThreadId());
+CHECK_LOOKUP_MY_THREAD(me);
+GC_init_thread_local(&me->tlfs);
+UNLOCK();
+#endif
+}
+#if defined(USE_PTHREAD_LOCKS)
+GC_INNER void GC_lock(void)
+{
+pthread_mutex_lock(&GC_allocate_ml);
+}
+#endif
+#if defined(THREAD_LOCAL_ALLOC)
+GC_INNER void GC_mark_thread_local_free_lists(void)
+{
+int i;
+GC_thread p;
+for (i=0;i < THREAD_TABLE_SZ;++i){
+for (p=GC_threads[i];0!=p;p=p->tm.next){
+if (!KNOWN_FINISHED(p)){
+#ifdef DEBUG_THREADS
+GC_log_printf("Marking thread locals for 0x%x\n",(int)p->id);
+#endif
+GC_mark_thread_local_fls_for(&(p->tlfs));
+}
+}
+}
+}
+#if defined(GC_ASSERTIONS)
+void GC_check_tls(void)
+{
+int i;
+GC_thread p;
+for (i=0;i < THREAD_TABLE_SZ;++i){
+for (p=GC_threads[i];0!=p;p=p->tm.next){
+if (!KNOWN_FINISHED(p))
+GC_check_tls_for(&(p->tlfs));
+}
+}
+#if defined(USE_CUSTOM_SPECIFIC)
+if (GC_thread_key!=0)
+GC_check_tsd_marks(GC_thread_key);
+#endif
+}
+#endif
+#endif
+#ifndef GC_NO_THREAD_REDIRECTS
+#define CreateThread GC_CreateThread
+#define ExitThread GC_ExitThread
+#undef _beginthreadex
+#define _beginthreadex GC_beginthreadex
+#undef _endthreadex
+#define _endthreadex GC_endthreadex
+#endif
+#endif
+#ifndef GC_PTHREAD_START_STANDALONE
+#if defined(__GNUC__)&&defined(__linux__)
+#undef __EXCEPTIONS
+#endif
+#if defined(GC_PTHREADS)&&!defined(GC_WIN32_THREADS)
+#include <pthread.h>
+#include <sched.h>
+GC_INNER_PTHRSTART void*GC_CALLBACK GC_inner_start_routine(
+struct GC_stack_base*sb,void*arg)
+{
+void*(*start)(void*);
+void*start_arg;
+void*result;
+volatile GC_thread me=
+GC_start_rtn_prepare_thread(&start,&start_arg,sb,arg);
+#ifndef NACL
+pthread_cleanup_push(GC_thread_exit_proc,me);
+#endif
+result=(*start)(start_arg);
+#if defined(DEBUG_THREADS)&&!defined(GC_PTHREAD_START_STANDALONE)
+GC_log_printf("Finishing thread %p\n",(void*)pthread_self());
+#endif
+me->status=result;
+GC_end_stubborn_change(me);
+#ifndef NACL
+pthread_cleanup_pop(1);
+#endif
+return result;
+}
+#endif
+#endif
+#ifndef GC_NO_THREAD_REDIRECTS
+#define GC_PTHREAD_REDIRECTS_ONLY
+#ifndef GC_PTHREAD_REDIRECTS_H
+#define GC_PTHREAD_REDIRECTS_H
+#if defined(GC_H)&&defined(GC_PTHREADS)
+#ifndef GC_PTHREAD_REDIRECTS_ONLY
+#include <pthread.h>
+#ifndef GC_NO_DLOPEN
+#include <dlfcn.h>
+#endif
+#ifndef GC_NO_PTHREAD_SIGMASK
+#include <signal.h>
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifndef GC_SUSPEND_THREAD_ID
+#define GC_SUSPEND_THREAD_ID pthread_t
+#endif
+#ifndef GC_NO_DLOPEN
+GC_API void*GC_dlopen(const char*,int);
+#endif
+#ifndef GC_NO_PTHREAD_SIGMASK
+#if defined(GC_PTHREAD_SIGMASK_NEEDED)||defined(_BSD_SOURCE)||defined(_GNU_SOURCE)||(_POSIX_C_SOURCE>=199506L)||(_XOPEN_SOURCE>=500)
+GC_API int GC_pthread_sigmask(int,const sigset_t*,
+sigset_t*);
+#endif
+#endif
+#ifndef GC_PTHREAD_CREATE_CONST
+#define GC_PTHREAD_CREATE_CONST const
+#endif
+GC_API int GC_pthread_create(pthread_t*,
+GC_PTHREAD_CREATE_CONST pthread_attr_t*,
+void*(*)(void*),void*);
+GC_API int GC_pthread_join(pthread_t,void**);
+GC_API int GC_pthread_detach(pthread_t);
+#ifndef GC_NO_PTHREAD_CANCEL
+GC_API int GC_pthread_cancel(pthread_t);
+#endif
+#if defined(GC_HAVE_PTHREAD_EXIT)&&!defined(GC_PTHREAD_EXIT_DECLARED)
+#define GC_PTHREAD_EXIT_DECLARED
+GC_API void GC_pthread_exit(void*)GC_PTHREAD_EXIT_ATTRIBUTE;
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+#if!defined(GC_NO_THREAD_REDIRECTS)&&!defined(GC_USE_LD_WRAP)
+#undef pthread_create
+#undef pthread_join
+#undef pthread_detach
+#define pthread_create GC_pthread_create
+#define pthread_join GC_pthread_join
+#define pthread_detach GC_pthread_detach
+#ifndef GC_NO_PTHREAD_SIGMASK
+#undef pthread_sigmask
+#define pthread_sigmask GC_pthread_sigmask
+#endif
+#ifndef GC_NO_DLOPEN
+#undef dlopen
+#define dlopen GC_dlopen
+#endif
+#ifndef GC_NO_PTHREAD_CANCEL
+#undef pthread_cancel
+#define pthread_cancel GC_pthread_cancel
+#endif
+#ifdef GC_HAVE_PTHREAD_EXIT
+#undef pthread_exit
+#define pthread_exit GC_pthread_exit
+#endif
+#endif
+#endif
+#endif
+#endif