From 775c4c34b548eca795efc39d56eeac96c5394ad9 Mon Sep 17 00:00:00 2001 From: spaceface Date: Mon, 18 Apr 2022 09:50:21 +0200 Subject: [PATCH] builtin: compile the gc statically by default (#14063) --- .github/workflows/ci.yml | 2 +- thirdparty/libgc/gc.c | 44943 ++++++++-------- thirdparty/libgc/gc.h | 1081 - thirdparty/libgc/include/gc.h | 2 + thirdparty/libgc/include/gc/cord.h | 377 + thirdparty/libgc/include/gc/cord_pos.h | 128 + thirdparty/libgc/include/gc/ec.h | 89 + thirdparty/libgc/include/gc/gc.h | 2172 + thirdparty/libgc/include/gc/gc_backptr.h | 96 + .../libgc/include/gc/gc_config_macros.h | 457 + thirdparty/libgc/include/gc/gc_inline.h | 208 + thirdparty/libgc/include/gc/gc_mark.h | 328 + .../libgc/include/gc/gc_pthread_redirects.h | 124 + thirdparty/libgc/include/gc/gc_tiny_fl.h | 90 + thirdparty/libgc/include/gc/gc_typed.h | 122 + thirdparty/libgc/include/gc/gc_version.h | 47 + thirdparty/libgc/include/gc/leak_detector.h | 68 + vlib/builtin/builtin_d_gcboehm.c.v | 86 +- vlib/v/cflag/cflags.v | 2 +- 19 files changed, 27379 insertions(+), 23043 deletions(-) delete mode 100644 thirdparty/libgc/gc.h create mode 100644 thirdparty/libgc/include/gc.h create mode 100644 thirdparty/libgc/include/gc/cord.h create mode 100644 thirdparty/libgc/include/gc/cord_pos.h create mode 100644 thirdparty/libgc/include/gc/ec.h create mode 100644 thirdparty/libgc/include/gc/gc.h create mode 100644 thirdparty/libgc/include/gc/gc_backptr.h create mode 100644 thirdparty/libgc/include/gc/gc_config_macros.h create mode 100644 thirdparty/libgc/include/gc/gc_inline.h create mode 100644 thirdparty/libgc/include/gc/gc_mark.h create mode 100644 thirdparty/libgc/include/gc/gc_pthread_redirects.h create mode 100644 thirdparty/libgc/include/gc/gc_tiny_fl.h create mode 100644 thirdparty/libgc/include/gc/gc_typed.h create mode 100644 thirdparty/libgc/include/gc/gc_version.h create mode 100644 thirdparty/libgc/include/gc/leak_detector.h diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55b3d9a9e..d9fe1b2a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -131,7 +131,7 @@ jobs: run: | ./v -gc boehm_leak -o testcase_leak vlib/v/tests/testcase_leak.vv ./testcase_leak 2>leaks.txt - grep "Found 1 leaked object" leaks.txt && grep ", sz=1000," leaks.txt + grep "Found 1 leaked object" leaks.txt && grep -P ", sz=\s?1000," leaks.txt - name: Test leak detector not being active for `-gc boehm` run: | ./v -gc boehm -o testcase_leak vlib/v/tests/testcase_leak.vv diff --git a/thirdparty/libgc/gc.c b/thirdparty/libgc/gc.c index 245909792..014554676 100644 --- a/thirdparty/libgc/gc.c +++ b/thirdparty/libgc/gc.c @@ -27,37 +27,43 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#if!defined(GC_BUILD)&&!defined(NOT_GCBUILD) +#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) +#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) +#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) +#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) +#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) +#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!") +#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_MINOR 2 #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. +#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 @@ -66,12 +72,14 @@ #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)) +#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 +#define GC_GNUC_PREREQ(major, minor) 0 #endif -#if defined(SOLARIS_THREADS)||defined(_SOLARIS_THREADS)||defined(_SOLARIS_PTHREADS)||defined(GC_SOLARIS_PTHREADS) +#if defined(SOLARIS_THREADS) || defined(_SOLARIS_THREADS) \ + || defined(_SOLARIS_PTHREADS) || defined(GC_SOLARIS_PTHREADS) #ifndef GC_SOLARIS_THREADS #define GC_SOLARIS_THREADS #endif @@ -79,7 +87,7 @@ #if defined(IRIX_THREADS) #define GC_IRIX_THREADS #endif -#if defined(DGUX_THREADS)&&!defined(GC_DGUX386_THREADS) +#if defined(DGUX_THREADS) && !defined(GC_DGUX386_THREADS) #define GC_DGUX386_THREADS #endif #if defined(AIX_THREADS) @@ -103,10 +111,16 @@ #if defined(USE_LD_WRAP) #define GC_USE_LD_WRAP #endif -#if defined(GC_WIN32_PTHREADS)&&!defined(GC_WIN32_THREADS) +#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) +#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 @@ -115,66 +129,80 @@ #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)) +#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)) +#elif (defined(__DragonFly__) || defined(__FreeBSD_kernel__) \ + || defined(__FreeBSD__)) && !defined(GC_NO_FREEBSD) #define GC_FREEBSD_THREADS #elif defined(__NetBSD__) #define GC_NETBSD_THREADS -#elif defined(__alpha)||defined(__alpha__) +#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)) +#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__))) +#elif defined(__sparc) \ + || ((defined(sun) || defined(__sun)) \ + && (defined(i386) || defined(__i386__) \ + || defined(__amd64) || defined(__amd64__))) #define GC_SOLARIS_THREADS -#elif defined(__APPLE__)&&defined(__MACH__) +#elif defined(__APPLE__) && defined(__MACH__) #define GC_DARWIN_THREADS #endif -#if defined(DGUX)&&(defined(i386)||defined(__i386__)) +#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) +#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__)) +#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) +#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) +#if !defined(_PTHREADS) && defined(GC_NETBSD_THREADS) #define _PTHREADS #endif -#if defined(GC_DGUX386_THREADS)&&!defined(_POSIX4A_DRAFT10_SOURCE) +#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) +#if !defined(_REENTRANT) && defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) #define _REENTRANT 1 #endif #define __GC -#if!defined(_WIN32_WCE)||defined(__GNUC__) +#if !defined(_WIN32_WCE) || defined(__GNUC__) #include -#if defined(__MINGW32__)&&!defined(_WIN32_WCE) +#if defined(__MINGW32__) && !defined(_WIN32_WCE) #include #endif #else #include #ifndef _PTRDIFF_T_DEFINED #define _PTRDIFF_T_DEFINED -typedef long ptrdiff_t; + typedef long ptrdiff_t; #endif #endif -#if!defined(GC_NOT_DLL)&&!defined(GC_DLL)&&((defined(_DLL)&&!defined(__GNUC__))||(defined(DLL_EXPORT)&&defined(GC_BUILD))) +#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(GC_DLL) && !defined(GC_API) #if defined(__CEGCC__) #if defined(GC_BUILD) #define GC_API __declspec(dllexport) @@ -182,14 +210,15 @@ typedef long ptrdiff_t; #define GC_API __declspec(dllimport) #endif #elif defined(__MINGW32__) -#if defined(__cplusplus)&&defined(GC_BUILD) +#if defined(__cplusplus) && defined(GC_BUILD) #define GC_API extern __declspec(dllexport) -#elif defined(GC_BUILD)||defined(__MINGW32_DELAY_LOAD__) +#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__) +#elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \ + || defined(__CYGWIN__) #ifdef GC_BUILD #define GC_API extern __declspec(dllexport) #else @@ -208,7 +237,8 @@ typedef long ptrdiff_t; #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)) +#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 @@ -225,12 +255,13 @@ typedef long ptrdiff_t; #ifndef GC_ATTR_MALLOC #ifdef GC_OOM_FUNC_RETURNS_ALIAS #define GC_ATTR_MALLOC -#elif GC_GNUC_PREREQ(3,1) +#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) +#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 @@ -239,30 +270,30 @@ typedef long ptrdiff_t; #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))) +#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))) +#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) +#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))) +#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) +#if GC_GNUC_PREREQ(4, 0) #define GC_ATTR_CONST __attribute__((__const__)) #else #define GC_ATTR_CONST @@ -272,55 +303,72 @@ typedef long ptrdiff_t; #ifdef GC_BUILD #undef GC_ATTR_DEPRECATED #define GC_ATTR_DEPRECATED -#elif GC_GNUC_PREREQ(4,0) +#elif GC_GNUC_PREREQ(4, 0) #define GC_ATTR_DEPRECATED __attribute__((__deprecated__)) -#elif defined(_MSC_VER)&&_MSC_VER>=1200 +#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 +#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__) +#if defined(__linux__) || defined(__GLIBC__) +#if !defined(__native_client__) #include #endif -#if (__GLIBC__==2&&__GLIBC_MINOR__>=1||__GLIBC__ > 2)&&!defined(__ia64__)&&!defined(GC_MISSING_EXECINFO_H)&&!defined(GC_HAVE_BUILTIN_BACKTRACE) +#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__) +#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) +#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) +#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) +#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) +#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__)) +#if GC_GNUC_PREREQ(4, 0) && (defined(__i386__) || defined(__amd64__) \ + || defined(__x86_64__) ) \ + && !defined(GC_NO_RETURN_ADDR_PARENT) #define GC_HAVE_RETURN_ADDR_PARENT -#define GC_RETURN_ADDR_PARENT (GC_word)__builtin_extract_return_addr(__builtin_return_address(1)) +#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) +#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) +#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__) @@ -332,9 +380,11 @@ typedef long ptrdiff_t; #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)) +#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) +#if GC_GNUC_PREREQ(2, 7) #define GC_PTHREAD_EXIT_ATTRIBUTE __attribute__((__noreturn__)) #elif defined(__NORETURN) #define GC_PTHREAD_EXIT_ATTRIBUTE __NORETURN @@ -342,25 +392,30 @@ typedef long ptrdiff_t; #define GC_PTHREAD_EXIT_ATTRIBUTE #endif #endif -#if (!defined(GC_HAVE_PTHREAD_EXIT)||defined(__native_client__))&&!defined(GC_NO_PTHREAD_CANCEL) +#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) +#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)) +#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 +#elif __cplusplus >= 201103L || _MSVC_LANG >= 201103L #define GC_NOEXCEPT noexcept #else #define GC_NOEXCEPT throw() @@ -369,59 +424,59 @@ typedef long ptrdiff_t; #endif #endif #ifdef __cplusplus -extern "C" { + extern "C" { #endif -typedef void*GC_PTR; +typedef void * GC_PTR; #ifdef _WIN64 -#if defined(__int64)&&!defined(CPPCHECK) -typedef unsigned __int64 GC_word; -typedef __int64 GC_signed_word; +#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; + typedef unsigned long long GC_word; + typedef long long GC_signed_word; #endif #else -typedef unsigned long GC_word; -typedef long GC_signed_word; + 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); + 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); +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 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); +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_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); +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); +#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); @@ -435,15 +490,15 @@ 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); +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 + GC_ATTR_DEPRECATED #endif -int GC_dont_gc; + 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); @@ -463,7 +518,7 @@ 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 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); @@ -472,8 +527,8 @@ GC_API GC_ATTR_DEPRECATED unsigned long GC_time_limit; 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; + 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); @@ -489,6 +544,8 @@ 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_disable_automatic_collection(int); +GC_API int GC_CALL GC_get_disable_automatic_collection(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); @@ -496,51 +553,51 @@ 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 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_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); +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); @@ -548,29 +605,31 @@ 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*); +GC_API size_t GC_CALL GC_get_obtained_from_os_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_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_word obtained_from_os_bytes; }; -GC_API size_t GC_CALL GC_get_prof_stats(struct GC_prof_stats_s*, -size_t); +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); + 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); @@ -581,316 +640,342 @@ 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_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 void GC_CALL GC_start_incremental_collection(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); +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); +#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) +#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) +#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) +#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))) +#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); + 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_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**); +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_TOGGLE_REF_DROP, + GC_TOGGLE_REF_STRONG, + GC_TOGGLE_REF_WEAK } GC_ToggleRefStatus; -typedef GC_ToggleRefStatus (GC_CALLBACK*GC_toggleref_func)(void*); +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 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") +#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); + GC_API void GC_CALL GC_noop1(GC_word); #ifdef LINT2 -#define GC_reachable_here(ptr)GC_noop1(~(GC_word)(ptr)^(~(GC_word)0)) +#define GC_reachable_here(ptr) GC_noop1(~(GC_word)(ptr)^(~(GC_word)0)) #else -#define GC_reachable_here(ptr)GC_noop1((GC_word)(ptr)) +#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); +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_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); +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) +#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); + 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 +#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); +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; + 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); +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); +#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_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_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)--) +#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*); +#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) +#if defined(GC_H) && defined(GC_PTHREADS) #ifndef GC_PTHREAD_REDIRECTS_ONLY #include #ifndef GC_NO_DLOPEN @@ -900,40 +985,42 @@ GC_API void (GC_CALLBACK*GC_is_visible_print_proc)(void*); #include #endif #ifdef __cplusplus -extern "C" { + 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); + 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*); +#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); + 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); + GC_API int GC_pthread_cancel(pthread_t); #endif -#if defined(GC_HAVE_PTHREAD_EXIT)&&!defined(GC_PTHREAD_EXIT_DECLARED) +#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; + 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) +#if !defined(GC_NO_THREAD_REDIRECTS) && !defined(GC_USE_LD_WRAP) #undef pthread_create #undef pthread_join #undef pthread_detach @@ -960,34 +1047,37 @@ GC_API void GC_pthread_exit(void*)GC_PTHREAD_EXIT_ATTRIBUTE; #endif #endif #ifdef __cplusplus -extern "C" { + 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 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) + 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) +#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__) +#if !defined(_WIN32_WCE) && !defined(__CEGCC__) #include #endif -#if defined(GC_BUILD)||!defined(GC_DONT_INCLUDE_WINDOWS_H) +#if defined(GC_BUILD) || !defined(GC_DONT_INCLUDE_WINDOWS_H) #include #define GC_WINDOWS_H_INCLUDED #endif #ifdef __cplusplus -extern "C" { + extern "C" { #endif #ifdef GC_UNDERSCORE_STDCALL #define GC_CreateThread _GC_CreateThread @@ -1000,10 +1090,11 @@ extern "C" { #define DECLSPEC_NORETURN __declspec(noreturn) #endif #endif -#if!defined(_UINTPTR_T)&&!defined(_UINTPTR_T_DEFINED)&&!defined(UINTPTR_MAX) -typedef GC_word GC_uintptr_t; +#if !defined(_UINTPTR_T) && !defined(_UINTPTR_T_DEFINED) \ + && !defined(UINTPTR_MAX) + typedef GC_word GC_uintptr_t; #else -typedef uintptr_t GC_uintptr_t; + typedef uintptr_t GC_uintptr_t; #endif #ifdef _WIN64 #define GC_WIN32_SIZE_T GC_uintptr_t @@ -1017,37 +1108,37 @@ typedef uintptr_t GC_uintptr_t; #define GC_DllMain _GC_DllMain #endif #ifdef GC_WINDOWS_H_INCLUDED -GC_API BOOL WINAPI GC_DllMain(HINSTANCE, -ULONG, -LPVOID); + GC_API BOOL WINAPI GC_DllMain(HINSTANCE , + ULONG , + LPVOID ); #else -GC_API int __stdcall GC_DllMain(void*,unsigned long,void*); + 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); + 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 @@ -1065,28 +1156,37 @@ GC_API void GC_CALL GC_endthreadex(unsigned); #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__) +#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() + 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) + 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) + 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 @@ -1096,54 +1196,59 @@ GC_API void*GC_CALL GC_find_limit(void*,int); #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) +#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 (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) +#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) +#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) +#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) +#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) +#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) +#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) +#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) +#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 @@ -1152,36 +1257,59 @@ GC_API void*GC_CALL GC_find_limit(void*,int); #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);} +#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;} +#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) + 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 -#if!defined(sony_news) +#if !defined(sony_news) #include #endif #ifdef DGUX @@ -1196,14 +1324,18 @@ extern void*(*GC_amiga_allocwrapper_do)(size_t,void*(GC_CALL*)(size_t)); #endif #ifdef PARALLEL_MARK #define AO_REQUIRE_CAS -#if!defined(__GNUC__)&&!defined(AO_ASSUME_WINDOWS98) +#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__) +#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 @@ -1211,129 +1343,137 @@ extern void*(*GC_amiga_allocwrapper_do)(size_t,void*(GC_CALL*)(size_t)); #define GC_GRANULE_WORDS 2 #endif #endif -#if GC_GRANULE_WORDS==2 -#define GC_WORDS_TO_GRANULES(n)((n)>>1) +#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) +#define GC_WORDS_TO_GRANULES(n) ((n)*sizeof(void *)/GC_GRANULE_BYTES) #endif #ifndef GC_TINY_FREELISTS -#if GC_GRANULE_BYTES==16 +#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) +#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" { + extern "C" { #endif #define GC_PROC_BYTES 100 -#if defined(GC_BUILD)||defined(NOT_GCBUILD) -struct GC_ms_entry; +#if defined(GC_BUILD) || defined(NOT_GCBUILD) + struct GC_ms_entry; #else -struct GC_ms_entry { void*opaque;}; + 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); +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_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 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())) +#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); + 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); +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) +#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) +#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*); +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_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 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); +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*); +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); + 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; @@ -1343,23 +1483,24 @@ typedef int GC_bool; #define TRUE 1 #define FALSE 0 #ifndef PTR_T_DEFINED -typedef char*ptr_t; + typedef char * ptr_t; #define PTR_T_DEFINED #endif #ifndef SIZE_MAX #include #endif -#if defined(SIZE_MAX)&&!defined(CPPCHECK) +#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) +#if GC_GNUC_PREREQ(3, 0) && !defined(LINT2) +#define EXPECT(expr, outcome) __builtin_expect(expr,outcome) #else -#define EXPECT(expr,outcome)(expr) +#define EXPECT(expr, outcome) (expr) #endif -#define SIZET_SAT_ADD(a,b)(EXPECT((a)< GC_SIZE_MAX - (b),TRUE)?(a)+(b):GC_SIZE_MAX) +#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 @@ -1371,10 +1512,10 @@ typedef char*ptr_t; #undef _MAX_PATH #endif #ifndef PTR_T_DEFINED -typedef char*ptr_t; + typedef char * ptr_t; #define PTR_T_DEFINED #endif -#if!defined(sony_news) +#if !defined(sony_news) #include #endif #ifdef __cplusplus @@ -1385,31 +1526,36 @@ typedef char*ptr_t; #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))) +#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 +#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)) +#define COVERT_DATAFLOW(w) (~(GC_word)(w)^(~(GC_word)0)) #else -#define COVERT_DATAFLOW(w)((GC_word)(w)) +#define COVERT_DATAFLOW(w) ((GC_word)(w)) #endif -#if defined(__ANDROID__)&&!defined(HOST_ANDROID) +#if defined(__ANDROID__) && !defined(HOST_ANDROID) #define HOST_ANDROID 1 #endif -#if defined(TIZEN)&&!defined(HOST_TIZEN) +#if defined(TIZEN) && !defined(HOST_TIZEN) #define HOST_TIZEN 1 #endif -#if defined(__SYMBIAN32__)&&!defined(SYMBIAN) +#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__) +#if (defined(linux) || defined(__linux__) || defined(HOST_ANDROID)) \ + && !defined(LINUX) && !defined(__native_client__) #define LINUX #endif #if defined(__NetBSD__) @@ -1418,18 +1564,20 @@ EXTERN_C_BEGIN #if defined(__OpenBSD__) #define OPENBSD #endif -#if (defined(__FreeBSD__)||defined(__DragonFly__)||defined(__FreeBSD_kernel__))&&!defined(FREEBSD)&&!defined(SN_TARGET_ORBIS) +#if (defined(__FreeBSD__) || defined(__DragonFly__) \ + || defined(__FreeBSD_kernel__)) && !defined(FREEBSD) \ + && !defined(GC_NO_FREEBSD) #define FREEBSD #endif -#if defined(macosx)||(defined(__APPLE__)&&defined(__MACH__)) +#if defined(macosx) || (defined(__APPLE__) && defined(__MACH__)) #define DARWIN -EXTERN_C_END + EXTERN_C_END #include -EXTERN_C_BEGIN + EXTERN_C_BEGIN #endif #if defined(__native_client__) #define NACL -#if!defined(__portable_native_client__)&&!defined(__arm__) +#if !defined(__portable_native_client__) && !defined(__arm__) #define I386 #define mach_type_known #else @@ -1437,67 +1585,73 @@ EXTERN_C_BEGIN #endif #if defined(__aarch64__) #define AARCH64 -#if!defined(LINUX)&&!defined(DARWIN)&&!defined(FREEBSD)&&!defined(NETBSD)&&!defined(NN_BUILD_TARGET_PLATFORM_NX)&&!defined(OPENBSD) +#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__) +#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) +#elif !defined(LINUX) && !defined(NETBSD) && !defined(FREEBSD) \ + && !defined(OPENBSD) && !defined(DARWIN) && !defined(_WIN32) \ + && !defined(__CEGCC__) && !defined(NN_PLATFORM_CTR) \ + && !defined(GC_NO_NOSYS) && !defined(SN_TARGET_PSP2) \ + && !defined(SYMBIAN) #define NOSYS #define mach_type_known #endif #endif -#if defined(sun)&&defined(mc68000)&&!defined(CPPCHECK) +#if defined(sun) && defined(mc68000) && !defined(CPPCHECK) #error SUNOS4 no longer supported #endif -#if defined(hp9000s300)&&!defined(CPPCHECK) +#if defined(hp9000s300) && !defined(CPPCHECK) #error M68K based HP machines no longer supported #endif -#if defined(OPENBSD)&&defined(m68k) +#if defined(OPENBSD) && defined(m68k) #define M68K #define mach_type_known #endif -#if defined(OPENBSD)&&defined(__sparc__) +#if defined(OPENBSD) && defined(__sparc__) #define SPARC #define mach_type_known #endif -#if defined(OPENBSD)&&defined(__arm__) +#if defined(OPENBSD) && defined(__arm__) #define ARM32 #define mach_type_known #endif -#if defined(OPENBSD)&&defined(__aarch64__) +#if defined(OPENBSD) && defined(__aarch64__) #define AARCH64 #define mach_type_known #endif -#if defined(OPENBSD)&&defined(__sh__) +#if defined(OPENBSD) && defined(__sh__) #define SH #define mach_type_known #endif -#if defined(NETBSD)&&(defined(m68k)||defined(__m68k__)) +#if defined(NETBSD) && (defined(m68k) || defined(__m68k__)) #define M68K #define mach_type_known #endif -#if defined(NETBSD)&&defined(__powerpc__) +#if defined(NETBSD) && defined(__powerpc__) #define POWERPC #define mach_type_known #endif -#if defined(NETBSD)&&(defined(__arm32__)||defined(__arm__)) +#if defined(NETBSD) && (defined(__arm32__) || defined(__arm__)) #define ARM32 #define mach_type_known #endif -#if defined(NETBSD)&&defined(__aarch64__) +#if defined(NETBSD) && defined(__aarch64__) #define AARCH64 #define mach_type_known #endif -#if defined(NETBSD)&&defined(__sh__) +#if defined(NETBSD) && defined(__sh__) #define SH #define mach_type_known #endif -#if defined(vax)||defined(__vax__) +#if defined(vax) || defined(__vax__) #define VAX #ifdef ultrix #define ULTRIX @@ -1506,23 +1660,24 @@ EXTERN_C_BEGIN #endif #define mach_type_known #endif -#if defined(NETBSD)&&defined(__vax__) +#if defined(NETBSD) && defined(__vax__) #define VAX #define mach_type_known #endif -#if defined(mips)||defined(__mips)||defined(_mips) +#if defined(mips) || defined(__mips) || defined(_mips) #define MIPS -#if defined(nec_ews)||defined(_nec_ews) +#if defined(nec_ews) || defined(_nec_ews) #define EWS4800 #endif -#if!defined(LINUX)&&!defined(EWS4800)&&!defined(NETBSD)&&!defined(OPENBSD) -#if defined(ultrix)||defined(__ultrix) +#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__) +#if defined(NETBSD) && defined(__MIPSEL__) #undef ULTRIX #endif #define mach_type_known @@ -1531,7 +1686,7 @@ EXTERN_C_BEGIN #define I386 #define mach_type_known #endif -#if defined(__NIOS2__)||defined(__NIOS2)||defined(__nios2__) +#if defined(__NIOS2__) || defined(__NIOS2) || defined(__nios2__) #define NIOS2 #define mach_type_known #endif @@ -1539,44 +1694,45 @@ EXTERN_C_BEGIN #define OR1K #define mach_type_known #endif -#if defined(DGUX)&&(defined(i386)||defined(__i386__)) +#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__)) +#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__)) +#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) +#if (defined(sun) || defined(__sun)) && defined(__amd64) #define X86_64 #define SOLARIS #define mach_type_known #endif -#if (defined(__OS2__)||defined(__EMX__))&&defined(__32BIT__) +#if (defined(__OS2__) || defined(__EMX__)) && defined(__32BIT__) #define I386 #define OS2 #define mach_type_known #endif -#if defined(ibm032)&&!defined(CPPCHECK) +#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 +#if (defined(sun) || defined(__sun)) && (defined(sparc) || defined(__sparc)) + EXTERN_C_END #include -EXTERN_C_BEGIN + 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) +#elif defined(sparc) && defined(unix) && !defined(sun) && !defined(linux) \ + && !defined(FREEBSD) && !defined(NETBSD) && !defined(OPENBSD) #define SPARC #define DRSNX #define mach_type_known @@ -1586,11 +1742,11 @@ EXTERN_C_BEGIN #define AIX #define mach_type_known #endif -#if defined(NETBSD)&&defined(__sparc__) +#if defined(NETBSD) && defined(__sparc__) #define SPARC #define mach_type_known #endif -#if defined(_M_XENIX)&&defined(_M_SYSV)&&defined(_M_I386) +#if defined(_M_XENIX) && defined(_M_SYSV) && defined(_M_I386) #define I386 #if defined(_SCO_ELF) #define SCO_ELF @@ -1599,120 +1755,129 @@ EXTERN_C_BEGIN #endif #define mach_type_known #endif -#if defined(_AUX_SOURCE)&&!defined(CPPCHECK) +#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__) +#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) +#if !defined(LINUX) && !defined(HPUX) && !defined(OPENBSD) #define HPUX #endif #define mach_type_known #endif -#if defined(__ia64)&&(defined(_HPUX_SOURCE)||defined(__HP_aCC)) +#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_) +#if (defined(__BEOS__) || defined(__HAIKU__)) && defined(_X86_) #define I386 #define HAIKU #define mach_type_known #endif -#if defined(__HAIKU__)&&(defined(__amd64__)||defined(__x86_64__)) +#if defined(__HAIKU__) && (defined(__amd64__) || defined(__x86_64__)) #define X86_64 #define HAIKU #define mach_type_known #endif -#if defined(OPENBSD)&&defined(__amd64__) +#if defined(OPENBSD) && defined(__amd64__) #define X86_64 #define mach_type_known #endif -#if defined(LINUX)&&(defined(i386)||defined(__i386__)) +#if defined(LINUX) && (defined(i386) || defined(__i386__)) #define I386 #define mach_type_known #endif -#if defined(LINUX)&&defined(__x86_64__) +#if defined(LINUX) && defined(__x86_64__) #define X86_64 #define mach_type_known #endif -#if defined(LINUX)&&(defined(__ia64__)||defined(__ia64)) +#if defined(LINUX) && (defined(__ia64__) || defined(__ia64)) #define IA64 #define mach_type_known #endif -#if defined(LINUX)&&defined(__aarch64__) +#if defined(LINUX) && defined(__aarch64__) #define AARCH64 #define mach_type_known #endif -#if defined(LINUX)&&(defined(__arm)||defined(__arm__)) +#if defined(LINUX) && (defined(__arm) || defined(__arm__)) #define ARM32 #define mach_type_known #endif -#if defined(LINUX)&&defined(__cris__) +#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__)) +#if defined(LINUX) && defined(__loongarch__) +#define LOONGARCH +#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__) +#if defined(LINUX) && defined(__mc68000__) #define M68K #define mach_type_known #endif -#if defined(LINUX)&&(defined(sparc)||defined(__sparc__)) +#if defined(LINUX) && (defined(sparc) || defined(__sparc__)) #define SPARC #define mach_type_known #endif -#if defined(LINUX)&&defined(__sh__) +#if defined(LINUX) && defined(__sh__) #define SH #define mach_type_known #endif -#if defined(LINUX)&&defined(__avr32__) +#if defined(LINUX) && defined(__avr32__) #define AVR32 #define mach_type_known #endif -#if defined(LINUX)&&defined(__m32r__) +#if defined(LINUX) && defined(__m32r__) #define M32R #define mach_type_known #endif -#if defined(__alpha)||defined(__alpha__) +#if defined(__alpha) || defined(__alpha__) #define ALPHA -#if!defined(LINUX)&&!defined(NETBSD)&&!defined(OPENBSD)&&!defined(FREEBSD) +#if !defined(LINUX) && !defined(NETBSD) && !defined(OPENBSD) \ + && !defined(FREEBSD) #define OSF1 #endif #define mach_type_known #endif -#if defined(_AMIGA)&&!defined(AMIGA) +#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)) +#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) +#if defined(__MWERKS__) && defined(__powerc) && !defined(__MACH__) \ + && !defined(SYMBIAN) #define POWERPC #define MACOS #define mach_type_known #endif -#if defined(OPENBSD)&&defined(__powerpc__) +#if defined(OPENBSD) && defined(__powerpc__) #define POWERPC #define mach_type_known #endif #if defined(DARWIN) -#if defined(__ppc__)||defined(__ppc64__) +#if defined(__ppc__) || defined(__ppc64__) #define POWERPC #define mach_type_known -#elif defined(__x86_64__)||defined(__x86_64) +#elif defined(__x86_64__) || defined(__x86_64) #define X86_64 #define mach_type_known #elif defined(__i386__) @@ -1726,95 +1891,97 @@ EXTERN_C_BEGIN #define mach_type_known #endif #endif -#if defined(__rtems__)&&(defined(i386)||defined(__i386__)) +#if defined(__rtems__) && (defined(i386) || defined(__i386__)) #define I386 #define RTEMS #define mach_type_known #endif -#if defined(NeXT)&&defined(mc68000) +#if defined(NeXT) && defined(mc68000) #define M68K #define NEXT #define mach_type_known #endif -#if defined(NeXT)&&(defined(i386)||defined(__i386__)) +#if defined(NeXT) && (defined(i386) || defined(__i386__)) #define I386 #define NEXT #define mach_type_known #endif -#if defined(OPENBSD)&&(defined(i386)||defined(__i386__)) +#if defined(OPENBSD) && (defined(i386) || defined(__i386__)) #define I386 #define mach_type_known #endif -#if defined(NETBSD)&&(defined(i386)||defined(__i386__)) +#if defined(NETBSD) && (defined(i386) || defined(__i386__)) #define I386 #define mach_type_known #endif -#if defined(NETBSD)&&defined(__x86_64__) +#if defined(NETBSD) && defined(__x86_64__) #define X86_64 #define mach_type_known #endif -#if defined(FREEBSD)&&(defined(i386)||defined(__i386__)) +#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__)) +#if defined(FREEBSD) && (defined(__amd64__) || defined(__x86_64__)) #define X86_64 #define mach_type_known #endif -#if defined(FREEBSD)&&defined(__sparc__) +#if defined(FREEBSD) && defined(__sparc__) #define SPARC #define mach_type_known #endif -#if defined(FREEBSD)&&(defined(powerpc)||defined(__powerpc__)) +#if defined(FREEBSD) && (defined(powerpc) || defined(__powerpc__)) #define POWERPC #define mach_type_known #endif -#if defined(FREEBSD)&&defined(__arm__) +#if defined(FREEBSD) && defined(__arm__) #define ARM32 #define mach_type_known #endif -#if defined(FREEBSD)&&defined(__aarch64__) +#if defined(FREEBSD) && defined(__aarch64__) #define AARCH64 #define mach_type_known #endif -#if defined(FREEBSD)&&(defined(mips)||defined(__mips)||defined(_mips)) +#if defined(FREEBSD) && (defined(mips) || defined(__mips) || defined(_mips)) #define MIPS #define mach_type_known #endif -#if defined(bsdi)&&(defined(i386)||defined(__i386__)) +#if defined(bsdi) && (defined(i386) || defined(__i386__)) #define I386 #define BSDI #define mach_type_known #endif -#if!defined(mach_type_known)&&defined(__386BSD__) +#if !defined(mach_type_known) && defined(__386BSD__) #define I386 #define THREE86BSD #define mach_type_known #endif -#if defined(_CX_UX)&&defined(_M88K) +#if defined(_CX_UX) && defined(_M88K) #define M88K #define CX_UX #define mach_type_known #endif -#if defined(DGUX)&&defined(m88k) +#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) +#if defined(_WIN32_WCE) || defined(__CEGCC__) || defined(__MINGW32CE__) +#if defined(SH3) || defined(SH4) #define SH #endif -#if defined(x86)||defined(__i386__) +#if defined(x86) || defined(__i386__) #define I386 #endif -#if defined(_M_ARM)||defined(ARM)||defined(_ARM_) +#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) +#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 @@ -1829,13 +1996,13 @@ EXTERN_C_BEGIN #ifndef MSWIN32 #define MSWIN32 #endif -#if defined(WINAPI_FAMILY)&&(WINAPI_FAMILY==WINAPI_FAMILY_APP) +#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) +#if defined(_MSC_VER) && defined(_M_IA64) #define IA64 #define MSWIN32 #endif @@ -1847,7 +2014,7 @@ EXTERN_C_BEGIN #endif #define mach_type_known #endif -#if defined(__CYGWIN32__)||defined(__CYGWIN__) +#if defined(__CYGWIN32__) || defined(__CYGWIN__) #if defined(__LP64__) #define X86_64 #else @@ -1861,7 +2028,7 @@ EXTERN_C_BEGIN #define INTERIX #define mach_type_known #endif -#if defined(__MINGW32__)&&!defined(mach_type_known) +#if defined(__MINGW32__) && !defined(mach_type_known) #define I386 #define MSWIN32 #define mach_type_known @@ -1871,26 +2038,26 @@ EXTERN_C_BEGIN #define MSWIN32 #define mach_type_known #endif -#if defined(_UTS)&&!defined(mach_type_known) +#if defined(_UTS) && !defined(mach_type_known) #define S370 #define UTS4 #define mach_type_known #endif -#if defined(__pj__)&&!defined(CPPCHECK) +#if defined(__pj__) && !defined(CPPCHECK) #error PicoJava no longer supported #endif -#if defined(__embedded__)&&defined(PPC) +#if defined(__embedded__) && defined(PPC) #define POWERPC #define NOSYS #define mach_type_known #endif -#if defined(__WATCOMC__)&&defined(__386__) +#if defined(__WATCOMC__) && defined(__386__) #define I386 -#if!defined(OS2)&&!defined(MSWIN32)&&!defined(DOS4GW) +#if !defined(OS2) && !defined(MSWIN32) && !defined(DOS4GW) #if defined(__OS2__) #define OS2 #else -#if defined(__WINDOWS_386__)||defined(__NT__) +#if defined(__WINDOWS_386__) || defined(__NT__) #define MSWIN32 #else #define DOS4GW @@ -1899,15 +2066,15 @@ EXTERN_C_BEGIN #endif #define mach_type_known #endif -#if defined(__s390__)&&defined(LINUX) +#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 +#define HURD +#define I386 +#define mach_type_known #endif #endif #if defined(__TANDEM) @@ -1915,15 +2082,15 @@ EXTERN_C_BEGIN #define NONSTOP #define mach_type_known #endif -#if defined(__arc__)&&defined(LINUX) +#if defined(__arc__) && defined(LINUX) #define ARC #define mach_type_known #endif -#if defined(__hexagon__)&&defined(LINUX) +#if defined(__hexagon__) && defined(LINUX) #define HEXAGON #define mach_type_known #endif -#if defined(__tile__)&&defined(LINUX) +#if defined(__tile__) && defined(LINUX) #ifdef __tilegx__ #define TILEGX #else @@ -1931,7 +2098,7 @@ EXTERN_C_BEGIN #endif #define mach_type_known #endif -#if defined(__riscv)&&(defined(FREEBSD)||defined(LINUX)) +#if defined(__riscv) && (defined(FREEBSD) || defined(LINUX)) #define RISCV #define mach_type_known #endif @@ -1949,15 +2116,179 @@ EXTERN_C_BEGIN #define mach_type_known #endif #if defined(__EMSCRIPTEN__) +#define EMSCRIPTEN #define I386 #define mach_type_known #endif -#if!defined(mach_type_known)&&!defined(CPPCHECK) +#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__) +#if GC_GNUC_PREREQ(2, 8) \ + && !GC_GNUC_PREREQ(11, 0) \ + && !defined(__INTEL_COMPILER) && !defined(__PATHCC__) \ + && !defined(__FUJITSU) \ + && !(defined(POWERPC) && defined(DARWIN)) \ + && !defined(RTEMS) \ + && !defined(__ARMCC_VERSION) \ + && (!defined(__clang__) \ + || GC_CLANG_PREREQ(8, 0) ) #define HAVE_BUILTIN_UNWIND_INIT #endif +#ifdef CYGWIN32 +#define OS_TYPE "CYGWIN32" +#define RETRY_GET_THREAD_CONTEXT +#ifdef USE_WINALLOC +#define GWW_VDB +#elif defined(USE_MMAP) +#define USE_MMAP_ANON +#endif +#endif +#ifdef DARWIN +#define OS_TYPE "DARWIN" +#define DYNAMIC_LOADING +#define DATASTART ((ptr_t)get_etext()) +#define DATAEND ((ptr_t)get_end()) +#define USE_MMAP_ANON + EXTERN_C_END +#include + EXTERN_C_BEGIN +#define GETPAGESIZE() (unsigned)getpagesize() +#define NO_PTHREAD_TRYLOCK +#endif +#ifdef FREEBSD +#define OS_TYPE "FREEBSD" +#define FREEBSD_STACKBOTTOM +#ifdef __ELF__ +#define DYNAMIC_LOADING +#endif +#if !defined(ALPHA) && !defined(SPARC) + extern char etext[]; +#define DATASTART GC_FreeBSDGetDataStart(0x1000, (ptr_t)etext) +#define DATASTART_USES_BSDGETDATASTART +#ifndef GC_FREEBSD_THREADS +#define MPROTECT_VDB +#endif +#endif +#endif +#ifdef HAIKU +#define OS_TYPE "HAIKU" +#define DYNAMIC_LOADING +#define MPROTECT_VDB + EXTERN_C_END +#include + EXTERN_C_BEGIN +#define GETPAGESIZE() (unsigned)B_PAGE_SIZE +#endif +#ifdef HPUX +#define OS_TYPE "HPUX" + extern int __data_start[]; +#define DATASTART ((ptr_t)(__data_start)) +#ifdef USE_MMAP +#define USE_MMAP_ANON +#endif +#define DYNAMIC_LOADING + EXTERN_C_END +#include + EXTERN_C_BEGIN +#define GETPAGESIZE() (unsigned)sysconf(_SC_PAGE_SIZE) +#endif +#ifdef LINUX +#define OS_TYPE "LINUX" + EXTERN_C_END +#include + EXTERN_C_BEGIN +#define COUNT_UNMAPPED_REGIONS +#if !defined(MIPS) && !defined(POWERPC) +#define LINUX_STACKBOTTOM +#endif +#if defined(__ELF__) && !defined(IA64) +#define DYNAMIC_LOADING +#endif +#if defined(__ELF__) && !defined(ARC) && !defined(RISCV) \ + && !defined(S390) && !defined(TILEGX) && !defined(TILEPRO) + extern int _end[]; +#define DATAEND ((ptr_t)(_end)) +#endif +#endif +#ifdef MACOS +#define OS_TYPE "MACOS" +#ifndef __LOWMEM__ + EXTERN_C_END +#include + EXTERN_C_BEGIN +#endif +#define STACKBOTTOM ((ptr_t)LMGetCurStackBase()) +#define DATAEND +#endif +#ifdef MSWIN32 +#define OS_TYPE "MSWIN32" +#define DATAEND +#define GWW_VDB +#endif +#ifdef MSWINCE +#define OS_TYPE "MSWINCE" +#define DATAEND +#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 +#elif !defined(MIPS) + extern char etext[]; +#define DATASTART ((ptr_t)(etext)) +#endif +#endif +#ifdef NEXT +#define OS_TYPE "NEXT" +#define DATASTART ((ptr_t)get_etext()) +#define DATASTART_IS_FUNC +#define DATAEND +#endif +#ifdef OPENBSD +#define OS_TYPE "OPENBSD" +#if !defined(M68K) +#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 SOLARIS +#define OS_TYPE "SOLARIS" + extern int _etext[], _end[]; + ptr_t GC_SysVGetDataStart(size_t, ptr_t); +#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 +#ifndef GC_THREADS +#define MPROTECT_VDB +#endif +#define DYNAMIC_LOADING + EXTERN_C_END +#include +#include + EXTERN_C_BEGIN +#ifdef USERLIMIT +#define STACKBOTTOM ((ptr_t)USRSTACK) +#else +#define HEURISTIC2 +#endif +#endif +#define STACK_GRAN 0x1000000 #ifdef SYMBIAN #define MACH_TYPE "SYMBIAN" #define OS_TYPE "SYMBIAN" @@ -1966,95 +2297,54 @@ EXTERN_C_BEGIN #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; + extern ptr_t GC_data_start; #define DATASTART GC_data_start #define DYNAMIC_LOADING #else -extern char etext[]; + 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) +#if !defined(REDIRECT_MALLOC) #define MPROTECT_VDB #endif #ifdef __ELF__ -#define DYNAMIC_LOADING -EXTERN_C_END -#include -EXTERN_C_BEGIN -#if defined(__GLIBC__)&&__GLIBC__>=2 +#if defined(__GLIBC__) && __GLIBC__ >= 2 #define SEARCH_FOR_DATA_START #else -extern char**__environ; + 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)) + extern int etext[]; +#define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff)) #endif #endif #ifdef AMIGA #define OS_TYPE "AMIGA" #define DATAEND -#define GETPAGESIZE()4096 +#define GETPAGESIZE() 4096 #endif #ifdef MACOS -#ifndef __LOWMEM__ -EXTERN_C_END -#include -EXTERN_C_BEGIN -#endif -#define OS_TYPE "MACOS" -#define STACKBOTTOM ((ptr_t)LMGetCurStackBase()) -#define DATAEND -#define GETPAGESIZE()4096 +#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 -EXTERN_C_BEGIN -#endif -#define OS_TYPE "MACOS" -#define STACKBOTTOM ((ptr_t)LMGetCurStackBase()) -#define DATAEND #endif #ifdef LINUX #if defined(__powerpc64__) @@ -2066,22 +2356,21 @@ EXTERN_C_BEGIN #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)) +#if !defined(REDIRECT_MALLOC) +#define MPROTECT_VDB +#endif +#ifndef SOFT_VDB +#define SOFT_VDB +#endif #endif #ifdef DARWIN -#define OS_TYPE "DARWIN" -#define DYNAMIC_LOADING #if defined(__ppc64__) #define ALIGNMENT 8 #define CPP_WORDSZ 64 @@ -2094,36 +2383,21 @@ extern int _end[]; #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 -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))) +#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__) @@ -2135,33 +2409,19 @@ extern int _end[]; #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; + 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()) @@ -2181,16 +2441,16 @@ extern int __bss_start; #define STACKBOTTOM ((ptr_t)((ulong)&errno)) #endif #define USE_MMAP_ANON -extern int _data[],_end[]; + extern int _data[], _end[]; #define DATASTART ((ptr_t)((ulong)_data)) #define DATAEND ((ptr_t)((ulong)_end)) -extern int errno; + extern int errno; #define DYNAMIC_LOADING #endif #ifdef NOSYS -#define ALIGNMENT 4 #define OS_TYPE "NOSYS" -extern void __end[],__dso_handle[]; +#define ALIGNMENT 4 + extern void __end[], __dso_handle[]; #define DATASTART ((ptr_t)__dso_handle) #define DATAEND ((ptr_t)(__end)) #undef STACK_GRAN @@ -2204,20 +2464,20 @@ extern void __end[],__dso_handle[]; #define DYNAMIC_LOADING #endif #define DATASTART ((ptr_t)0x10020000) -extern int _end[]; + 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 GETPAGESIZE() 65536 #define MAX_NACL_GC_THREADS 1024 #endif #ifdef VAX #define MACH_TYPE "VAX" #define ALIGNMENT 4 -extern char etext[]; + extern char etext[]; #define DATASTART ((ptr_t)(etext)) #ifdef BSD #define OS_TYPE "BSD" @@ -2230,7 +2490,7 @@ extern char etext[]; #endif #ifdef SPARC #define MACH_TYPE "SPARC" -#if defined(__arch64__)||defined(__sparcv9) +#if defined(__arch64__) || defined(__sparcv9) #define ALIGNMENT 8 #define CPP_WORDSZ 64 #define ELF_CLASS ELFCLASS64 @@ -2239,103 +2499,50 @@ extern char etext[]; #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 DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)_etext) #define PROC_VDB -EXTERN_C_END -#include -#include -EXTERN_C_BEGIN -#ifdef USERLIMIT -#define STACKBOTTOM ((ptr_t)USRSTACK) -#else -#define HEURISTIC2 -#endif -#define GETPAGESIZE()(unsigned)sysconf(_SC_PAGESIZE) -#define DYNAMIC_LOADING +#define GETPAGESIZE() (unsigned)sysconf(_SC_PAGESIZE) #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) + 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) +#if !defined(__ELF__) && !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); + extern int _etext[]; + ptr_t GC_SysVGetDataStart(size_t, ptr_t); #ifdef __arch64__ -#define DATASTART GC_SysVGetDataStart(0x100000,(ptr_t)_etext) +#define DATASTART GC_SysVGetDataStart(0x100000, (ptr_t)_etext) #else -#define DATASTART GC_SysVGetDataStart(0x10000,(ptr_t)_etext) +#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[]; + 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) + 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)) @@ -2344,7 +2551,7 @@ void*GC_find_limit(void*,int); #endif #ifdef I386 #define MACH_TYPE "I386" -#if (defined(__LP64__)||defined(_WIN64))&&!defined(CPPCHECK) +#if (defined(__LP64__) || defined(_WIN64)) && !defined(CPPCHECK) #error This should be handled as X86_64 #else #define CPP_WORDSZ 32 @@ -2352,11 +2559,11 @@ void*GC_find_limit(void*,int); #endif #ifdef SEQUENT #define OS_TYPE "SEQUENT" -extern int etext[]; -#define DATASTART ((ptr_t)((((word)(etext))+0xfff)&~0xfff)) + extern int etext[]; +#define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff)) #define STACKBOTTOM ((ptr_t)0x3ffff000) #endif -#if defined(__EMSCRIPTEN__) +#ifdef EMSCRIPTEN #define OS_TYPE "EMSCRIPTEN" #define DATASTART (ptr_t)ALIGNMENT #define DATAEND (ptr_t)ALIGNMENT @@ -2367,62 +2574,31 @@ extern int etext[]; #define OS_TYPE "QNX" #define SA_RESTART 0 #define HEURISTIC1 -extern char etext[]; -extern int _end[]; + 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 -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 + extern int etext[]; +#define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff)) #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 -EXTERN_C_BEGIN -#ifdef USERLIMIT -#define STACKBOTTOM ((ptr_t)USRSTACK) -#else -#define HEURISTIC2 -#endif +#define DATASTART GC_SysVGetDataStart(0x1000, (ptr_t)_etext) #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)) + 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[]; + extern int etext[]; #define DATASTART ((ptr_t)(etext)) #define STACKBOTTOM ((ptr_t)0x08048000) #define DYNAMIC_LOADING @@ -2430,94 +2606,95 @@ extern int etext[]; #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)) + 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 + EXTERN_C_END #include -EXTERN_C_BEGIN -#define GETPAGESIZE()(unsigned)sysconf(_SC_PAGESIZE) + 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 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) +#if !defined(REDIRECT_MALLOC) #define MPROTECT_VDB #else #endif #define HEAP_START (ptr_t)0x1000 #ifdef __ELF__ -#define DYNAMIC_LOADING -EXTERN_C_END -#include -EXTERN_C_BEGIN -#if defined(__GLIBC__)&&__GLIBC__>=2||defined(HOST_ANDROID)||defined(HOST_TIZEN) +#if defined(__GLIBC__) && __GLIBC__ >= 2 \ + || defined(HOST_ANDROID) || defined(HOST_TIZEN) #define SEARCH_FOR_DATA_START #else -extern char**__environ; + 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))) +#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)) + 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))) +#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))) +#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))) +#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__) +#if defined(__GLIBC__) && !defined(__UCLIBC__) \ + && !defined(GLIBC_TSX_BUG_FIXED) #define GLIBC_2_19_TSX_BUG -EXTERN_C_END + EXTERN_C_END #include -EXTERN_C_BEGIN + EXTERN_C_BEGIN +#endif +#ifndef SOFT_VDB +#define SOFT_VDB #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 +#define DATAEND ((ptr_t)GC_DATAEND) +#ifndef USE_WINALLOC # #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__[]; + 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 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 @@ -2525,92 +2702,60 @@ extern int _bss_end__[]; #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 + 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)) + 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 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" +#define HEURISTIC2 + extern char etext[]; +#define DATASTART ((ptr_t)(etext)) #endif #ifdef BSDI #define OS_TYPE "BSDI" -#endif -#if defined(NETBSD)||defined(THREE86BSD)||defined(BSDI) #define HEURISTIC2 -extern char etext[]; + 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 + EXTERN_C_END #include -EXTERN_C_BEGIN -extern int etext[]; -void*rtems_get_stack_bottom(void); + 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) @@ -2619,11 +2764,11 @@ void*rtems_get_stack_bottom(void); #endif #ifdef DOS4GW #define OS_TYPE "DOS4GW" -extern long __nullarea; -extern char _end; -extern char*_STACKTOP; -#pragma aux __nullarea "*"; -#pragma aux _end "*"; + 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)) @@ -2635,26 +2780,16 @@ extern char*_STACKTOP; #define SIG_SUSPEND SIGUSR1 #define SIG_THR_RESTART SIGUSR2 #define SEARCH_FOR_DATA_START -extern int _end[]; + 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 -EXTERN_C_BEGIN -#define GETPAGESIZE()(unsigned)getpagesize() -#define NO_PTHREAD_TRYLOCK -#if TARGET_OS_IPHONE&&!defined(NO_DYLD_BIND_FULLY_IMAGE) +#if TARGET_OS_IPHONE && !defined(NO_DYLD_BIND_FULLY_IMAGE) #define NO_DYLD_BIND_FULLY_IMAGE #endif #endif @@ -2662,21 +2797,26 @@ EXTERN_C_BEGIN #ifdef NS32K #define MACH_TYPE "NS32K" #define ALIGNMENT 4 -extern char**environ; + extern char **environ; #define DATASTART ((ptr_t)(&environ)) #define STACKBOTTOM ((ptr_t)0xfffff000) #endif +#ifdef LOONGARCH +#define MACH_TYPE "LoongArch" +#ifdef LINUX +#pragma weak __data_start + extern int __data_start[]; +#define DATASTART ((ptr_t)(__data_start)) +#define CPP_WORDSZ _LOONGARCH_SZPTR +#define ALIGNMENT (_LOONGARCH_SZPTR/8) +#endif +#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[]; + 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) @@ -2686,51 +2826,54 @@ extern int __data_start[]; #ifndef HBLKSIZE #define HBLKSIZE 4096 #endif -#if __GLIBC__==2&&__GLIBC_MINOR__>=2||__GLIBC__ > 2 +#if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2 || __GLIBC__ > 2 #define LINUX_STACKBOTTOM #else #define STACKBOTTOM ((ptr_t)0x7fff8000) #endif #endif #ifdef EWS4800 +#define OS_TYPE "EWS4800" #define HEURISTIC2 -#if defined(_MIPS_SZPTR)&&(_MIPS_SZPTR==64) -extern int _fdata[],_end[]; +#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[]; + 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))) + 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 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 OS_TYPE "ULTRIX" #define HEURISTIC2 #define DATASTART ((ptr_t)0x10000000) -#define OS_TYPE "ULTRIX" #define ALIGNMENT 4 #endif #ifdef IRIX5 +#define OS_TYPE "IRIX5" #define HEURISTIC2 -extern int _fdata[]; + 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) @@ -2740,57 +2883,30 @@ extern int _fdata[]; #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 +#ifndef __ELF__ #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 +#ifdef NONSTOP #define OS_TYPE "NONSTOP" +#define CPP_WORDSZ 32 #define ALIGNMENT 4 #define DATASTART ((ptr_t)0x08000000) -extern char**environ; + extern char **environ; #define DATAEND ((ptr_t)(environ - 0x10)) #define STACKBOTTOM ((ptr_t)0x4fffffff) #endif @@ -2799,36 +2915,24 @@ extern char**environ; #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[]; + 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[]; + 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 @@ -2840,54 +2944,31 @@ extern int __data_start[]; #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 +#ifndef GC_THREADS +#define MPROTECT_VDB #endif #ifdef USE_HPUX_FIXED_STACKBOTTOM #define STACKBOTTOM ((ptr_t)0x7b033000) #elif defined(USE_ENVIRON_POINTER) -extern char**environ; + extern char ** environ; #define STACKBOTTOM ((ptr_t)environ) -#elif!defined(HEURISTIC2) +#elif !defined(HEURISTIC2) #define HPUX_MAIN_STACKBOTTOM #define NEED_FIND_LIMIT #endif -#define DYNAMIC_LOADING -EXTERN_C_END -#include -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) +#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 @@ -2895,41 +2976,24 @@ extern int _end[]; #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[]; + 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) + 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)) @@ -2938,30 +3002,26 @@ void*GC_find_limit(void*,int); #ifdef OSF1 #define OS_TYPE "OSF1" #define DATASTART ((ptr_t)0x140000000) -extern int _end[]; + 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))) + 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[]; + extern int _end[]; #define DATAEND ((ptr_t)(_end)) -#if!defined(REDIRECT_MALLOC) +#endif +#if !defined(REDIRECT_MALLOC) #define MPROTECT_VDB #endif #endif @@ -2973,67 +3033,52 @@ extern int _end[]; #define CPP_WORDSZ 32 #define ALIGNMENT 4 #else -#if!defined(_LP64)&&!defined(CPPCHECK) +#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; + extern char ** environ; #define STACKBOTTOM ((ptr_t)environ) #define HPUX_STACKBOTTOM -#define DYNAMIC_LOADING -EXTERN_C_END -#include -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; + 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; + 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) +#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 +#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 -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) + 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 @@ -3045,29 +3090,30 @@ EXTERN_C_BEGIN #ifdef M88K #define MACH_TYPE "M88K" #define ALIGNMENT 4 -extern int etext[]; +#define STACKBOTTOM ((char*)0xf0000000) + extern int etext[]; #ifdef CX_UX #define OS_TYPE "CX_UX" -#define DATASTART ((ptr_t)((((word)(etext)+0x3fffff)&~0x3fffff)+0x10000)) +#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) + 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) + 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 @@ -3086,16 +3132,18 @@ ptr_t GC_SysVGetDataStart(size_t,ptr_t); #endif #endif #ifdef LINUX -#define OS_TYPE "LINUX" -#define LINUX_STACKBOTTOM -#define DYNAMIC_LOADING -#define COUNT_UNMAPPED_REGIONS -extern int __data_start[] __attribute__((__weak__)); + extern int __data_start[] __attribute__((__weak__)); #define DATASTART ((ptr_t)(__data_start)) -extern int _end[] __attribute__((__weak__)); + extern int _end[] __attribute__((__weak__)); #define DATAEND ((ptr_t)(_end)) #define CACHE_LINE_SIZE 256 -#define GETPAGESIZE()4096 +#define GETPAGESIZE() 4096 +#if !defined(REDIRECT_MALLOC) +#define MPROTECT_VDB +#endif +#ifndef SOFT_VDB +#define SOFT_VDB +#endif #endif #endif #ifdef AARCH64 @@ -3111,88 +3159,46 @@ extern int _end[] __attribute__((__weak__)); #define HBLKSIZE 4096 #endif #ifdef LINUX -#define OS_TYPE "LINUX" -#define LINUX_STACKBOTTOM -#define COUNT_UNMAPPED_REGIONS -#if!defined(REDIRECT_MALLOC) +#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[]; + 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 -EXTERN_C_BEGIN -#define GETPAGESIZE()(unsigned)getpagesize() -#define NO_PTHREAD_TRYLOCK -#if TARGET_OS_IPHONE&&!defined(NO_DYLD_BIND_FULLY_IMAGE) +#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[]; + 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); + 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 OS_TYPE "NOSYS" + extern int __data_start[]; #define DATASTART ((ptr_t)__data_start) -extern void*__stack_base__; + extern void *__stack_base__; #define STACKBOTTOM ((ptr_t)__stack_base__) #endif #endif @@ -3205,109 +3211,58 @@ extern void*__stack_base__; #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) +#if !defined(REDIRECT_MALLOC) #define MPROTECT_VDB #endif -#define DYNAMIC_LOADING -EXTERN_C_END -#include -EXTERN_C_BEGIN -#if defined(__GLIBC__)&&__GLIBC__>=2||defined(HOST_ANDROID)||defined(HOST_TIZEN) +#if defined(__GLIBC__) && __GLIBC__ >= 2 \ + || defined(HOST_ANDROID) || defined(HOST_TIZEN) #define SEARCH_FOR_DATA_START #else -extern char**__environ; + 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 -EXTERN_C_BEGIN -#define GETPAGESIZE()(unsigned)getpagesize() -#define NO_PTHREAD_TRYLOCK -#if TARGET_OS_IPHONE&&!defined(NO_DYLD_BIND_FULLY_IMAGE) +#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); + 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[]; + extern unsigned char Image$$ZI$$ZI$$Base[]; #define DATASTART (ptr_t)(Image$$ZI$$ZI$$Base) -extern unsigned char Image$$ZI$$ZI$$Limit[]; + extern unsigned char Image$$ZI$$ZI$$Limit[]; #define DATAEND (ptr_t)(Image$$ZI$$ZI$$Limit) -void*n3ds_get_stack_bottom(void); + 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 OS_TYPE "NOSYS" + extern int __data_start[]; #define DATASTART ((ptr_t)(__data_start)) -extern void*__stack_base__; + extern void *__stack_base__; #define STACKBOTTOM ((ptr_t)(__stack_base__)) #endif #endif @@ -3316,56 +3271,26 @@ extern void*__stack_base__; #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) +#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 +#ifdef MSWINCE #endif #endif #ifdef SH4 #define MACH_TYPE "SH4" #define ALIGNMENT 4 #ifdef MSWINCE -#define OS_TYPE "MSWINCE" -#define DATAEND #endif #endif #ifdef AVR32 @@ -3373,13 +3298,7 @@ extern int _end[]; #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 @@ -3387,13 +3306,7 @@ extern int _end[]; #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 @@ -3411,152 +3324,83 @@ extern int _end[]; #ifndef CACHE_LINE_SIZE #define CACHE_LINE_SIZE 64 #endif -#ifdef SN_TARGET_ORBIS -#define OS_TYPE "SN_TARGET_ORBIS" +#ifdef PLATFORM_GETMEM +#define OS_TYPE "PLATFORM_GETMEM" #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 + EXTERN_C_END +#include + EXTERN_C_BEGIN + void *platform_get_stack_bottom(void); +#define STACKBOTTOM ((ptr_t)platform_get_stack_bottom()) #endif #ifdef LINUX -#define OS_TYPE "LINUX" -#define LINUX_STACKBOTTOM -#if!defined(REDIRECT_MALLOC) +#if !defined(REDIRECT_MALLOC) #define MPROTECT_VDB #else #endif -#define COUNT_UNMAPPED_REGIONS -#define DYNAMIC_LOADING -EXTERN_C_END -#include -EXTERN_C_BEGIN #define SEARCH_FOR_DATA_START -extern int _end[]; -#define DATAEND ((ptr_t)(_end)) -#if defined(__GLIBC__)&&!defined(__UCLIBC__) +#if defined(__GLIBC__) && !defined(__UCLIBC__) #define USE_MMAP_ANON +#endif +#if defined(__GLIBC__) && !defined(__UCLIBC__) \ + && !defined(GETCONTEXT_FPU_BUG_FIXED) #define GETCONTEXT_FPU_EXCMASK_BUG +#endif +#if defined(__GLIBC__) && !defined(__UCLIBC__) \ + && !defined(GLIBC_TSX_BUG_FIXED) #define GLIBC_2_19_TSX_BUG -EXTERN_C_END + EXTERN_C_END #include -EXTERN_C_BEGIN + EXTERN_C_BEGIN +#endif +#ifndef SOFT_VDB +#define SOFT_VDB #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 -EXTERN_C_BEGIN -#define GETPAGESIZE()(unsigned)getpagesize() -#define NO_PTHREAD_TRYLOCK -#if TARGET_OS_IPHONE&&!defined(NO_DYLD_BIND_FULLY_IMAGE) +#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 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 OPENBSD #endif #ifdef HAIKU -#define OS_TYPE "HAIKU" -EXTERN_C_END -#include -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 -EXTERN_C_BEGIN -#ifdef USERLIMIT -#define STACKBOTTOM ((ptr_t)USRSTACK) -#else -#define HEURISTIC2 -#endif +#define DATASTART GC_SysVGetDataStart(0x1000, (ptr_t)_etext) #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 +#ifndef USE_WINALLOC #if defined(THREAD_LOCAL_ALLOC) #else #define MPROTECT_VDB #endif -#ifdef USE_MMAP -#define USE_MMAP_ANON -#endif #endif #endif #ifdef MSWIN_XBOX1 @@ -3564,30 +3408,26 @@ EXTERN_C_BEGIN #define NO_GETENV #define DATASTART (ptr_t)ALIGNMENT #define DATAEND (ptr_t)ALIGNMENT -LONG64 durango_get_stack_bottom(void); + LONG64 durango_get_stack_bottom(void); #define STACKBOTTOM ((ptr_t)durango_get_stack_bottom()) -#define GETPAGESIZE()4096 +#define GETPAGESIZE() 4096 #ifndef USE_MMAP #define USE_MMAP 1 #endif -#define PROT_NONE 0 -#define PROT_READ 1 +#define PROT_NONE 0 +#define PROT_READ 1 #define PROT_WRITE 2 -#define PROT_EXEC 4 +#define PROT_EXEC 4 #define MAP_PRIVATE 2 -#define MAP_FIXED 0x10 -#define MAP_FAILED ((void*)-1) +#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) +#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 @@ -3596,11 +3436,7 @@ LONG64 durango_get_stack_bottom(void); #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__)); + extern int __data_start[] __attribute__((__weak__)); #define DATASTART ((ptr_t)__data_start) #endif #endif @@ -3609,56 +3445,39 @@ extern int __data_start[] __attribute__((__weak__)); #define MACH_TYPE "HEXAGON" #define ALIGNMENT 4 #ifdef LINUX -#define OS_TYPE "LINUX" -#define LINUX_STACKBOTTOM -#if!defined(REDIRECT_MALLOC) +#if !defined(REDIRECT_MALLOC) #define MPROTECT_VDB #endif -#define COUNT_UNMAPPED_REGIONS -#define DYNAMIC_LOADING -EXTERN_C_END -#include -EXTERN_C_BEGIN #if defined(__GLIBC__) #define SEARCH_FOR_DATA_START -#elif!defined(CPPCHECK) +#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 PREFETCH(x) __insn_prefetch(x) #define CACHE_LINE_SIZE 64 #ifdef LINUX -#define OS_TYPE "LINUX" -extern int __data_start[]; + 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 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) +#define CLEAR_DOUBLE(x) (*(long long *)(x) = 0) #endif -#define PREFETCH(x)__insn_prefetch_l1(x) +#define PREFETCH(x) __insn_prefetch_l1(x) #define CACHE_LINE_SIZE 64 #ifdef LINUX -#define OS_TYPE "LINUX" -extern int __data_start[]; + extern int __data_start[]; #define DATASTART ((ptr_t)__data_start) -#define LINUX_STACKBOTTOM -#define COUNT_UNMAPPED_REGIONS -#define DYNAMIC_LOADING #endif #endif #ifdef RISCV @@ -3666,43 +3485,32 @@ extern int __data_start[]; #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__)); + 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) +#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) +#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) +#if defined(USE_MMAP_ANON) && !defined(USE_MMAP) #define USE_MMAP 1 -#elif (defined(LINUX)||defined(OPENBSD))&&defined(USE_MMAP) +#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) +#if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC) \ + && !defined(USE_PROC_FOR_LIBRARIES) #define USE_PROC_FOR_LIBRARIES #endif #ifndef STACK_GROWS_UP @@ -3715,54 +3523,62 @@ extern int __data_start[] __attribute__((__weak__)); #define OS_TYPE "" #endif #ifndef DATAEND -#if!defined(CPPCHECK) -extern int end[]; +#if !defined(CPPCHECK) + extern int end[]; #endif #define DATAEND ((ptr_t)(end)) #endif -#if defined(HOST_ANDROID)&&defined(__clang__)&&!defined(BROKEN_UUENDUU_SYM) +#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) + 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 +#if (defined(SVR4) || defined(HOST_ANDROID) || defined(HOST_TIZEN)) \ + && !defined(GETPAGESIZE) + EXTERN_C_END #include -EXTERN_C_BEGIN -#define GETPAGESIZE()(unsigned)sysconf(_SC_PAGESIZE) + 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 +#if defined(SOLARIS) || defined(IRIX5) || defined(LINUX) \ + || defined(NETBSD) || defined(FREEBSD) || defined(HPUX) + EXTERN_C_END #include -EXTERN_C_BEGIN + EXTERN_C_BEGIN #endif -#define GETPAGESIZE()(unsigned)getpagesize() +#define GETPAGESIZE() (unsigned)getpagesize() #endif -#if defined(HOST_ANDROID)&&!(__ANDROID_API__>=23)&&((defined(MIPS)&&(CPP_WORDSZ==32))||defined(ARM32)||defined(I386)) +#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) +#if defined(SOLARIS) || defined(DRSNX) || defined(UTS4) #define SVR4 #endif -#if defined(SOLARIS)||defined(DRSNX) +#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)) +#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) +#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) +#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)) +#if !defined(NO_MARKER_SPECIAL_SIGMASK) \ + && (defined(NACL) || defined(GC_WIN32_PTHREADS)) #define NO_MARKER_SPECIAL_SIGMASK #endif #ifdef GC_NETBSD_THREADS @@ -3771,23 +3587,26 @@ EXTERN_C_BEGIN #define GC_NETBSD_THREADS_WORKAROUND #endif #ifdef GC_OPENBSD_THREADS -EXTERN_C_END + EXTERN_C_END #include -EXTERN_C_BEGIN + 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) +#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 +#define CPP_WORDSZ (__SIZEOF_POINTER__ * 8) +#elif CPP_WORDSZ != 32 && CPP_WORDSZ != 64 #error Bad word size #endif -#if!defined(ALIGNMENT)&&!defined(CPPCHECK) +#if !defined(ALIGNMENT) && !defined(CPPCHECK) #error Undefined ALIGNMENT #endif #ifdef PCR @@ -3799,39 +3618,65 @@ EXTERN_C_BEGIN #undef MPROTECT_VDB #define PCR_VDB #endif -#if!defined(STACKBOTTOM)&&(defined(ECOS)||defined(NOSYS))&&!defined(CPPCHECK) +#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) +#if defined(SMALL_CONFIG) && !defined(GC_DISABLE_INCREMENTAL) #define GC_DISABLE_INCREMENTAL #endif -#if (defined(MSWIN32)||defined(MSWINCE))&&!defined(USE_WINALLOC) +#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)) +#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)) +#if defined(USE_MUNMAP) && !defined(MUNMAP_THRESHOLD) \ + && (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(USE_MUNMAP) && defined(COUNT_UNMAPPED_REGIONS) \ + && !defined(GC_UNMAPPED_REGIONS_SOFT_LIMIT) #if defined(__DragonFly__) -#define GC_UNMAPPED_REGIONS_SOFT_LIMIT (1000000/4) +#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) +#if defined(GC_DISABLE_INCREMENTAL) || defined(DEFAULT_VDB) #undef GWW_VDB #undef MPROTECT_VDB #undef PCR_VDB #undef PROC_VDB +#undef SOFT_VDB +#endif +#ifdef NO_GWW_VDB +#undef GWW_VDB +#endif +#ifdef NO_MPROTECT_VDB +#undef MPROTECT_VDB +#endif +#ifdef NO_SOFT_VDB +#undef SOFT_VDB +#endif +#if defined(SOFT_VDB) && defined(SOFT_VDB_LINUX_VER_STATIC_CHECK) + EXTERN_C_END +#include + EXTERN_C_BEGIN +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0) +#undef SOFT_VDB +#endif #endif #ifdef GC_DISABLE_INCREMENTAL #undef CHECKSUMS @@ -3842,46 +3687,62 @@ EXTERN_C_BEGIN #if defined(BASE_ATOMIC_OPS_EMULATED) #undef MPROTECT_VDB #endif -#if defined(USE_PROC_FOR_LIBRARIES)&&defined(GC_LINUX_THREADS) +#if defined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS) #undef MPROTECT_VDB #endif -#if defined(MPROTECT_VDB)&&defined(GC_PREFER_MPROTECT_VDB) +#if defined(MPROTECT_VDB) && defined(GC_PREFER_MPROTECT_VDB) #undef PCR_VDB #undef PROC_VDB #endif #ifdef PROC_VDB #undef MPROTECT_VDB +#undef SOFT_VDB #endif -#if defined(MPROTECT_VDB)&&!defined(MSWIN32)&&!defined(MSWINCE) +#if defined(MPROTECT_VDB) && !defined(MSWIN32) && !defined(MSWINCE) #include #endif -#if defined(SIGBUS)&&!defined(HAVE_SIGBUS)&&!defined(CPPCHECK) +#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) +#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) +#if !defined(PCR_VDB) && !defined(PROC_VDB) && !defined(MPROTECT_VDB) \ + && !defined(GWW_VDB) && !defined(SOFT_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) +#if !defined(PROC_VDB) && !defined(SOFT_VDB) \ + && !defined(NO_VDB_FOR_STATIC_ROOTS) +#define NO_VDB_FOR_STATIC_ROOTS +#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) +#if GC_GNUC_PREREQ(3, 0) && !defined(NO_PREFETCH) +#define PREFETCH(x) __builtin_prefetch((x), 0, 0) #else -#define PREFETCH(x)(void)0 +#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) +#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 +#define GC_PREFETCH_FOR_WRITE(x) (void)0 #endif #endif #ifndef CACHE_LINE_SIZE @@ -3894,136 +3755,163 @@ EXTERN_C_BEGIN #define STATIC static #endif #endif -#if defined(LINUX)&&(defined(USE_PROC_FOR_LIBRARIES)||defined(IA64)||!defined(SMALL_CONFIG)) +#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__) +#if defined(LINUX) || defined(HURD) || defined(__GLIBC__) #define REGISTER_LIBRARIES_EARLY #endif #if defined(SEARCH_FOR_DATA_START) -extern ptr_t GC_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) +#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) +#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) +#if !defined(CPPCHECK) +#if defined(GC_IRIX_THREADS) && !defined(IRIX5) #error Inconsistent configuration #endif -#if defined(GC_LINUX_THREADS)&&!defined(LINUX)&&!defined(NACL) +#if defined(GC_LINUX_THREADS) && !defined(LINUX) && !defined(NACL) #error Inconsistent configuration #endif -#if defined(GC_NETBSD_THREADS)&&!defined(NETBSD) +#if defined(GC_NETBSD_THREADS) && !defined(NETBSD) #error Inconsistent configuration #endif -#if defined(GC_FREEBSD_THREADS)&&!defined(FREEBSD) +#if defined(GC_FREEBSD_THREADS) && !defined(FREEBSD) #error Inconsistent configuration #endif -#if defined(GC_SOLARIS_THREADS)&&!defined(SOLARIS) +#if defined(GC_SOLARIS_THREADS) && !defined(SOLARIS) #error Inconsistent configuration #endif -#if defined(GC_HPUX_THREADS)&&!defined(HPUX) +#if defined(GC_HPUX_THREADS) && !defined(HPUX) #error Inconsistent configuration #endif -#if defined(GC_AIX_THREADS)&&!defined(_AIX) +#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) +#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) +#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)) +#if defined(PCR) || defined(GC_WIN32_THREADS) || defined(GC_PTHREADS) \ + || ((defined(NN_PLATFORM_CTR) || defined(NINTENDO_SWITCH) \ + || 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 +#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 +#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) +#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)) +#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)) +#define MIN_STACK_SIZE (8 * HBLKSIZE * sizeof(word)) #endif -#if defined(HOST_ANDROID)&&!defined(THREADS)&&!defined(USE_GET_STACKBASE_FOR_MAIN) +#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) +#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) +#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) +#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 +#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)) +#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) +#if defined(CAN_HANDLE_FORK) && !defined(CAN_CALL_ATFORK) \ + && !defined(GC_NO_CAN_CALL_ATFORK) && !defined(HOST_TIZEN) \ + && !defined(HURD) && (!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)) +#if !defined(CAN_HANDLE_FORK) && !defined(HAVE_NO_FORK) \ + && !(defined(CYGWIN32) || defined(SOLARIS) || defined(UNIX_LIKE)) #define HAVE_NO_FORK #endif -#if!defined(USE_MARK_BITS)&&!defined(USE_MARK_BYTES)&&defined(PARALLEL_MARK) +#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) +#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) +#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) +#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__) +#if defined(_WIN64) && !defined(__GNUC__) #define STRTOULL _strtoui64 -#elif defined(_LLP64)||defined(__LLP64__)||defined(_WIN64) +#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 +#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) +#define GC_WORD_C(val) ((word)val##UL) #endif #endif #if defined(__has_feature) -#if __has_feature(address_sanitizer)&&!defined(ADDRESS_SANITIZER) +#if __has_feature(address_sanitizer) && !defined(ADDRESS_SANITIZER) #define ADDRESS_SANITIZER #endif -#if __has_feature(memory_sanitizer)&&!defined(MEMORY_SANITIZER) +#if __has_feature(memory_sanitizer) && !defined(MEMORY_SANITIZER) #define MEMORY_SANITIZER #endif -#if __has_feature(thread_sanitizer)&&!defined(THREAD_SANITIZER) +#if __has_feature(thread_sanitizer) && !defined(THREAD_SANITIZER) #define THREAD_SANITIZER #endif #else @@ -4037,24 +3925,26 @@ extern ptr_t GC_data_start; #if defined(SPARC) #define CAN_SAVE_CALL_ARGS #endif -#if (defined(I386)||defined(X86_64))&&(defined(LINUX)||defined(__GLIBC__)) +#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) +#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) +#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) +#if !defined(SAVE_CALL_COUNT) || defined(CPPCHECK) #define NFRAMES 6 #else -#define NFRAMES ((SAVE_CALL_COUNT+1)&~1) +#define NFRAMES ((SAVE_CALL_COUNT + 1) & ~1) #endif #define NEED_CALLINFO #endif @@ -4063,100 +3953,127 @@ extern ptr_t GC_data_start; #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) +#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) +#if defined(MAKE_BACK_GRAPH) && !defined(DBG_HDRS_ALL) #define DBG_HDRS_ALL 1 #endif -#if defined(POINTER_MASK)&&!defined(POINTER_SHIFT) +#if defined(POINTER_MASK) && !defined(POINTER_SHIFT) #define POINTER_SHIFT 0 #endif -#if defined(POINTER_SHIFT)&&!defined(POINTER_MASK) +#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)< 32 #define HASH_TL #endif -#if defined(LARGE_CONFIG)||!defined(SMALL_CONFIG) +#if defined(LARGE_CONFIG) || !defined(SMALL_CONFIG) #define LOG_BOTTOM_SZ 10 #else #define LOG_BOTTOM_SZ 11 #endif -#define BOTTOM_SZ (1<>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) +#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;} } + 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; + hdr * index[BOTTOM_SZ]; + struct bi * asc_link; + struct bi * desc_link; + word key; #ifdef HASH_TL -struct bi*hash_link; + 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)]) +#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) +#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)) +#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) +#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)) @@ -4282,7 +4237,7 @@ EXTERN_C_END #ifndef GC_ATTR_NO_SANITIZE_MEMORY #ifndef MEMORY_SANITIZER #define GC_ATTR_NO_SANITIZE_MEMORY -#elif GC_CLANG_PREREQ(3,8) +#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)) @@ -4291,14 +4246,14 @@ EXTERN_C_END #ifndef GC_ATTR_NO_SANITIZE_THREAD #ifndef THREAD_SANITIZER #define GC_ATTR_NO_SANITIZE_THREAD -#elif GC_CLANG_PREREQ(3,8) +#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) +#if GC_GNUC_PREREQ(3, 4) #define GC_ATTR_UNUSED __attribute__((__unused__)) #else #define GC_ATTR_UNUSED @@ -4306,17 +4261,19 @@ EXTERN_C_END #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__) +#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) +#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) +#if GC_GNUC_PREREQ(4, 0) #define GC_ATTR_NOINLINE __attribute__((__noinline__)) -#elif _MSC_VER>=1400 +#elif _MSC_VER >= 1400 #define GC_ATTR_NOINLINE __declspec(noinline) #else #define GC_ATTR_NOINLINE @@ -4324,7 +4281,7 @@ EXTERN_C_END #endif #ifndef GC_API_OSCALL #if defined(__GNUC__) -#if GC_GNUC_PREREQ(4,0)&&!defined(GC_NO_VISIBILITY) +#if GC_GNUC_PREREQ(4, 0) && !defined(GC_NO_VISIBILITY) #define GC_API_OSCALL extern __attribute__((__visibility__("default"))) #else #define GC_API_OSCALL extern @@ -4336,80 +4293,80 @@ EXTERN_C_END #ifndef GC_API_PRIV #define GC_API_PRIV GC_API #endif -#if defined(THREADS)&&!defined(NN_PLATFORM_CTR) +#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" { + extern "C" { #endif -typedef GC_word AO_t; + 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; + 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) +#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_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_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_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_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_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_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_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_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_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_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_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_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_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); -} + 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 +#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 @@ -4417,7 +4374,7 @@ __ATOMIC_RELEASE,__ATOMIC_RELAXED); #define AO_HAVE_compiler_barrier 1 #endif #endif -#if defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32) +#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 #endif @@ -4432,83 +4389,112 @@ __ATOMIC_RELEASE,__ATOMIC_RELAXED); #include #include #endif -EXTERN_C_BEGIN + EXTERN_C_BEGIN #ifdef PCR -GC_EXTERN PCR_Th_ML GC_allocate_ml; + 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 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_PS3) \ + || defined(GC_WIN32_THREADS) || defined(BASE_ATOMIC_OPS_EMULATED) \ + || defined(LINT2)) && defined(GC_PTHREADS) #define USE_PTHREAD_LOCKS #undef USE_SPIN_LOCK +#if defined(LINT2) && !defined(NO_PTHREAD_TRYLOCK) +#define NO_PTHREAD_TRYLOCK +#endif #endif -#if defined(GC_WIN32_THREADS)&&!defined(USE_PTHREAD_LOCKS) +#if defined(GC_WIN32_THREADS) && !defined(USE_PTHREAD_LOCKS) #define NO_THREAD (DWORD)(-1) -GC_EXTERN CRITICAL_SECTION GC_allocate_ml; + 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()) + 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 +#define I_DONT_HOLD_LOCK() TRUE #else -#define I_DONT_HOLD_LOCK()(!GC_need_to_lock||GC_lock_holder!=GetCurrentThreadId()) +#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);} +#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) +#define UNCOND_LOCK() EnterCriticalSection(&GC_allocate_ml) +#define UNCOND_UNLOCK() LeaveCriticalSection(&GC_allocate_ml) #endif #elif defined(GC_PTHREADS) -EXTERN_C_END + EXTERN_C_END #include -EXTERN_C_BEGIN -#if!defined(GC_WIN32_PTHREADS) -#define NUMERIC_THREAD_ID(id)((unsigned long)(id)) -#define THREAD_EQUAL(id1,id2)((id1)==(id2)) + 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)) +#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)) +#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 + 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) + 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); + 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);} +#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) +#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 @@ -4516,77 +4502,92 @@ GC_INNER void GC_lock(void); #endif #endif #ifdef USE_PTHREAD_LOCKS -EXTERN_C_END + EXTERN_C_END #include -EXTERN_C_BEGIN -GC_EXTERN pthread_mutex_t GC_allocate_ml; + 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);} + 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) +#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();} + 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) +#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 + 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())) +#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; + 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) +#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) +#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)) +#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 +#define set_need_to_lock() (void)0 #else -#if defined(GC_ALWAYS_MULTITHREADED)&&!defined(CPPCHECK) +#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; + 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)) +#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) +#define set_need_to_lock() (void)(GC_need_to_lock = TRUE) #endif #endif -EXTERN_C_END + EXTERN_C_END #else -#define LOCK()(void)0 -#define UNLOCK()(void)0 +#define LOCK() (void)0 +#define UNLOCK() (void)0 #ifdef GC_ASSERTIONS -#define I_HOLD_LOCK()TRUE -#define I_DONT_HOLD_LOCK()TRUE +#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() +#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) +#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 @@ -4601,36 +4602,38 @@ EXTERN_C_END #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) +#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) +#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) +#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); +#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); + GC_INNER void GC_process_togglerefs(void); #endif #ifndef SMALL_CONFIG -GC_INNER void GC_print_finalization_stats(void); + GC_INNER void GC_print_finalization_stats(void); #endif #else -#define GC_INVOKE_FINALIZERS()(void)0 +#define GC_INVOKE_FINALIZERS() (void)0 #endif -#if!defined(DONT_ADD_BYTE_AT_END) +#if !defined(DONT_ADD_BYTE_AT_END) #ifdef LINT2 -#define EXTRA_BYTES ((size_t)(GC_all_interior_pointers?1:0)) +#define EXTRA_BYTES ((size_t)(GC_all_interior_pointers? 1 : 0)) #else #define EXTRA_BYTES (size_t)GC_all_interior_pointers #endif @@ -4648,19 +4651,19 @@ GC_INNER void GC_print_finalization_stats(void); #endif #define BL_LIMIT GC_black_list_spacing #ifdef NEED_CALLINFO -struct callinfo { -word ci_pc; + struct callinfo { + word ci_pc; #if NARGS > 0 -word ci_arg[NARGS]; + word ci_arg[NARGS]; #endif -#if (NFRAMES*(NARGS+1))% 2==1 -word ci_dummy; +#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]); + 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 @@ -4669,158 +4672,225 @@ EXTERN_C_END #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_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)) +#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 +#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)) + 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 +#define HAVE_CLOCK_GETTIME 1 #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) +#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 -#if defined(FREEBSD)&&!defined(CLOCKS_PER_SEC) +#if defined(FREEBSD) && !defined(CLOCKS_PER_SEC) #include #define CLOCKS_PER_SEC CLK_TCK #endif -#if!defined(CLOCKS_PER_SEC) +#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)) +#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) +#if defined(SPARC) && defined(SUNOS4) \ + || (defined(M68K) && defined(NEXT)) || defined(VAX) #define BCOPY_EXISTS -#elif defined(AMIGA)||defined(DARWIN) +#elif defined(AMIGA) || defined(DARWIN) #include #define BCOPY_EXISTS -#elif defined(MACOS)&&defined(POWERPC) +#elif defined(MACOS) && defined(POWERPC) #include -#define bcopy(x,y,n)BlockMoveData(x,y,n) -#define bzero(x,n)BlockZero(x,n) +#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) +#if !defined(BCOPY_EXISTS) || defined(CPPCHECK) #include -#define BCOPY(x,y,n)memcpy(y,x,(size_t)(n)) -#define BZERO(x,n)memset(x,0,(size_t)(n)) +#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)) +#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 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; + 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 +#if defined(SMALL_CONFIG) || defined(PCR) +#define GC_on_abort(msg) (void)0 #else -GC_API_PRIV GC_abort_func GC_on_abort; + GC_API_PRIV GC_abort_func GC_on_abort; #endif #if defined(CPPCHECK) -#define ABORT(msg){ GC_on_abort(msg);abort();} +#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) +#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_ERRINFO_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_ERRINFO_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_ERRINFO_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) +#define EXIT() PCR_Base_Exit(1,PCR_waitForever) #else -#define EXIT()(GC_on_abort(NULL),exit(1)) +#define EXIT() (GC_on_abort(NULL), exit(1 )) #endif -#define WARN(msg,arg)(*GC_current_warn_proc)(( char*)("GC Warning:" msg),(word)(arg)) +#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) +#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 + 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) + 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) +#define GETENV(name) getenv(name) #endif EXTERN_C_END #if defined(DARWIN) @@ -4829,127 +4899,128 @@ EXTERN_C_END #include #endif #if defined(POWERPC) -#if CPP_WORDSZ==32 -#define GC_THREAD_STATE_T ppc_thread_state_t +#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_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 +#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 +#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_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) && 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 +#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 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) +#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 +#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 +#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_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 +#define THREAD_FLD_NAME(x) __ ## x #else -#define THREAD_FLD_NAME(x)x +#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) +#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) +#define THREAD_FLD(x) THREAD_FLD_NAME(x) #endif #endif #include -#if __STDC_VERSION__>=201112L +#if __STDC_VERSION__ >= 201112L #include #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 +#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 +#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)) +#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) +#if defined(LARGE_CONFIG) || !defined(SMALL_CONFIG) #ifdef ALPHA #define CPP_LOG_HBLKSIZE 13 -#elif defined(SN_TARGET_ORBIS)||defined(SN_TARGET_PSP2) +#elif defined(SN_TARGET_PSP2) #define CPP_LOG_HBLKSIZE 16 #else #define CPP_LOG_HBLKSIZE 12 @@ -4958,85 +5029,98 @@ EXTERN_C_BEGIN #define CPP_LOG_HBLKSIZE 10 #endif #else -#if HBLKSIZE==512 +#if HBLKSIZE == 512 #define CPP_LOG_HBLKSIZE 9 -#elif HBLKSIZE==1024 +#elif HBLKSIZE == 1024 #define CPP_LOG_HBLKSIZE 10 -#elif HBLKSIZE==2048 +#elif HBLKSIZE == 2048 #define CPP_LOG_HBLKSIZE 11 -#elif HBLKSIZE==4096 +#elif HBLKSIZE == 4096 #define CPP_LOG_HBLKSIZE 12 -#elif HBLKSIZE==8192 +#elif HBLKSIZE == 8192 #define CPP_LOG_HBLKSIZE 13 -#elif HBLKSIZE==16384 +#elif HBLKSIZE == 16384 #define CPP_LOG_HBLKSIZE 14 -#elif!defined(CPPCHECK) +#elif !defined(CPPCHECK) #error Bad HBLKSIZE value #endif #undef HBLKSIZE #endif -#define CPP_HBLKSIZE (1<>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) +#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) +#ifndef LOG_PHT_ENTRIES #ifdef LARGE_CONFIG -#if CPP_WORDSZ==32 +#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 +#elif !defined(SMALL_CONFIG) +#define LOG_PHT_ENTRIES 18 #else -#define LOG_PHT_ENTRIES 15 +#define LOG_PHT_ENTRIES 15 #endif -#define PHT_ENTRIES ((word)1<>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<> 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; + word w; + signed_word sw; + void *vp; #ifdef PARALLEL_MARK -volatile AO_t ao; + 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 + 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 @@ -5046,79 +5130,81 @@ unsigned char hb_flags; #ifdef MARK_BIT_PER_GRANULE #define LARGE_BLOCK 0x20 #endif -unsigned short hb_last_reclaimed; + unsigned short hb_last_reclaimed; #ifdef MARK_BIT_PER_OBJ -unsigned32 hb_inv_sz; -#define LARGE_INV_SZ (1<<16) + unsigned32 hb_inv_sz; +#define LARGE_INV_SZ (1 << 16) #endif -word hb_sz; -word hb_descr; + word hb_sz; + word hb_descr; #ifdef MARK_BIT_PER_GRANULE -unsigned short*hb_map; + unsigned short * hb_map; #endif #ifdef PARALLEL_MARK -volatile AO_t hb_n_marks; + volatile AO_t hb_n_marks; #else -size_t hb_n_marks; + 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 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]; +#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)) +#define HBLK_OBJS(sz_in_bytes) (HBLKSIZE/(sz_in_bytes)) struct hblk { -char hb_body[HBLKSIZE]; + 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 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< 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)) +#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 @@ -5130,215 +5216,224 @@ GC_bool r_tmp; #endif #endif typedef struct GC_ms_entry { -ptr_t mse_start; -union word_ptr_ao_u mse_descr; + 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 disappearing_link **head; + word entries; + unsigned log_size; }; struct fnlz_roots_s { -struct finalizable_object**fo_head; -struct finalizable_object*finalize_now; + struct finalizable_object **fo_head; + struct finalizable_object *finalize_now; }; union toggle_ref_u { -void*strong_ref; -GC_hidden_pointer weak_ref; + void *strong_ref; + GC_hidden_pointer weak_ref; }; typedef struct { -word ed_bitmap; -GC_bool ed_continued; + word ed_bitmap; + GC_bool ed_continued; } typed_ext_descr_t; +struct HeapSect { + ptr_t hs_start; + size_t hs_bytes; +}; 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; + word _heapsize; + word _requested_heapsize; + ptr_t _last_heap_addr; + word _large_free_bytes; + word _large_allocd_bytes; + word _max_large_allocd_bytes; + word _bytes_allocd_before_gc; +#define GC_our_mem_bytes GC_arrays._our_mem_bytes + word _our_mem_bytes; #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; + 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; +#if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX)) +#define USE_SCRATCH_LAST_END_PTR +#define GC_scratch_last_end_ptr GC_arrays._scratch_last_end_ptr + ptr_t _scratch_last_end_ptr; +#endif + mse *_mark_stack; + mse *_mark_stack_limit; #ifdef PARALLEL_MARK -mse*volatile _mark_stack_top; + mse *volatile _mark_stack_top; #else -mse*_mark_stack_top; + mse *_mark_stack_top; #endif -word _composite_in_use; -word _atomic_in_use; + word _composite_in_use; + word _atomic_in_use; #ifdef USE_MUNMAP #define GC_unmapped_bytes GC_arrays._unmapped_bytes -word _unmapped_bytes; + word _unmapped_bytes; #ifdef COUNT_UNMAPPED_REGIONS #define GC_num_unmapped_regions GC_arrays._num_unmapped_regions -signed_word _num_unmapped_regions; + signed_word _num_unmapped_regions; #endif #else #define GC_unmapped_bytes 0 #endif -bottom_index*_all_nils; + bottom_index * _all_nils; #define GC_scan_ptr GC_arrays._scan_ptr -struct hblk*_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; + mse *_main_local_mark_stack; #define GC_first_nonempty GC_arrays._first_nonempty -volatile AO_t _first_nonempty; + volatile AO_t _first_nonempty; #endif #define GC_mark_stack_size GC_arrays._mark_stack_size -size_t _mark_stack_size; + size_t _mark_stack_size; #define GC_mark_state GC_arrays._mark_state -mark_state_t _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; + GC_bool _mark_stack_too_small; #define GC_objects_are_marked GC_arrays._objects_are_marked -GC_bool _objects_are_marked; + GC_bool _objects_are_marked; #ifdef ENABLE_TRACE #define GC_trace_addr GC_arrays._trace_addr -ptr_t _trace_addr; + ptr_t _trace_addr; #endif +#define GC_capacity_heap_sects GC_arrays._capacity_heap_sects + size_t _capacity_heap_sects; #define GC_n_heap_sects GC_arrays._n_heap_sects -word _n_heap_sects; -#if defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32) + 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; + word _n_heap_bases; #endif #ifdef USE_PROC_FOR_LIBRARIES #define GC_n_memory GC_arrays._n_memory -word _n_memory; + word _n_memory; #endif #ifdef GC_GCJ_SUPPORT #define GC_gcjobjfreelist GC_arrays._gcjobjfreelist -ptr_t*_gcjobjfreelist; + ptr_t *_gcjobjfreelist; #endif #define GC_fo_entries GC_arrays._fo_entries -word _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; + struct dl_hashtbl_s _ll_hashtbl; #endif -struct dl_hashtbl_s _dl_hashtbl; -struct fnlz_roots_s _fnlz_roots; -unsigned _log_fo_table_size; + 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; + 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; + int _trace_buf_ptr; #endif #ifdef ENABLE_DISCLAIM #define GC_finalized_kind GC_arrays._finalized_kind -int _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; + 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; + 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; + volatile AO_t _explicit_typing_initialized; #else -GC_bool _explicit_typing_initialized; + 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) + 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]; + struct roots * _root_index[RT_SIZE]; #endif #ifdef SAVE_CALL_CHAIN #define GC_last_stack GC_arrays._last_stack -struct callinfo _last_stack[NFRAMES]; + struct callinfo _last_stack[NFRAMES]; #endif #ifndef SEPARATE_GLOBALS #define GC_objfreelist GC_arrays._objfreelist -void*_objfreelist[MAXOBJGRANULES+1]; + void *_objfreelist[MAXOBJGRANULES+1]; #define GC_aobjfreelist GC_arrays._aobjfreelist -void*_aobjfreelist[MAXOBJGRANULES+1]; + void *_aobjfreelist[MAXOBJGRANULES+1]; #endif -void*_uobjfreelist[MAXOBJGRANULES+1]; + void *_uobjfreelist[MAXOBJGRANULES+1]; #ifdef GC_ATOMIC_UNCOLLECTABLE #define GC_auobjfreelist GC_arrays._auobjfreelist -void*_auobjfreelist[MAXOBJGRANULES+1]; + void *_auobjfreelist[MAXOBJGRANULES+1]; #endif -size_t _size_map[MAXOBJBYTES+1]; + 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]; + 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]; + char _valid_offsets[VALID_OFFSET_SZ]; #ifndef GC_DISABLE_INCREMENTAL #define GC_grungy_pages GC_arrays._grungy_pages -page_hash_table _grungy_pages; + page_hash_table _grungy_pages; #define GC_dirty_pages GC_arrays._dirty_pages -volatile page_hash_table _dirty_pages; + volatile page_hash_table _dirty_pages; #endif -#if (defined(CHECKSUMS)&&defined(GWW_VDB))||defined(PROC_VDB) +#if (defined(CHECKSUMS) && (defined(GWW_VDB) || defined(SOFT_VDB))) \ + || defined(PROC_VDB) #define GC_written_pages GC_arrays._written_pages -page_hash_table _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]; + struct HeapSect *_heap_sects; #if defined(USE_PROC_FOR_LIBRARIES) #define GC_our_memory GC_arrays._our_memory -struct HeapSect _our_memory[MAX_HEAP_SECTS]; + struct HeapSect _our_memory[MAX_HEAP_SECTS]; #endif -#if defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32) +#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32) #define GC_heap_bases GC_arrays._heap_bases -ptr_t _heap_bases[MAX_HEAP_SECTS]; + ptr_t _heap_bases[MAX_HEAP_SECTS]; #endif #ifdef MSWINCE #define GC_heap_lengths GC_arrays._heap_lengths -word _heap_lengths[MAX_HEAP_SECTS]; + 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]; + 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 @@ -5360,210 +5455,233 @@ GC_API_PRIV GC_FAR struct _GC_arrays GC_arrays; #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 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; + 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 + 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)) +#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]; + 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 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)) +#define endGC_aobjfreelist (beginGC_aobjfreelist + sizeof(GC_aobjfreelist)) #endif #define PTRFREE 0 -#define NORMAL 1 +#define NORMAL 1 #define UNCOLLECTABLE 2 #ifdef GC_ATOMIC_UNCOLLECTABLE #define AUNCOLLECTABLE 3 -#define IS_UNCOLLECTABLE(k)(((k)&~1)==UNCOLLECTABLE) +#define IS_UNCOLLECTABLE(k) (((k) & ~1) == UNCOLLECTABLE) #define GC_N_KINDS_INITIAL_VALUE 4 #else -#define IS_UNCOLLECTABLE(k)((k)==UNCOLLECTABLE) +#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)) +#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) +#define ROUNDUP_PAGESIZE_IF_MMAP(lb) ROUNDUP_PAGESIZE(lb) #else -#define ROUNDUP_PAGESIZE_IF_MMAP(lb)(lb) +#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); +#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[]; + 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; + GC_fn_type fn; + void * client_data; }; struct GC_traced_stack_sect_s { -ptr_t saved_stack_ptr; + ptr_t saved_stack_ptr; #ifdef IA64 -ptr_t saved_backing_store_ptr; -ptr_t backing_store_end; + ptr_t saved_backing_store_ptr; + ptr_t backing_store_end; #endif -struct GC_traced_stack_sect_s*prev; + 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; + 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; + 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); + 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) +#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)) +#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)) +#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<hb_marks[divWORDSZ(n)]&=~((word)1<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)) +#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 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))) +#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); +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); +#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); +#ifdef NO_VDB_FOR_STATIC_ROOTS +#define GC_push_conditional_static(b, t, all) \ + ((void)(all), GC_push_all(b, t)) +#else + GC_INNER void GC_push_conditional_static(void *b, void *t, GC_bool all); #endif -GC_INNER void GC_push_roots(GC_bool all,ptr_t cold_gc_frame); +#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); + 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); +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); +#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); + 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); +#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); + 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_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**); +#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); +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); + 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); +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); + 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); + 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); + GC_INNER GC_bool GC_is_static_root(void *p); #ifdef TRACE_BUF -void GC_add_trace_entry(char*kind,word arg1,word arg2); + 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_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); @@ -5571,119 +5689,125 @@ GC_INNER ptr_t GC_scratch_alloc(size_t bytes); #else #define GC_scratch_recycle_no_gww GC_scratch_recycle_inner #endif -GC_INNER void GC_scratch_recycle_inner(void*ptr,size_t bytes); +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); + 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 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 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) +#define GC_gcollect_inner() \ + (void)GC_try_to_collect_inner(GC_never_stop_func) #ifdef THREADS -GC_EXTERN GC_bool GC_in_thread_creation; + 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); +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); + 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 +#define GC_DBG_EXTRAS GC_RETURN_ADDR_PARENT, NULL, 0 #else -#define GC_DBG_EXTRAS GC_RETURN_ADDR,NULL,0 +#define GC_DBG_EXTRAS GC_RETURN_ADDR, NULL, 0 #endif #else -#define GC_DBG_EXTRAS "unknown",0 +#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) + 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 +#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*); +#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); +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); #ifdef USE_PROC_FOR_LIBRARIES -GC_INNER void GC_add_to_our_memory(ptr_t p,size_t bytes); + GC_INNER void GC_add_to_our_memory(ptr_t p, size_t bytes); #else -#define GC_add_to_our_memory(p,bytes) +#define GC_add_to_our_memory(p, bytes) \ + (GC_our_mem_bytes += (bytes), (void)(p)) #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); +#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); + 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; +#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); + 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); +#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); + void GC_print_back_graph_stats(void); #endif #ifdef THREADS -GC_INNER void GC_free_inner(void*p); + 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); + 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 +#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); + 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 +#define GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE \ + GC_generic_malloc_inner_ignore_off_page #ifdef THREADS #define GC_INTERNAL_FREE GC_free_inner #else @@ -5691,140 +5815,163 @@ GC_INNER void GC_debug_free_inner(void*p); #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)); -} + 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; + 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))) +#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); +#if !defined(NO_VDB_FOR_STATIC_ROOTS) && !defined(PROC_VDB) + GC_INNER GC_bool GC_is_vdb_for_static_roots(void); +#endif +#ifdef CAN_HANDLE_FORK +#if defined(PROC_VDB) || defined(SOFT_VDB) + GC_INNER void GC_dirty_update_child(void); +#else +#define GC_dirty_update_child() (void)0 +#endif +#endif + 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) + 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_STORE_BACK_PTR(source, dest) (void)(source) #define GC_MARKED_FOR_FINALIZATION(dest) #endif -void GC_noop6(word,word,word,word,word,word); +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))) +#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) +#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); +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_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; + 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 +#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); + 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 +#if defined(SMALL_CONFIG) || defined(GC_ANDROID_LOG) +#define GC_ERRINFO_PRINTF GC_INFOLOG_PRINTF +#else +#define GC_ERRINFO_PRINTF GC_log_printf #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 +#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 +#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)) +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; + 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; + 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; + 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; +#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; + 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 +#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; +#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; + GC_EXTERN GC_bool GC_dont_query_stack_min; #endif #elif defined(IA64) -GC_EXTERN ptr_t GC_save_regs_ret_val; + 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); + 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); +#if defined(GLIBC_2_19_TSX_BUG) && defined(THREADS) + GC_INNER int GC_parse_version(int *pminor, const char *pverstr); #endif -#if defined(CHECKSUMS)||defined(PROC_VDB) -GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk*h); +#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); +#if defined(MPROTECT_VDB) && !defined(DARWIN) + void GC_record_fault(struct hblk * h); #endif -void GC_check_dirty(void); + void GC_check_dirty(void); #endif GC_INNER void GC_default_print_heap_obj_proc(ptr_t p); GC_INNER void GC_setpagesize(void); @@ -5832,122 +5979,141 @@ 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); +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); + 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); + 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); + 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); + GC_INNER void GC_init_win32(void); #endif -#if!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(CYGWIN32) -GC_INNER void*GC_roots_present(ptr_t); +#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); + 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); +#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); + 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); + 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); + 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); + GC_INNER GC_bool GC_register_main_static_data(void); #ifdef DARWIN -GC_INNER void GC_init_dyld(void); + 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); + 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); +#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)); + 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); +#if defined(DYNAMIC_LOADING) && defined(USE_PROC_FOR_LIBRARIES) + GC_INNER const char *GC_parse_map_entry(const char *maps_ptr, + ptr_t *start, ptr_t *end, + const char **prot, + unsigned *maj_dev, + const 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); +#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); + GC_INNER const 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); +#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) +#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]) +#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) +#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)) +#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) +#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 + 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) + 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 @@ -5956,75 +6122,88 @@ GC_INNER void GC_start_mark_threads_inner(void); #ifndef GC_OPENBSD_UTHREADS #define SIG_SUSPEND SIGXFSZ #endif -#elif defined(_SIGRTMIN)&&!defined(CPPCHECK) -#define SIG_SUSPEND _SIGRTMIN+6 +#elif defined(_SIGRTMIN) && !defined(CPPCHECK) +#define SIG_SUSPEND _SIGRTMIN + 6 #else -#define SIG_SUSPEND SIGRTMIN+6 +#define SIG_SUSPEND SIGRTMIN + 6 #endif #endif -#if defined(GC_PTHREADS)&&!defined(GC_SEM_INIT_PSHARED) +#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 +#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 -EXTERN_C_BEGIN + EXTERN_C_BEGIN #endif -#define SETJMP(env)sigsetjmp(env,1) -#define LONGJMP(env,val)siglongjmp(env,val) +#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) +#define SETJMP(env) hal_setjmp(env) #else -#define SETJMP(env)setjmp(env) +#define SETJMP(env) setjmp(env) #endif -#define LONGJMP(env,val)longjmp(env,val) +#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)) +#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 + EXTERN_C_END #include -EXTERN_C_BEGIN -#if!defined(PCR) + EXTERN_C_BEGIN +#if !defined(PCR) #define NEED_FIND_LIMIT #endif -GC_INNER ptr_t GC_FreeBSDGetDataStart(size_t,ptr_t); + 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) +#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) \ + && !defined(NEED_FIND_LIMIT) #define NEED_FIND_LIMIT #endif -#if defined(IA64)&&!defined(NEED_FIND_LIMIT) +#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); +#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; +#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) +#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 +#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) +#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 +#define DISABLE_CANCEL(state) (void)0 +#define RESTORE_CANCEL(state) (void)0 +#define ASSERT_CANCEL_DISABLED() (void)0 #endif EXTERN_C_END #endif @@ -6034,89 +6213,90 @@ EXTERN_C_END #ifndef GC_H #endif #ifdef __cplusplus -extern "C" { + 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_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 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); +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 +#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) +#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)) +#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) +#define HIDE_BACK_PTR(p) GC_HIDE_POINTER(p) #endif #ifdef KEEP_BACK_PTRS -GC_hidden_pointer oh_back_ptr; + GC_hidden_pointer oh_back_ptr; #endif #ifdef MAKE_BACK_GRAPH -GC_hidden_pointer oh_bg_ptr; + GC_hidden_pointer oh_bg_ptr; #endif -#if defined(KEEP_BACK_PTRS)!=defined(MAKE_BACK_GRAPH) -word oh_dummy; +#if defined(KEEP_BACK_PTRS) != defined(MAKE_BACK_GRAPH) + word oh_dummy; #endif #endif -const char*oh_string; -signed_word oh_int; + const char * oh_string; + signed_word oh_int; #ifdef NEED_CALLINFO -struct callinfo oh_ci[NFRAMES]; + struct callinfo oh_ci[NFRAMES]; #endif #ifndef SHORT_DBG_HDRS -word oh_sz; -word oh_sf; + 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 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) +#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) + 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) + 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 ADD_CALL_CHAIN(base, ra) #define PRINT_CALL_CHAIN(base) #endif #ifdef GC_ADD_CALLER @@ -6125,921 +6305,1034 @@ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]); #define OPT_RA #endif #ifdef SHORT_DBG_HDRS -#define GC_has_other_debug_info(p)1 +#define GC_has_other_debug_info(p) 1 #else -GC_INNER int GC_has_other_debug_info(ptr_t p); + 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) +#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) +#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) +#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) +#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) +#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; + 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; + 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; +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 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)); + 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)); + } + if (EXPECT(new_in_progress_space != NULL, TRUE)) + 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)); + GC_scratch_recycle_no_gww(in_progress_space, + n_in_progress * sizeof(ptr_t)); #elif defined(LINT2) -GC_noop1((word)in_progress_space); + 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; + 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; + 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); + --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)) +#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++; + 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); -} + 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) +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)); + 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_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); + 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; + 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); + 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_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"); + 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; +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)); -} -} + 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); -} + 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); + 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) +STATIC void GC_clear_bl(word *doomed) { -BZERO(doomed,sizeof(page_hash_table)); + BZERO(doomed, sizeof(page_hash_table)); } -STATIC void GC_copy_bl(word*old,word*dest) +STATIC void GC_copy_bl(word *old, word *dest) { -BCOPY(old,dest,sizeof(page_hash_table)); + 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; -} + 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); + 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); } -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) +#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) +#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) + 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) + 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)){ + 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"); -} + 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); -} -} + 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) + 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) + 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)){ + 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); + 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); + 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; + 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 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"); -} + 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; -} -} + 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; + 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) +#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) +#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) +#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) +#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) +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;} +#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<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) +#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) +#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 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; +#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)) + 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; + 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 { + 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; -} + 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; + gran_displ -= gran_offset; #endif -base-=obj_displ; -} -} -} + 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)) + 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 #%lu: passed validity tests\n", + (unsigned long)GC_gc_no)); + SET_MARK_BIT_EXIT_IF_SET(hhdr, gran_displ); + TRACE(source, GC_log_printf("GC #%lu: previously unmarked\n", + (unsigned long)GC_gc_no)); + TRACE_TARGET(base, GC_log_printf("GC #%lu: marking %p from %p instead\n", + (unsigned long)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 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 @@ -7054,2050 +7347,2174 @@ EXTERN_C_END #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*); + 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) +#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) +#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) +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; + 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) + 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; -} + 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(); + 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)) +#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; + 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) + 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); + hdr * result; + GET_HDR(h, result); + return(result); #else -return(HDR_INNER(h)); + return(HDR_INNER(h)); #endif } -GC_INNER hdr* +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_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; + ptr_t result = GC_scratch_free_ptr; + size_t bytes_to_get; + bytes = ROUNDUP_GRANULE_SIZE(bytes); + for (;;) { + GC_ASSERT((word)GC_scratch_end_ptr >= (word)result); + if (bytes <= (word)GC_scratch_end_ptr - (word)result) { + GC_scratch_free_ptr = result + bytes; + 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); + if (result != NULL) { + GC_add_to_our_memory(result, bytes_to_get); +#ifdef USE_SCRATCH_LAST_END_PTR + GC_scratch_last_end_ptr = result + bytes; +#endif + } + return result; + } + bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(MINHINCR * HBLKSIZE); + result = (ptr_t)GET_MEM(bytes_to_get); + if (EXPECT(NULL == result, FALSE)) { + WARN("Out of memory - trying to allocate requested amount" + " (%" WARN_PRIdPTR " bytes)...\n", (word)bytes); + bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(bytes); + result = (ptr_t)GET_MEM(bytes_to_get); + if (result != NULL) { + GC_add_to_our_memory(result, bytes_to_get); +#ifdef USE_SCRATCH_LAST_END_PTR + GC_scratch_last_end_ptr = result + bytes; +#endif + } + return result; + } + GC_add_to_our_memory(result, bytes_to_get); + GC_scratch_free_ptr = result; + GC_scratch_end_ptr = GC_scratch_free_ptr + bytes_to_get; +#ifdef USE_SCRATCH_LAST_END_PTR + GC_scratch_last_end_ptr = GC_scratch_end_ptr; +#endif + } +} +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; + 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; -} + 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()); + 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; + 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); + 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<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<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<desc_link; -} -return(0); + 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 #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); + 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]); + 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); + GC_ASSERT(I_HOLD_LOCK()); + 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(); + 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; -} + 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); -} + 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); + 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); + (*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); + (*GC_is_valid_displacement_print_proc)((ptr_t)p); + return(p); } -STATIC void GC_CALLBACK GC_default_is_visible_print_proc(void*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); + 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; +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) -{ + 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); -} + 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); -} + if ((word)p <= (word)GC_approx_sp() + && (word)p > (word)GC_stackbottom) { + return(TRUE); + } #endif -return(FALSE); -} + return(FALSE); + } #endif -GC_API void*GC_CALL GC_is_visible(void*p) +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(); + 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); -} + 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_is_visible_print_proc)((ptr_t)p); + return(p); } -GC_API void*GC_CALL GC_pre_incr (void**p,ptrdiff_t how_much) +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); + 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) +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); + 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) +#if GC_GNUC_PREREQ(3, 0) +#define GC_EXPECT(expr, outcome) __builtin_expect(expr,outcome) #else -#define GC_EXPECT(expr,outcome)(expr) +#define GC_EXPECT(expr, outcome) (expr) #endif #ifndef GC_ASSERT #ifdef NDEBUG #define GC_ASSERT(expr) #else #include -#define GC_ASSERT(expr)assert(expr) +#define GC_ASSERT(expr) assert(expr) #endif #endif #ifdef __cplusplus -extern "C" { + 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) +#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 +#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); +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); + 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); +#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 #ifdef GC_USE_ENTIRE_HEAP -int GC_use_entire_heap=TRUE; + int GC_use_entire_heap = TRUE; #else -int GC_use_entire_heap=FALSE; + 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) +#define N_HBLK_FLS ((HUGE_THRESHOLD - UNIQUE_THRESHOLD) / FL_COMPRESSION \ + + UNIQUE_THRESHOLD) #ifndef GC_GCJ_SUPPORT -STATIC + STATIC #endif -struct hblk*GC_hblkfreelist[N_HBLK_FLS+1]={ 0 }; + struct hblk * GC_hblkfreelist[N_HBLK_FLS+1] = { 0 }; #ifndef GC_GCJ_SUPPORT -STATIC + STATIC #endif -word GC_free_bytes[N_HBLK_FLS+1]={ 0 }; + 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; + 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; + 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) +#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) +#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; + 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; + 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; + 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; + 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; + 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); + GC_ASSERT(((1ULL << 32) + byte_sz - 1) / byte_sz == inv_sz); #endif -hhdr->hb_inv_sz=inv_sz; -} + 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; + { + 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; +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) + 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); + 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; + 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){ + 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&®ions>=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; -} -} -} + 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; + 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; + 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; + 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; + 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); +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(); +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(I_HOLD_LOCK()); + 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){ + 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; + if (may_split == AVOID_SPLIT_REMAPPED && !IS_MAPPED(hhdr)) + continue; #endif -thishdr=GC_install_header(thishbp); -if (0!=thishdr){ + 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){ + 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); -} + 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; + 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; + 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; + 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); + GC_remove_header(hbp); + hbp = prev; + hhdr = prevhdr; + } + } + GC_large_free_bytes += size; + GC_add_to_fl(hbp, hhdr); } #include -#if!defined(MACOS)&&!defined(MSWINCE) +#if !defined(MACOS) && !defined(MSWINCE) #include -#if!defined(SN_TARGET_ORBIS)&&!defined(SN_TARGET_PSP2)&&!defined(__CC_ARM) +#if !defined(GC_NO_TYPES) && !defined(SN_TARGET_PSP2) \ + && !defined(__CC_ARM) #include #endif #endif -word GC_non_gc_bytes=0; -word GC_gc_no=0; +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; -} + 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; + GC_INNER GC_bool GC_incremental = FALSE; + STATIC GC_bool GC_should_start_incremental_collection = FALSE; #endif GC_API int GC_CALL GC_is_incremental_mode(void) { -return (int)GC_incremental; + return (int)GC_incremental; } #ifdef THREADS -int GC_parallel=FALSE; + int GC_parallel = FALSE; #endif -#if defined(GC_FULL_FREQ)&&!defined(CPPCHECK) -int GC_full_freq=GC_FULL_FREQ; +#if defined(GC_FULL_FREQ) && !defined(CPPCHECK) + int GC_full_freq = GC_FULL_FREQ; #else -int GC_full_freq=19; + int GC_full_freq = 19; #endif -STATIC GC_bool GC_need_full_gc=FALSE; +STATIC GC_bool GC_need_full_gc = FALSE; #ifdef THREAD_LOCAL_ALLOC -GC_INNER GC_bool GC_world_stopped=FALSE; + GC_INNER GC_bool GC_world_stopped = FALSE; #endif -STATIC word GC_used_heap_size_after_full=0; +STATIC GC_bool GC_disable_automatic_collection = FALSE; +GC_API void GC_CALL GC_set_disable_automatic_collection(int value) +{ + DCL_LOCK_STATE; + LOCK(); + GC_disable_automatic_collection = (GC_bool)value; + UNLOCK(); +} +GC_API int GC_CALL GC_get_disable_automatic_collection(void) +{ + int value; + DCL_LOCK_STATE; + LOCK(); + value = (int)GC_disable_automatic_collection; + UNLOCK(); + return value; +} +STATIC word GC_used_heap_size_after_full = 0; EXTERN_C_BEGIN -extern const char*const GC_copyright[]; +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.", +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-2021 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); + 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; + return (GC_VERSION_MAJOR << 16) | (GC_VERSION_MINOR << 8) | + GC_VERSION_MICRO; } #ifdef GC_DONT_EXPAND -int GC_dont_expand=TRUE; + int GC_dont_expand = TRUE; #else -int GC_dont_expand=FALSE; + int GC_dont_expand = FALSE; #endif -#if defined(GC_FREE_SPACE_DIVISOR)&&!defined(CPPCHECK) -word GC_free_space_divisor=GC_FREE_SPACE_DIVISOR; +#if defined(GC_FREE_SPACE_DIVISOR) && !defined(CPPCHECK) + word GC_free_space_divisor = GC_FREE_SPACE_DIVISOR; #else -word GC_free_space_divisor=3; + word GC_free_space_divisor = 3; #endif GC_INNER int GC_CALLBACK GC_never_stop_func(void) { -return(0); + return(0); } -#if defined(GC_TIME_LIMIT)&&!defined(CPPCHECK) -unsigned long GC_time_limit=GC_TIME_LIMIT; +#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; + unsigned long GC_time_limit = GC_TIME_UNLIMITED; #else -unsigned long GC_time_limit=50; + 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; + 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(); + 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; + 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) +#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); + 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); -} + 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; + GC_INNER word GC_total_stacksize = 0; #endif -static size_t min_bytes_allocd_minimum=1; +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_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; + return min_bytes_allocd_minimum; } static word min_bytes_allocd(void) { -word result; -word stack_size; -word total_root_size; -word scan_size; + word result; + word stack_size; + word total_root_size; + word scan_size; #ifdef THREADS -if (GC_need_to_lock){ -stack_size=GC_total_stacksize; + 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); + GC_log_printf("Total stacks size: %lu\n", + (unsigned long)stack_size); #endif -} else + } else #endif -{ + { #ifdef STACK_NOT_SCANNED -stack_size=0; + 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; + 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); -} + 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)); + 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 GC_collect_at_heapsize = GC_WORD_MAX; +GC_API void GC_CALL GC_start_incremental_collection(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; +#ifndef GC_DISABLE_INCREMENTAL + DCL_LOCK_STATE; + if (!GC_incremental) return; + LOCK(); + GC_should_start_incremental_collection = TRUE; + ENTER_GC(); + GC_collect_a_little_inner(1); + EXIT_GC(); + UNLOCK(); +#endif } -return(GC_adj_bytes_allocd()>=last_min_bytes_allocd -||GC_heapsize>=GC_collect_at_heapsize); +GC_INNER GC_bool GC_should_collect(void) +{ + static word last_min_bytes_allocd; + static word last_gc_no; + GC_ASSERT(I_HOLD_LOCK()); + if (last_gc_no != GC_gc_no) { + last_min_bytes_allocd = min_bytes_allocd(); + last_gc_no = GC_gc_no; + } +#ifndef GC_DISABLE_INCREMENTAL + if (GC_should_start_incremental_collection) { + GC_should_start_incremental_collection = FALSE; + return TRUE; + } +#endif + if (GC_disable_automatic_collection) return FALSE; + 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_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(); + 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_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)(); + if (GC_start_call_back != 0) { + (*GC_start_call_back)(); + } } -} -STATIC GC_bool GC_is_full_gc=FALSE; +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 { + 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++; -} -} + 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);} + 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)){ + 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); + GC_save_callers(GC_last_stack); #endif -GC_finish_collection(); -} else { -if (!GC_is_full_gc){ -GC_n_attempts++; -} -} -} + GC_finish_collection(); + } else { + if (!GC_is_full_gc) { + GC_n_attempts++; + } + } + } } -STATIC GC_on_collection_event_proc GC_on_collection_event=0; +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(); + 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_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(); + 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(); + 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(); + 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(); + 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); + 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 @@ -9105,1770 +9522,1848 @@ return(TRUE); #ifndef MAX_PRIOR_ATTEMPTS #define MAX_PRIOR_ATTEMPTS 1 #endif -STATIC int GC_deficit=0; -STATIC int GC_rate=GC_RATE; +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_ASSERT(value > 0); + GC_rate = value; } GC_API int GC_CALL GC_get_rate(void) { -return GC_rate; + return GC_rate; } -static int max_prior_attempts=MAX_PRIOR_ATTEMPTS; +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_ASSERT(value >= 0); + max_prior_attempts = value; } GC_API int GC_CALL GC_get_max_prior_attempts(void) { -return max_prior_attempts; + 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; + 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; + 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; -} + for (i = GC_deficit; i < max_deficit; i++) { + if (GC_mark_some(NULL)) + break; + } #ifdef PARALLEL_MARK -GC_parallel_mark_disabled=FALSE; + GC_parallel_mark_disabled = FALSE; #endif -if (i < max_deficit){ + if (i < max_deficit) { #ifdef SAVE_CALL_CHAIN -GC_save_callers(GC_last_stack); + GC_save_callers(GC_last_stack); #endif #ifdef PARALLEL_MARK -if (GC_parallel) -GC_wait_for_reclaim(); + if (GC_parallel) + GC_wait_for_reclaim(); #endif -if (GC_n_attempts < max_prior_attempts -&&GC_time_limit!=GC_TIME_UNLIMITED){ + 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; + 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); + 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; + 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 +#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; + int i; #ifndef NO_CLOCK -CLOCK_TYPE start_time=CLOCK_TYPE_INITIALIZER; + 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(); + 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(); + GC_cond_register_dynamic_libraries(); #endif #ifndef NO_CLOCK -if (GC_PRINT_STATS_FLAG) -GET_TIME(start_time); + if (GC_PRINT_STATS_FLAG) + GET_TIME(start_time); #endif -#if!defined(GC_NO_FINALIZATION)&&!defined(GC_TOGGLE_REFS_NOT_NEEDED) -GC_process_togglerefs(); +#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); + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_PRE_STOP_WORLD); #endif -STOP_WORLD(); + STOP_WORLD(); #ifdef THREADS -if (GC_on_collection_event) -GC_on_collection_event(GC_EVENT_POST_STOP_WORLD); + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_POST_STOP_WORLD); #endif #ifdef THREAD_LOCAL_ALLOC -GC_world_stopped=TRUE; + 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); + 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(); + 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; + 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())){ + 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; -} -} + 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; + GC_parallel_mark_disabled = FALSE; #endif -if (i>=0){ -GC_COND_LOG_PRINTF("Abandoned stopped marking after" -" %d iterations\n",i); -GC_deficit=i; + 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; + GC_world_stopped = FALSE; #endif #ifdef THREADS -if (GC_on_collection_event) -GC_on_collection_event(GC_EVENT_PRE_START_WORLD); + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_PRE_START_WORLD); #endif -START_WORLD(); + START_WORLD(); #ifdef THREADS -if (GC_on_collection_event) -GC_on_collection_event(GC_EVENT_POST_START_WORLD); -#endif -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); + if (GC_on_collection_event) + GC_on_collection_event(GC_EVENT_POST_START_WORLD); +#endif + return FALSE; + } + GC_gc_no++; +#ifdef USE_MUNMAP + GC_ASSERT(GC_heapsize >= GC_unmapped_bytes); +#endif + GC_ASSERT(GC_our_mem_bytes >= GC_heapsize); + GC_DBGLOG_PRINTF("GC #%lu freed %ld bytes, heap %lu KiB (" + IF_USE_MUNMAP("+ %lu KiB unmapped ") + "+ %lu KiB internal)\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)), + TO_KiB_UL(GC_our_mem_bytes - GC_heapsize)); + 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); + GC_on_collection_event(GC_EVENT_PRE_START_WORLD); #endif -} + } #ifdef THREAD_LOCAL_ALLOC -GC_world_stopped=FALSE; + GC_world_stopped = FALSE; #endif -START_WORLD(); + START_WORLD(); #ifdef THREADS -if (GC_on_collection_event) -GC_on_collection_event(GC_EVENT_POST_START_WORLD); + 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); + 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 -} + 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--; + 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; + 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; + 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; + word limit = (GC_WORD_MAX >> 1) / 50; #else -const word limit=GC_WORD_MAX/100; + 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)); + 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; + 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(); + 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); + if (GC_print_stats) + GET_TIME(start_time); #endif -if (GC_on_collection_event) -GC_on_collection_event(GC_EVENT_RECLAIM_START); + 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); -} + 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(); + GC_finalize(); #endif #ifndef NO_CLOCK -if (GC_print_stats) -GET_TIME(finalize_time); + if (GC_print_stats) + GET_TIME(finalize_time); #endif -if (GC_print_back_height){ + 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); + 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(); + 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); + 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); + 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_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(); + (void)GC_try_to_collect_general(0, FALSE); + if (GC_have_errors) GC_print_all_errors(); } -STATIC word GC_heapsize_at_forced_unmap=0; +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); + 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_INNER void GC_add_to_our_memory(ptr_t p, size_t bytes) + { + GC_ASSERT(p != NULL); + 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++; + GC_our_mem_bytes += bytes; + } +#endif +STATIC void GC_add_to_heap(struct hblk *p, size_t bytes) +{ + hdr * phdr; + word endp; + size_t old_capacity = 0; + void *old_heap_sects = NULL; +#ifdef GC_ASSERTIONS + unsigned i; +#endif + GC_ASSERT((word)p % HBLKSIZE == 0); + GC_ASSERT(bytes % HBLKSIZE == 0); + GC_ASSERT(bytes > 0); + GC_ASSERT(GC_all_nils != NULL); + if (GC_n_heap_sects == GC_capacity_heap_sects) { +#ifndef INITIAL_HEAP_SECTS +#define INITIAL_HEAP_SECTS 32 +#endif + size_t new_capacity = GC_n_heap_sects > 0 ? + (size_t)GC_n_heap_sects * 2 : INITIAL_HEAP_SECTS; + void *new_heap_sects = + GC_scratch_alloc(new_capacity * sizeof(struct HeapSect)); + if (EXPECT(NULL == new_heap_sects, FALSE)) { + new_capacity = (size_t)GC_n_heap_sects + INITIAL_HEAP_SECTS; + new_heap_sects = + GC_scratch_alloc(new_capacity * sizeof(struct HeapSect)); + if (NULL == new_heap_sects) + ABORT("Insufficient memory for heap sections"); + } + old_capacity = GC_capacity_heap_sects; + old_heap_sects = GC_heap_sects; + if (GC_n_heap_sects > 0) + BCOPY(old_heap_sects, new_heap_sects, + GC_n_heap_sects * sizeof(struct HeapSect)); + GC_capacity_heap_sects = new_capacity; + GC_heap_sects = (struct HeapSect *)new_heap_sects; + GC_COND_LOG_PRINTF("Grew heap sections array to %lu elements\n", + (unsigned long)new_capacity); + } + 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); +#ifdef GC_ASSERTIONS + for (i = 0; i < GC_n_heap_sects; i++) { + word hs_start = (word)GC_heap_sects[i].hs_start; + word hs_end = hs_start + GC_heap_sects[i].hs_bytes; + word p_e = (word)p + bytes; + GC_ASSERT(!((hs_start <= (word)p && (word)p < hs_end) + || (hs_start < p_e && p_e <= hs_end) + || ((word)p < hs_start && hs_end < p_e))); + } +#endif + 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 (old_capacity > 0) { +#ifndef GWW_VDB + GC_scratch_recycle_no_gww(old_heap_sects, + old_capacity * sizeof(struct HeapSect)); +#else + GC_noop1((word)old_heap_sects); +#endif + } +} +#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_max_heapsize = n; +} +GC_word GC_max_retries = 0; +GC_INNER void GC_scratch_recycle_inner(void *ptr, size_t bytes) +{ + size_t page_offset; + size_t displ = 0; + size_t recycled_bytes; + if (NULL == ptr) return; + GC_ASSERT(bytes != 0); + GC_ASSERT(GC_page_size != 0); + page_offset = (word)ptr & (GC_page_size - 1); + if (page_offset != 0) + displ = GC_page_size - page_offset; + recycled_bytes = bytes > displ ? (bytes - displ) & ~(GC_page_size - 1) : 0; + GC_COND_LOG_PRINTF("Recycle %lu/%lu scratch-allocated bytes at %p\n", + (unsigned long)recycled_bytes, (unsigned long)bytes, ptr); + if (recycled_bytes > 0) + GC_add_to_heap((struct hblk *)((word)ptr + displ), recycled_bytes); } -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); + 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); + if (EXPECT(NULL == space, FALSE)) { + WARN("Failed to expand heap by %" WARN_PRIdPTR " bytes\n", + (word)bytes); + return(FALSE); + } + GC_add_to_our_memory((ptr_t)space, bytes); + 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_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); + 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; +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; + 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_allocd_bytes_per_finalizer = value; } GC_API GC_word GC_CALL GC_get_allocd_bytes_per_finalizer(void) { -return GC_allocd_bytes_per_finalizer; + return GC_allocd_bytes_per_finalizer; } -static word last_fo_entries=0; -static word last_bytes_finalized=0; +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(); + 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 (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); + GC_noop1((word)&flh); #endif -if (NULL==*flh){ -GC_new_hblk(gran,kind); + 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); + 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 #endif #include #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; -} + 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; -} + 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() +#define RANDOM() GC_random() #else #include #define GC_RAND_MAX RAND_MAX -#if defined(__GLIBC__)||defined(SOLARIS)||defined(HPUX)||defined(IRIX5)||defined(OSF1) -#define RANDOM()random() +#if defined(__GLIBC__) || defined(SOLARIS) \ + || defined(HPUX) || defined(IRIX5) || defined(OSF1) +#define RANDOM() random() #else -#define RANDOM()(long)rand() +#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)){ + 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; + 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))); + 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); + ((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); + ((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0); #endif -((oh*)p)->oh_string=string; -((oh*)p)->oh_int=linenum; + ((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; + ((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}; + 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_fn fn) { -GC_describe_type_fns[kind]=fn; + GC_describe_type_fns[kind] = fn; } -#define GET_OH_LINENUM(ohdr)((int)(ohdr)->oh_int) +#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 +#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()); + 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; + 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); + 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); -} + 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()); + 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(,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){} + 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(, 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()); + 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; + 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; + 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)); + 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); + 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); +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(); + 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) +#if defined(HAVE_DLADDR) && defined(GC_HAVE_RETURN_ADDR_PARENT) #include -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)); + 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); -} + if (s == NULL) { + GC_caller_func_offset(ra, &s, &i); + } #endif -return store_debug_info(result,lb,"GC_debug_malloc",OPT_RA s,i); + 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) +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); + 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) +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); + 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) +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); + 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)); -} + 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){ + 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){ + 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; + errno = ENOMEM; #endif -return NULL; -} -if (len > 0) -BCOPY(str,copy,len); -copy[len]='\0'; -return copy; + return NULL; + } + if (len > 0) + BCOPY(str, copy, len); + copy[len] = '\0'; + return copy; } #ifdef GC_REQUIRE_WCSDUP #include -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){ + 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; + errno = ENOMEM; #endif -return NULL; -} -BCOPY(str,copy,lb); -return copy; -} + 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) +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); + 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); -} + 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 +#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) +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; + 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) + 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 { + 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 + 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) + && ((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 + ) { + 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)); + || 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"); + 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; -} + ((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; + 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; + 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); + 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); + 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); -} + 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 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; + 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]); + 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); -} -} + 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_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; + 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; + GC_finalization_proc cl_fn; + void * cl_data; }; -STATIC void*GC_make_closure(GC_finalization_proc fn,void*data) +STATIC void * GC_make_closure(GC_finalization_proc fn, void * data) { -struct closure*result= + struct closure * result = #ifdef DBG_HDRS_ALL -(struct closure*)GC_debug_malloc(sizeof (struct closure), -GC_EXTRAS); + (struct closure *) GC_debug_malloc(sizeof (struct closure), + GC_EXTRAS); #else -(struct closure*)GC_malloc(sizeof (struct closure)); + (struct closure *) GC_malloc(sizeof (struct closure)); #endif -if (result!=0){ -result->cl_fn=fn; -result->cl_data=data; + if (result != 0) { + result -> cl_fn = fn; + result -> cl_data = data; + } + return((void *)result); } -return((void*)result); -} -STATIC void GC_CALLBACK GC_debug_invoke_finalizer(void*obj,void*data) +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); + 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); +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); + (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); + (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); + (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 @@ -10876,1706 +11371,1702 @@ return GC_debug_realloc(p,lb,GC_DBG_EXTRAS); #ifndef GC_H #endif #ifdef __cplusplus -extern "C" { + 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); + 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) +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; + word hidden_key; + struct hash_chain_entry * next; }; struct disappearing_link { -struct hash_chain_entry prolog; + 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; +#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; + 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; +#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)) +#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)) +#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); + 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); + 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); + 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<=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<>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 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<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<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(); + 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"); + 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; +#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; + 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(); + 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; + 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; -} + 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; -} + 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 + 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 +#if defined(_MSC_VER) && defined(I386) + GC_ATTR_NOINLINE #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 + GC_mark_stack_top = GC_push_obj(p, HDR(p), GC_mark_stack_top, + GC_mark_stack + GC_mark_stack_size); } 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){} + 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<=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(); + 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); + 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); + 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<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< 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); -} -} -} + 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; + STATIC word GC_old_dl_entries = 0; #ifndef GC_LONG_REFS_NOT_NEEDED -STATIC word GC_old_ll_entries=0; + 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<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); + 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<=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); + 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(); + 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); + GC_make_disappearing_links_disappear(&GC_ll_hashtbl, FALSE); + GC_make_disappearing_links_disappear(&GC_ll_hashtbl, TRUE); #endif -if (GC_fail_count){ + if (GC_fail_count) { #ifdef THREADS -GC_reset_finalizer_nested(); + GC_reset_finalizer_nested(); #else -GC_finalizer_nested=0; + 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<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(); -} + 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; + return AO_load((volatile AO_t *)&GC_fnlz_roots.finalize_now) != 0; #else -return GC_fnlz_roots.finalize_now!=NULL; + 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; + int count = 0; + word bytes_freed_before = 0; + DCL_LOCK_STATE; + while (GC_should_invoke_finalizers()) { + struct finalizable_object * curr_fo; #ifdef THREADS -LOCK(); + LOCK(); #endif -if (count==0){ -bytes_freed_before=GC_bytes_freed; -} -curr_fo=GC_fnlz_roots.finalize_now; + 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; + 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; + 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; + 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){ + 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; + 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; + 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)(); + 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)); -} +#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" { + 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); +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_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); +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) +#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) +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; + 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; + 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 #include -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); +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; + 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; -} + 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 { + 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); + ((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); + GC_ASSERT(hhdr -> hb_n_marks == 0); #endif -hhdr->hb_n_marks=1; -UNLOCK(); -} + hhdr -> hb_n_marks = 1; + UNLOCK(); + } + } + return op; } -return op; -} -GC_API GC_ATTR_MALLOC void*GC_CALL GC_malloc_uncollectable(size_t lb) +GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_uncollectable(size_t lb) { -return GC_generic_malloc_uncollectable(lb,UNCOLLECTABLE); + 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); -} + 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) +#if defined(REDIRECT_MALLOC) && !defined(REDIRECT_MALLOC_IN_HEADER) #ifndef MSWINCE #include #endif -#define GC_debug_malloc_replacement(lb)GC_debug_malloc(lb,GC_DBG_EXTRAS) +#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); + 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); -} + 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); + 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); -} + { + 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; -} + 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; -} + 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; -} +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(); -} + 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) + 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(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) -{ + 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; -} +#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); + REDIRECT_FREE_F(p); #endif -} + } #endif #include #include @@ -12585,1533 +13076,1557 @@ REDIRECT_FREE_F(p); #ifndef GC_ALLOC_PTRS_H #define GC_ALLOC_PTRS_H #ifdef __cplusplus -extern "C" { + extern "C" { +#endif +#ifndef GC_API_PRIV +#define GC_API_PRIV GC_API +#endif +#ifndef GC_APIVAR_CONST +#if defined(GC_BUILD) || !defined(GC_DLL) +#define GC_APIVAR_CONST const +#else +#define GC_APIVAR_CONST +#endif #endif -GC_API void**const GC_objfreelist_ptr; -GC_API void**const GC_aobjfreelist_ptr; -GC_API void**const GC_uobjfreelist_ptr; +GC_API_PRIV void ** GC_APIVAR_CONST GC_objfreelist_ptr; +GC_API_PRIV void ** GC_APIVAR_CONST GC_aobjfreelist_ptr; +GC_API_PRIV void ** GC_APIVAR_CONST GC_uobjfreelist_ptr; #ifdef GC_ATOMIC_UNCOLLECTABLE -GC_API void**const GC_auobjfreelist_ptr; + GC_API_PRIV void ** GC_APIVAR_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); +GC_API_PRIV void GC_CALL GC_incr_bytes_allocd(size_t ); +GC_API_PRIV void GC_CALL GC_incr_bytes_freed(size_t ); #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; +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; + void ** const GC_auobjfreelist_ptr = GC_auobjfreelist; #endif -GC_API int GC_CALL GC_get_kind_and_size(const void*p,size_t*psize) +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; + 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) +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: + 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){ + 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; + 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(); -} + 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); + 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); + 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); + GC_free(p); #endif + } + return result; } -return result; -} -#if defined(REDIRECT_MALLOC)&&!defined(REDIRECT_REALLOC) +#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)); -} +#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 { +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; + ((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_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) +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); + 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) +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); + return GC_generic_malloc_ignore_off_page(lb, PTRFREE); } -GC_API void GC_CALL GC_incr_bytes_allocd(size_t n) +void GC_CALL GC_incr_bytes_allocd(size_t n) { -GC_bytes_allocd+=n; + GC_bytes_allocd += n; } -GC_API void GC_CALL GC_incr_bytes_freed(size_t n) +void GC_CALL GC_incr_bytes_freed(size_t n) { -GC_bytes_freed+=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; + 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; + 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; + 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; + while ((hbp = rlh[lg]) != NULL) { + hhdr = HDR(hbp); + rlh[lg] = 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){ + 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(); + 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; -} + 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; + 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(); + rlh = ok -> ok_reclaim_list; + if (NULL == rlh) break; + } +#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; + 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 -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){ +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; + return ERROR_INVALID_PARAMETER; #else -return EINVAL; + return EINVAL; #endif -} -if ((*memptr=GC_memalign(align,lb))==NULL){ + } + if ((*memptr = GC_memalign(align, lb)) == NULL) { #ifdef MSWINCE -return ERROR_NOT_ENOUGH_MEMORY; + return ERROR_NOT_ENOUGH_MEMORY; #else -return ENOMEM; + return ENOMEM; #endif + } + return 0; } -return 0; -} -GC_API GC_ATTR_MALLOC char*GC_CALL GC_strdup(const char*s) +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){ + 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; + errno = ENOMEM; #endif -return NULL; + return NULL; + } + BCOPY(s, copy, lb); + return copy; } -BCOPY(s,copy,lb); -return copy; -} -GC_API GC_ATTR_MALLOC char*GC_CALL GC_strndup(const char*str,size_t size) +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){ + 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; + errno = ENOMEM; #endif -return NULL; -} -if (EXPECT(len > 0,TRUE)) -BCOPY(str,copy,len); -copy[len]='\0'; -return copy; + return NULL; + } + if (EXPECT(len > 0, TRUE)) + BCOPY(str, copy, len); + copy[len] = '\0'; + return copy; } #ifdef GC_REQUIRE_WCSDUP #include -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){ + 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; + errno = ENOMEM; #endif -return NULL; -} -BCOPY(str,copy,lb); -return copy; -} + 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) -{ -} + 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_API void GC_CALL GC_end_stubborn_change(const void *p) { -GC_dirty(p); + GC_dirty(p); } -GC_API void GC_CALL GC_ptr_store_and_dirty(void*p,const void*q) +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); + *(const void **)p = q; + GC_dirty(p); + REACHABLE_AFTER_DIRTY(q); } -#if defined(__MINGW32__)&&!defined(__MINGW_EXCPT_DEFINE_PSDK)&&defined(__i386__) +#if defined(__MINGW32__) && !defined(__MINGW_EXCPT_DEFINE_PSDK) \ + && defined(__i386__) #define __MINGW_EXCPT_DEFINE_PSDK 1 #endif #include -#if defined(MSWIN32)&&defined(__GNUC__) +#if defined(MSWIN32) && defined(__GNUC__) #include #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) +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(); +#if defined(AO_HAVE_compiler_barrier) && !defined(BASE_ATOMIC_OPS_EMULATED) + AO_compiler_barrier(); #else -GC_noop1(0); + 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 }, + 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 }, + { &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; +#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; + 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); + return(GC_mark_state != MS_NONE); } -GC_INNER void GC_clear_hdr_marks(hdr*hhdr) +GC_INNER void GC_clear_hdr_marks(hdr *hhdr) { -size_t last_bit; + size_t last_bit; #ifdef AO_HAVE_load -last_bit=FINAL_MARK_BIT((size_t)AO_load((volatile AO_t*)&hhdr->hb_sz)); + 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); + 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; + 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) +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); + 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; -} + 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; -} + 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; + hhdr -> hb_n_marks = n_marks; #else -hhdr->hb_n_marks=HBLK_OBJS(sz); + hhdr -> hb_n_marks = HBLK_OBJS(sz); #endif } -static void clear_marks_for_block(struct hblk*h,word dummy GC_ATTR_UNUSED) +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); + 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) +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; -} + 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) +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--; + 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; + if (n_marks != 0 || !GC_parallel) + hhdr -> hb_n_marks = n_marks; #else -hhdr->hb_n_marks=n_marks; + hhdr -> hb_n_marks = n_marks; #endif + } } -} -GC_API int GC_CALL GC_is_marked(const void*p) +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); + 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_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()); + GC_ASSERT(I_HOLD_LOCK()); #ifndef GC_DISABLE_INCREMENTAL -if (GC_incremental){ + if (GC_incremental) { #ifdef CHECKSUMS -GC_read_dirty(FALSE); -GC_check_dirty(); + GC_read_dirty(FALSE); + GC_check_dirty(); #else -GC_read_dirty(GC_mark_state==MS_INVALID); + GC_read_dirty(GC_mark_state == MS_INVALID); #endif -} -GC_n_rescuing_pages=0; + } + 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; + 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); + STATIC void GC_do_parallel_mark(void); #endif #ifdef GC_DISABLE_INCREMENTAL -#define GC_push_next_marked_dirty(h)GC_push_next_marked(h) +#define GC_push_next_marked_dirty(h) GC_push_next_marked(h) #else -STATIC struct hblk*GC_push_next_marked_dirty(struct hblk*h); + 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 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)){ + 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: + 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); + 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) +#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) + __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) +#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; + er.alt_path = &&handle_ex; #pragma GCC diagnostic pop -#elif!defined(CPPCHECK) -er.alt_path=&&handle_ex; +#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; + 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; + 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; + if (GC_auto_incremental) { + static GC_bool is_warned = FALSE; + if (!is_warned) { + is_warned = TRUE; + 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: + { + 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(); + START_WORLD(); + GC_cond_register_dynamic_libraries(); + STOP_WORLD(); #endif -GC_invalidate_mark_state(); -GC_scan_ptr=NULL; -ret_val=FALSE; -goto rm_handler; -} + 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_mark_state = MS_INVALID; + GC_mark_stack_top = GC_mark_stack-1; } -GC_INNER mse*GC_signal_mark_stack_overflow(mse*msp) +GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp) { -GC_mark_state=MS_INVALID; + GC_mark_state = MS_INVALID; #ifdef PARALLEL_MARK -if (!GC_parallel) -GC_mark_stack_too_small=TRUE; + if (!GC_parallel) + GC_mark_stack_too_small = TRUE; #else -GC_mark_stack_too_small=TRUE; + 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_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; +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; + 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); + 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++; + 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); + if ((word)GC_trace_addr >= (word)current_p + && (word)GC_trace_addr < (word)(current_p + descr)) { + GC_log_printf("GC #%lu: large section; start %p, len %lu," + " splitting (parallel) at %p\n", + (unsigned long)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--; + if ((word)GC_trace_addr >= (word)current_p + && (word)GC_trace_addr < (word)(current_p + descr)) { + GC_log_printf("GC #%lu: large section; start %p, len %lu," + " splitting at %p\n", + (unsigned long)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&¤t < (word)greatest_ha){ -PREFETCH((ptr_t)current); + if ((word)GC_trace_addr >= (word)current_p + && (word)GC_trace_addr < (word)(current_p + + WORDS_TO_BYTES(WORDSZ-2))) { + GC_log_printf("GC #%lu: tracing from %p bitmap descr %lu\n", + (unsigned long)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--; + if (GC_trace_addr == current_p) { + GC_log_printf("GC #%lu: considering(3) %p -> %p\n", + (unsigned long)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--; + 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 #%lu: tracing from %p, proc descr %lu\n", + (unsigned long)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; + 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); -{ + if ((word)GC_trace_addr >= (word)current_p + && (word)GC_trace_addr < (word)(current_p + descr)) { + GC_log_printf("GC #%lu: small object; start %p, len %lu\n", + (unsigned long)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&¤t < (word)greatest_ha){ -PREFETCH((ptr_t)current); + 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; -} + if (GC_trace_addr == current_p) { + GC_log_printf("GC #%lu: considering(1) %p -> %p\n", + (unsigned long)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); -} + if (GC_trace_addr == current_p) { + GC_log_printf("GC #%lu: considering(2) %p -> %p\n", + (unsigned long)GC_gc_no, (void *)current_p, + (void *)deferred); + } #endif -PUSH_CONTENTS((ptr_t)deferred,mark_stack_top, -mark_stack_limit,current_p); -next_object:; + PUSH_CONTENTS((ptr_t)deferred, mark_stack_top, + mark_stack_limit, current_p); + next_object:; #endif -} -} -return mark_stack_top; + } + } + 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; +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) +#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; + 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(); + 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); -} -} + 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_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_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); + 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)); + 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; + 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_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); + alloc_mark_stack(INITIAL_MARK_STACK_SIZE); } -GC_API void GC_CALL GC_push_all(void*bottom,void*top) +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; + 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; + 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; + 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 { + 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 + 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); + } + } + } +#ifndef NO_VDB_FOR_STATIC_ROOTS +#ifndef PROC_VDB + STATIC GC_bool GC_static_page_was_dirty(struct hblk *h) + { + return get_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h)); + } +#endif + GC_INNER void GC_push_conditional_static(void *bottom, void *top, + GC_bool all) + { +#ifdef PROC_VDB + GC_push_conditional(bottom, top, all); +#else + if (all || !GC_is_vdb_for_static_roots()) { + GC_push_all(bottom, top); + } else { + GC_push_selected((ptr_t)bottom, (ptr_t)top, + GC_static_page_was_dirty); + } +#endif + } #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); -} + 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); -} +#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) + 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; -} + 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); + GC_dirty(p); #endif -GC_mark_stack_top=GC_push_contents_hdr(r,GC_mark_stack_top, -GC_mark_stack_limit, -source,hhdr,FALSE); + 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 @@ -14119,2262 +14634,2277 @@ source,hhdr,FALSE); #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; + 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"); + 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(); + 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; +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); -} + 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) +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; + 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); -} + 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 +#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 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 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) +#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; +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; -} + 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; + 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; +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; -} + 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; + 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; +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; -} + 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; + GC_mark_stack_top = mark_stack_top; } #endif #endif #endif -STATIC void GC_push_marked(struct hblk*h,hdr*hhdr) +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++; + 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)){ + 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; + 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; + case 4: + GC_push_marked4(h, hhdr); + break; #endif #endif #else -case 1: + 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; -} + 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; -} + 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 { + 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"); + if (NULL == h) ABORT("Bad HDR() definition"); #endif -} -GC_push_marked(h,hhdr); -return(h+OBJ_SZ_TO_BLOCKS(hhdr->hb_sz)); + } + 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 { + 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"); + 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); -} + } + 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); -} else + if ((hhdr -> hb_flags & MARK_UNCONDITIONALLY) != 0) { + GC_push_unconditionally(h, hhdr); + break; + } #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)); + h += OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz); + hhdr = HDR(h); + } + return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz)); } #include -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); -} +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; + 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; + 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"); -} + 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)":""); + 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); + 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_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(); + DCL_LOCK_STATE; + if (!EXPECT(GC_is_initialized, TRUE)) GC_init(); + LOCK(); #ifdef THREADS -GC_roots_were_cleared=TRUE; + 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*)); + 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"); + GC_log_printf("Clear all data root sections\n"); #endif -UNLOCK(); + 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) + 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(); -} + 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){ + 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)){ + 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); -} + 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); + 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; + sp = (word)&sp; #endif -return((ptr_t)sp); + 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; -} + 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_static(b, t, all)) +#else +#define GC_PUSH_CONDITIONAL(b, t, all) GC_push_conditional_static(b, t, all) +#endif +STATIC void GC_push_conditional_with_exclusions(ptr_t bottom, ptr_t top, + GC_bool all) +{ + 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); -} -} + 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) +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); + 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); + GC_push_all_stack((ptr_t)traced_stack_sect, lo); #else -GC_push_all_stack(lo,(ptr_t)traced_stack_sect); + 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)); + 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); + GC_push_all_stack(hi, lo); #else -GC_push_all_stack(lo,hi); + 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) +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); + 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); + 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); + GC_push_all(bottom, cold_gc_frame + sizeof(ptr_t)); + GC_push_all_eager(cold_gc_frame, top); #endif -} else + } else #endif -{ -GC_push_all_eager(bottom,top); -} + { + GC_push_all_eager(bottom, top); + } #ifdef TRACE_BUF -GC_add_trace_entry("GC_push_all_stack",(word)bottom,(word)top); + 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) +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); + 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)); + 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); + GC_push_all_stack_partially_eager(hi, lo, cold_gc_frame); #else -GC_push_all_stack_partially_eager(lo,hi,cold_gc_frame); + 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) + void * context GC_ATTR_UNUSED) { #if defined(THREADS) #ifdef STACK_GROWS_DOWN -GC_push_all_eager(GC_approx_sp(),cold_gc_frame); + GC_push_all_eager(GC_approx_sp(), cold_gc_frame); #else -GC_push_all_eager(cold_gc_frame,GC_approx_sp()); + 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); + 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; + { + 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(); +#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; + 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); -} -} + 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(); + GC_push_finalizer_structures(); #endif #ifdef THREADS -if (GC_no_dls||GC_roots_were_cleared) -GC_push_thread_structures(); + if (GC_no_dls || GC_roots_were_cleared) + GC_push_thread_structures(); #endif -if (GC_push_typed_structures) -GC_push_typed_structures(); + if (GC_push_typed_structures) + GC_push_typed_structures(); #if defined(THREAD_LOCAL_ALLOC) -if (GC_world_stopped) -GC_mark_thread_local_free_lists(); + if (GC_world_stopped) + GC_mark_thread_local_free_lists(); #endif #ifndef STACK_NOT_SCANNED -GC_push_regs_and_stack(cold_gc_frame); + GC_push_regs_and_stack(cold_gc_frame); #endif -if (GC_push_other_roots!=0){ -(*GC_push_other_roots)(); -} + if (GC_push_other_roots != 0) { + (*GC_push_other_roots)(); + } } #ifdef ENABLE_DISCLAIM #endif #include -GC_INNER signed_word GC_bytes_found=0; +GC_INNER signed_word GC_bytes_found = 0; #if defined(PARALLEL_MARK) -GC_INNER signed_word GC_fl_builder_count=0; + 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); +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; + 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_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]; + 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); + GC_print_heap_obj(p); #endif -GC_free(p); -} -if (have_errors + GC_free(p); + } + if (have_errors #ifndef GC_ABORT_ON_LEAK -&&GETENV("GC_ABORT_ON_LEAK")!=NULL + && GETENV("GC_ABORT_ON_LEAK") != NULL #endif -){ -ABORT("Leaked or smashed objects encountered"); -} -LOCK(); -printing_errors=FALSE; -UNLOCK(); + ) { + ABORT("Leaked or smashed objects encountered"); + } + LOCK(); + printing_errors = FALSE; + UNLOCK(); } -GC_INNER GC_bool GC_block_empty(hdr*hhdr) +GC_INNER GC_bool GC_block_empty(hdr *hhdr) { -return (hhdr->hb_n_marks==0); + return (hhdr -> hb_n_marks == 0); } -STATIC GC_bool GC_block_nearly_full(hdr*hhdr,word sz) +STATIC GC_bool GC_block_nearly_full(hdr *hhdr, word sz) { -return hhdr->hb_n_marks > HBLK_OBJS(sz)*7/8; + 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) +GC_INLINE word *GC_clear_block(word *p, word sz, 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); + word *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; + 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 + *count += sz; + return p; +} +STATIC ptr_t GC_reclaim_clear(struct hblk *hbp, hdr *hhdr, word sz, + ptr_t list, signed_word *count) +{ + word bit_no = 0; + ptr_t p, plim; + GC_ASSERT(hhdr == GC_find_header((ptr_t)hbp)); #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); + GC_ASSERT(sz == hhdr -> hb_sz); +#else +#endif + GC_ASSERT((sz & (BYTES_PER_WORD-1)) == 0); + p = hbp->hb_body; + plim = p + HBLKSIZE - sz; + while ((word)p <= (word)plim) { + if (mark_bit_from_hdr(hhdr, bit_no)) { + p += sz; + } else { + obj_link(p) = list; + list = p; + p = (ptr_t)GC_clear_block((word *)p, sz, count); + } + bit_no += MARK_BIT_OFFSET(sz); + } + 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; + STATIC ptr_t GC_disclaim_and_reclaim(struct hblk *hbp, hdr *hhdr, word sz, + ptr_t list, signed_word *count) + { + word bit_no = 0; + ptr_t p, plim; + 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; + GC_ASSERT(sz == hhdr -> hb_sz); +#endif + p = hbp->hb_body; + plim = p + HBLKSIZE - sz; + for (; (word)p <= (word)plim; bit_no += MARK_BIT_OFFSET(sz)) { + if (mark_bit_from_hdr(hhdr, bit_no)) { + p += sz; + } else if ((*disclaim)(p)) { + set_mark_bit_from_hdr(hhdr, bit_no); + hhdr -> hb_n_marks++; + p += sz; + } else { + obj_link(p) = list; + list = p; + p = (ptr_t)GC_clear_block((word *)p, sz, count); + } + } + 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); + 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); -} -} + 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) +#define IS_PTRFREE_SAFE(hhdr) \ + (AO_load((volatile AO_t *)&(hhdr)->hb_descr) == 0) #else -#define IS_PTRFREE_SAFE(hhdr)((hhdr)->hb_descr==0) +#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) +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); + 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)); + 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); -} + 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]; + 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); + sz = (word)AO_load((volatile AO_t *)&hhdr->hb_sz); #else -sz=hhdr->hb_sz; + 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; + 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 (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 { + 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); + 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); + GC_ASSERT(hhdr -> hb_n_marks <= 2 * (HBLKSIZE/sz + 1) + 16); #else -GC_ASSERT(sz*hhdr->hb_n_marks<=HBLKSIZE); + GC_ASSERT(sz * hhdr -> hb_n_marks <= HBLKSIZE); #endif -if (report_if_found){ -GC_reclaim_small_nonempty_block(hbp,sz, -TRUE); -} else if (empty){ + 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) + 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; + size_t number_of_blocks; + size_t total_bytes; }; #ifdef USE_MARK_BYTES -unsigned GC_n_set_marks(hdr*hhdr) +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); + 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); + 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 GC_n_set_marks(hdr *hhdr) { -unsigned result=0; -word i; -word n_mark_words; + 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); + 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; + n_mark_words = MARK_BITS_SZ; #endif -for (i=0;i < n_mark_words - 1;i++){ -result+=set_bits(hhdr->hb_marks[i]); -} + 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++; + 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; -} + 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; + 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); + 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); + GC_reclaim_all((GC_stop_func)0, FALSE); #elif defined(ENABLE_DISCLAIM) -GC_reclaim_unconditionally_marked(); + 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; + 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); -} -} -} -} + 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); -} -} -} -} + 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; + 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); -} -} +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) + 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); + 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) + 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); +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))) +#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) +#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; +#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; + word ld_tag; #define LEAF_TAG 1 -size_t ld_size; -size_t ld_nelements; -GC_descr ld_descriptor; + size_t ld_size; + size_t ld_nelements; + GC_descr ld_descriptor; }; struct ComplexArrayDescriptor { -word ad_tag; + word ad_tag; #define ARRAY_TAG 2 -size_t ad_nelements; -union ComplexDescriptor*ad_element_descr; + size_t ad_nelements; + union ComplexDescriptor * ad_element_descr; }; struct SequenceDescriptor { -word sd_tag; + word sd_tag; #define SEQUENCE_TAG 3 -union ComplexDescriptor*sd_first; -union ComplexDescriptor*sd_second; + union ComplexDescriptor * sd_first; + union ComplexDescriptor * sd_second; }; typedef union ComplexDescriptor { -struct LeafDescriptor ld; -struct ComplexArrayDescriptor ad; -struct SequenceDescriptor sd; + 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 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); + 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) +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); + 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); +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 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); + 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&¤t<=(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"); + 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 { + 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; + 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 #include @@ -16385,12 +16915,13 @@ return op; #ifdef GC_SOLARIS_THREADS #include #endif -#if defined(UNIX_LIKE)||defined(CYGWIN32)||defined(SYMBIAN)||(defined(CONSOLE_LOG)&&defined(MSWIN32)) +#if defined(UNIX_LIKE) || defined(CYGWIN32) || defined(SYMBIAN) \ + || (defined(CONSOLE_LOG) && defined(MSWIN32)) #include #include #include #endif -#if defined(CONSOLE_LOG)&&defined(MSWIN32)&&defined(_MSC_VER) +#if defined(CONSOLE_LOG) && defined(MSWIN32) && defined(_MSC_VER) #include #endif #ifdef NONSTOP @@ -16399,1313 +16930,1350 @@ return op; #ifdef THREADS #ifdef PCR #include "il/PCR_IL.h" -GC_INNER PCR_Th_ML GC_allocate_ml; + 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) + GC_INNER WapiMutex GC_allocate_ml_PSP2 = { 0, NULL }; +#elif defined(GC_DEFN_ALLOCATE_ML) || defined(SN_TARGET_PS3) #include -GC_INNER pthread_mutex_t GC_allocate_ml; + GC_INNER pthread_mutex_t GC_allocate_ml; #endif #endif #ifdef DYNAMIC_LOADING -#define GC_REGISTER_MAIN_STATIC_DATA()GC_register_main_static_data() +#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 +#define GC_REGISTER_MAIN_STATIC_DATA() FALSE #else -#define GC_REGISTER_MAIN_STATIC_DATA()TRUE +#define GC_REGISTER_MAIN_STATIC_DATA() TRUE #endif #ifdef NEED_CANCEL_DISABLE_COUNT -__thread unsigned char GC_cancel_disable_count=0; + __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; +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; + 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; +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; + GC_INNER GC_bool GC_print_back_height = TRUE; #else -GC_INNER GC_bool GC_print_back_height=FALSE; + 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; + GC_INNER GC_bool GC_dump_regularly = TRUE; #else -GC_INNER GC_bool GC_dump_regularly=FALSE; + GC_INNER GC_bool GC_dump_regularly = FALSE; #endif #ifndef NO_CLOCK -STATIC CLOCK_TYPE GC_init_time; + STATIC CLOCK_TYPE GC_init_time; #endif #endif #ifdef KEEP_BACK_PTRS -GC_INNER long GC_backtraces=0; + GC_INNER long GC_backtraces = 0; #endif #ifdef FIND_LEAK -int GC_find_leak=1; + int GC_find_leak = 1; #else -int GC_find_leak=0; + int GC_find_leak = 0; #endif #ifndef SHORT_DBG_HDRS #ifdef GC_FINDLEAK_DELAY_FREE -GC_INNER GC_bool GC_findleak_delay_free=TRUE; + GC_INNER GC_bool GC_findleak_delay_free = TRUE; #else -GC_INNER GC_bool GC_findleak_delay_free=FALSE; + GC_INNER GC_bool GC_findleak_delay_free = FALSE; #endif #endif #ifdef ALL_INTERIOR_POINTERS -int GC_all_interior_pointers=1; + int GC_all_interior_pointers = 1; #else -int GC_all_interior_pointers=0; + int GC_all_interior_pointers = 0; #endif #ifdef FINALIZE_ON_DEMAND -int GC_finalize_on_demand=1; + int GC_finalize_on_demand = 1; #else -int GC_finalize_on_demand=0; + int GC_finalize_on_demand = 0; #endif #ifdef JAVA_FINALIZATION -int GC_java_finalization=1; + int GC_java_finalization = 1; #else -int GC_java_finalization=0; + int GC_java_finalization = 0; #endif -GC_finalizer_notifier_proc GC_finalizer_notifier= -(GC_finalizer_notifier_proc)0; +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; + GC_INNER GC_bool GC_force_unmap_on_gcollect = TRUE; #else -GC_INNER GC_bool GC_force_unmap_on_gcollect=FALSE; + 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) +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); + return(0); } -GC_oom_func GC_oom_fn=GC_default_oom_fn; +GC_oom_func GC_oom_fn = GC_default_oom_fn; #ifdef CAN_HANDLE_FORK #ifdef HANDLE_FORK -GC_INNER int GC_handle_fork=1; + GC_INNER int GC_handle_fork = 1; #else -GC_INNER int GC_handle_fork=FALSE; + GC_INNER int GC_handle_fork = FALSE; #endif -#elif!defined(HAVE_NO_FORK) -GC_API void GC_CALL GC_atfork_prepare(void) -{ +#elif !defined(HAVE_NO_FORK) + GC_API void GC_CALL GC_atfork_prepare(void) + { #ifdef THREADS -ABORT("fork()handling unsupported"); + ABORT("fork() handling unsupported"); #endif -} -GC_API void GC_CALL GC_atfork_parent(void) -{ -} -GC_API void GC_CALL GC_atfork_child(void) -{ -} + } + 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){ + 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(); + GC_init(); #ifndef THREADS -if (GC_manual_vdb) -return; + if (GC_manual_vdb) + return; #endif #endif -ABORT("fork()handling unsupported"); -} + 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); + 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); + 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) -{ +#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)); + word volatile dummy[SMALL_CLEAR_SIZE]; + BZERO(( void *)dummy, sizeof(dummy)); #endif -return arg; -} + 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; + 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); + 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 + void *GC_clear_stack_inner(void *arg, +#if defined(__APPLE_CC__) && !GC_CLANG_PREREQ(6, 0) + volatile #endif -ptr_t limit) -{ + 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); -} + 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]); + GC_noop1(dummy[0]); #else -GC_noop1(COVERT_DATAFLOW(dummy)); + GC_noop1(COVERT_DATAFLOW(dummy)); #endif -return(arg); -} + 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(); + 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]; + 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); + 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; } -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) +GC_API size_t GC_CALL GC_get_heap_size(void) { -hdr*hhdr=HDR(p); -return (size_t)hhdr->hb_sz; + return (size_t)(GC_heapsize - GC_unmapped_bytes); } -GC_API size_t GC_CALL GC_get_heap_size(void) +GC_API size_t GC_CALL GC_get_obtained_from_os_bytes(void) { -return (size_t)(GC_heapsize - GC_unmapped_bytes); + return (size_t)GC_our_mem_bytes; } GC_API size_t GC_CALL GC_get_free_bytes(void) { -return (size_t)(GC_large_free_bytes - GC_unmapped_bytes); + 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; + return (size_t)GC_unmapped_bytes; } GC_API size_t GC_CALL GC_get_bytes_since_gc(void) { -return (size_t)GC_bytes_allocd; + 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); + 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; + 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); + pstats->markers_m1 = (word)((signed_word)GC_markers_m1); #else -pstats->markers_m1=0; + 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; -} + 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; + pstats->obtained_from_os_bytes = GC_our_mem_bytes; + } #include -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; -} -} + 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)) + 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; + 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; + 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]; + size_t bytes_to_get; + 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); + bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP((size_t)len + 1); + content = (char *)GET_MEM(bytes_to_get); + if (content == NULL) { + CloseHandle(hFile); + return; + } + GC_add_to_our_memory(content, bytes_to_get); + 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; + 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; + return GC_is_initialized; } -#if defined(GC_WIN32_THREADS)&&((defined(MSWIN32)&&!defined(CONSOLE_LOG))||defined(MSWINCE)) -GC_INNER CRITICAL_SECTION GC_write_cs; +#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; +#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){ + 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; -} -} + 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; +#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; -} + 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) -{ + STATIC void GC_win32_MessageBoxA(const char *msg, const char *caption, + unsigned flags) + { #ifndef DONT_USE_USER32_DLL -(void)MessageBoxA(NULL,msg,caption,flags); + (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); -} + 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){} +#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; + 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; + 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; + 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; -} + { + 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; +#if defined(GC_INITIAL_HEAP_SIZE) && !defined(CPPCHECK) + initial_heap_sz = GC_INITIAL_HEAP_SIZE; #else -initial_heap_sz=MINHINCR*HBLKSIZE; + initial_heap_sz = MINHINCR * HBLKSIZE; #endif -DISABLE_CANCEL(cancel_state); + DISABLE_CANCEL(cancel_state); #ifdef THREADS #ifndef GC_ALWAYS_MULTITHREADED -GC_ASSERT(!GC_need_to_lock); + 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) + { + 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); + 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 + 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); -} + InitializeCriticalSection(&GC_allocate_ml); + } #endif #endif -#if defined(GC_WIN32_THREADS)&&((defined(MSWIN32)&&!defined(CONSOLE_LOG))||defined(MSWINCE)) -InitializeCriticalSection(&GC_write_cs); +#if defined(GC_WIN32_THREADS) \ + && ((defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE)) + InitializeCriticalSection(&GC_write_cs); #endif -GC_setpagesize(); + GC_setpagesize(); #ifdef MSWIN32 -GC_init_win32(); + GC_init_win32(); #endif #ifdef GC_READ_ENV_FILE -GC_envfile_init(); + GC_envfile_init(); #endif -#if!defined(NO_CLOCK)||!defined(SMALL_CONFIG) +#if !defined(NO_CLOCK) || !defined(SMALL_CONFIG) #ifdef GC_PRINT_VERBOSE_STATS -GC_print_stats=VERBOSE; + 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; -} + 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")); +#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; + if (NULL == file_name) + file_name = GC_LOG_STD_NAME; #else -if (0!=file_name) + if (0 != file_name) #endif -{ + { #if defined(_MSC_VER) -int log_d=_open(file_name,O_CREAT|O_WRONLY|O_APPEND); + 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); + 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"); + 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') + if (str != NULL && *str == '0' && *(str + 1) == '\0') #else -if (str==NULL||(*str=='0'&&*(str+1)=='\0')) + if (str == NULL || (*str == '0' && *(str + 1) == '\0')) #endif -{ -GC_stdout=log_d; -GC_stderr=log_d; -} -} -} -} + { + 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; -} +#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; -} + { + 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){ + 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")) { +#ifdef LINT2 + GC_disable(); +#else + GC_dont_gc = 1; +#endif + } + 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); + 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; + 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; -} -} -} + { + 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; -} -} + { + 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(); + { + 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; + 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); + 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); + 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); +#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(); + GC_init_linux_data_start(); #endif -#if defined(NETBSD)&&defined(__ELF__) -GC_init_netbsd_elf(); +#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(); +#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(); -} + } 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); +#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); + GC_STATIC_ASSERT((signed_word)(-1) < (signed_word)0); #endif -GC_STATIC_ASSERT(sizeof (struct hblk)==HBLKSIZE); + GC_STATIC_ASSERT(sizeof (struct hblk) == HBLKSIZE); #ifndef THREADS -GC_ASSERT(!((word)GC_stackbottom HOTTER_THAN (word)GC_approx_sp())); + GC_ASSERT(!((word)GC_stackbottom HOTTER_THAN (word)GC_approx_sp())); #endif + GC_init_headers(); #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(); + 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_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(); + 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) +#if defined(LINT2) \ + && !(defined(GC_ASSERTIONS) && defined(GC_ALWAYS_MULTITHREADED)) + LOCK(); + GC_thr_init(); + UNLOCK(); +#else + GC_thr_init(); +#endif #ifdef PARALLEL_MARK -#if defined(GC_ASSERTIONS)&&defined(GC_ALWAYS_MULTITHREADED) -UNLOCK(); +#if defined(GC_ASSERTIONS) && defined(GC_ALWAYS_MULTITHREADED) + UNLOCK(); #endif -GC_start_mark_threads_inner(); -#if defined(GC_ASSERTIONS)&&defined(GC_ALWAYS_MULTITHREADED) -LOCK(); + 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(); + 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); +#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); -} + 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(); +#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(); +#if defined(DYNAMIC_LOADING) && defined(DARWIN) + GC_init_dyld(); #endif -RESTORE_CANCEL(cancel_state); + 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(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) + 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 #endif -STATIC HANDLE GC_log=0; + 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 +#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 +#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 -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; + 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) + 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; + BOOL appendToFile = FALSE; #endif -#if!defined(NO_GETENV_WIN32)||!defined(OLD_WIN32_LOG_FILE) -TCHAR pathBuf[_MAX_PATH+0x10]; -logPath=pathBuf; +#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 + 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); + 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); -} + 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)); + 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; + return 0; #else -return -1; + return -1; #endif -} -res=WriteFile(GC_log,buf,(DWORD)len,&written,NULL); -#if defined(_MSC_VER)&&defined(_DEBUG)&&!defined(NO_CRT) + } + 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)) + { + 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 #ifndef GC_ANDROID_LOG_TAG @@ -17714,60 +18282,63 @@ return res; #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) +#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) + 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) + 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) +#if !defined(GC_NO_TYPES) && !defined(SN_TARGET_PSP2) +#if !defined(AMIGA) && !defined(MSWIN32) && !defined(MSWIN_XBOX1) \ + && !defined(__CC_ARM) #include #endif -#if!defined(ECOS)&&!defined(NOSYS) +#if !defined(ECOS) && !defined(NOSYS) #include #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) + STATIC int GC_write(int fd, const char *buf, size_t len) + { +#if defined(ECOS) || defined(PLATFORM_WRITE) || defined(SN_TARGET_PSP2) \ + || defined(NOSYS) #ifdef ECOS #else #endif -return len; + return len; #else -int bytes_written=0; -IF_CANCEL(int cancel_state;) -DISABLE_CANCEL(cancel_state); -while ((unsigned)bytes_written < len){ + 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); + 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)); + int result = _write(fd, buf + bytes_written, + (unsigned)(len - bytes_written)); #else -int result=write(fd,buf+bytes_written,len - bytes_written); + 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); + 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) + } +#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) +#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 @@ -17777,672 +18348,685 @@ return(bytes_written); #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); +#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)); + (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 + 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"); -} + ) { + ABORT("write to stdout failed"); + } #endif + } } -} -void GC_err_printf(const char*format,...) +void GC_err_printf(const char *format, ...) { -char buf[BUFSZ+1]; -GC_PRINTF_FILLBUF(buf,format); -GC_err_puts(buf); + char buf[BUFSZ + 1]; + GC_PRINTF_FILLBUF(buf, format); + GC_err_puts(buf); } -void GC_log_printf(const char*format,...) +void GC_log_printf(const char *format, ...) { -char buf[BUFSZ+1]; -GC_PRINTF_FILLBUF(buf,format); + char buf[BUFSZ + 1]; + GC_PRINTF_FILLBUF(buf, format); #ifdef NACL -(void)WRITE(GC_log,buf,strlen(buf)); + (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 + 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"); -} + ) { + 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); -} + 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 GC_err_puts(const char *s) { -(void)WRITE(GC_stderr,s,strlen(s)); + (void)WRITE(GC_stderr, s, strlen(s)); } -STATIC void GC_CALLBACK GC_default_warn_proc(char*msg,GC_word arg) +STATIC void GC_CALLBACK GC_default_warn_proc(char *msg, GC_word arg) { -GC_warn_printf(msg,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) +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); -} + 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)); + DCL_LOCK_STATE; + GC_ASSERT(NONNULL_ARG_NOT_NULL(p)); #ifdef GC_WIN32_THREADS #ifdef CYGWIN32 -GC_ASSERT(GC_is_initialized); + GC_ASSERT(GC_is_initialized); #else -if (!GC_is_initialized)GC_init(); + if (!GC_is_initialized) GC_init(); #endif #endif -LOCK(); -GC_current_warn_proc=p; -UNLOCK(); + 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); + 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) -{ +#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; + skip_gc_atexit = TRUE; #endif -if (msg!=NULL){ + if (msg != NULL) { #ifdef MSGBOX_ON_ERROR -GC_win32_MessageBoxA(msg,"Fatal error in GC",MB_ICONERROR|MB_OK); + 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; -} +#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(); + 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(); + 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; + 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; + GC_obj_kinds[result].ok_mark_unconditionally = FALSE; + GC_obj_kinds[result].ok_disclaim_proc = 0; #endif -} else { -ABORT("Too many kinds"); -} -return result; + } else { + ABORT("Too many kinds"); + } + return result; } -GC_API unsigned GC_CALL GC_new_kind(void**fl,GC_word descr,int adjust, -int clear) +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; + 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; + 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; + 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) +GC_API void * GC_CALL GC_call_with_alloc_lock(GC_fn_type fn, void *client_data) { -void*result; -DCL_LOCK_STATE; + void * result; + DCL_LOCK_STATE; #ifdef THREADS -LOCK(); + LOCK(); #endif -result=(*fn)(client_data); + result = (*fn)(client_data); #ifdef THREADS -UNLOCK(); + UNLOCK(); #endif -return(result); + return(result); } -GC_API void*GC_CALL GC_call_with_stack_base(GC_stack_base_func fn,void*arg) +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; + struct GC_stack_base base; + void *result; + base.mem_base = (void *)&base; #ifdef IA64 -base.reg_base=(void*)GC_save_regs_in_stack(); + base.reg_base = (void *)GC_save_regs_in_stack(); #endif -result=fn(&base,arg); -GC_noop1(COVERT_DATAFLOW(&base)); -return result; + result = fn(&base, arg); + GC_noop1(COVERT_DATAFLOW(&base)); + return result; } #ifndef THREADS -GC_INNER ptr_t GC_blocked_sp=NULL; +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; + 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); + 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); + GC_noop1((word)GC_traced_stack_sect - (word)GC_blocked_sp); #endif -GC_traced_stack_sect=stacksect.prev; + GC_traced_stack_sect = stacksect.prev; #ifdef IA64 -GC_blocked_register_sp=stacksect.saved_backing_store_ptr; + GC_blocked_register_sp = stacksect.saved_backing_store_ptr; #endif -GC_blocked_sp=stacksect.saved_stack_ptr; -return client_data; + GC_blocked_sp = stacksect.saved_stack_ptr; + return client_data; } -STATIC void GC_do_blocking_inner(ptr_t data,void*context GC_ATTR_UNUSED) +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); + 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(); + GC_blocked_sp = GC_save_regs_in_stack(); #else -GC_blocked_sp=(ptr_t)&d; + GC_blocked_sp = (ptr_t) &d; #endif #ifdef IA64 -GC_blocked_register_sp=GC_save_regs_in_stack(); + GC_blocked_register_sp = GC_save_regs_in_stack(); #endif -d->client_data=(d->fn)(d->client_data); + d -> client_data = (d -> fn)(d -> client_data); #ifdef SPARC -GC_ASSERT(GC_blocked_sp!=NULL); + GC_ASSERT(GC_blocked_sp != NULL); #else -GC_ASSERT(GC_blocked_sp==(ptr_t)(&d)); + 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; + 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; + 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; + } + 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; + 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 -return&GC_stackbottom; -} + 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 -GC_API void*GC_CALL GC_do_blocking(GC_fn_type fn,void*client_data) +static void block_add_size(struct hblk *h, word pbytes) { -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; + hdr *hhdr = HDR(h); + *(word *)pbytes += (WORDS_TO_BYTES(hhdr->hb_sz) + (HBLKSIZE - 1)) + & ~(word)(HBLKSIZE - 1); } -#if!defined(NO_DEBUGGING) -GC_API void GC_CALL GC_dump(void) +GC_API size_t GC_CALL GC_get_memory_use(void) { -DCL_LOCK_STATE; -LOCK(); -GC_dump_named(NULL); -UNLOCK(); + word bytes = 0; + DCL_LOCK_STATE; + LOCK(); + GC_apply_to_all_blocks(block_add_size, (word)(&bytes)); + UNLOCK(); + return (size_t)bytes; } -GC_API void GC_CALL GC_dump_named(const char*name) +GC_API GC_word GC_CALL GC_get_gc_no(void) { -#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; + 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_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_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(); + 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_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(); + 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_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_find_leak = value; } GC_API int GC_CALL GC_get_find_leak(void) { -return GC_find_leak; + 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(); -} + 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; + 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_ASSERT(value != -1); + GC_finalize_on_demand = value; } GC_API int GC_CALL GC_get_finalize_on_demand(void) { -return GC_finalize_on_demand; + 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_ASSERT(value != -1); + GC_java_finalization = value; } GC_API int GC_CALL GC_get_java_finalization(void) { -return GC_java_finalization; + return GC_java_finalization; } GC_API void GC_CALL GC_set_dont_expand(int value) { -GC_ASSERT(value!=-1); -GC_dont_expand=value; + GC_ASSERT(value != -1); + GC_dont_expand = value; } GC_API int GC_CALL GC_get_dont_expand(void) { -return GC_dont_expand; + return GC_dont_expand; } GC_API void GC_CALL GC_set_no_dls(int value) { -GC_ASSERT(value!=-1); -GC_no_dls=value; + GC_ASSERT(value != -1); + GC_no_dls = value; } GC_API int GC_CALL GC_get_no_dls(void) { -return GC_no_dls; + return GC_no_dls; } GC_API void GC_CALL GC_set_non_gc_bytes(GC_word value) { -GC_non_gc_bytes=value; + GC_non_gc_bytes = value; } GC_API GC_word GC_CALL GC_get_non_gc_bytes(void) { -return GC_non_gc_bytes; + 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_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; + 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_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; + return GC_max_retries; } GC_API void GC_CALL GC_set_dont_precollect(int value) { -GC_ASSERT(value!=-1); -GC_dont_precollect=value; + GC_ASSERT(value != -1); + GC_dont_precollect = value; } GC_API int GC_CALL GC_get_dont_precollect(void) { -return GC_dont_precollect; + return GC_dont_precollect; } GC_API void GC_CALL GC_set_full_freq(int value) { -GC_ASSERT(value>=0); -GC_full_freq=value; + GC_ASSERT(value >= 0); + GC_full_freq = value; } GC_API int GC_CALL GC_get_full_freq(void) { -return GC_full_freq; + 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_ASSERT((long)value != -1L); + GC_time_limit = value; } GC_API unsigned long GC_CALL GC_get_time_limit(void) { -return GC_time_limit; + 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_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; + 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(); + 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(); + 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); + GC_ASSERT(!GC_world_stopped); #endif -STOP_WORLD(); + STOP_WORLD(); #ifdef THREAD_LOCAL_ALLOC -GC_world_stopped=TRUE; + GC_world_stopped = TRUE; #endif -} -GC_API void GC_CALL GC_start_world_external(void) -{ + } + GC_API void GC_CALL GC_start_world_external(void) + { #ifdef THREAD_LOCAL_ALLOC -GC_ASSERT(GC_world_stopped); -GC_world_stopped=FALSE; + GC_ASSERT(GC_world_stopped); + GC_world_stopped = FALSE; #else -GC_ASSERT(GC_is_initialized); + GC_ASSERT(GC_is_initialized); #endif -START_WORLD(); -UNLOCK(); -} + 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) +#if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS) \ + && !defined(MSWINCE) && !defined(SN_TARGET_ORBIS) \ + && !defined(SN_TARGET_PSP2) && !defined(__CC_ARM) #include -#if!defined(MSWIN32)&&!defined(MSWIN_XBOX1) +#if !defined(MSWIN32) && !defined(MSWIN_XBOX1) #include #endif #endif #include -#if defined(MSWINCE)||defined(SN_TARGET_PS3) +#if defined(MSWINCE) || defined(SN_TARGET_PS3) #define SIGSEGV 0 #else #include #endif -#if defined(UNIX_LIKE)||defined(CYGWIN32)||defined(NACL)||defined(SYMBIAN) +#if defined(UNIX_LIKE) || defined(CYGWIN32) || defined(NACL) \ + || defined(SYMBIAN) #include #endif -#if defined(LINUX)||defined(LINUX_STACKBOTTOM) +#if defined(LINUX) || defined(LINUX_STACKBOTTOM) #include #endif #ifdef AMIGA #define GC_AMIGA_DEF -#if!defined(GC_AMIGA_DEF)&&!defined(GC_AMIGA_SB)&&!defined(GC_AMIGA_DS)&&!defined(GC_AMIGA_AM) +#if !defined(GC_AMIGA_DEF) && !defined(GC_AMIGA_SB) && !defined(GC_AMIGA_DS) && !defined(GC_AMIGA_AM) #include #include #define GC_AMIGA_DEF @@ -18462,79 +19046,79 @@ UNLOCK(); #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; -} + 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; + 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]){ + 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); -} -} + 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"); -} + 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(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; +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; +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; + 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; +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 @@ -18560,256 +19144,256 @@ 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)); + 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)); -} + 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; +char *chipmax; size_t latestsize; #endif #ifdef GC_AMIGA_FASTALLOC -void*GC_amiga_get_mem(size_t size){ -struct GC_Amiga_AllocedMemoryHeader*gc_am; +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)); + 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_amchipmax||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){ + 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(); + 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); -} -} + 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; + else{ + nullretries++; + } + if(ret!=NULL && (char *)ret<=chipmax) chipa+=size; #endif -} + } #ifdef GC_AMIGA_RETRY -else{ -void*ret2; -if( -AllocFunction!=GC_malloc_uncollectable + else{ + void *ret2; + if( + AllocFunction!=GC_malloc_uncollectable #ifdef GC_ATOMIC_UNCOLLECTABLE -&&AllocFunction!=GC_malloc_atomic_uncollectable + && AllocFunction!=GC_malloc_atomic_uncollectable #endif -){ -ret2=GC_amiga_rec_alloc(size,AllocFunction,0); -}else{ -ret2=(*AllocFunction)(size); + ){ + ret2=GC_amiga_rec_alloc(size,AllocFunction,0); + }else{ + ret2=(*AllocFunction)(size); #ifdef GC_AMIGA_PRINTSTATS -if((char*)ret2chipmax){ -GC_free(ret); -ret=ret2; -}else{ -GC_free(ret2); -} -} -#endif -} + if((char *)ret2chipmax){ + GC_free(ret); + ret=ret2; + }else{ + GC_free(ret2); + } + } +#endif + } #if defined(CPPCHECK) -if (GC_amiga_dontalloc) + if (GC_amiga_dontalloc) #endif -GC_amiga_dontalloc=FALSE; -return ret; + GC_amiga_dontalloc=FALSE; + return ret; } void (*GC_amiga_toany)(void)=NULL; void GC_amiga_set_toany(void (*func)(void)){ -GC_amiga_toany=func; + 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){ +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(); + if(!GC_dont_gc){ + GC_gcollect(); #ifdef GC_AMIGA_PRINTSTATS -numcollects++; + numcollects++; #endif -ret=(*AllocFunction)(size); -} -if(ret==NULL) + 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); + 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++; -} + else{ + nullretries++; + } #endif + } + return ret; } -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); +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){ +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); + 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)){ + 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(); + if(!GC_dont_gc){ + GC_gcollect(); #ifdef GC_AMIGA_PRINTSTATS -numcollects++; + numcollects++; #endif -ret=GC_realloc(old_object,new_size_in_bytes); -} -if(ret==NULL) + 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); + 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); -} + 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) #include #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 +#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 #include #include +#endif +#if defined(ADD_HEAP_GUARD_PAGES) || defined(LINUX_STACKBOTTOM) \ + || defined(MMAP_SUPPORTED) || defined(NEED_PROC_MAPS) #include #endif #ifdef DARWIN #include #endif #ifdef DJGPP -typedef long unsigned int caddr_t; + typedef long unsigned int caddr_t; #endif #ifdef PCR #include "mm/PCR_MM.h" #endif -#if defined(GC_DARWIN_THREADS)&&defined(MPROTECT_VDB) +#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) +#if !defined(GC_DARWIN_THREADS) #error darwin_stop_world.h included without GC_DARWIN_THREADS defined #endif #include #include EXTERN_C_BEGIN struct thread_stop_info { -mach_port_t mach_thread; -ptr_t stack_ptr; + mach_port_t mach_thread; + ptr_t stack_ptr; }; #ifndef DARWIN_DONT_PARSE_STACK -GC_INNER ptr_t GC_FindTopOfStack(unsigned long); + 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); + 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); + 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); +#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; +#if !defined(NO_EXECUTE_PERMISSION) + STATIC GC_bool GC_pages_executable = TRUE; #else -STATIC GC_bool GC_pages_executable=FALSE; + STATIC GC_bool GC_pages_executable = FALSE; #endif #define IGNORE_PAGES_EXECUTABLE 1 +#if ((defined(LINUX_STACKBOTTOM) || defined(NEED_PROC_MAPS) \ + || defined(PROC_VDB) || defined(SOFT_VDB)) && !defined(PROC_READ)) \ + || defined(CPPCHECK) +#define PROC_READ read +#endif +#if defined(LINUX_STACKBOTTOM) || defined(NEED_PROC_MAPS) + STATIC ssize_t GC_repeat_read(int fd, char *buf, size_t count) + { + size_t num_read = 0; + ASSERT_CANCEL_DISABLED(); + while (num_read < count) { + ssize_t result = PROC_READ(fd, buf + num_read, count - num_read); + if (result < 0) return result; + if (result == 0) break; + num_read += result; + } + return num_read; + } +#endif #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; + 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; + char buf[GET_FILE_LEN_BUF_SZ]; + do { + result = PROC_READ(f, buf, sizeof(buf)); + 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 const 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; + size_t old_maps_size = 0; #endif -GC_ASSERT(I_HOLD_LOCK()); + GC_ASSERT(I_HOLD_LOCK()); #ifdef THREADS -maps_size=GC_get_maps_len(); -if (0==maps_size)return 0; + maps_size = GC_get_maps_len(); + if (0 == maps_size) + ABORT("Cannot determine length of /proc/self/maps"); #else -maps_size=4000; + maps_size = 4000; #endif -do { -int f; -while (maps_size>=maps_buf_sz){ + do { + int f; + while (maps_size >= maps_buf_sz) { #ifdef LINT2 -GC_noop1((word)maps_buf); + GC_noop1((word)maps_buf); #else -GC_scratch_recycle_no_gww(maps_buf,maps_buf_sz); + 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); + while (maps_size >= maps_buf_sz) maps_buf_sz *= 2; + maps_buf = GC_scratch_alloc(maps_buf_sz); + if (NULL == maps_buf) + ABORT_ARG1("Insufficient space for /proc/self/maps buffer", + ", %lu bytes requested", (unsigned long)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; + maps_size = GC_get_maps_len(); + if (0 == maps_size) + ABORT("Cannot determine length of /proc/self/maps"); +#endif + } + GC_ASSERT(maps_buf_sz >= maps_size + 1); + f = open("/proc/self/maps", O_RDONLY); + if (-1 == f) + ABORT_ARG1("Cannot open /proc/self/maps", + ": errno= %d", errno); #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); + old_maps_size = maps_size; +#endif + maps_size = 0; + do { + result = GC_repeat_read(f, maps_buf, maps_buf_sz-1); + if (result <= 0) { + ABORT_ARG1("Failed to read /proc/self/maps", + ": errno= %d", result < 0 ? errno : 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); -} + 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 + } 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; -} + || 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 const char *GC_parse_map_entry(const char *maps_ptr, + ptr_t *start, ptr_t *end, + const char **prot, unsigned *maj_dev, + const char **mapping_name) + { + const unsigned char *start_start, *end_start, *maj_dev_start; + const unsigned char *p; + if (maps_ptr == NULL || *maps_ptr == '\0') { + return NULL; + } + p = (const unsigned char *)maps_ptr; + while (isspace(*p)) ++p; + start_start = p; + GC_ASSERT(isxdigit(*start_start)); + *start = (ptr_t)strtoul((const char *)start_start, (char **)&p, 16); + GC_ASSERT(*p=='-'); + ++p; + end_start = p; + GC_ASSERT(isxdigit(*end_start)); + *end = (ptr_t)strtoul((const char *)end_start, (char **)&p, 16); + GC_ASSERT(isspace(*p)); + while (isspace(*p)) ++p; + GC_ASSERT(*p == 'r' || *p == '-'); + *prot = (const 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((const char *)maj_dev_start, NULL, 16); + if (mapping_name != NULL) { + while (*p && *p != '\n' && *p != '/' && *p != '[') p++; + *mapping_name = (const char *)p; + } + while (*p && *p++ != '\n'); + return (const 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) + { + const char *prot; + ptr_t my_start, my_end; + unsigned int maj_dev; + const char *maps_ptr = GC_get_maps(); + for (;;) { + maps_ptr = GC_parse_map_entry(maps_ptr, &my_start, &my_end, + &prot, &maj_dev, 0); + if (NULL == maps_ptr) break; + if (prot[1] == 'w' && maj_dev == 0 + && (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; -} + GC_INNER GC_bool GC_text_mapping(char *nm, ptr_t *startp, ptr_t *endp) + { + size_t nm_len = strlen(nm); + const char *prot, *map_path; + ptr_t my_start, my_end; + unsigned int maj_dev; + const char *maps_ptr = GC_get_maps(); + for (;;) { + maps_ptr = GC_parse_map_entry(maps_ptr, &my_start, &my_end, + &prot, &maj_dev, &map_path); + if (NULL == maps_ptr) break; + if (prot[0] == 'r' && prot[1] == '-' && prot[2] == 'x') { + const 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; -} + 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 +#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; -} + 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"); + 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); -} + 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 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"; -} +#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); -} + 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 -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)); -} -} + 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); -} + __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 -#if!defined(__IBMC__)&&!defined(__WATCOMC__) +#if !defined(__IBMC__) && !defined(__WATCOMC__) struct exe_hdr { -unsigned short magic_number; -unsigned short padding[29]; -long new_exe_offset; + 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 +#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]; + 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 +#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; + 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 +#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 @@ -19289,121 +19884,125 @@ unsigned long reserved; #define INCL_DOSMEMMGR #include #endif -GC_INNER size_t GC_page_size=0; -#if defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32) +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); +#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; + 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) -{ +#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; + sb -> mem_base = ((NT_TIB*)NtCurrentTeb())->StackBase; #else -void*_tlsbase; -__asm__ ("movl %%fs:4,%0" -:"=r" (_tlsbase)); -sb->mem_base=_tlsbase; + void * _tlsbase; + __asm__ ("movl %%fs:4, %0" + : "=r" (_tlsbase)); + sb -> mem_base = _tlsbase; #endif -return GC_SUCCESS; -} + 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"); + GC_INNER void GC_setpagesize(void) + { +#if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(SOFT_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; + GC_page_size = HBLKSIZE; #endif -} + } #endif #ifdef HAIKU #include -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; -} + 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; -} + 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 @@ -19411,604 +20010,624 @@ return GC_SUCCESS; #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; +#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; + static GC_fault_handler_t old_segv_handler; #ifdef HAVE_SIGBUS -static GC_fault_handler_t old_bus_handler; + 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; + 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; + act.sa_flags = SA_RESTART | SA_NODEFER; #else -act.sa_flags=SA_RESTART; + act.sa_flags = SA_RESTART; #endif -(void)sigemptyset(&act.sa_mask); + (void) sigemptyset(&act.sa_mask); #ifdef GC_IRIX_THREADS -(void)sigaction(SIGSEGV,0,&old_segv_act); -(void)sigaction(SIGSEGV,&act,0); + (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); + (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); + old_segv_handler = signal(SIGSEGV, h); #ifdef HAVE_SIGBUS -old_bus_handler=signal(SIGBUS,h); + old_bus_handler = signal(SIGBUS, h); #endif #endif -#if defined(CPPCHECK)&&defined(ADDRESS_SANITIZER) -GC_noop1((word)&__asan_default_options); +#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)) +#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); + 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); -} + (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 #include -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; -} + 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); + return (ptr_t)GC_find_limit(GC_approx_sp(), FALSE); #else -return (ptr_t)GC_find_limit(GC_approx_sp(),TRUE); + return (ptr_t)GC_find_limit(GC_approx_sp(), TRUE); #endif -} + } #endif #ifdef HPUX_STACKBOTTOM #include #include -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)); -} + 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 #include #define STAT_SKIP 27 #ifdef USE_LIBC_PRIVATES -EXTERN_C_BEGIN + EXTERN_C_BEGIN #pragma weak __libc_stack_end -extern ptr_t __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; + extern ptr_t __libc_ia64_register_backing_store_base; #endif -EXTERN_C_END + EXTERN_C_END #endif #ifdef IA64 -GC_INNER ptr_t GC_get_register_stack_base(void) -{ -ptr_t result; + 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 + 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) + { #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; + char stat_buf[STAT_BUF_SIZE]; + int f; + word result; + ssize_t i, buf_offset = 0, len; #ifdef USE_LIBC_PRIVATES -if (0!=&__libc_stack_end&&0!=__libc_stack_end){ + 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; -} + 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; -} + 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 (-1 == f) + ABORT_ARG1("Could not open /proc/self/stat", ": errno= %d", errno); + len = GC_repeat_read(f, stat_buf, sizeof(stat_buf)); + if (len < 0) + ABORT_ARG1("Failed to read /proc/self/stat", + ": errno= %d", errno); + 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_ARG1("Absurd stack bottom value", + ": 0x%lx", (unsigned long)result); + return (ptr_t)result; + } #endif #ifdef FREEBSD_STACKBOTTOM #include #include #include -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; -} + 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(); -} + 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__) +#elif defined(EMSCRIPTEN) #include -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; -} + 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)) +#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 #ifdef HAVE_PTHREAD_NP_H #include #endif -#elif defined(DARWIN)&&!defined(NO_PTHREAD_GET_STACKADDR_NP) +#elif defined(DARWIN) && !defined(NO_PTHREAD_GET_STACKADDR_NP) #include #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; + 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))) + 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) + if (pthread_getattr_np(pthread_self(), &attr) == 0) #endif -{ -if (pthread_attr_getstack(&attr,&stackaddr,&size)==0 -&&stackaddr!=NULL){ -(void)pthread_attr_destroy(&attr); + { + if (pthread_attr_getstack(&attr, &stackaddr, &size) == 0 + && stackaddr != NULL) { + (void)pthread_attr_destroy(&attr); #ifdef STACK_GROWS_DOWN -stackaddr=(char*)stackaddr+size; + 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); + 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; + 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); + result = (ptr_t)(((word)GC_approx_sp() + STACKBOTTOM_ALIGNMENT_M1) + & ~STACKBOTTOM_ALIGNMENT_M1); #else -result=(ptr_t)((word)GC_approx_sp()&~STACKBOTTOM_ALIGNMENT_M1); + result = (ptr_t)((word)GC_approx_sp() & ~STACKBOTTOM_ALIGNMENT_M1); #endif #elif defined(HPUX_MAIN_STACKBOTTOM) -result=GC_hpux_main_stack_base(); + result = GC_hpux_main_stack_base(); #elif defined(LINUX_STACKBOTTOM) -result=GC_linux_main_stack_base(); + result = GC_linux_main_stack_base(); #elif defined(FREEBSD_STACKBOTTOM) -result=GC_freebsd_main_stack_base(); + result = GC_freebsd_main_stack_base(); #elif defined(HEURISTIC2) -{ -ptr_t sp=GC_approx_sp(); + { + 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; -} + 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; -} + 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; + } +#elif defined(STACK_NOT_SCANNED) || defined(CPPCHECK) + result = NULL; #else -#error None of HEURISTIC*and*STACKBOTTOM defined! +#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)); +#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); +#if !defined(CPPCHECK) + GC_ASSERT((word)GC_approx_sp() HOTTER_THAN (word)result); #endif -return(result); -} + 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) +#if (defined(HAVE_PTHREAD_ATTR_GET_NP) || defined(HAVE_PTHREAD_GETATTR_NP)) \ + && defined(THREADS) && !defined(HAVE_GET_STACK_BASE) #include #ifdef HAVE_PTHREAD_NP_H #include #endif -GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base*b) -{ -pthread_attr_t attr; -size_t size; + 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; + 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); + 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; + 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; -} + 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) +#if defined(GC_DARWIN_THREADS) && !defined(NO_PTHREAD_GET_STACKADDR_NP) #include -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; -} + 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 #include #include -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; -} + 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) +#if defined(GC_SOLARIS_THREADS) && !defined(_STRICT_STDC) #include #include #include -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; -} + 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; -} + 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); + 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); + b -> mem_base = GC_find_limit(GC_approx_sp(), TRUE); #ifdef IA64 -b->reg_base=GC_find_limit(GC_save_regs_in_stack(),FALSE); + b -> reg_base = GC_find_limit(GC_save_regs_in_stack(), FALSE); #endif #else -b->mem_base=GC_find_limit(GC_approx_sp(),FALSE); + b -> mem_base = GC_find_limit(GC_approx_sp(), FALSE); #endif -RESTORE_CANCEL(cancel_state); -UNLOCK(); -return GC_SUCCESS; -} + 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; + 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; + 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; -} + 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; + 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; + 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); + 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) @@ -20019,286 +20638,280 @@ GC_add_roots_inner((ptr_t)O32_BASE(seg), #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; + 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"); + { + char * str = GETENV("GC_USE_GETWRITEWATCH"); #if defined(GC_PREFER_MPROTECT_VDB) -if (str==NULL||(*str=='0'&&*(str+1)=='\0')){ -done=TRUE; -return; -} + if (str == NULL || (*str == '0' && *(str + 1) == '\0')) { + done = TRUE; + return; + } #else -if (str!=NULL&&*str=='0'&&*(str+1)=='\0'){ -done=TRUE; -return; -} + 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; -} + { + 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; + } + } + done = TRUE; + } #else #define GetWriteWatch_alloc_flag 0 #endif -#if defined(MSWIN32)||defined(MSWINCE)||defined(CYGWIN32) +#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; + 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); + 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; -} + 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) -{ + 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){ + 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); + volatile AO_t zero = 0; + (void)AO_fetch_and_add((volatile AO_t *)result, zero); #else -char v=*result; + char v = *result; #if defined(CPPCHECK) -GC_noop1((word)&v); + GC_noop1((word)&v); #endif -*result=v; + *result = v; #endif -GC_reset_fault_handler(); -} else { -GC_reset_fault_handler(); -result=(char*)GC_find_limit(DATAEND,FALSE); -} -return ( ptr_t)result; -} + 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); -} + 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 @@ -20306,365 +20919,374 @@ return(result); #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 (;;){ + 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); + 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); + 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); + 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 !__POWERPC__ + extern void* GC_MacGetDataStart(void); #if __option(far_data) -extern void*GC_MacGetDataEnd(void); + extern void* GC_MacGetDataEnd(void); #endif -GC_add_roots_inner((ptr_t)GC_MacGetDataStart(), -(ptr_t)LMGetCurrentA5(),FALSE); + 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); + 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); + 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) +#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 +#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) +#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; + 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; +#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)){ + 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); + 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); -} + 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); -} + 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; + 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; -} -} + __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: + { + 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(); + __UNLOCK_MALLOC(); #endif -return(result); + 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; + 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); + return GC_unix_sbrk_get_mem(bytes); #endif } #endif #endif #ifdef OS2 -void*os2_alloc(size_t bytes) +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); + 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); -} + 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); + 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) + 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; +#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; + ptr_t GC_win32_get_mem(size_t bytes) + { + ptr_t result; #ifndef USE_WINALLOC -result=GC_unix_get_mem(bytes); + 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 +#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) +#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); + 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) + } +#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) + if (GLOBAL_ALLOC_TEST) #endif -{ -while (GC_n_heap_bases--> 0){ + { + while (GC_n_heap_bases-- > 0) { #ifdef CYGWIN32 #else -GlobalFree(GC_heap_bases[GC_n_heap_bases]); + GlobalFree(GC_heap_bases[GC_n_heap_bases]); #endif -GC_heap_bases[GC_n_heap_bases]=0; -} -return; -} + 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; -} + 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 @@ -20672,17 +21294,24 @@ GC_heap_bases[GC_n_heap_bases]=0; #endif #if defined(HAIKU) #include -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; -} + 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 +#if (defined(USE_MUNMAP) || defined(MPROTECT_VDB)) && !defined(USE_WINALLOC) +#define ABORT_ON_REMAP_FAIL(C_msg_prefix, start_addr, len) \ + ABORT_ARG3(C_msg_prefix " failed", \ + " at %p (length %lu), errno= %d", \ + (void *)(start_addr), (unsigned long)(len), errno) #endif #ifdef USE_MUNMAP -#if!defined(NN_PLATFORM_CTR)&&!defined(MSWIN32)&&!defined(MSWINCE)&&!defined(MSWIN_XBOX1) +#if !defined(NN_PLATFORM_CTR) && !defined(MSWIN32) && !defined(MSWINCE) \ + && !defined(MSWIN_XBOX1) #include #ifdef SN_TARGET_PS3 #include @@ -20692,671 +21321,717 @@ return NULL; #include #include #endif -STATIC ptr_t GC_unmap_start(ptr_t start,size_t bytes) +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; + 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) +static void block_unmap_inner(ptr_t start_addr, size_t len) { -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; + 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; -} + 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); + 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__) + if (len != 0) { +#if defined(AIX) || defined(CYGWIN32) || defined(HAIKU) \ + || (defined(LINUX) && !defined(PREFER_MMAP_PROT_NONE)) \ + || defined(HPUX) + if (mprotect(start_addr, len, PROT_NONE)) + ABORT_ON_REMAP_FAIL("unmap: mprotect", start_addr, len); +#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); + void * result = mmap(start_addr, len, PROT_NONE, + MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON, + zero_fd, 0); + if (EXPECT(MAP_FAILED == result, FALSE)) + ABORT_ON_REMAP_FAIL("unmap: mmap", start_addr, len); + if (result != (void *)start_addr) + ABORT("unmap: mmap() result differs from start_addr"); +#if defined(CPPCHECK) || defined(LINT2) + GC_noop1((word)result); #endif #endif -} -GC_unmapped_bytes+=len; + GC_unmapped_bytes += len; + } #endif } -GC_INNER void GC_remap(ptr_t start,size_t bytes) +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 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; + ptr_t start_addr = GC_unmap_start(start, bytes); + ptr_t end_addr = GC_unmap_end(start, bytes); + block_unmap_inner(start_addr, (size_t)(end_addr - start_addr)); } -#else +GC_INNER void GC_remap(ptr_t start, size_t bytes) { -#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; + 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; -} -#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 + 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 (EXPECT(MAP_FAILED == result, FALSE)) + ABORT_ON_REMAP_FAIL("remap: mmap", start_addr, len); + if (result != (void *)start_addr) + ABORT("remap: mmap() result differs from start_addr"); +#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))) + ABORT_ON_REMAP_FAIL("remap: mprotect", start_addr, len); +#endif + } +#undef IGNORE_PAGES_EXECUTABLE + GC_unmapped_bytes -= len; #endif -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; + 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); + block_unmap_inner(start_addr, (size_t)(end_addr - start_addr)); } #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); -} +#ifdef 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) +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); + 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) +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); + GC_push_all_stack((ptr_t)p, (ptr_t)p + size); + return(PCR_ERes_okay); } -extern struct PCR_MM_ProcsRep*GC_old_allocator; +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"); -} + 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; + 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_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]; -} + return GC_push_other_roots; +} +#if defined(SOFT_VDB) && !defined(NO_SOFT_VDB_LINUX_VER_RUNTIME_CHECK) \ + || (defined(GLIBC_2_19_TSX_BUG) && defined(THREADS)) + GC_INNER int GC_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 +#if (defined(CHECKSUMS) && (defined(GWW_VDB) || defined(SOFT_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]; +#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); -} + 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); + GC_ASSERT(!output_unneeded); + GC_or_pages(GC_written_pages, GC_grungy_pages); #endif -} + } +#elif defined(SOFT_VDB) + static int clear_refs_fd = -1; +#define GC_GWW_AVAILABLE() (clear_refs_fd != -1) #else -#define GC_GWW_AVAILABLE()FALSE +#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; -} + 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) +#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(); -} + 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. +#error No test_and_set operation: Introduces a race. #endif #endif #ifdef MPROTECT_VDB #ifdef DARWIN #include -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) + STATIC mach_port_t GC_task_self = 0; +#define PROTECT_INNER(addr, len, allow_write, C_msg_prefix) \ + if (vm_protect(GC_task_self, (vm_address_t)(addr), (vm_size_t)(len), \ + FALSE, VM_PROT_READ \ + | ((allow_write) ? VM_PROT_WRITE : 0) \ + | (GC_pages_executable ? VM_PROT_EXECUTE : 0)) \ + == KERN_SUCCESS) {} else ABORT(C_msg_prefix \ + "vm_protect() failed") +#elif !defined(USE_WINALLOC) #include #include -#if!defined(CYGWIN32)&&!defined(HAIKU) +#if !defined(CYGWIN32) && !defined(HAIKU) #include #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") +#define PROTECT_INNER(addr, len, allow_write, C_msg_prefix) \ + if (mprotect((caddr_t)(addr), (size_t)(len), \ + PROT_READ | ((allow_write) ? PROT_WRITE : 0) \ + | (GC_pages_executable ? PROT_EXEC : 0)) >= 0) { \ + } else if (GC_pages_executable) { \ + ABORT_ON_REMAP_FAIL(C_msg_prefix \ + "mprotect vdb executable pages", \ + addr, len); \ + } else ABORT_ON_REMAP_FAIL(C_msg_prefix "mprotect vdb", addr, len) #undef IGNORE_PAGES_EXECUTABLE #else #ifndef MSWINCE #include #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 + static DWORD protect_junk; +#define PROTECT_INNER(addr, len, allow_write, C_msg_prefix) \ + if (VirtualProtect(addr, len, \ + GC_pages_executable ? \ + ((allow_write) ? PAGE_EXECUTE_READWRITE : \ + PAGE_EXECUTE_READ) : \ + (allow_write) ? PAGE_READWRITE : \ + PAGE_READONLY, \ + &protect_junk)) { \ + } else ABORT_ARG1(C_msg_prefix "VirtualProtect failed", \ + ": errcode= 0x%X", (unsigned)GetLastError()) +#endif +#define PROTECT(addr, len) PROTECT_INNER(addr, len, FALSE, "") +#define UNPROTECT(addr, len) PROTECT_INNER(addr, len, TRUE, "un-") #if defined(MSWIN32) -typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_HNDLR_PTR; + 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*); + typedef LONG (WINAPI *SIG_HNDLR_PTR)(struct _EXCEPTION_POINTERS *); #undef SIG_DFL -#define SIG_DFL (SIG_HNDLR_PTR)(-1) +#define SIG_DFL (SIG_HNDLR_PTR) (-1) #elif defined(DARWIN) -typedef void (*SIG_HNDLR_PTR)(); + typedef void (* SIG_HNDLR_PTR)(); #else -typedef void (*SIG_HNDLR_PTR)(int,siginfo_t*,void*); -typedef void (*PLAIN_HNDLR_PTR)(int); + 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 +#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; + 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; + 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; +#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) -{ + 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; + hdr *result; + GET_HDR((ptr_t)addr, result); + return result != NULL; #else -return HDR_INNER(addr)!=NULL; + return HDR_INNER(addr) != NULL; #endif -} + } #else -#define is_header_found_async(addr)(HDR(addr)!=NULL) +#define is_header_found_async(addr) (HDR(addr) != NULL) #endif #ifndef DARWIN -#if!defined(MSWIN32)&&!defined(MSWINCE) +#if !defined(MSWIN32) && !defined(MSWINCE) #include -#if defined(FREEBSD)||defined(HURD)||defined(HPUX) -#define SIG_OK (sig==SIGBUS||sig==SIGSEGV) +#if defined(FREEBSD) || defined(HURD) || defined(HPUX) +#define SIG_OK (sig == SIGBUS || sig == SIGSEGV) #else -#define SIG_OK (sig==SIGSEGV) +#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) +#if defined(AARCH64) || defined(ARM32) || defined(MIPS) \ + || __FreeBSD__ >= 7 +#define CODE_OK (si -> si_code == SEGV_ACCERR) #elif defined(POWERPC) #define AIM #include -#define CODE_OK (si->si_code==EXC_DSI||si->si_code==SEGV_ACCERR) +#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) +#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) +#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 (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) +#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) +#define CODE_OK (si -> si_code == SEGV_ACCERR) #endif #ifndef NO_GETCONTEXT #include #endif -STATIC void GC_write_fault_handler(int sig,siginfo_t*si,void*raw_sc) + 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) +#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; + { +#if !defined(MSWIN32) && !defined(MSWINCE) + char *addr = (char *)si->si_addr; #else -char*addr=(char*)(exc_info->ExceptionRecord -->ExceptionInformation[1]); + 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); + 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); + 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; + 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 +#ifdef SOFT_VDB + static GC_bool soft_dirty_init(void); +#endif + 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"); + } +#ifdef GWW_VDB + if (GC_gww_dirty_init()) { + GC_COND_LOG_PRINTF("Using GetWriteWatch()\n"); + return TRUE; + } +#elif defined(SOFT_VDB) + if (soft_dirty_init()) { + GC_COND_LOG_PRINTF("Using soft-dirty bit feature\n"); + return TRUE; + } #endif -} -#if defined(MSWIN32)||defined(MSWINCE) -return EXCEPTION_CONTINUE_SEARCH; +#ifdef 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) #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; -} + 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(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; -} + GC_ASSERT(GC_is_initialized); +#if defined(GWW_VDB) || defined(SOFT_VDB) + if (GC_GWW_AVAILABLE()) + return GC_PROTECTS_NONE; +#endif + 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)) +#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); -} -} -} -} + 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 +#if !defined(THREADS) && (defined(PROC_VDB) || defined(SOFT_VDB)) + static pid_t saved_proc_pid; #endif #ifdef PROC_VDB #include @@ -21366,261 +22041,573 @@ PROTECT(current_start,(ptr_t)current - (ptr_t)current_start); #include #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]; -}; + 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 #include #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; + STATIC size_t GC_proc_buf_size = INITIAL_BUF_SZ; + STATIC char *GC_proc_buf = NULL; + STATIC int GC_proc_fd = -1; + static GC_bool proc_dirty_open_files(void) + { + char buf[40]; + pid_t pid = getpid(); + (void)snprintf(buf, sizeof(buf), "/proc/%ld/pagedata", (long)pid); + buf[sizeof(buf) - 1] = '\0'; + GC_proc_fd = open(buf, O_RDONLY); + if (-1 == GC_proc_fd) { + 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); +#ifndef THREADS + saved_proc_pid = pid; +#endif + return TRUE; + } +#ifdef CAN_HANDLE_FORK + GC_INNER void GC_dirty_update_child(void) + { + if (-1 == GC_proc_fd) + return; + close(GC_proc_fd); + if (!proc_dirty_open_files()) + GC_incremental = FALSE; + } +#endif 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; + 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)); + } + if (!proc_dirty_open_files()) + return FALSE; + 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; + int nmaps; + char * bufp = GC_proc_buf; + int i; +#ifndef THREADS + if (getpid() != saved_proc_pid + && (-1 == GC_proc_fd + || (close(GC_proc_fd), !proc_dirty_open_files()))) { + if (!output_unneeded) + memset(GC_grungy_pages, 0xff, sizeof(page_hash_table)); + memset(GC_written_pages, 0xff, sizeof(page_hash_table)); + return; + } +#endif + BZERO(GC_grungy_pages, sizeof(GC_grungy_pages)); + if (PROC_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 (PROC_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]); + 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; + 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)); -} + 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"); + GC_log_printf("Proc VDB read done\n"); +#endif + GC_or_pages(GC_written_pages, GC_grungy_pages); +} +#endif +#ifdef SOFT_VDB +#ifndef VDB_BUF_SZ +#define VDB_BUF_SZ 16384 +#endif + static int open_proc_fd(pid_t pid, const char *proc_filename, int mode) + { + int f; + char buf[40]; + (void)snprintf(buf, sizeof(buf), "/proc/%ld/%s", (long)pid, + proc_filename); + buf[sizeof(buf) - 1] = '\0'; + f = open(buf, mode); + if (-1 == f) { + WARN("/proc/self/%s open failed; cannot enable GC incremental mode\n", + proc_filename); + } else if (fcntl(f, F_SETFD, FD_CLOEXEC) == -1) { + WARN("Could not set FD_CLOEXEC for /proc\n", 0); + } + return f; + } +#include + typedef uint64_t pagemap_elem_t; + static pagemap_elem_t *soft_vdb_buf; + static int pagemap_fd; + static GC_bool soft_dirty_open_files(void) + { + pid_t pid = getpid(); + clear_refs_fd = open_proc_fd(pid, "clear_refs", O_WRONLY); + if (-1 == clear_refs_fd) + return FALSE; + pagemap_fd = open_proc_fd(pid, "pagemap", O_RDONLY); + if (-1 == pagemap_fd) { + close(clear_refs_fd); + clear_refs_fd = -1; + return FALSE; + } +#ifndef THREADS + saved_proc_pid = pid; #endif -GC_or_pages(GC_written_pages,GC_grungy_pages); -#undef READ -} + return TRUE; + } +#ifdef CAN_HANDLE_FORK + GC_INNER void GC_dirty_update_child(void) + { + if (-1 == clear_refs_fd) + return; + close(clear_refs_fd); + close(pagemap_fd); + if (!soft_dirty_open_files()) + GC_incremental = FALSE; + } +#endif +#define PM_SOFTDIRTY_MASK ((pagemap_elem_t)1 << 55) + static GC_bool detect_soft_dirty_supported(ptr_t vaddr) + { + off_t fpos; + pagemap_elem_t buf[1]; + *vaddr = 1; + GC_ASSERT(GC_page_size != 0); + fpos = (off_t)((word)vaddr / GC_page_size * sizeof(pagemap_elem_t)); + if (lseek(pagemap_fd, fpos, SEEK_SET) == (off_t)(-1)) + return FALSE; + if (PROC_READ(pagemap_fd, buf, sizeof(buf)) != (int)sizeof(buf)) + return FALSE; + return (buf[0] & PM_SOFTDIRTY_MASK) != 0; + } +#ifndef NO_SOFT_VDB_LINUX_VER_RUNTIME_CHECK +#include +#include + static GC_bool ensure_min_linux_ver(int major, int minor) { + struct utsname info; + int actual_major; + int actual_minor = -1; + if (uname(&info) == -1) { + return FALSE; + } + if (strcmp(info.sysname, "Linux")) { + WARN("Cannot ensure Linux version as running on other OS: %s\n", + info.sysname); + return FALSE; + } + actual_major = GC_parse_version(&actual_minor, info.release); + return actual_major > major + || (actual_major == major && actual_minor >= minor); + } +#endif +#ifdef MPROTECT_VDB + static GC_bool soft_dirty_init(void) +#else + GC_INNER GC_bool GC_dirty_init(void) +#endif + { + GC_ASSERT(NULL == soft_vdb_buf); +#ifdef MPROTECT_VDB + char * str = GETENV("GC_USE_GETWRITEWATCH"); +#ifdef GC_PREFER_MPROTECT_VDB + if (str == NULL || (*str == '0' && *(str + 1) == '\0')) + return FALSE; +#else + if (str != NULL && *str == '0' && *(str + 1) == '\0') + return FALSE; +#endif +#endif +#ifndef NO_SOFT_VDB_LINUX_VER_RUNTIME_CHECK + if (!ensure_min_linux_ver(3, 18)) { + GC_COND_LOG_PRINTF( + "Running on old kernel lacking correct soft-dirty bit support\n"); + return FALSE; + } +#endif + if (!soft_dirty_open_files()) + return FALSE; + soft_vdb_buf = (pagemap_elem_t *)GC_scratch_alloc(VDB_BUF_SZ); + if (NULL == soft_vdb_buf) + ABORT("Insufficient space for /proc pagemap buffer"); + if (!detect_soft_dirty_supported((ptr_t)soft_vdb_buf)) { + GC_COND_LOG_PRINTF("Soft-dirty bit is not supported by kernel\n"); + GC_scratch_recycle_no_gww(soft_vdb_buf, VDB_BUF_SZ); + soft_vdb_buf = NULL; + close(clear_refs_fd); + clear_refs_fd = -1; + close(pagemap_fd); + return FALSE; + } + return TRUE; + } + static off_t pagemap_buf_fpos; + static size_t pagemap_buf_len; + static const pagemap_elem_t *pagemap_buffered_read(size_t *pres, + off_t fpos, size_t len, + off_t next_fpos_hint) + { + ssize_t res; + size_t ofs; + GC_ASSERT(len > 0); + if (pagemap_buf_fpos <= fpos + && fpos < pagemap_buf_fpos + (off_t)pagemap_buf_len) { + ofs = (size_t)(fpos - pagemap_buf_fpos); + res = (ssize_t)(pagemap_buf_fpos + pagemap_buf_len - fpos); + } else { + off_t aligned_pos = fpos & ~(GC_page_size < VDB_BUF_SZ + ? GC_page_size-1 : VDB_BUF_SZ-1); + for (;;) { + size_t count; + if ((0 == pagemap_buf_len + || pagemap_buf_fpos + (off_t)pagemap_buf_len != aligned_pos) + && lseek(pagemap_fd, aligned_pos, SEEK_SET) == (off_t)(-1)) + ABORT_ARG2("Failed to lseek /proc/self/pagemap", + ": offset= %lu, errno= %d", (unsigned long)fpos, errno); + ofs = (size_t)(fpos - aligned_pos); + GC_ASSERT(ofs < VDB_BUF_SZ); + if (next_fpos_hint > aligned_pos + && next_fpos_hint - aligned_pos < VDB_BUF_SZ) { + count = VDB_BUF_SZ; + } else { + count = len + ofs; + if (count > VDB_BUF_SZ) + count = VDB_BUF_SZ; + } + GC_ASSERT(count % sizeof(pagemap_elem_t) == 0); + res = PROC_READ(pagemap_fd, soft_vdb_buf, count); + if (res > (ssize_t)ofs) + break; + if (res <= 0) + ABORT_ARG1("Failed to read /proc/self/pagemap", + ": errno= %d", res < 0 ? errno : 0); + aligned_pos = fpos; + } + pagemap_buf_fpos = aligned_pos; + pagemap_buf_len = (size_t)res; + res -= (ssize_t)ofs; + } + GC_ASSERT(ofs % sizeof(pagemap_elem_t) == 0); + *pres = (size_t)res < len ? (size_t)res : len; + return &soft_vdb_buf[ofs / sizeof(pagemap_elem_t)]; + } + static void soft_set_grungy_pages(ptr_t vaddr , ptr_t limit, + ptr_t next_start_hint) + { + GC_ASSERT(GC_page_size != 0); + while ((word)vaddr < (word)limit) { + size_t res; + word limit_buf; + const pagemap_elem_t *bufp = pagemap_buffered_read(&res, + (off_t)((word)vaddr / GC_page_size * sizeof(pagemap_elem_t)), + (size_t)((((word)limit - (word)vaddr + GC_page_size-1) + / GC_page_size) * sizeof(pagemap_elem_t)), + (off_t)((word)next_start_hint / GC_page_size + * sizeof(pagemap_elem_t))); + if (res % sizeof(pagemap_elem_t) != 0) { + memset(GC_grungy_pages, 0xff, sizeof(page_hash_table)); + WARN("Incomplete read of pagemap, not multiple of entry size\n", 0); + break; + } + limit_buf = ((word)vaddr & ~(GC_page_size-1)) + + (res / sizeof(pagemap_elem_t)) * GC_page_size; + for (; (word)vaddr < limit_buf; vaddr += GC_page_size, bufp++) + if ((*bufp & PM_SOFTDIRTY_MASK) != 0) { + struct hblk * h; + ptr_t next_vaddr = vaddr + GC_page_size; +#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); + } + } + } + } + GC_INLINE void GC_soft_read_dirty(GC_bool output_unneeded) + { + ssize_t res; +#ifndef THREADS + if (getpid() != saved_proc_pid + && (-1 == clear_refs_fd + || (close(clear_refs_fd), close(pagemap_fd), + !soft_dirty_open_files()))) { + if (!output_unneeded) { + memset(GC_grungy_pages, 0xff, sizeof(page_hash_table)); +#ifdef CHECKSUMS + memset(GC_written_pages, 0xff, sizeof(page_hash_table)); +#endif + } + return; + } +#endif + if (!output_unneeded) { + word i; + BZERO(GC_grungy_pages, sizeof(GC_grungy_pages)); + pagemap_buf_len = 0; + for (i = 0; i != GC_n_heap_sects; ++i) { + ptr_t vaddr = GC_heap_sects[i].hs_start; + soft_set_grungy_pages(vaddr, vaddr + GC_heap_sects[i].hs_bytes, + i < GC_n_heap_sects-1 ? + GC_heap_sects[i+1].hs_start : NULL); + } +#ifdef CHECKSUMS + GC_or_pages(GC_written_pages, GC_grungy_pages); +#endif +#ifndef NO_VDB_FOR_STATIC_ROOTS + for (i = 0; (int)i < n_root_sets; ++i) { + soft_set_grungy_pages(GC_static_roots[i].r_start, + GC_static_roots[i].r_end, + (int)i < n_root_sets-1 ? + GC_static_roots[i+1].r_start : NULL); + } +#endif + } + res = write(clear_refs_fd, "4\n", 2); + if (res != 2) + ABORT_ARG1("Failed to write to /proc/self/clear_refs", + ": errno= %d", res < 0 ? errno : 0); + } #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; +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; + 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); + 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); + 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 + 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)); + || !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(); + if (!GC_manual_vdb) + GC_protect_heap(); #endif -return; -} + return; + } #ifdef GWW_VDB -GC_gww_read_dirty(output_unneeded); + GC_gww_read_dirty(output_unneeded); #elif defined(PROC_VDB) -GC_proc_read_dirty(output_unneeded); + GC_proc_read_dirty(output_unneeded); +#elif defined(SOFT_VDB) + GC_soft_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"); -} + { + 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 + } +#if !defined(NO_VDB_FOR_STATIC_ROOTS) && !defined(PROC_VDB) + GC_INNER GC_bool GC_is_vdb_for_static_roots(void) + { + if (GC_manual_vdb) return FALSE; +#if defined(MPROTECT_VDB) + return GC_GWW_AVAILABLE(); +#else + GC_ASSERT(GC_incremental); + return TRUE; #endif -} -GC_INNER GC_bool GC_page_was_dirty(struct hblk*h) -{ + } +#endif + GC_INNER GC_bool GC_page_was_dirty(struct hblk *h) + { + word index; #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; -} + 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) + if (!GC_manual_vdb) + return TRUE; +#elif defined(PROC_VDB) + if (GC_manual_vdb) +#endif + { + if (NULL == HDR(h)) + return TRUE; + } + index = PHT_HASH(h); + return get_pht_entry_from_index(GC_grungy_pages, index); + } +#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) || defined(SOFT_VDB) + word index; #ifdef MPROTECT_VDB -if (!GC_GWW_AVAILABLE()) -return TRUE; + if (!GC_GWW_AVAILABLE()) + return TRUE; #endif -return NULL==HDR(h) -||get_pht_entry_from_index(GC_written_pages,PHT_HASH(h)); +#if defined(PROC_VDB) + if (GC_manual_vdb) +#endif + { + if (NULL == HDR(h)) + return TRUE; + } + index = PHT_HASH(h); + return get_pht_entry_from_index(GC_written_pages, index); #else -(void)h; -return TRUE; + (void)h; + return TRUE; #endif -} + } #endif -GC_INNER void GC_remove_protection(struct hblk*h,word nblocks, -GC_bool is_ptrfree) -{ + 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); + (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) + 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 #include #include @@ -21628,530 +22615,531 @@ UNPROTECT(h_trunc,(ptr_t)h_end - (ptr_t)h_trunc); #include EXTERN_C_BEGIN extern boolean_t -exc_server(mach_msg_header_t*,mach_msg_header_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); +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*); +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*); +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); +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); + 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); + 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) + 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); + 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) + 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); + 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]; + 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; + 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 -}, + 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, + 0, #endif -0 + 0 }; typedef struct { -mach_msg_header_t head; + mach_msg_header_t head; } GC_msg_t; typedef enum { -GC_MP_NORMAL, -GC_MP_DISCARDING, -GC_MP_STOPPED + 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); -} + 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]; + 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]; + mach_msg_header_t head; + mach_msg_body_t msgh_body; + char data[1024]; }; -STATIC void*GC_mprotect_thread(void*arg) +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; + 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; + 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; + (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(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){ + 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)); + 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"); + 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); -} -} + 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; + 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"); + 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)"); + 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"); + 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); + 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"); -} -} + { + 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< 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){ + 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; + 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"); + ABORT("thread_get_state failed in catch_exception_raise"); #endif -} -addr=(char*)exc_state.DARWIN_EXC_STATE_DAR; -if (!is_header_found_async(addr)){ + } + 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 -} + 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; + 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"); + __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; -} + 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_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; + return 1; #else -return (int)GC_pages_executable; + return (int)GC_pages_executable; #endif } -#if defined(I386)&&defined(LINUX)&&defined(SAVE_CALL_CHAIN) +#if defined(I386) && defined(LINUX) && defined(SAVE_CALL_CHAIN) #include -struct frame { -struct frame*fr_savfp; -long fr_savpc; + struct frame { + struct frame *fr_savfp; + long fr_savpc; #if NARGS > 0 -long fr_arg[NARGS]; + long fr_arg[NARGS]; #endif -}; + }; #endif #if defined(SPARC) #if defined(LINUX) #include #if defined(SAVE_CALL_CHAIN) -struct frame { -long fr_local[8]; -long fr_arg[6]; -struct frame*fr_savfp; -long fr_savpc; + struct frame { + long fr_local[8]; + long fr_arg[6]; + struct frame *fr_savfp; + long fr_savpc; #ifndef __arch64__ -char*fr_stret; + char *fr_stret; #endif -long fr_argd[6]; -long fr_argx[0]; -}; + long fr_argd[6]; + long fr_argx[0]; + }; #endif #elif defined (DRSNX) #include #elif defined(OPENBSD) #include -#elif defined(FREEBSD)||defined(NETBSD) +#elif defined(FREEBSD) || defined(NETBSD) #include #else #include @@ -22171,9 +23159,9 @@ long fr_argx[0]; #define GC_MSVC_DBG_H #include #ifdef __cplusplus -extern "C" { + extern "C" { #endif -#if!MSVC_DBG_DLL +#if !MSVC_DBG_DLL #define MSVC_DBG_EXPORT #elif MSVC_DBG_BUILD #define MSVC_DBG_EXPORT __declspec(dllexport) @@ -22183,22 +23171,22 @@ extern "C" { #ifndef MAX_SYM_NAME #define MAX_SYM_NAME 2000 #endif -typedef void*HANDLE; +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); +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 @@ -22206,250 +23194,252 @@ MSVC_DBG_EXPORT char**backtrace_symbols(void*const addresses[],int count); #endif #endif #ifdef SAVE_CALL_CHAIN -#if NARGS==0&&NFRAMES % 2==0&&defined(GC_HAVE_BUILTIN_BACKTRACE) +#if NARGS == 0 && NFRAMES % 2 == 0 \ + && defined(GC_HAVE_BUILTIN_BACKTRACE) #ifdef REDIRECT_MALLOC #ifdef THREADS -__thread + __thread #endif -GC_bool GC_in_save_callers=FALSE; + 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; + 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; + 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; + GC_in_save_callers = FALSE; #endif } #else -#if (defined(OPENBSD)||defined(NETBSD)||defined(FREEBSD))&&defined(SPARC) +#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)) +#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; + struct frame *frame; + struct frame *fp; + int nframes = 0; #ifdef I386 -asm("movl %%ebp,%0":"=r"(frame)); -fp=frame; + 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); + frame = (struct frame *)GC_save_regs_in_stack(); + fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS); #endif -for (;!((word)fp HOTTER_THAN (word)frame) + for (; !((word)fp HOTTER_THAN (word)frame) #ifndef THREADS -&&!((word)GC_stackbottom HOTTER_THAN (word)fp) + && !((word)GC_stackbottom HOTTER_THAN (word)fp) #elif defined(STACK_GROWS_UP) -&&fp!=NULL + && fp != NULL #endif -&&nframes < NFRAMES; -fp=(struct frame*)((long)fp->FR_SAVFP+BIAS),nframes++){ + && nframes < NFRAMES; + fp = (struct frame *)((long) fp -> FR_SAVFP + BIAS), nframes++) { #if NARGS > 0 -int i; + int i; #endif -info[nframes].ci_pc=fp->FR_SAVPC; + 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]); -} + for (i = 0; i < NARGS; i++) { + info[nframes].ci_arg[i] = ~(fp->fr_arg[i]); + } #endif -} -if (nframes < NFRAMES)info[nframes].ci_pc=0; + } + 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"); + 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"); + 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; + 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 (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; + { + 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]; + static char exe_name[EXE_SZ]; #define CMD_SZ 200 -char cmd_buf[CMD_SZ]; + char cmd_buf[CMD_SZ]; #define RESULT_SZ 200 -static char result_buf[RESULT_SZ]; -size_t result_len; -char*old_preload; + 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'; -} + 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]); + GC_noop1((unsigned char)name[0]); #endif -name=result_buf; -} while (0); + 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); + 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; + } +#if defined(LINUX) && !defined(SMALL_CONFIG) + if (stop) + break; #endif -} -LOCK(); ---reentry_count; -UNLOCK(); + } + 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"); -} +#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG) + void GC_print_address_map(void) + { + const char *maps = GC_get_maps(); + GC_err_printf("---------- Begin address map ----------\n"); + GC_err_puts(maps); + GC_err_printf("---------- End address map ----------\n"); + } #endif #if defined(THREAD_LOCAL_ALLOC) #ifndef THREADS @@ -22463,22 +23453,35 @@ GC_err_printf("----------End address map----------\n"); #endif #include 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(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) +#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))) +#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) +#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__ @@ -22498,100 +23501,103 @@ EXTERN_C_BEGIN #endif #endif typedef struct thread_local_freelists { -void*_freelists[THREAD_FREELISTS_KINDS][TINY_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) + void * gcj_freelists[TINY_FREELISTS]; +#define ERROR_FL ((void *)GC_WORD_MAX) #endif #define DIRECT_GRANULES (HBLKSIZE/GRANULE_BYTES) -}*GC_tlfs; +} *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) 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; +#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) +#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_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; +#define GC_remove_specific_after_fork(key, t) (void)0 + typedef DWORD GC_key_t; #elif defined(USE_CUSTOM_SPECIFIC) -EXTERN_C_END + EXTERN_C_END #ifndef GC_SPECIFIC_H #define GC_SPECIFIC_H #include EXTERN_C_BEGIN -#define MALLOC_CLEAR(n)GC_INTERNAL_MALLOC(n,NORMAL) +#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 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)) +#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) + 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) + 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; + 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 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; + 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; + 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); +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 + EXTERN_C_BEGIN #else #error implement me #endif @@ -22599,10 +23605,10 @@ 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); + 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); + void GC_check_tsd_marks(tsd *key); #endif #endif #ifndef GC_ATTR_TLS_FAST @@ -22610,228 +23616,228 @@ void GC_check_tsd_marks(tsd*key); #endif extern #if defined(USE_COMPILER_TLS) -__thread GC_ATTR_TLS_FAST + __thread GC_ATTR_TLS_FAST #elif defined(USE_WIN32_COMPILER_TLS) -__declspec(thread)GC_ATTR_TLS_FAST + __declspec(thread) GC_ATTR_TLS_FAST #endif -GC_key_t GC_thread_key; + GC_key_t GC_thread_key; EXTERN_C_END #endif #endif #include #if defined(USE_COMPILER_TLS) -__thread GC_ATTR_TLS_FAST + __thread GC_ATTR_TLS_FAST #elif defined(USE_WIN32_COMPILER_TLS) -__declspec(thread)GC_ATTR_TLS_FAST + __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; -} +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; + if (fl[0] == ERROR_FL) return; #endif -if ((word)(fl[0])>=HBLKSIZE){ -return_single_freelist(fl[0],&gfl[1]); -} + 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); -} + 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; -} + 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; + p -> gcj_freelists[j] = (void *)(word)1; #endif -} + } #ifdef GC_GCJ_SUPPORT -p->gcj_freelists[0]=ERROR_FL; + 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); -} + 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); + 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) +GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_kind(size_t bytes, int kind) { -size_t granules; -void*tsd; -void*result; + 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 (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))); + 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); + 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; + 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; -} +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); -} + 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); -} + 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]); -} + 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]); + 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_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; +#if !defined(GC_OPENBSD_UTHREADS) && !defined(NACL) \ + && !defined(PLATFORM_STOP_WORLD) && !defined(SN_TARGET_PSP2) + volatile AO_t last_stop_count; #endif -ptr_t stack_ptr; + 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]; + ptr_t reg_storage[NACL_GC_REG_STORAGE_SIZE]; +#elif defined(PLATFORM_HAVE_GC_REG_STORAGE_SIZE) + word registers[PLATFORM_GC_REG_STORAGE_SIZE]; #endif }; GC_INNER void GC_stop_init(void); @@ -22845,74 +23851,81 @@ EXTERN_C_END EXTERN_C_BEGIN typedef struct GC_Thread_Rep { #ifdef THREAD_SANITIZER -char dummy[sizeof(oh)]; + char dummy[sizeof(oh)]; #endif -struct GC_Thread_Rep*next; -pthread_t id; + struct GC_Thread_Rep * next; + pthread_t id; #ifdef USE_TKILL_ON_ANDROID -pid_t kernel_id; + 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; + 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; + 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; + 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; + ptr_t backing_store_end; + ptr_t backing_store_ptr; #endif -struct GC_traced_stack_sect_s*traced_stack_sect; -void*status; + struct GC_traced_stack_sect_s *traced_stack_sect; + void * status; #ifdef THREAD_LOCAL_ALLOC -struct thread_local_freelists tlfs GC_ATTR_WORD_ALIGNED; + struct thread_local_freelists tlfs GC_ATTR_WORD_ALIGNED; #endif -}*GC_thread; +} * 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) +#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) +#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); + 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); + 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 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*); + 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 @@ -22921,57 +23934,57 @@ EXTERN_C_END #include #include #ifdef POWERPC -#if CPP_WORDSZ==32 +#if CPP_WORDSZ == 32 #define PPC_RED_ZONE_SIZE 224 -#elif CPP_WORDSZ==64 +#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; + 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){ + StackFrame *frame = (StackFrame *)stack_start; + if (stack_start == 0) { #ifdef POWERPC -#if CPP_WORDSZ==32 -__asm__ __volatile__ ("lwz %0,0(r1)":"=r" (frame)); +#if CPP_WORDSZ == 32 + __asm__ __volatile__ ("lwz %0,0(r1)" : "=r" (frame)); #else -__asm__ __volatile__ ("ld %0,0(r1)":"=r" (frame)); + __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; + 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; + 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); + GC_noop1((word)&frame); #endif -ABORT("GC_FindTopOfStack(0)is not implemented"); + ABORT("GC_FindTopOfStack(0) is not implemented"); #endif -} + } #ifdef DEBUG_THREADS_EXTRA -GC_log_printf("FindTopOfStack start at sp=%p\n",(void*)frame); + 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; -} + 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); + GC_log_printf("FindTopOfStack finish at sp= %p\n", (void *)frame); #endif -return (ptr_t)frame; + return (ptr_t)frame; } #endif #ifdef GC_NO_THREADS_DISCOVERY @@ -22979,545 +23992,559 @@ return (ptr_t)frame; #elif defined(GC_DISCOVER_TASK_THREADS) #define GC_query_task_threads TRUE #else -STATIC GC_bool GC_query_task_threads=FALSE; + 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"); +#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); + GC_ASSERT(!GC_need_to_lock); #endif #ifndef GC_DISCOVER_TASK_THREADS -GC_query_task_threads=TRUE; + GC_query_task_threads = TRUE; #endif -GC_init_parallel(); + 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) +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(); + ptr_t lo; + if (thread == my_thread) { + GC_ASSERT(!thread_blocked); + lo = GC_approx_sp(); #ifndef DARWIN_DONT_PARSE_STACK -*phi=GC_FindTopOfStack(0); + *phi = GC_FindTopOfStack(0); #endif -} else if (thread_blocked){ + } else if (thread_blocked) { #if defined(CPPCHECK) -if (NULL==p)ABORT("Invalid GC_thread passed to GC_stack_range_for"); + if (NULL == p) ABORT("Invalid GC_thread passed to GC_stack_range_for"); #endif -lo=p->stop_info.stack_ptr; + 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; + *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); -} + 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; + do { + kern_result = thread_get_state(thread, GC_MACH_THREAD_STATE, + (natural_t *)&state, + &thread_state_count); + } while (kern_result == KERN_ABORTED); + } #ifdef DEBUG_THREADS -GC_log_printf("thread_get_state returns value=%d\n",kern_result); + GC_log_printf("thread_get_state returns %d\n", kern_result); #endif -if (kern_result!=KERN_SUCCESS) -ABORT("thread_get_state failed"); + if (kern_result != KERN_SUCCESS) + ABORT("thread_get_state failed"); #if defined(I386) -lo=(ptr_t)state.THREAD_FLD(esp); + 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)); + *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); + 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)); + *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); + 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)); + *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); + 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)); + *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); + 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)); + *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; + 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; + *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; -} + 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)); + GC_log_printf("Darwin: Stack for thread %p is [%p,%p)\n", + (void *)(word)thread, (void *)lo, (void *)(*phi)); #endif -return lo; + 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(); + 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; + 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; -} + 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 + 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) + || (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; + || 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; + 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; + 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); + 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); -} + if (GC_parallel) { + GC_acquire_mark_lock(); + GC_ASSERT(GC_fl_builder_count == 0); + } #endif -if (GC_query_task_threads){ + 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); -} -} -} -} + 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(); -} + if (GC_auto_incremental) { + GC_mprotect_stop(); + } #endif #ifdef PARALLEL_MARK -if (GC_parallel) -GC_release_mark_lock(); + if (GC_parallel) + GC_release_mark_lock(); #endif #ifdef DEBUG_THREADS -GC_log_printf("World stopped from %p\n",(void*)(word)my_thread); + GC_log_printf("World stopped from %p\n", (void *)(word)my_thread); #endif -mach_port_deallocate(my_task,my_thread); + 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; + 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"); + 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); + 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); -} + 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(); + task_t my_task = current_task(); #ifdef DEBUG_THREADS -GC_log_printf("World starting\n"); + GC_log_printf("World starting\n"); #endif #ifdef MPROTECT_VDB -if (GC_auto_incremental){ -GC_mprotect_resume(); -} + if (GC_auto_incremental) { + GC_mprotect_resume(); + } #endif -if (GC_query_task_threads){ + 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 { + 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); -} + 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"); + 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) +#if !defined(MACOS) && !defined(GC_NO_TYPES) && !defined(SN_TARGET_PSP2) \ + && !defined(_WIN32_WCE) && !defined(__CC_ARM) #include #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) +#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) +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 @@ -23535,13 +24562,15 @@ STATIC GC_has_static_roots_func GC_has_static_roots=0; #endif #if defined(OPENBSD) #include -#if (OpenBSD>=200519)&&!defined(HAVE_DL_ITERATE_PHDR) +#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))) +#if defined(SCO_ELF) || defined(DGUX) || defined(HURD) || defined(NACL) \ + || (defined(__ELF__) && (defined(LINUX) || defined(FREEBSD) \ + || defined(NETBSD) || defined(OPENBSD))) #include -#if!defined(OPENBSD)&&!defined(HOST_ANDROID) +#if !defined(OPENBSD) && !defined(HOST_ANDROID) #include #endif #ifdef HOST_ANDROID @@ -23552,421 +24581,423 @@ STATIC GC_has_static_roots_func GC_has_static_roots=0; #undef EM_ALPHA #endif #include -#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 +#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 -EXTERN_C_END + EXTERN_C_END #endif #endif #ifndef ElfW #if defined(FREEBSD) -#if __ELF_WORD_SIZE==32 -#define ElfW(type)Elf32_##type +#if __ELF_WORD_SIZE == 32 +#define ElfW(type) Elf32_##type #else -#define ElfW(type)Elf64_##type +#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 +#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 +#if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32 +#define ElfW(type) Elf32_##type #else -#define ElfW(type)Elf64_##type +#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; +#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; -} + 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) +#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))) + 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 #include #include #include #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; -} +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(const char *maps) +{ + const char *prot; + 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 (;;) { + maps = GC_parse_map_entry(maps, &start, &end, &prot, &maj_dev, 0); + if (NULL == maps) 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); -} -} + 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_register_map_entries(GC_get_maps()); } GC_INNER GC_bool GC_register_main_static_data(void) { -return FALSE; + 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) +#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 + 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) +#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 + EXTERN_C_BEGIN #pragma weak dl_iterate_phdr -EXTERN_C_END + 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; + 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 -} -} +#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; + 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 + GC_page_size - 1) & + ~(GC_page_size - 1))); + 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; + return FALSE; #else -return 0==COVERT_DATAFLOW(dl_iterate_phdr); + 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; + 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){ + { + 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; + 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; + 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; + 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); + { + 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); + 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; + } + return TRUE; } #define HAVE_REGISTER_MAIN_STATIC_DATA #else -#if defined(NETBSD)||defined(OPENBSD) +#if defined(NETBSD) || defined(OPENBSD) #include #ifndef DT_DEBUG -#define DT_DEBUG 21 +#define DT_DEBUG 21 #endif #ifndef PT_LOAD -#define PT_LOAD 1 +#define PT_LOAD 1 #endif #ifndef PF_W -#define PF_W 2 +#define PF_W 2 #endif -#elif!defined(HOST_ANDROID) +#elif !defined(HOST_ANDROID) #include #endif #ifndef HOST_ANDROID @@ -23977,87 +25008,87 @@ EXTERN_C_BEGIN #ifdef __GNUC__ #pragma weak _DYNAMIC #endif -extern ElfW(Dyn)_DYNAMIC[]; +extern ElfW(Dyn) _DYNAMIC[]; EXTERN_C_END -STATIC struct link_map* +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) + 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; + 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; + 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; + 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)) + 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 #include #include @@ -24069,350 +25100,348 @@ break; #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; + 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; + 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; + 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) + 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 -STATIC void GC_cond_add_roots(char*base,char*limit) -{ + 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 -} + 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; + GC_INNER GC_bool GC_register_main_static_data(void) + { +#if defined(MSWINCE) || defined(CYGWIN32) + return FALSE; #else -return GC_no_win32_dlls; + 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) + 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; + 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; + 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)); + 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 + 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) + || (protect == PAGE_READWRITE && buf.Type == MEM_PRIVATE) #else -||(!GC_wnt&&buf.Type==MEM_PRIVATE) + || (!GC_wnt && buf.Type == MEM_PRIVATE) #endif -) -&&!GC_is_heap_base(buf.AllocationBase)){ + ) + && !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) + 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 EXTERN_C_BEGIN -extern char*sys_errlist[]; +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; + 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,®ioninfo, -sizeof(regioninfo),®ionreturnsize); -if (status!=0) -ABORT("ldr_inq_region failed"); -if (!(regioninfo.lri_prot&LDR_W)) -continue; + GC_log_printf("---Module---\n"); + GC_log_printf("Module ID: %ld\n", moduleinfo.lmi_modid); + GC_log_printf("Count of regions: %d\n", moduleinfo.lmi_nregion); + GC_log_printf("Flags for module: %016lx\n", moduleinfo.lmi_flags); + GC_log_printf("Module pathname: \"%s\"\n", moduleinfo.lmi_name); +#endif + for (region = 0; region < moduleinfo.lmi_nregion; region++) { + status = ldr_inq_region(mypid, moduleid, region, ®ioninfo, + sizeof(regioninfo), ®ionreturnsize); + 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); + GC_log_printf("--- Region ---\n"); + GC_log_printf("Region number: %ld\n", regioninfo.lri_region_no); + GC_log_printf("Protection flags: %016x\n", regioninfo.lri_prot); + GC_log_printf("Virtual address: %p\n", regioninfo.lri_vaddr); + GC_log_printf("Mapped address: %p\n", regioninfo.lri_mapaddr); + GC_log_printf("Region size: %ld\n", regioninfo.lri_size); + GC_log_printf("Region name: \"%s\"\n", regioninfo.lri_name); #endif -GC_add_roots_inner((char*)regioninfo.lri_mapaddr, -(char*)regioninfo.lri_mapaddr+regioninfo.lri_size, -TRUE); -} -} + GC_add_roots_inner((char *)regioninfo.lri_mapaddr, + (char *)regioninfo.lri_mapaddr + regioninfo.lri_size, + TRUE); + } + } } #endif #if defined(HPUX) #include #include EXTERN_C_BEGIN -extern char*sys_errlist[]; +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){ + 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; + 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]:""); -} + 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++; -} + GC_log_printf("---Shared library---\n"); + GC_log_printf("filename= \"%s\"\n", shl_desc->filename); + GC_log_printf("index= %d\n", index); + GC_log_printf("handle= %08x\n", (unsigned long) shl_desc->handle); + GC_log_printf("text seg.start= %08x\n", shl_desc->tstart); + GC_log_printf("text seg.end= %08x\n", shl_desc->tend); + GC_log_printf("data seg.start= %08x\n", shl_desc->dstart); + GC_log_printf("data seg.end= %08x\n", shl_desc->dend); + GC_log_printf("ref.count= %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 #include #include -GC_INNER void GC_register_dynamic_libraries(void) -{ -int ldibuflen=8192; -for (;;){ -int len; -struct ld_info*ldi; + 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; -} -} + 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__ @@ -24424,142 +25453,142 @@ break; #endif #include 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" } + 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" +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; +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)){ + 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; + 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; + 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; + 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)); + 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(); + 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) @@ -24567,128 +25596,129 @@ GC_INNER void GC_register_dynamic_libraries(void) } GC_INNER void GC_init_dyld(void) { -static GC_bool initialized=FALSE; -if (initialized)return; + static GC_bool initialized = FALSE; + if (initialized) return; #ifdef DARWIN_DEBUG -GC_log_printf("Registering dyld callbacks...\n"); + 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; + _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){ + 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"); + 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"); -} + 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; + return FALSE; } #endif #if defined(HAIKU) #include -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); -} -} + 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; -} + 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_func callback) { -GC_has_static_roots=callback; + GC_has_static_roots = callback; } -#if defined(GC_PTHREADS)&&!defined(GC_NO_DLOPEN) +#if defined(GC_PTHREADS) && !defined(GC_NO_DLOPEN) #undef GC_MUST_RESTORE_REDEFINED_DLOPEN -#if defined(dlopen)&&!defined(GC_USE_LD_WRAP) +#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(); -} + 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); +#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 +#define WRAP_DLFUNC(f) GC_##f +#define REAL_DLFUNC(f) f #endif -GC_API void*WRAP_DLFUNC(dlopen)(const char*path,int mode) +GC_API void * WRAP_DLFUNC(dlopen)(const char *path, int mode) { -void*result; + void * result; #ifndef USE_PROC_FOR_LIBRARIES -disable_gc_for_dlopen(); + disable_gc_for_dlopen(); #endif -result=REAL_DLFUNC(dlopen)(path,mode); + result = REAL_DLFUNC(dlopen)(path, mode); #ifndef USE_PROC_FOR_LIBRARIES -GC_enable(); + GC_enable(); #endif -return(result); + return(result); } #ifdef GC_USE_LD_WRAP -GC_API void*GC_dlopen(const char*path,int mode) -{ -return dlopen(path,mode); -} + 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) +#if !defined(PLATFORM_MACH_DEP) +#if !defined(PLATFORM_MACH_DEP) && !defined(SN_TARGET_PSP2) #include #ifdef AMIGA #ifndef __GNUC__ @@ -24697,146 +25727,149 @@ return dlopen(path,mode); #include #endif #endif -#if defined(MACOS)&&defined(__MWERKS__) +#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; + 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(®s); -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; + 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(®s); + 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) -{ -} + void GC_push_regs(void) + { + } #define HAVE_PUSH_REGS -#elif defined(M68K)&&defined(AMIGA) -void GC_push_regs(void) -{ +#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)); + 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 -} + 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. -} -} +#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(); -} + void GC_push_regs(void) + { + PushMacRegisters(); + } #define HAVE_PUSH_REGS #endif #endif #endif -#if defined(HAVE_PUSH_REGS)&&defined(THREADS) +#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) +#if !defined(HAVE_PUSH_REGS) && defined(UNIX_LIKE) #include #ifndef NO_GETCONTEXT -#if defined(DARWIN)&&(MAC_OS_X_VERSION_MAX_ALLOWED>=1060) +#if defined(DARWIN) \ + && (MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 ) #include #else #include @@ -24847,95 +25880,101 @@ PushMacRegisters(); #endif #endif GC_ATTR_NO_SANITIZE_ADDR -GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t,void*), -volatile ptr_t arg) +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; + volatile int dummy; + volatile ptr_t context = 0; #if defined(HAVE_PUSH_REGS) -GC_push_regs(); -#elif defined(__EMSCRIPTEN__) + GC_push_regs(); +#elif defined(EMSCRIPTEN) #else -#if defined(UNIX_LIKE)&&!defined(NO_GETCONTEXT) -static signed char getcontext_works=0; -ucontext_t ctxt; +#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; + unsigned short old_fcw; #if defined(CPPCHECK) -GC_noop1((word)&old_fcw); + GC_noop1((word)&old_fcw); #endif -__asm__ __volatile__ ("fstcw %0":"=m" (*&old_fcw)); + __asm__ __volatile__ ("fstcw %0" : "=m" (*&old_fcw)); #else -int except_mask=fegetexcept(); + 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; -} + 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)); -} + __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"); + 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(); +#if defined(SPARC) || defined(IA64) + GC_save_regs_ret_val = GC_save_regs_in_stack(); #endif -if (NULL==context) + if (NULL == context) #endif -{ + { #if defined(HAVE_BUILTIN_UNWIND_INIT) -__builtin_unwind_init(); -#elif defined(NO_CRT)&&defined(MSWIN32) -CONTEXT ctx; -RtlCaptureContext(&ctx); + __builtin_unwind_init(); +#elif defined(NO_CRT) && defined(MSWIN32) + CONTEXT ctx; + RtlCaptureContext(&ctx); #else -jmp_buf regs; -word*i=(word*)®s; -ptr_t lim=(ptr_t)(®s)+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); + jmp_buf regs; + word * i = (word *)®s; + ptr_t lim = (ptr_t)(®s) + 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); + (void) _setjmp(regs); #endif #endif -} + } #endif -fn(arg,( void*)context); -GC_noop1(COVERT_DATAFLOW(&dummy)); + 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) +#endif +#if !defined(PLATFORM_STOP_WORLD) +#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) && \ + !defined(GC_DARWIN_THREADS) && !defined(PLATFORM_STOP_WORLD) \ + && !defined(SN_TARGET_PSP2) #ifdef NACL #include #include -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]; + 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 #else @@ -24944,13 +25983,14 @@ int GC_nacl_thread_used[MAX_NACL_GC_THREADS]; #include #include #include -#if (!defined(AO_HAVE_load_acquire)||!defined(AO_HAVE_store_release))&&!defined(CPPCHECK) +#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); + static void *GC_CALLBACK suspend_self_inner(void *client_data); #endif #ifdef DEBUG_THREADS #ifndef NSIG @@ -24964,397 +26004,424 @@ static void*GC_CALLBACK suspend_self_inner(void*client_data); #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"); -} + 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 + if (sigdelset(set, SIGSEGV) != 0 #ifdef HAVE_SIGBUS -||sigdelset(set,SIGBUS)!=0 + || sigdelset(set, SIGBUS) != 0 #endif -){ -ABORT("sigdelset failed"); -} + ) { + 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; +STATIC volatile AO_t GC_stop_count = 0; +STATIC volatile AO_t GC_world_is_stopped = FALSE; +#ifndef NO_RETRY_SIGNALS + STATIC GC_bool GC_retry_signals = TRUE; #else -STATIC GC_bool GC_retry_signals=FALSE; + 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 +#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 +#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; +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; + 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; + 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; + 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"); -} + 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); +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) + 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) + STATIC void GC_suspend_handler(int sig) #endif { -int old_errno=errno; -if (sig!=GC_sig_suspend){ + int old_errno = errno; + if (sig != GC_sig_suspend) { #if defined(GC_FREEBSD_THREADS) -if (0==sig)return; + 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); + 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; + void *context = 0; #endif -GC_suspend_handler_inner(NULL,context); -} + GC_suspend_handler_inner(NULL, context); + } #endif -errno=old_errno; + 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) +#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) +#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; -} + 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()); + 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(); + 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()); + 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) + 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); + 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); + GC_log_printf("Suspending %p\n", (void *)self); #endif -GC_ASSERT(((word)my_stop_count&THREAD_RESTARTED)==0); -me=GC_lookup_thread_async(self); + 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); + 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); + 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); + { + 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); + GC_log_printf("Continuing %p\n", (void *)self); #endif #ifndef GC_NETBSD_THREADS_WORKAROUND -if (GC_retry_signals) + if (GC_retry_signals) #endif -{ -sem_post(&GC_suspend_ack_sem); + { + sem_post(&GC_suspend_ack_sem); #ifdef GC_NETBSD_THREADS_WORKAROUND -if (GC_retry_signals) + 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); + { + 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"); -} -} + 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); + 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)) + 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; -} + 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(); + 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; + { + 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; +} +#ifdef HAVE_CLOCK_GETTIME +#define TS_NSEC_ADD(ts, ns) \ + (ts.tv_nsec += (ns), \ + (void)(ts.tv_nsec >= 1000000L*1000 ? \ + (ts.tv_nsec -= 1000000L*1000, ts.tv_sec++, 0) : 0)) +#endif +static void resend_lost_signals_retry(int n_live_threads, + int (*suspend_restart_all)(void)) +{ +#if defined(HAVE_CLOCK_GETTIME) && !defined(DONT_TIMEDWAIT_ACK_SEM) +#define TIMEOUT_BEFORE_RESEND 10000 + int i; + struct timespec ts; + if (n_live_threads > 0 && clock_gettime(CLOCK_REALTIME, &ts) == 0) { + TS_NSEC_ADD(ts, TIMEOUT_BEFORE_RESEND * 1000); + for (i = 0; i < n_live_threads; i++) { + if (0 != sem_timedwait(&GC_suspend_ack_sem, &ts)) + break; + } + n_live_threads -= i; + } +#endif + n_live_threads = resend_lost_signals(n_live_threads, suspend_restart_all); + suspend_restart_barrier(n_live_threads); } STATIC void GC_restart_handler(int sig) { #if defined(DEBUG_THREADS) -int old_errno=errno; + int old_errno = errno; #endif -if (sig!=GC_sig_thr_restart) -ABORT("Bad signal in restart handler"); + 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; + 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) + 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 -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); + 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; -} + 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 @@ -25362,505 +26429,546 @@ return is_suspended; #undef ao_store_release_async #endif #ifdef IA64 -#define IF_IA64(x)x +#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(); + 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); + 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;) -} + 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); + GC_log_printf("Stack for thread %p is [%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; + total_size += lo - hi; #else -total_size+=hi - lo; + 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); + 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); + GC_log_printf("Reg stack for thread %p is [%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; + 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; + } + } + 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; + pthread_t GC_stopping_thread; + int GC_stopping_pid = 0; #endif STATIC int GC_suspend_all(void) { -int n_live_threads=0; -int i; + int n_live_threads = 0; + int i; #ifndef NACL -GC_thread p; + 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; + 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; + if (p -> suspended_ext) continue; #endif -if (AO_load(&p->stop_info.last_stop_count)==GC_stop_count) -continue; -n_live_threads++; + 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); + 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 -} -} -} + { + 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) +#define NACL_PARK_WAIT_NANOSECONDS (100 * 1000) #endif -#define NANOS_PER_SECOND (1000UL*1000*1000) -unsigned long num_sleeps=0; +#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; + GC_log_printf("pthread_stop_world: number of 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_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; +#if !defined(GC_OPENBSD_UTHREADS) && !defined(NACL) + int n_live_threads; #endif -GC_ASSERT(I_HOLD_LOCK()); + 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); + 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(); + 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) { + resend_lost_signals_retry(n_live_threads, GC_suspend_all); + } else { + 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(); + 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; + 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) +#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) +#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) +#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; + 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; + 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; + 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; + 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++; + 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); + 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; -} + 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()); + int n_live_threads; + GC_ASSERT(I_HOLD_LOCK()); #ifdef DEBUG_THREADS -GC_log_printf("World starting\n"); + GC_log_printf("World starting\n"); #endif #ifndef GC_OPENBSD_UTHREADS -AO_store_release(&GC_world_is_stopped,FALSE); + AO_store_release(&GC_world_is_stopped, FALSE); #endif -n_live_threads=GC_restart_all(); + 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); + (void)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); -} + if (GC_retry_signals) { + resend_lost_signals_retry(n_live_threads, GC_restart_all); + } +#ifdef GC_NETBSD_THREADS_WORKAROUND + else { + suspend_restart_barrier(n_live_threads); + } +#endif #endif #ifdef DEBUG_THREADS -GC_log_printf("World started\n"); + GC_log_printf("World started\n"); #endif #else #ifdef DEBUG_THREADS -GC_log_printf("World starting...\n"); + 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); + 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"); +#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 + act.sa_flags = SA_RESTART #else -act.sa_flags=0 + act.sa_flags = 0 #endif #ifndef NO_SA_SIGACTION -|SA_SIGINFO + | SA_SIGINFO #endif -; -if (sigfillset(&act.sa_mask)!=0){ -ABORT("sigfillset failed"); -} + ; + 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"); -} + if(sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL) != 0) { + ABORT("sigprocmask failed"); + } #endif -GC_remove_allowed_signals(&act.sa_mask); + GC_remove_allowed_signals(&act.sa_mask); #ifndef NO_SA_SIGACTION -act.sa_sigaction=GC_suspend_handler; + act.sa_sigaction = GC_suspend_handler; #else -act.sa_handler=GC_suspend_handler; + act.sa_handler = GC_suspend_handler; #endif -if (sigaction(GC_sig_suspend,&act,NULL)!=0){ -ABORT("Cannot set SIG_SUSPEND handler"); -} + 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"); -} + 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(); + GC_unblock_gc_signals(); #endif #endif } #endif -#if defined(GC_PTHREADS)&&!defined(GC_WIN32_THREADS) +#endif +#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) #include #include #include #include #include #include -#if!defined(SN_TARGET_ORBIS)&&!defined(SN_TARGET_PSP2) -#if!defined(GC_RTEMS_PTHREADS) +#if !defined(SN_TARGET_ORBIS) && !defined(SN_TARGET_PSP2) +#if !defined(GC_RTEMS_PTHREADS) #include #endif #include @@ -25872,81 +26980,81 @@ GC_unblock_gc_signals(); #if defined(GC_DARWIN_THREADS) #ifndef GC_DARWIN_SEMAPHORE_H #define GC_DARWIN_SEMAPHORE_H -#if!defined(GC_DARWIN_THREADS) +#if !defined(GC_DARWIN_THREADS) #error darwin_semaphore.h included with GC_DARWIN_THREADS not defined #endif #ifdef __cplusplus -extern "C" { + extern "C" { #endif typedef struct { -pthread_mutex_t mutex; -pthread_cond_t cond; -int value; + 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; +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 #endif -#if defined(GC_DARWIN_THREADS)||defined(GC_FREEBSD_THREADS) +#if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS) #include #endif -#if defined(GC_NETBSD_THREADS)||defined(GC_OPENBSD_THREADS) +#if defined(GC_NETBSD_THREADS) || defined(GC_OPENBSD_THREADS) #include #include #endif -#if!defined(USE_SPIN_LOCK) -GC_INNER pthread_mutex_t GC_allocate_ml=PTHREAD_MUTEX_INITIALIZER; +#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; + GC_INNER unsigned long GC_lock_holder = NO_THREAD; #endif #if defined(GC_DGUX386_THREADS) #include #include -typedef unsigned int sem_t; + typedef unsigned int sem_t; #endif #undef pthread_create #ifndef GC_NO_PTHREAD_SIGMASK @@ -25960,7 +27068,8 @@ typedef unsigned int sem_t; #endif #undef pthread_join #undef pthread_detach -#if defined(GC_OSF1_THREADS)&&defined(_PTHREAD_USE_MANGLED_NAMES_)&&!defined(_PTHREAD_USE_PTDNAM_) +#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 @@ -25972,1843 +27081,1875 @@ typedef unsigned int sem_t; #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); +#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*); + int REAL_FUNC(pthread_sigmask)(int, const sigset_t *, sigset_t *); #endif #ifndef GC_NO_PTHREAD_CANCEL -int REAL_FUNC(pthread_cancel)(pthread_t); + int REAL_FUNC(pthread_cancel)(pthread_t); #endif #ifdef GC_HAVE_PTHREAD_EXIT -void REAL_FUNC(pthread_exit)(void*)GC_PTHREAD_EXIT_ATTRIBUTE; + void REAL_FUNC(pthread_exit)(void *) GC_PTHREAD_EXIT_ATTRIBUTE; #endif #else #ifdef GC_USE_DLOPEN_WRAP #include -#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); +#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); + 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); + 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); + 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 +#define WRAP_FUNC(f) GC_##f +#if !defined(GC_DGUX386_THREADS) +#define REAL_FUNC(f) f #else -#define REAL_FUNC(f)__d10_##f +#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); -} +#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); -} + 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); -} + 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); -} + 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; + 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; + 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"); + 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"); + 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)"); + 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"); + 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"); + 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"); + 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"); + 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) + 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) +#define INIT_REAL_SYMS() (void)0 +#define ASSERT_SYMS_INITIALIZED() GC_ASSERT(parallel_initialized) #endif -static GC_bool parallel_initialized=FALSE; +static GC_bool parallel_initialized = FALSE; #ifndef GC_ALWAYS_MULTITHREADED -GC_INNER GC_bool GC_need_to_lock=FALSE; + GC_INNER GC_bool GC_need_to_lock = FALSE; #endif -STATIC int GC_nprocs=1; +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)); -} -} -} + 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)); -} -} + 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); + 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 PARALLEL_MARK +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; -} + 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'; + 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); + (void)pthread_setname_np(name_buf); #else -if (pthread_setname_np(pthread_self(),name_buf)!=0) -WARN("pthread_setname_np failed\n",0); + 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) +#define set_marker_thread_name(id) (void)(id) #endif -STATIC void*GC_mark_thread(void*id) +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(); + 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; -} + 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); + GC_log_printf("Starting mark helper for mark number %lu\n", + (unsigned long)my_mark_no); #endif -GC_help_marker(my_mark_no); -} + 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; + 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; + 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; + int i; + pthread_attr_t attr; #ifndef NO_MARKER_SPECIAL_SIGMASK -sigset_t set,oldset; + sigset_t set, oldset; #endif -GC_ASSERT(I_DONT_HOLD_LOCK()); -if (available_markers_m1<=0)return; + 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"); + 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"); -} -} + { + 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; -} + 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; -} -} + 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); -} + 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); + (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}; +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); + GC_ASSERT(I_HOLD_LOCK()); + GC_PUSH_ALL_SYM(GC_threads); #if defined(THREAD_LOCAL_ALLOC) -GC_PUSH_ALL_SYM(GC_thread_key); + 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; -} + 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; + 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; + 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(); + result -> kernel_id = gettid(); #endif -result->next=GC_threads[hv]; -GC_threads[hv]=result; + result -> next = GC_threads[hv]; + GC_threads[hv] = result; #ifdef NACL -GC_nacl_gc_thread_self=result; -GC_nacl_initialize_gc_thread(); + 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); + 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; + 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()); + 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){ + 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); + mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread); #endif -GC_INTERNAL_FREE(p); -} + 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); -} + 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); + mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread); #endif -GC_INTERNAL_FREE(p); + GC_INTERNAL_FREE(p); #ifdef DEBUG_THREADS -GC_log_printf("Deleted thread %p,n_threads=%d\n", -(void*)id,GC_count_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_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<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); -} + 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; + 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(); +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 + GC_ATTR_NO_SANITIZE_THREAD #endif -static void store_to_threads_table(int hv,GC_thread me) -{ -GC_threads[hv]=me; -} + 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; + 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(); + me -> stop_info.mach_thread = mach_thread_self(); #endif #ifdef USE_TKILL_ON_ANDROID -me->kernel_id=gettid(); + 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)"); -} +#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 { + } else { #ifdef THREAD_LOCAL_ALLOC -if (!(p->flags&FINISHED)){ -GC_remove_specific_after_fork(GC_thread_key,p->id); -} + 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); +#if !defined(THREAD_SANITIZER) || !defined(CAN_CALL_ATFORK) + if (p != &first_thread) GC_INTERNAL_FREE(p); #endif -} -} -store_to_threads_table(hv,me); -} + } + } + 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()); + 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; + 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; + 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){ + 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; + 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; + if ((word)p->stack_end > (word)lo + && (word)p->stack_end <= (word)hi) + return TRUE; #endif -} -} -} -return FALSE; -} + } + } + } + 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()); + 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; -} + 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; -} +#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; -} + 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; -} + STATIC int GC_get_nprocs(void) + { +#define PROC_STAT_BUF_SZ ((1 + MAX_MARKERS) * 100) + char stat_buf[PROC_STAT_BUF_SZ+1]; + int f; + int result, i, len; + f = open("/proc/stat", O_RDONLY); + if (f < 0) { + WARN("Could not open /proc/stat\n", 0); + return 1; + } + len = STAT_READ(f, stat_buf, sizeof(stat_buf)-1); + if (len < 0) { + WARN("Failed to read /proc/stat, errno= %" WARN_PRIdPTR "\n", errno); + close(f); + return 1; + } + stat_buf[len] = '\0'; + close(f); + result = 1; + for (i = 0; i < len - 4; ++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; -} + 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(); -} -} + 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 +#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); + LOCK(); + DISABLE_CANCEL(fork_cancel_state); #if defined(PARALLEL_MARK) -if (GC_parallel) -GC_wait_for_reclaim(); + if (GC_parallel) + GC_wait_for_reclaim(); #endif -GC_wait_for_gc_completion(TRUE); + GC_wait_for_gc_completion(TRUE); #if defined(PARALLEL_MARK) -if (GC_parallel) -GC_acquire_mark_lock(); + if (GC_parallel) + GC_acquire_mark_lock(); #endif -GC_acquire_dirty_lock(); + GC_acquire_dirty_lock(); } -#if defined(GC_ASSERTIONS)&&defined(CAN_CALL_ATFORK) -GC_ATTR_NO_SANITIZE_THREAD +#if defined(GC_ASSERTIONS) && defined(CAN_CALL_ATFORK) + GC_ATTR_NO_SANITIZE_THREAD #endif static void fork_parent_proc(void) { -GC_release_dirty_lock(); + GC_release_dirty_lock(); #if defined(PARALLEL_MARK) -if (GC_parallel) -GC_release_mark_lock(); + if (GC_parallel) + GC_release_mark_lock(); #endif -RESTORE_CANCEL(fork_cancel_state); -UNLOCK(); + RESTORE_CANCEL(fork_cancel_state); + UNLOCK(); } -#if defined(GC_ASSERTIONS)&&defined(CAN_CALL_ATFORK) -GC_ATTR_NO_SANITIZE_THREAD +#if defined(GC_ASSERTIONS) && defined(CAN_CALL_ATFORK) + GC_ATTR_NO_SANITIZE_THREAD #endif static void fork_child_proc(void) { -GC_release_dirty_lock(); + GC_release_dirty_lock(); #if defined(PARALLEL_MARK) -if (GC_parallel) -GC_release_mark_lock(); + if (GC_parallel) + GC_release_mark_lock(); #endif -GC_remove_all_threads_but_me(); + GC_remove_all_threads_but_me(); #ifdef PARALLEL_MARK -GC_parallel=FALSE; + 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"); -} +#ifndef GC_DISABLE_INCREMENTAL + GC_dirty_update_child(); #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(); -} + 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; + __thread int GC_dummy_thread_local; #endif #ifdef PARALLEL_MARK -static void setup_mark_lock(void); -static unsigned required_markers_cnt=0; + 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; + 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); + 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){ + 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 + 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"); -} + 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"); + { + 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; + 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; + } + } + { + 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; + available_markers_m1 = 0; #endif -} else { + } 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; + { + 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); +#if defined(BASE_ATOMIC_OPS_EMULATED) && !defined(GC_DARWIN_THREADS) \ + && !defined(GC_OPENBSD_UTHREADS) && !defined(NACL) \ + && !defined(PLATFORM_STOP_WORLD) && !defined(SN_TARGET_PSP2) + { + cpu_set_t mask; + int cpu_set_cnt = 0; + int cpu_lowest_set = 0; + int i = GC_nprocs > 1 ? GC_nprocs : 2; + if (sched_getaffinity(0 , + sizeof(mask), &mask) == -1) + ABORT_ARG1("sched_getaffinity failed", ": errno= %d", errno); + while (i-- > 0) + if (CPU_ISSET(i, &mask)) { + cpu_lowest_set = i; + cpu_set_cnt++; + } + if (0 == cpu_set_cnt) + ABORT("sched_getaffinity returned empty mask"); + if (cpu_set_cnt > 1) { + CPU_ZERO(&mask); + CPU_SET(cpu_lowest_set, &mask); + if (sched_setaffinity(0, sizeof(mask), &mask) == -1) + ABORT_ARG1("sched_setaffinity failed", ": errno= %d", errno); + WARN("CPU affinity mask is set to %p\n", (word)1 << cpu_lowest_set); + } + } #endif -if (markers > MAX_MARKERS) -markers=MAX_MARKERS; -} -available_markers_m1=markers - 1; -} +#ifndef GC_DARWIN_THREADS + GC_stop_init(); #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(); -} + 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; + DCL_LOCK_STATE; #endif -if (parallel_initialized)return; -parallel_initialized=TRUE; -if (!GC_is_initialized)GC_init(); + 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(); + 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)); + 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; + me -> stop_info.stack_ptr = stack_ptr; #else -me->stop_info.stack_ptr=GC_approx_sp(); + 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); -} +#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; + me -> backing_store_ptr = stack_ptr; #endif -me->thread_blocked=(unsigned char)TRUE; -UNLOCK(); -d->client_data=(d->fn)(d->client_data); -LOCK(); + 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; + 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; + t -> backing_store_end = (ptr_t)sb->reg_base; #endif -return; -} -} -GC_stackbottom=(char*)sb->mem_base; + return; + } + } + GC_stackbottom = (char*)sb->mem_base; #ifdef IA64 -GC_register_stackbottom=(ptr_t)sb->reg_base; + GC_register_stackbottom = (ptr_t)sb->reg_base; #endif } -GC_API void*GC_CALL GC_get_my_stackbottom(struct GC_stack_base*sb) +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; + 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; + sb -> reg_base = me -> backing_store_end; #endif -} else { -sb->mem_base=GC_stackbottom; + } 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; + 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); + 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); + GC_noop1((word)me->traced_stack_sect); #endif -LOCK(); -me->traced_stack_sect=stacksect.prev; + LOCK(); + me -> traced_stack_sect = stacksect.prev; #ifdef IA64 -me->backing_store_ptr=stacksect.saved_backing_store_ptr; + 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; + 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) { + GC_ASSERT(I_HOLD_LOCK()); #ifdef DEBUG_THREADS -GC_log_printf( -"Unregistering thread %p,gc_thread=%p,n_threads=%d\n", -(void*)me->id,(void*)me,GC_count_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)); + 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; -} + 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); + 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); + 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); + 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_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) +GC_INNER_PTHRSTART void GC_thread_exit_proc(void *arg) { -IF_CANCEL(int cancel_state;) -DCL_LOCK_STATE; + 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); + 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_thread)COVERT_DATAFLOW(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; -} + 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_thread)COVERT_DATAFLOW(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) -{ + GC_API int WRAP_FUNC(pthread_cancel)(pthread_t thread) + { #ifdef CANCEL_SAFE -GC_thread t; -DCL_LOCK_STATE; + GC_thread t; + DCL_LOCK_STATE; #endif -INIT_REAL_SYMS(); + 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(); + 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); -} + 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_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) + const struct GC_stack_base *sb) { #ifndef GC_DARWIN_THREADS -me->stop_info.stack_ptr=(ptr_t)sb->mem_base; + 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"); + 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; + 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) +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"); + 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(); + me -> stop_info.mach_thread = mach_thread_self(); #endif -GC_record_stack_base(me,sb); + GC_record_stack_base(me, sb); #ifdef GC_EXPLICIT_SIGNALS_UNBLOCK -GC_unblock_gc_signals(); + GC_unblock_gc_signals(); #endif -return me; + 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_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) +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); + 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); + GC_noop1(me->flags); #endif -me->flags|=DETACHED; + me -> flags |= DETACHED; #if defined(THREAD_LOCAL_ALLOC) -GC_init_thread_local(&(me->tlfs)); + GC_init_thread_local(&(me->tlfs)); #endif -UNLOCK(); -return GC_SUCCESS; -} else if ((me->flags&FINISHED)!=0){ + UNLOCK(); + return GC_SUCCESS; + } else if ((me -> flags & FINISHED) != 0) { #ifdef GC_DARWIN_THREADS -me->stop_info.mach_thread=mach_thread_self(); + me -> stop_info.mach_thread = mach_thread_self(); #endif -GC_record_stack_base(me,sb); -me->flags&=~FINISHED; + GC_record_stack_base(me, sb); + me -> flags &= ~FINISHED; #ifdef GC_EXPLICIT_SIGNALS_UNBLOCK -GC_unblock_gc_signals(); + GC_unblock_gc_signals(); #endif #if defined(THREAD_LOCAL_ALLOC) -GC_init_thread_local(&(me->tlfs)); + GC_init_thread_local(&(me->tlfs)); #endif -UNLOCK(); -return GC_SUCCESS; -} else { -UNLOCK(); -return GC_DUPLICATE; -} + UNLOCK(); + return GC_SUCCESS; + } else { + UNLOCK(); + return GC_DUPLICATE; + } } struct start_info { -void*(*start_routine)(void*); -void*arg; -word flags; -sem_t registered; + 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; + 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); + 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; + LOCK(); + me = GC_register_my_thread_inner(sb, self); + me -> flags = si -> flags; #if defined(THREAD_LOCAL_ALLOC) -GC_init_thread_local(&(me->tlfs)); + GC_init_thread_local(&(me->tlfs)); #endif -UNLOCK(); -*pstart=si->start_routine; + UNLOCK(); + *pstart = si -> start_routine; #ifdef DEBUG_THREADS -GC_log_printf("start_routine=%p\n",(void*)(signed_word)(*pstart)); + GC_log_printf("start_routine= %p\n", (void *)(signed_word)(*pstart)); #endif -*pstart_arg=si->arg; -sem_post(&(si->registered)); -return me; + *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) -{ +#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; + struct GC_stack_base sb; #ifdef REDIRECT_MALLOC -GC_disable(); + GC_disable(); #endif -if (GC_get_stack_base(&sb)!=GC_SUCCESS) -ABORT("Failed to get thread stack base"); + 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(); + 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){ + { + 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(); + 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;) + 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)); + GC_log_printf("Started thread %p\n", (void *)(*new_thread)); #endif -DISABLE_CANCEL(cancel_state); -while (0!=sem_wait(&si.registered)){ + DISABLE_CANCEL(cancel_state); + while (0 != sem_wait(&si.registered)) { #if defined(GC_HAIKU_THREADS) -if (EACCES==errno)continue; + if (EACCES == errno) continue; #endif -if (EINTR!=errno)ABORT("sem_wait failed"); -} -RESTORE_CANCEL(cancel_state); -} -sem_destroy(&si.registered); -return(result); -} + 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) +#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(); + 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); + 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) +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; + 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) +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)){ + 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: + (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); + (void)AO_fetch_and_add1(&GC_spin_count); #endif -return; -case EBUSY: -break; -default: -ABORT("Unexpected error from pthread_mutex_trylock"); -} -} + return; + case EBUSY: + break; + default: + ABORT("Unexpected error from pthread_mutex_trylock"); + } + } #endif #ifdef LOCK_STATS -(void)AO_fetch_and_add1(&GC_block_count); + (void)AO_fetch_and_add1(&GC_block_count); #endif -pthread_mutex_lock(lock); + 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)) +#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 +#define is_collecting() GC_collecting #endif #if defined(USE_SPIN_LOCK) -GC_INNER volatile AO_TS_t GC_allocate_lock=AO_TS_INITIALIZER; +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; + 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); + 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; -} + 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< 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); -} -} + 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); -} + 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) + 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}}; + 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; -} + static pthread_mutex_t mark_mutex = PTHREAD_MUTEX_INITIALIZER; #endif +static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER; 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); -} + pthread_mutexattr_t mattr; + int glibc_minor = -1; + int glibc_major = GC_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())); +#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_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"); -} + 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; + 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_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_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; + 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"); -} + 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){} + 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; -} +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; + 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); -} -} + 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); + GC_noop1((word)entry); #endif -if (pthread_mutex_unlock(&key->lock)!=0) -ABORT("pthread_mutex_unlock failed (remove_specific after fork)"); + 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) +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); + 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); -} -} -} + 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; +#if !defined(USE_PTHREAD_LOCKS) + GC_INNER CRITICAL_SECTION GC_allocate_ml; #ifdef GC_ASSERTIONS -GC_INNER DWORD GC_lock_holder=NO_THREAD; + GC_INNER DWORD GC_lock_holder = NO_THREAD; #endif #else -GC_INNER pthread_mutex_t GC_allocate_ml=PTHREAD_MUTEX_INITIALIZER; + GC_INNER pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER; #ifdef GC_ASSERTIONS -GC_INNER unsigned long GC_lock_holder=NO_THREAD; + GC_INNER unsigned long GC_lock_holder = NO_THREAD; #endif #endif #undef CreateThread @@ -27823,39 +28964,41 @@ GC_INNER unsigned long GC_lock_holder=NO_THREAD; #ifndef GC_NO_PTHREAD_SIGMASK #undef pthread_sigmask #endif -STATIC void*GC_pthread_start(void*arg); -STATIC void GC_thread_exit_proc(void*arg); + STATIC void * GC_pthread_start(void * arg); + STATIC void GC_thread_exit_proc(void *arg); #include #ifdef CAN_CALL_ATFORK #include #endif -#elif!defined(MSWINCE) +#elif !defined(MSWINCE) #include #include #endif -static ptr_t copy_ptr_regs(word*regs,const CONTEXT*pcontext); +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) +#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) +#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) +#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; + STATIC GC_bool GC_win32_dll_threads = FALSE; #endif #else #ifndef GC_NO_THREADS_DISCOVERY @@ -27865,2289 +29008,2318 @@ STATIC GC_bool GC_win32_dll_threads=FALSE; #undef MAX_THREADS #define MAX_THREADS 1 #endif -typedef LONG*IE_t; -STATIC GC_bool GC_thr_initialized=FALSE; +typedef LONG * IE_t; +STATIC GC_bool GC_thr_initialized = FALSE; #ifndef GC_ALWAYS_MULTITHREADED -GC_INNER GC_bool GC_need_to_lock=FALSE; + GC_INNER GC_bool GC_need_to_lock = FALSE; #endif -static GC_bool parallel_initialized=FALSE; +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"); + ABORT("GC DllMain-based thread registration unsupported"); #else -GC_ASSERT(!parallel_initialized); + GC_ASSERT(!parallel_initialized); #ifndef GC_DISCOVER_TASK_THREADS -GC_win32_dll_threads=TRUE; + GC_win32_dll_threads = TRUE; #endif -GC_init_parallel(); + GC_init_parallel(); #endif } #define ADDR_LIMIT ((ptr_t)GC_WORD_MAX) struct GC_Thread_Rep { -union { + union { #ifndef GC_NO_THREADS_DISCOVERY -volatile AO_t in_use; -LONG long_in_use; + volatile AO_t in_use; + LONG long_in_use; #endif -struct GC_Thread_Rep*next; -} tm; -DWORD id; + struct GC_Thread_Rep * next; + } tm; + DWORD id; #ifdef MSWINCE -#define THREAD_HANDLE(t)(HANDLE)(word)(t)->id +#define THREAD_HANDLE(t) (HANDLE)(word)(t)->id #else -HANDLE handle; -#define THREAD_HANDLE(t)(t)->handle + HANDLE handle; +#define THREAD_HANDLE(t) (t)->handle #endif -ptr_t stack_base; -ptr_t last_stack_min; + ptr_t stack_base; + ptr_t last_stack_min; #ifdef IA64 -ptr_t backing_store_end; -ptr_t backing_store_ptr; + ptr_t backing_store_end; + ptr_t backing_store_ptr; #elif defined(I386) -ptr_t initial_stack_base; + 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; + 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; + unsigned char flags; #define FINISHED 1 #define DETACHED 2 -#define KNOWN_FINISHED(t)(((t)->flags)&FINISHED) -pthread_t pthread_id; -void*status; +#define KNOWN_FINISHED(t) (((t) -> flags) & FINISHED) + pthread_t pthread_id; + void *status; #else -#define KNOWN_FINISHED(t)0 +#define KNOWN_FINISHED(t) 0 #endif #ifdef THREAD_LOCAL_ALLOC -struct thread_local_freelists tlfs; + struct thread_local_freelists tlfs; #endif #ifdef RETRY_GET_THREAD_CONTEXT -ptr_t context_sp; -word context_regs[PUSHED_REGS_COUNT]; + 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; +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; + 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; + 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) -{ +#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){ + 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; + 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; -} + AO_nop_full(); + if (AO_load(&GC_attached_thread)) { + AO_store(&GC_attached_thread, FALSE); + return TRUE; + } #endif -} + } #endif -return FALSE; -} + 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; +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) +#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_bool first_thread_used = FALSE; STATIC GC_thread GC_new_thread(DWORD id) { -int hv=THREAD_TABLE_INDEX(id); -GC_thread result; + 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; + 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); + 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_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_INNER GC_bool GC_in_thread_creation = FALSE; GC_INLINE void GC_record_stack_base(GC_vthread me, -const struct GC_stack_base*sb) + const struct GC_stack_base *sb) { -me->stack_base=(ptr_t)sb->mem_base; + me -> stack_base = (ptr_t)sb->mem_base; #ifdef IA64 -me->backing_store_end=(ptr_t)sb->reg_base; + me -> backing_store_end = (ptr_t)sb->reg_base; #elif defined(I386) -me->initial_stack_base=(ptr_t)sb->mem_base; + me -> initial_stack_base = (ptr_t)sb->mem_base; #endif -if (me->stack_base==NULL) -ABORT("Bad stack base in GC_register_my_thread"); + 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) +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 + GC_vthread me; +#if defined(MPROTECT_VDB) && !defined(CYGWIN32) + if (GC_auto_incremental #ifdef GWW_VDB -&&!GC_gww_dirty_init() + && !GC_gww_dirty_init() #endif -) -GC_set_write_fault_handler(); + ) + 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"); -} + 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(); + 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 (!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))); + 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); + 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; + 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); -} + 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") +#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<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); -} + 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; + 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) +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 +#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 +#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) +#define GC_PTHREAD_PTRVAL(pthread_id) pthread_id +#elif defined(GC_WIN32_PTHREADS) || defined(GC_PTHREADS_PARAMARK) #include #if defined(__WINPTHREADS_VERSION_MAJOR) -#define GC_PTHREAD_PTRVAL(pthread_id)pthread_id +#define GC_PTHREAD_PTRVAL(pthread_id) pthread_id #else -#define GC_PTHREAD_PTRVAL(pthread_id)pthread_id.p +#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); + CloseHandle(t->handle); #endif #ifndef GC_NO_THREADS_DISCOVERY -if (GC_win32_dll_threads){ -t->stack_base=0; -t->id=0; -t->suspended=FALSE; + 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); -} -} + 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; -} + 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); -} -} + 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; + 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(); + set_need_to_lock(); } -GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base*sb) +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){ + 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); + me = GC_register_my_thread_inner(sb, thread_id); #if defined(CPPCHECK) -GC_noop1(me->flags); + GC_noop1(me->flags); #endif -me->flags|=DETACHED; + me -> flags |= DETACHED; #else -GC_register_my_thread_inner(sb,thread_id); + GC_register_my_thread_inner(sb, thread_id); #endif -UNLOCK(); -return GC_SUCCESS; -} else + UNLOCK(); + return GC_SUCCESS; + } else #ifdef GC_PTHREADS -if ((me->flags&FINISHED)!=0){ -GC_record_stack_base(me,sb); -me->flags&=~FINISHED; + 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)); + GC_init_thread_local((GC_tlfs)(&me->tlfs)); #endif -UNLOCK(); -return GC_SUCCESS; -} else + UNLOCK(); + return GC_SUCCESS; + } else #endif -{ -UNLOCK(); -return GC_DUPLICATE; -} + { + 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_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; + DCL_LOCK_STATE; #ifdef DEBUG_THREADS -GC_log_printf("Unregistering thread 0x%lx\n",(long)GetCurrentThreadId()); + GC_log_printf("Unregistering thread 0x%lx\n", (long)GetCurrentThreadId()); #endif -if (GC_win32_dll_threads){ + if (GC_win32_dll_threads) { #if defined(THREAD_LOCAL_ALLOC) -GC_ASSERT(FALSE); + GC_ASSERT(FALSE); #else -GC_delete_thread(GetCurrentThreadId()); + GC_delete_thread(GetCurrentThreadId()); #endif -} else { -#if defined(THREAD_LOCAL_ALLOC)||defined(GC_PTHREADS) -GC_thread me; + } 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)); + 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)); + 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 + if ((me -> flags & DETACHED) == 0) { + me -> flags |= FINISHED; + } else #endif -{ -GC_delete_thread(thread_id); -} + { + GC_delete_thread(thread_id); + } #if defined(THREAD_LOCAL_ALLOC) -GC_remove_specific(GC_thread_key); + GC_remove_specific(GC_thread_key); #endif -UNLOCK(); -} -return GC_SUCCESS; + UNLOCK(); + } + return GC_SUCCESS; } -GC_INNER void GC_do_blocking_inner(ptr_t data,void*context GC_ATTR_UNUSED) +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; + 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(); + 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); + 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; + me -> backing_store_ptr = stack_ptr; #endif -me->thread_blocked_sp=(ptr_t)&d; -UNLOCK(); -d->client_data=(d->fn)(d->client_data); -LOCK(); + 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); + 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; + 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(); + 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); + GC_noop1((word)me->traced_stack_sect); #endif -me->traced_stack_sect=stacksect.prev; + me -> traced_stack_sect = stacksect.prev; #ifdef IA64 -me->backing_store_ptr=stacksect.saved_backing_store_ptr; + me -> backing_store_ptr = stacksect.saved_backing_store_ptr; #endif -me->thread_blocked_sp=stacksect.saved_stack_ptr; -UNLOCK(); -return client_data; + 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_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; + 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; + 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; + t -> backing_store_end = (ptr_t)sb->reg_base; #endif } -GC_API void*GC_CALL GC_get_my_stackbottom(struct GC_stack_base*sb) +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; + 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; + sb -> reg_base = me -> backing_store_end; #endif -UNLOCK(); -return (void*)me; + 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) -{ + 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; -} -} + 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 { + 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; + 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)"); + 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 -} -static void fork_prepare_proc(void) -{ -LOCK(); + GC_wait_for_gc_completion(TRUE); #ifdef PARALLEL_MARK -if (GC_parallel) -GC_wait_for_reclaim(); + if (GC_parallel) + GC_acquire_mark_lock(); #endif -GC_wait_for_gc_completion(TRUE); + } + static void fork_parent_proc(void) + { #ifdef PARALLEL_MARK -if (GC_parallel) -GC_acquire_mark_lock(); + if (GC_parallel) + GC_release_mark_lock(); #endif -} -static void fork_parent_proc(void) -{ + UNLOCK(); + } + static void fork_child_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(); -} + 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()); + GC_ASSERT(I_HOLD_LOCK()); #ifndef GC_NO_THREADS_DISCOVERY -if (GC_win32_dll_threads){ -} else + if (GC_win32_dll_threads) { + } else #endif -{ -GC_PUSH_ALL_SYM(GC_threads); -} + { + GC_PUSH_ALL_SYM(GC_threads); + } #if defined(THREAD_LOCAL_ALLOC) -GC_PUSH_ALL_SYM(GC_thread_key); + 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_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) + 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) +#define GET_THREAD_CONTEXT_FLAGS (CONTEXT_INTEGER | CONTEXT_CONTROL) #endif STATIC void GC_suspend(GC_thread t) { #ifndef MSWINCE -DWORD exitCode; -#endif + DWORD exitCode; #ifdef RETRY_GET_THREAD_CONTEXT -int retry_cnt=0; -#define MAX_SUSPEND_THREAD_RETRIES (1000*1000) + int retry_cnt; +#define MAX_SUSPEND_THREAD_RETRIES (1000 * 1000) +#endif #endif #ifdef DEBUG_THREADS -GC_log_printf("Suspending 0x%x\n",(int)t->id); + GC_log_printf("Suspending 0x%x\n", (int)t->id); #endif -UNPROTECT_THREAD(t); -GC_acquire_dirty_lock(); + 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(); -} + 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(); + for (retry_cnt = 0;;) { + 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(); + 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; + t -> stack_base = 0; #else -GC_ASSERT(GC_win32_dll_threads); -GC_delete_gc_thread_no_free(t); + GC_ASSERT(GC_win32_dll_threads); + GC_delete_gc_thread_no_free(t); #endif -return; -} -if (SuspendThread(t->handle)==(DWORD)-1) -ABORT("SuspendThread failed"); + 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)); + 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; +#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()); + 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); -} + 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; +#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); +#if (defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE) + GC_ASSERT(!GC_write_disabled); + EnterCriticalSection(&GC_write_cs); #ifdef GC_ASSERTIONS -GC_write_disabled=TRUE; + 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) + 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; + GC_write_disabled = FALSE; #endif -LeaveCriticalSection(&GC_write_cs); + LeaveCriticalSection(&GC_write_cs); #endif #ifdef PARALLEL_MARK -if (GC_parallel) -GC_release_mark_lock(); + 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){ + 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){ + 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 { + 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); + 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; + } + } + } + } +#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) +#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 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); + 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; + 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)) +#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); + PUSH2(ContextFlags, SegFs); #endif -PUSH4(Edi,Esi,Ebx,Edx),PUSH2(Ecx,Eax),PUSH1(Ebp); -sp=(ptr_t)context.Esp; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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){ + 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 { + 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; -} + sp = thread->context_sp; + if (NULL == sp) { + return 0; + } #else -ABORT("GetThreadContext failed"); + ABORT("GetThreadContext failed"); #endif -} -} + } + } #ifdef THREAD_LOCAL_ALLOC -GC_ASSERT(thread->suspended||!GC_world_stopped); + 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)); + 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; -} -} + 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){ + 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){ + 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); + 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); + 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_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; + DWORD thread_id = GetCurrentThreadId(); + GC_bool found_me = FALSE; #ifndef SMALL_CONFIG -unsigned nthreads=0; + unsigned nthreads = 0; #endif -word total_size=0; + 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){ + 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){ + ++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; -} -} -} -} + ++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":""); + 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; + 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]; + 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; + 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; -} -} -} + 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]; + 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); + 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; + 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__) +#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) +#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) + STATIC void * GC_mark_thread(void * id) #elif defined(MSWINCE) -STATIC DWORD WINAPI GC_mark_thread(LPVOID id) + STATIC DWORD WINAPI GC_mark_thread(LPVOID id) #else -STATIC unsigned __stdcall GC_mark_thread(void*id) + 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(); + { + 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; -} + 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); + GC_log_printf("Starting mark helper for mark number %lu\n", + (unsigned long)my_mark_no); #endif -GC_help_marker(my_mark_no); -} -} + 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; + static int available_markers_m1 = 0; #else #define available_markers_m1 GC_markers_m1 #endif #ifdef GC_PTHREADS_PARAMARK #include -#if defined(GC_ASSERTIONS)&&!defined(NUMERIC_THREAD_ID) -#define NUMERIC_THREAD_ID(id)(unsigned long)(word)GC_PTHREAD_PTRVAL(id) +#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; + static pthread_cond_t mark_cv; #else -static pthread_cond_t mark_cv=PTHREAD_COND_INITIALIZER; + 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; + 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; + sigset_t set, oldset; #endif -GC_ASSERT(I_DONT_HOLD_LOCK()); -if (available_markers_m1<=0)return; + 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"); + 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; -} + 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; -} -} + 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); -} + 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; + 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; + 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())); + 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"); -} + 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"); -} -} + (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); -} -} + 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; + 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; + volatile AO_t GC_block_count = 0; + volatile AO_t GC_unlocked_count = 0; #endif -GC_INNER void GC_acquire_mark_lock(void) -{ + GC_INNER void GC_acquire_mark_lock(void) + { #ifndef THREAD_SANITIZER -GC_ASSERT(GC_mark_lock_holder!=GetCurrentThreadId()); + GC_ASSERT(GC_mark_lock_holder != GetCurrentThreadId()); #endif -if (InterlockedExchange(&GC_mark_mutex_state,1)!=0){ + 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"); -} -} + (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); + 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(); -} + 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(); + 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(); + 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); -} + 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) +#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); -} + 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"); -} + 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(); + GC_deinit(); #endif -return (int)exit_code; -} + 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; + 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")); + 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); + 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(); + GC_main_thread = GetCurrentThreadId(); #endif -GC_thr_initialized=TRUE; + GC_thr_initialized = TRUE; #ifdef CAN_HANDLE_FORK -if (GC_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 + 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"); -} + 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); + 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; + 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){ + { + 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; + markers = (int)GC_sysinfo.dwNumberOfProcessors; #else #ifdef _WIN64 -DWORD_PTR procMask=0; -DWORD_PTR sysMask; + DWORD_PTR procMask = 0; + DWORD_PTR sysMask; #else -DWORD procMask=0; -DWORD sysMask; + DWORD procMask = 0; + DWORD sysMask; #endif -int ncpu=0; -if ( + 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 { + 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); + 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; + 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; + GC_thread t; #endif -DCL_LOCK_STATE; -GC_ASSERT(!GC_win32_dll_threads); + 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)); + 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); + while ((t = GC_lookup_pthread(pthread_id)) == 0) + Sleep(10); #endif -result=pthread_join(pthread_id,retval); -if (0==result){ + 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(); -} + 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; -} + 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; + 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); + 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); + 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()); + 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); + 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; -} + 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); + GC_remove_specific(GC_thread_key); #endif -UNLOCK(); -} + 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) + 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 + 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&¶llel_initialized)return TRUE; -switch (reason){ -case DLL_THREAD_ATTACH: + 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; -} + if (GC_parallel) { + break; + } #endif -case DLL_PROCESS_ATTACH: -thread_id=GetCurrentThreadId(); -if (parallel_initialized&&GC_main_thread!=thread_id){ + 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"); + ABORT("Cannot initialize parallel marker from DllMain"); #else -struct GC_stack_base sb; + 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; -} + 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(); -} + 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(); + 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); -} + 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)){ + 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); + GC_log_printf("Marking thread locals for 0x%x\n", (int)p -> id); #endif -GC_mark_thread_local_fls_for(&(p->tlfs)); -} -} -} -} + 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)); -} -} + 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); + if (GC_thread_key != 0) + GC_check_tsd_marks(GC_thread_key); #endif -} + } #endif #endif #ifndef GC_NO_THREAD_REDIRECTS @@ -30160,107 +31332,36 @@ GC_check_tsd_marks(GC_thread_key); #endif #endif #ifndef GC_PTHREAD_START_STANDALONE -#if defined(__GNUC__)&&defined(__linux__) +#if defined(__GNUC__) && defined(__linux__) #undef __EXCEPTIONS #endif -#if defined(GC_PTHREADS)&&!defined(GC_WIN32_THREADS) +#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) #include #include -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); +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); + 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()); + 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); + me -> status = result; + GC_end_stubborn_change(me); #ifndef NACL -pthread_cleanup_pop(1); + pthread_cleanup_pop(1); #endif -return result; + 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 -#ifndef GC_NO_DLOPEN -#include -#endif -#ifndef GC_NO_PTHREAD_SIGMASK -#include -#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 diff --git a/thirdparty/libgc/gc.h b/thirdparty/libgc/gc.h deleted file mode 100644 index d0646f599..000000000 --- a/thirdparty/libgc/gc.h +++ /dev/null @@ -1,1081 +0,0 @@ -/* - * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers - * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. - * Copyright 1996-1999 by Silicon Graphics. All rights reserved. - * Copyright 1999 by Hewlett-Packard Company. All rights reserved. - * Copyright (C) 2007 Free Software Foundation, Inc - * Copyright (c) 2000-2011 by Hewlett-Packard Development Company. - * Copyright (c) 2009-2020 Ivan Maidanski - * - * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED - * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. - * - * Permission is hereby granted to use or copy this program - * for any purpose, provided the above notices are retained on all copies. - * Permission to modify the code and to distribute modified code is granted, - * provided the above notices are retained, and a notice that the code was - * modified is included with the above copyright notice. - */ - -#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 -#if defined(__MINGW32__)&&!defined(_WIN32_WCE) -#include -#endif -#else -#include -#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 -#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 -#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 -#endif -#if defined(GC_BUILD)||!defined(GC_DONT_INCLUDE_WINDOWS_H) -#include -#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 diff --git a/thirdparty/libgc/include/gc.h b/thirdparty/libgc/include/gc.h new file mode 100644 index 000000000..55ae4c6c1 --- /dev/null +++ b/thirdparty/libgc/include/gc.h @@ -0,0 +1,2 @@ +/* This file is installed for backward compatibility. */ +#include diff --git a/thirdparty/libgc/include/gc/cord.h b/thirdparty/libgc/include/gc/cord.h new file mode 100644 index 000000000..4ce89ffd7 --- /dev/null +++ b/thirdparty/libgc/include/gc/cord.h @@ -0,0 +1,377 @@ +/* + * Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +/* + * Cords are immutable character strings. A number of operations + * on long cords are much more efficient than their strings.h counterpart. + * In particular, concatenation takes constant time independent of the length + * of the arguments. (Cords are represented as trees, with internal + * nodes representing concatenation and leaves consisting of either C + * strings or a functional description of the string.) + * + * The following are reasonable applications of cords. They would perform + * unacceptably if C strings were used: + * - A compiler that produces assembly language output by repeatedly + * concatenating instructions onto a cord representing the output file. + * - A text editor that converts the input file to a cord, and then + * performs editing operations by producing a new cord representing + * the file after each character change (and keeping the old ones in an + * edit history) + * + * For optimal performance, cords should be built by + * concatenating short sections. + * This interface is designed for maximum compatibility with C strings. + * ASCII NUL characters may be embedded in cords using CORD_from_fn. + * This is handled correctly, but CORD_to_char_star will produce a string + * with embedded NULs when given such a cord. + * + * This interface is fairly big, largely for performance reasons. + * The most basic constants and functions: + * + * CORD - the type of a cord; + * CORD_EMPTY - empty cord; + * CORD_len(cord) - length of a cord; + * CORD_cat(cord1,cord2) - concatenation of two cords; + * CORD_substr(cord, start, len) - substring (or subcord); + * CORD_pos i; CORD_FOR(i, cord) { ... CORD_pos_fetch(i) ... } - + * examine each character in a cord. CORD_pos_fetch(i) is the char. + * CORD_fetch(int i) - Retrieve i'th character (slowly). + * CORD_cmp(cord1, cord2) - compare two cords. + * CORD_from_file(FILE * f) - turn a read-only file into a cord. + * CORD_to_char_star(cord) - convert to C string. + * (Non-NULL C constant strings are cords.) + * CORD_printf (etc.) - cord version of printf. Use %r for cords. + */ +#ifndef CORD_H +#define CORD_H + +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + +#if defined(GC_DLL) && !defined(CORD_NOT_DLL) + /* Same as for GC_API in gc_config_macros.h. */ +# ifdef CORD_BUILD +# if defined(__MINGW32__) || defined(__CEGCC__) +# define CORD_API __declspec(dllexport) +# elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \ + || defined(__CYGWIN__) || defined(__WATCOMC__) +# define CORD_API extern __declspec(dllexport) +# elif defined(__GNUC__) && !defined(GC_NO_VISIBILITY) \ + && (__GNUC__ >= 4 || defined(GC_VISIBILITY_HIDDEN_SET)) + /* Only matters if used in conjunction with -fvisibility=hidden option. */ +# define CORD_API extern __attribute__((__visibility__("default"))) +# endif +# else +# if defined(__MINGW32__) || defined(__CEGCC__) || defined(_MSC_VER) \ + || defined(__DMC__) || defined(__BORLANDC__) || defined(__CYGWIN__) +# define CORD_API __declspec(dllimport) +# elif defined(__WATCOMC__) +# define CORD_API extern __declspec(dllimport) +# endif +# endif /* !CORD_BUILD */ +#endif /* GC_DLL */ + +#ifndef CORD_API +# define CORD_API extern +#endif + +/* Cords have type const char *. This is cheating quite a bit, and not */ +/* 100% portable. But it means that nonempty character string */ +/* constants may be used as cords directly, provided the string is */ +/* never modified in place. The empty cord is represented by, and */ +/* can be written as, 0. */ + +typedef const char * CORD; + +/* An empty cord is always represented as nil */ +#define CORD_EMPTY 0 + +/* Is a nonempty cord represented as a C string? */ +#define CORD_IS_STRING(s) (*(s) != '\0') + +/* Concatenate two cords. If the arguments are C strings, they may */ +/* not be subsequently altered. */ +CORD_API CORD CORD_cat(CORD x, CORD y); + +/* Concatenate a cord and a C string with known length. Except for the */ +/* empty string case, this is a special case of CORD_cat. Since the */ +/* length is known, it can be faster. */ +/* The string y is shared with the resulting CORD. Hence it should */ +/* not be altered by the caller. */ +CORD_API CORD CORD_cat_char_star(CORD x, const char * y, size_t leny); + +/* Compute the length of a cord */ +CORD_API size_t CORD_len(CORD x); + +/* Cords may be represented by functions defining the ith character */ +typedef char (* CORD_fn)(size_t i, void * client_data); + +/* Turn a functional description into a cord. */ +CORD_API CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len); + +/* Return the substring (subcord really) of x with length at most n, */ +/* starting at position i. (The initial character has position 0.) */ +CORD_API CORD CORD_substr(CORD x, size_t i, size_t n); + +/* Return the argument, but rebalanced to allow more efficient */ +/* character retrieval, substring operations, and comparisons. */ +/* This is useful only for cords that were built using repeated */ +/* concatenation. Guarantees log time access to the result, unless */ +/* x was obtained through a large number of repeated substring ops */ +/* or the embedded functional descriptions take longer to evaluate. */ +/* May reallocate significant parts of the cord. The argument is not */ +/* modified; only the result is balanced. */ +CORD_API CORD CORD_balance(CORD x); + +/* The following traverse a cord by applying a function to each */ +/* character. This is occasionally appropriate, especially where */ +/* speed is crucial. But, since C doesn't have nested functions, */ +/* clients of this sort of traversal are clumsy to write. Consider */ +/* the functions that operate on cord positions instead. */ + +/* Function to iteratively apply to individual characters in cord. */ +typedef int (* CORD_iter_fn)(char c, void * client_data); + +/* Function to apply to substrings of a cord. Each substring is a */ +/* a C character string, not a general cord. */ +typedef int (* CORD_batched_iter_fn)(const char * s, void * client_data); +#define CORD_NO_FN ((CORD_batched_iter_fn)0) + +/* Apply f1 to each character in the cord, in ascending order, */ +/* starting at position i. If */ +/* f2 is not CORD_NO_FN, then multiple calls to f1 may be replaced by */ +/* a single call to f2. The parameter f2 is provided only to allow */ +/* some optimization by the client. This terminates when the right */ +/* end of this string is reached, or when f1 or f2 return != 0. In the */ +/* latter case CORD_iter returns != 0. Otherwise it returns 0. */ +/* The specified value of i must be < CORD_len(x). */ +CORD_API int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1, + CORD_batched_iter_fn f2, void * client_data); + +/* A simpler version that starts at 0, and without f2: */ +CORD_API int CORD_iter(CORD x, CORD_iter_fn f1, void * client_data); +#define CORD_iter(x, f1, cd) CORD_iter5(x, 0, f1, CORD_NO_FN, cd) + +/* Similar to CORD_iter5, but end-to-beginning. No provisions for */ +/* CORD_batched_iter_fn. */ +CORD_API int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data); + +/* A simpler version that starts at the end: */ +CORD_API int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +/* Functions that operate on cord positions. The easy way to traverse */ +/* cords. A cord position is logically a pair consisting of a cord */ +/* and an index into that cord. But it is much faster to retrieve a */ +/* character based on a position than on an index. Unfortunately, */ +/* positions are big (order of a few 100 bytes), so allocate them with */ +/* caution. */ +/* Things in cord_pos.h should be treated as opaque, except as */ +/* described below. Also note that */ +/* CORD_pos_fetch, CORD_next and CORD_prev have both macro and function */ +/* definitions. The former may evaluate their argument more than once. */ +#include "cord_pos.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/* + Visible definitions from above: + + typedef CORD_pos[1]; + + * Extract the cord from a position: + CORD CORD_pos_to_cord(CORD_pos p); + + * Extract the current index from a position: + size_t CORD_pos_to_index(CORD_pos p); + + * Fetch the character located at the given position: + char CORD_pos_fetch(CORD_pos p); + + * Initialize the position to refer to the given cord and index. + * Note that this is the most expensive function on positions: + void CORD_set_pos(CORD_pos p, CORD x, size_t i); + + * Advance the position to the next character. + * P must be initialized and valid. + * Invalidates p if past end: + void CORD_next(CORD_pos p); + + * Move the position to the preceding character. + * P must be initialized and valid. + * Invalidates p if past beginning: + void CORD_prev(CORD_pos p); + + * Is the position valid, i.e. inside the cord? + int CORD_pos_valid(CORD_pos p); +*/ +#define CORD_FOR(pos, cord) \ + for (CORD_set_pos(pos, cord, 0); CORD_pos_valid(pos); CORD_next(pos)) + + +/* An out of memory handler to call. May be supplied by client. */ +/* Must not return. */ +extern void (* CORD_oom_fn)(void); + +/* Dump the representation of x to stdout in an implementation defined */ +/* manner. Intended for debugging only. */ +CORD_API void CORD_dump(CORD x); + +/* The following could easily be implemented by the client. They are */ +/* provided in cordxtra.c for convenience. */ + +/* Concatenate a character to the end of a cord. */ +CORD_API CORD CORD_cat_char(CORD x, char c); + +/* Concatenate n cords. */ +CORD_API CORD CORD_catn(int n, /* CORD */ ...); + +/* Return the character in CORD_substr(x, i, 1) */ +CORD_API char CORD_fetch(CORD x, size_t i); + +/* Return < 0, 0, or > 0, depending on whether x < y, x = y, x > y */ +CORD_API int CORD_cmp(CORD x, CORD y); + +/* A generalization that takes both starting positions for the */ +/* comparison, and a limit on the number of characters to be compared. */ +CORD_API int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, + size_t len); + +/* Find the first occurrence of s in x at position start or later. */ +/* Return the position of the first character of s in x, or */ +/* CORD_NOT_FOUND if there is none. */ +CORD_API size_t CORD_str(CORD x, size_t start, CORD s); + +/* Return a cord consisting of i copies of (possibly NUL) c. Dangerous */ +/* in conjunction with CORD_to_char_star. */ +/* The resulting representation takes constant space, independent of i. */ +CORD_API CORD CORD_chars(char c, size_t i); +#define CORD_nul(i) CORD_chars('\0', (i)) + +/* Turn a file into cord. The file must be seekable. Its contents */ +/* must remain constant. The file may be accessed as an immediate */ +/* result of this call and/or as a result of subsequent accesses to */ +/* the cord. Short files are likely to be immediately read, but */ +/* long files are likely to be read on demand, possibly relying on */ +/* stdio for buffering. */ +/* We must have exclusive access to the descriptor f, i.e. we may */ +/* read it at any time, and expect the file pointer to be */ +/* where we left it. Normally this should be invoked as */ +/* CORD_from_file(fopen(...)) */ +/* CORD_from_file arranges to close the file descriptor when it is no */ +/* longer needed (e.g. when the result becomes inaccessible). */ +/* The file f must be such that ftell reflects the actual character */ +/* position in the file, i.e. the number of characters that can be */ +/* or were read with fread. On UNIX systems this is always true. On */ +/* MS Windows systems, f must be opened in binary mode. */ +CORD_API CORD CORD_from_file(FILE * f); + +/* Equivalent to the above, except that the entire file will be read */ +/* and the file pointer will be closed immediately. */ +/* The binary mode restriction from above does not apply. */ +CORD_API CORD CORD_from_file_eager(FILE * f); + +/* Equivalent to the above, except that the file will be read on demand.*/ +/* The binary mode restriction applies. */ +CORD_API CORD CORD_from_file_lazy(FILE * f); + +/* Turn a cord into a C string. The result shares no structure with */ +/* x, and is thus modifiable. */ +CORD_API char * CORD_to_char_star(CORD x); + +/* Turn a C string into a CORD. The C string is copied, and so may */ +/* subsequently be modified. */ +CORD_API CORD CORD_from_char_star(const char *s); + +/* Identical to the above, but the result may share structure with */ +/* the argument and is thus not modifiable. */ +CORD_API const char * CORD_to_const_char_star(CORD x); + +/* Write a cord to a file, starting at the current position. No */ +/* trailing NULs are newlines are added. */ +/* Returns EOF if a write error occurs, 1 otherwise. */ +CORD_API int CORD_put(CORD x, FILE * f); + +/* "Not found" result for the following two functions. */ +#define CORD_NOT_FOUND ((size_t)(-1)) + +/* A vague analog of strchr. Returns the position (an integer, not */ +/* a pointer) of the first occurrence of (char) c inside x at position */ +/* i or later. The value i must be < CORD_len(x). */ +CORD_API size_t CORD_chr(CORD x, size_t i, int c); + +/* A vague analog of strrchr. Returns index of the last occurrence */ +/* of (char) c inside x at position i or earlier. The value i */ +/* must be < CORD_len(x). */ +CORD_API size_t CORD_rchr(CORD x, size_t i, int c); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +/* The following are also not primitive, but are implemented in */ +/* cordprnt.c. They provide functionality similar to the ANSI C */ +/* functions with corresponding names, but with the following */ +/* additions and changes: */ +/* 1. A %r conversion specification specifies a CORD argument. Field */ +/* width, precision, etc. have the same semantics as for %s. */ +/* (Note that %c, %C, and %S were already taken.) */ +/* 2. The format string is represented as a CORD. */ +/* 3. CORD_sprintf and CORD_vsprintf assign the result through the 1st */ +/* argument. Unlike their ANSI C versions, there is no need to guess */ +/* the correct buffer size. */ +/* 4. Most of the conversions are implement through the native */ +/* vsprintf. Hence they are usually no faster, and */ +/* idiosyncrasies of the native printf are preserved. However, */ +/* CORD arguments to CORD_sprintf and CORD_vsprintf are NOT copied; */ +/* the result shares the original structure. This may make them */ +/* very efficient in some unusual applications. */ +/* The format string is copied. */ +/* All functions return the number of characters generated or -1 on */ +/* error. This complies with the ANSI standard, but is inconsistent */ +/* with some older implementations of sprintf. */ + +/* The implementation of these is probably less portable than the rest */ +/* of this package. */ + +#ifndef CORD_NO_IO + +#include + +# ifdef __cplusplus + extern "C" { +# endif + +CORD_API int CORD_sprintf(CORD * out, CORD format, ...); +CORD_API int CORD_vsprintf(CORD * out, CORD format, va_list args); +CORD_API int CORD_fprintf(FILE * f, CORD format, ...); +CORD_API int CORD_vfprintf(FILE * f, CORD format, va_list args); +CORD_API int CORD_printf(CORD format, ...); +CORD_API int CORD_vprintf(CORD format, va_list args); + +# ifdef __cplusplus + } /* extern "C" */ +# endif + +#endif /* CORD_NO_IO */ + +#endif /* CORD_H */ diff --git a/thirdparty/libgc/include/gc/cord_pos.h b/thirdparty/libgc/include/gc/cord_pos.h new file mode 100644 index 000000000..29d5df902 --- /dev/null +++ b/thirdparty/libgc/include/gc/cord_pos.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +/* This should never be included directly; included only from cord.h. */ +#if !defined(CORD_POSITION_H) && defined(CORD_H) +#define CORD_POSITION_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* The representation of CORD_position. This is private to the */ +/* implementation, but the size is known to clients. Also */ +/* the implementation of some exported macros relies on it. */ +/* Don't use anything defined here and not in cord.h. */ + +# define MAX_DEPTH 48 + /* The maximum depth of a balanced cord + 1. */ + /* We don't let cords get deeper than MAX_DEPTH. */ + +struct CORD_pe { + CORD pe_cord; + size_t pe_start_pos; +}; + +/* A structure describing an entry on the path from the root */ +/* to current position. */ +typedef struct CORD_Pos { + size_t cur_pos; + int path_len; +# define CORD_POS_INVALID (0x55555555) + /* path_len == INVALID <==> position invalid */ + const char *cur_leaf; /* Current leaf, if it is a string. */ + /* If the current leaf is a function, */ + /* then this may point to function_buf */ + /* containing the next few characters. */ + /* Always points to a valid string */ + /* containing the current character */ + /* unless cur_end is 0. */ + size_t cur_start; /* Start position of cur_leaf */ + size_t cur_end; /* Ending position of cur_leaf */ + /* 0 if cur_leaf is invalid. */ + struct CORD_pe path[MAX_DEPTH + 1]; + /* path[path_len] is the leaf corresponding to cur_pos */ + /* path[0].pe_cord is the cord we point to. */ +# define FUNCTION_BUF_SZ 8 + char function_buf[FUNCTION_BUF_SZ]; /* Space for next few chars */ + /* from function node. */ +} CORD_pos[1]; + +/* Extract the cord from a position: */ +CORD_API CORD CORD_pos_to_cord(CORD_pos p); + +/* Extract the current index from a position: */ +CORD_API size_t CORD_pos_to_index(CORD_pos p); + +/* Fetch the character located at the given position: */ +CORD_API char CORD_pos_fetch(CORD_pos p); + +/* Initialize the position to refer to the give cord and index. */ +/* Note that this is the most expensive function on positions: */ +CORD_API void CORD_set_pos(CORD_pos p, CORD x, size_t i); + +/* Advance the position to the next character. */ +/* P must be initialized and valid. */ +/* Invalidates p if past end: */ +CORD_API void CORD_next(CORD_pos p); + +/* Move the position to the preceding character. */ +/* P must be initialized and valid. */ +/* Invalidates p if past beginning: */ +CORD_API void CORD_prev(CORD_pos p); + +/* Is the position valid, i.e. inside the cord? */ +CORD_API int CORD_pos_valid(CORD_pos p); + +CORD_API char CORD__pos_fetch(CORD_pos); +CORD_API void CORD__next(CORD_pos); +CORD_API void CORD__prev(CORD_pos); + +#define CORD_pos_fetch(p) \ + (((p)[0].cur_end != 0)? \ + (p)[0].cur_leaf[(p)[0].cur_pos - (p)[0].cur_start] \ + : CORD__pos_fetch(p)) + +#define CORD_next(p) \ + (((p)[0].cur_pos + 1 < (p)[0].cur_end)? \ + (p)[0].cur_pos++ \ + : (CORD__next(p), 0)) + +#define CORD_prev(p) \ + (((p)[0].cur_end != 0 && (p)[0].cur_pos > (p)[0].cur_start)? \ + (p)[0].cur_pos-- \ + : (CORD__prev(p), 0)) + +#define CORD_pos_to_index(p) ((p)[0].cur_pos) + +#define CORD_pos_to_cord(p) ((p)[0].path[0].pe_cord) + +#define CORD_pos_valid(p) ((p)[0].path_len != CORD_POS_INVALID) + +/* Some grubby stuff for performance-critical friends: */ +#define CORD_pos_chars_left(p) ((long)((p)[0].cur_end) - (long)((p)[0].cur_pos)) + /* Number of characters in cache. <= 0 ==> none */ + +#define CORD_pos_advance(p,n) ((p)[0].cur_pos += (n) - 1, CORD_next(p)) + /* Advance position by n characters */ + /* 0 < n < CORD_pos_chars_left(p) */ + +#define CORD_pos_cur_char_addr(p) \ + (p)[0].cur_leaf + ((p)[0].cur_pos - (p)[0].cur_start) + /* address of current character in cache. */ + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif diff --git a/thirdparty/libgc/include/gc/ec.h b/thirdparty/libgc/include/gc/ec.h new file mode 100644 index 000000000..e7e0f7f51 --- /dev/null +++ b/thirdparty/libgc/include/gc/ec.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +#ifndef EC_H +#define EC_H + +# ifndef CORD_H +# include "cord.h" +# endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Extensible cords are strings that may be destructively appended to. */ +/* They allow fast construction of cords from characters that are */ +/* being read from a stream. */ +/* + * A client might look like: + * + * { + * CORD_ec x; + * CORD result; + * char c; + * FILE *f; + * + * ... + * CORD_ec_init(x); + * while(...) { + * c = getc(f); + * ... + * CORD_ec_append(x, c); + * } + * result = CORD_balance(CORD_ec_to_cord(x)); + * + * If a C string is desired as the final result, the call to CORD_balance + * may be replaced by a call to CORD_to_char_star. + */ + +# ifndef CORD_BUFSZ +# define CORD_BUFSZ 128 +# endif + +typedef struct CORD_ec_struct { + CORD ec_cord; + char * ec_bufptr; + char ec_buf[CORD_BUFSZ+1]; +} CORD_ec[1]; + +/* This structure represents the concatenation of ec_cord with */ +/* ec_buf[0 ... (ec_bufptr-ec_buf-1)] */ + +/* Flush the buffer part of the extended cord into ec_cord. */ +/* Note that this is almost the only real function, and it is */ +/* implemented in 6 lines in cordxtra.c */ +void CORD_ec_flush_buf(CORD_ec x); + +/* Convert an extensible cord to a cord. */ +# define CORD_ec_to_cord(x) (CORD_ec_flush_buf(x), (x)[0].ec_cord) + +/* Initialize an extensible cord. */ +#define CORD_ec_init(x) \ + ((x)[0].ec_cord = 0, (void)((x)[0].ec_bufptr = (x)[0].ec_buf)) + +/* Append a character to an extensible cord. */ +#define CORD_ec_append(x, c) \ + ((void)((x)[0].ec_bufptr == (x)[0].ec_buf + CORD_BUFSZ \ + ? (CORD_ec_flush_buf(x), 0) : 0), \ + (void)(*(x)[0].ec_bufptr++ = (c))) + +/* Append a cord to an extensible cord. Structure remains shared with */ +/* original. */ +void CORD_ec_append_cord(CORD_ec x, CORD s); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* EC_H */ diff --git a/thirdparty/libgc/include/gc/gc.h b/thirdparty/libgc/include/gc/gc.h new file mode 100644 index 000000000..90385bed0 --- /dev/null +++ b/thirdparty/libgc/include/gc/gc.h @@ -0,0 +1,2172 @@ +/* + * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers + * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. + * Copyright 1996-1999 by Silicon Graphics. All rights reserved. + * Copyright 1999 by Hewlett-Packard Company. All rights reserved. + * Copyright (C) 2007 Free Software Foundation, Inc + * Copyright (c) 2000-2011 by Hewlett-Packard Development Company. + * Copyright (c) 2009-2020 Ivan Maidanski + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +/* + * Note that this defines a large number of tuning hooks, which can + * safely be ignored in nearly all cases. For normal use it suffices + * to call only GC_MALLOC and perhaps GC_REALLOC. + * For better performance, also look at GC_MALLOC_ATOMIC, and + * GC_enable_incremental. If you need an action to be performed + * immediately before an object is collected, look at GC_register_finalizer. + * Everything else is best ignored unless you encounter performance + * problems. + */ + +#ifndef GC_H +#define GC_H + +/* Help debug mixed up preprocessor symbols. */ +#if (defined(WIN64) && !defined(_WIN64)) && defined(_MSC_VER) +#pragma message("Warning: Expecting _WIN64 for x64 targets! Notice the leading underscore!") +#endif + +#include "gc_version.h" + /* Define version numbers here to allow test on build machine */ + /* for cross-builds. Note that this defines the header */ + /* version number, which may or may not match that of the */ + /* dynamic library. GC_get_version() can be used to obtain */ + /* the latter. */ + +#include "gc_config_macros.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef void * GC_PTR; /* preserved only for backward compatibility */ + +/* Define word and signed_word to be unsigned and signed types of the */ +/* size as char * or void *. There seems to be no way to do this */ +/* even semi-portably. The following is probably no better/worse */ +/* than almost anything else. */ +/* The ANSI standard suggests that size_t and ptrdiff_t might be */ +/* better choices. But those had incorrect definitions on some older */ +/* systems. Notably "typedef int size_t" is WRONG. */ +#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 + +/* Get the GC library version. The returned value is a constant in the */ +/* form: ((version_major<<16) | (version_minor<<8) | version_micro). */ +GC_API unsigned GC_CALL GC_get_version(void); + +/* Public read-only variables */ +/* The supplied getter functions are preferred for new code. */ + +GC_API GC_ATTR_DEPRECATED GC_word GC_gc_no; + /* Counter incremented per collection. */ + /* Includes empty GCs at startup. */ +GC_API GC_word GC_CALL GC_get_gc_no(void); + /* GC_get_gc_no() is unsynchronized, so */ + /* it requires GC_call_with_alloc_lock() to */ + /* avoid data races on multiprocessors. */ + +#ifdef GC_THREADS + GC_API GC_ATTR_DEPRECATED int GC_parallel; + /* GC is parallelized for performance on */ + /* multiprocessors. Set to a non-zero value */ + /* only implicitly if collector is built with */ + /* PARALLEL_MARK defined, and if either */ + /* GC_MARKERS (or GC_NPROCS) environment */ + /* variable is set to > 1, or multiple cores */ + /* (processors) are available, or the client */ + /* calls GC_set_markers_count() before the GC */ + /* initialization. The getter does */ + /* not use or need synchronization (i.e. */ + /* acquiring the GC lock). GC_parallel value */ + /* is equal to the number of marker threads */ + /* minus one (i.e. number of existing parallel */ + /* marker threads excluding the initiating one).*/ + GC_API int GC_CALL GC_get_parallel(void); + + /* Set the number of marker threads (including the initiating one) */ + /* to the desired value at start-up. Zero value means the collector */ + /* is to decide. Has no effect if called after GC initialization. */ + /* If the correct non-zero value is passed, then GC_parallel should */ + /* be set to the value minus one. The function does not use any */ + /* synchronization. */ + GC_API void GC_CALL GC_set_markers_count(unsigned); +#endif + + +/* Public R/W variables */ +/* The supplied setter and getter functions are preferred for new code. */ + +typedef void * (GC_CALLBACK * GC_oom_func)(size_t /* bytes_requested */); +GC_API GC_ATTR_DEPRECATED GC_oom_func GC_oom_fn; + /* When there is insufficient memory to satisfy */ + /* an allocation request, we return */ + /* (*GC_oom_fn)(size). By default this just */ + /* returns NULL. */ + /* If it returns, it must return 0 or a valid */ + /* pointer to a previously allocated heap */ + /* object. GC_oom_fn must not be 0. */ + /* Both the supplied setter and the getter */ + /* acquire the GC lock (to avoid data races). */ +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 /* new_size */); +GC_API GC_ATTR_DEPRECATED GC_on_heap_resize_proc GC_on_heap_resize; + /* Invoked when the heap grows or shrinks. */ + /* Called with the world stopped (and the */ + /* allocation lock held). May be 0. */ +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); + /* Both the supplied setter and the getter */ + /* acquire the GC lock (to avoid data races). */ + +typedef enum { + GC_EVENT_START /* COLLECTION */, + GC_EVENT_MARK_START, + GC_EVENT_MARK_END, + GC_EVENT_RECLAIM_START, + GC_EVENT_RECLAIM_END, + GC_EVENT_END /* COLLECTION */, + GC_EVENT_PRE_STOP_WORLD /* STOPWORLD_BEGIN */, + GC_EVENT_POST_STOP_WORLD /* STOPWORLD_END */, + GC_EVENT_PRE_START_WORLD /* STARTWORLD_BEGIN */, + GC_EVENT_POST_START_WORLD /* STARTWORLD_END */, + GC_EVENT_THREAD_SUSPENDED, + GC_EVENT_THREAD_UNSUSPENDED +} GC_EventType; + +typedef void (GC_CALLBACK * GC_on_collection_event_proc)(GC_EventType); + /* Invoked to indicate progress through the */ + /* collection process. Not used for thread */ + /* suspend/resume notifications. Called with */ + /* the GC lock held (or, even, the world */ + /* stopped). May be 0 (means no notifier). */ +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); + /* Both the supplied setter and the getter */ + /* acquire the GC lock (to avoid data races). */ + +#if defined(GC_THREADS) || (defined(GC_BUILD) && defined(NN_PLATFORM_CTR)) + typedef void (GC_CALLBACK * GC_on_thread_event_proc)(GC_EventType, + void * /* thread_id */); + /* Invoked when a thread is suspended or */ + /* resumed during collection. Called with the */ + /* GC lock held (and the world stopped */ + /* partially). May be 0 (means no notifier). */ + 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); + /* Both the supplied setter and the getter */ + /* acquire the GC lock (to avoid data races). */ +#endif + +GC_API GC_ATTR_DEPRECATED int GC_find_leak; + /* Set to true to turn on the leak-finding mode */ + /* (do not actually garbage collect, but simply */ + /* report inaccessible memory that was not */ + /* deallocated with GC_FREE). Initial value */ + /* is determined by FIND_LEAK macro. */ + /* The value should not typically be modified */ + /* after GC initialization (and, thus, it does */ + /* not use or need synchronization). */ +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; + /* Arrange for pointers to object interiors to */ + /* be recognized as valid. Typically should */ + /* not be changed after GC initialization (in */ + /* case of calling it after the GC is */ + /* initialized, the setter acquires the GC lock */ + /* (to avoid data races). The initial value */ + /* depends on whether the GC is built with */ + /* ALL_INTERIOR_POINTERS macro defined or not. */ + /* Unless DONT_ADD_BYTE_AT_END is defined, this */ + /* also affects whether sizes are increased by */ + /* at least a byte to allow "off the end" */ + /* pointer recognition. Must be only 0 or 1. */ +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; + /* If nonzero, finalizers will only be run in */ + /* response to an explicit GC_invoke_finalizers */ + /* call. The default is determined by whether */ + /* the FINALIZE_ON_DEMAND macro is defined */ + /* when the collector is built. */ + /* The setter and getter are unsynchronized. */ +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; + /* Mark objects reachable from finalizable */ + /* objects in a separate post-pass. This makes */ + /* it a bit safer to use non-topologically- */ + /* ordered finalization. Default value is */ + /* determined by JAVA_FINALIZATION macro. */ + /* Enables register_finalizer_unreachable to */ + /* work correctly. */ + /* The setter and getter are unsynchronized. */ +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; + /* Invoked by the collector when there are */ + /* objects to be finalized. Invoked at most */ + /* once per GC cycle. Never invoked unless */ + /* GC_finalize_on_demand is set. */ + /* Typically this will notify a finalization */ + /* thread, which will call GC_invoke_finalizers */ + /* in response. May be 0 (means no notifier). */ + /* Both the supplied setter and the getter */ + /* acquire the GC lock (to avoid data races). */ +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; /* != 0 ==> Do not collect. This overrides */ + /* explicit GC_gcollect() calls as well. */ + /* Used as a counter, so that nested enabling */ + /* and disabling work correctly. Should */ + /* normally be updated with GC_enable() and */ + /* GC_disable() calls. Direct assignment to */ + /* GC_dont_gc is deprecated. To check whether */ + /* GC is disabled, GC_is_disabled() is */ + /* preferred for new code. */ + +GC_API GC_ATTR_DEPRECATED int GC_dont_expand; + /* Do not expand the heap unless explicitly */ + /* requested or forced to. The setter and */ + /* getter are unsynchronized. */ +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; + /* Causes the non-incremental collector to use the */ + /* entire heap before collecting. This sometimes */ + /* results in more large block fragmentation, since */ + /* very large blocks will tend to get broken up */ + /* during each GC cycle. It is likely to result in a */ + /* larger working set, but lower collection */ + /* frequencies, and hence fewer instructions executed */ + /* in the collector. */ + +GC_API GC_ATTR_DEPRECATED int GC_full_freq; + /* Number of partial collections between */ + /* full collections. Matters only if */ + /* GC_is_incremental_mode(). */ + /* Full collections are also triggered if */ + /* the collector detects a substantial */ + /* increase in the number of in-use heap */ + /* blocks. Values in the tens are now */ + /* perfectly reasonable, unlike for */ + /* earlier GC versions. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ +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; + /* Bytes not considered candidates for */ + /* collection. Used only to control scheduling */ + /* of collections. Updated by */ + /* GC_malloc_uncollectable and GC_free. */ + /* Wizards only. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ +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; + /* Don't register dynamic library data segments. */ + /* Wizards only. Should be used only if the */ + /* application explicitly registers all roots. */ + /* (In some environments like Microsoft Windows */ + /* and Apple's Darwin, this may also prevent */ + /* registration of the main data segment as part */ + /* of the root set.) */ + /* The setter and getter are unsynchronized. */ +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; + /* We try to make sure that we allocate at */ + /* least N/GC_free_space_divisor bytes between */ + /* collections, where N is twice the number */ + /* of traced bytes, plus the number of untraced */ + /* bytes (bytes in "atomic" objects), plus */ + /* a rough estimate of the root set size. */ + /* N approximates GC tracing work per GC. */ + /* The initial value is GC_FREE_SPACE_DIVISOR. */ + /* Increasing its value will use less space */ + /* but more collection time. Decreasing it */ + /* will appreciably decrease collection time */ + /* at the expense of space. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ + /* In GC v7.1 (and before), the setter returned */ + /* the old value. */ +GC_API void GC_CALL GC_set_free_space_divisor(GC_word); +GC_API GC_word GC_CALL GC_get_free_space_divisor(void); + +GC_API GC_ATTR_DEPRECATED GC_word GC_max_retries; + /* The maximum number of GCs attempted before */ + /* reporting out of memory after heap */ + /* expansion fails. Initially 0. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ +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; + /* The cold end (bottom) of user stack. */ + /* May be set in the client prior to */ + /* calling any GC_ routines. This */ + /* avoids some overhead, and */ + /* potentially some signals that can */ + /* confuse debuggers. Otherwise the */ + /* collector attempts to set it */ + /* automatically. */ + /* For multi-threaded code, this is the */ + /* cold end of the stack for the */ + /* primordial thread. Portable clients */ + /* should use GC_get_stack_base(), */ + /* GC_call_with_gc_active() and */ + /* GC_register_my_thread() instead. */ + +GC_API GC_ATTR_DEPRECATED int GC_dont_precollect; + /* Do not collect as part of GC */ + /* initialization. Should be set only */ + /* if the client wants a chance to */ + /* manually initialize the root set */ + /* before the first collection. */ + /* Interferes with blacklisting. */ + /* Wizards only. The setter and getter */ + /* are unsynchronized (and no external */ + /* locking is needed since the value is */ + /* accessed at GC initialization only). */ +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; + /* If incremental collection is enabled, */ + /* we try to terminate collections */ + /* after this many milliseconds (plus */ + /* the amount of nanoseconds as given in */ + /* the latest GC_set_time_limit_tv call, */ + /* if any). Not a hard time bound. */ + /* Setting this variable to */ + /* GC_TIME_UNLIMITED will essentially */ + /* disable incremental collection while */ + /* leaving generational collection */ + /* enabled. */ +#define GC_TIME_UNLIMITED 999999 + /* Setting GC_time_limit to this value */ + /* will disable the "pause time exceeded"*/ + /* tests. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ + /* The setter does not update the value of the */ + /* nanosecond part of the time limit (it is */ + /* zero unless ever set by GC_set_time_limit_tv */ + /* call). */ +GC_API void GC_CALL GC_set_time_limit(unsigned long); +GC_API unsigned long GC_CALL GC_get_time_limit(void); + +/* A portable type definition of time with a nanosecond precision. */ +struct GC_timeval_s { + unsigned long tv_ms; /* time in milliseconds */ + unsigned long tv_nsec;/* nanoseconds fraction (<1000000) */ +}; + +/* Public procedures */ + +/* Set/get the time limit of the incremental collections. This is */ +/* similar to GC_set_time_limit and GC_get_time_limit but the time is */ +/* provided with the nanosecond precision. The value of tv_nsec part */ +/* should be less than a million. If the value of tv_ms part is */ +/* GC_TIME_UNLIMITED then tv_nsec is ignored. Initially, the value of */ +/* tv_nsec part of the time limit is zero. The functions do not use */ +/* any synchronization. Defined only if the library has been compiled */ +/* without NO_CLOCK. */ +GC_API void GC_CALL GC_set_time_limit_tv(struct GC_timeval_s); +GC_API struct GC_timeval_s GC_CALL GC_get_time_limit_tv(void); + +/* Set/get the minimum value of the ratio of allocated bytes since GC */ +/* to the amount of finalizers created since that GC (value > */ +/* GC_bytes_allocd / (GC_fo_entries - last_fo_entries)) which triggers */ +/* the collection instead heap expansion. The value has no effect in */ +/* the GC incremental mode. The default value is 10000 unless */ +/* GC_ALLOCD_BYTES_PER_FINALIZER macro with a custom value is defined */ +/* to build libgc. The default value might be not the right choice for */ +/* clients where e.g. most objects have a finalizer. Zero value */ +/* effectively disables taking amount of finalizers in the decision */ +/* whether to collect or not. The functions do not use any */ +/* synchronization. */ +GC_API void GC_CALL GC_set_allocd_bytes_per_finalizer(GC_word); +GC_API GC_word GC_CALL GC_get_allocd_bytes_per_finalizer(void); + +/* Tell the collector to start various performance measurements. */ +/* Only the total time taken by full collections is calculated, as */ +/* of now. And, currently, there is no way to stop the measurements. */ +/* The function does not use any synchronization. Defined only if the */ +/* library has been compiled without NO_CLOCK. */ +GC_API void GC_CALL GC_start_performance_measurement(void); + +/* Get the total time of all full collections since the start of the */ +/* performance measurements. The measurement unit is one millisecond. */ +/* Note that the returned value wraps around on overflow. */ +/* The function does not use any synchronization. Defined only if the */ +/* library has been compiled without NO_CLOCK. */ +GC_API unsigned long GC_CALL GC_get_full_gc_total_time(void); + +/* Set whether the GC will allocate executable memory pages or not. */ +/* A non-zero argument instructs the collector to allocate memory with */ +/* the executable flag on. Must be called before the collector is */ +/* initialized. May have no effect on some platforms. The default */ +/* value is controlled by NO_EXECUTE_PERMISSION macro (if present then */ +/* the flag is off). Portable clients should have */ +/* GC_set_pages_executable(1) call (before GC_INIT) provided they are */ +/* going to execute code on any of the GC-allocated memory objects. */ +GC_API void GC_CALL GC_set_pages_executable(int); + +/* Returns non-zero value if the GC is set to the allocate-executable */ +/* mode. The mode could be changed by GC_set_pages_executable (before */ +/* GC_INIT) unless the former has no effect on the platform. Does not */ +/* use or need synchronization (i.e. acquiring the allocator lock). */ +GC_API int GC_CALL GC_get_pages_executable(void); + +/* The setter and getter of the minimum value returned by the internal */ +/* min_bytes_allocd(). The value should not be zero; the default value */ +/* is one. Not synchronized. */ +GC_API void GC_CALL GC_set_min_bytes_allocd(size_t); +GC_API size_t GC_CALL GC_get_min_bytes_allocd(void); + +/* Set/get the size in pages of units operated by GC_collect_a_little. */ +/* The value should not be zero. Not synchronized. */ +GC_API void GC_CALL GC_set_rate(int); +GC_API int GC_CALL GC_get_rate(void); + +/* Set/get the maximum number of prior attempts at the world-stop */ +/* marking. Not synchronized. */ +GC_API void GC_CALL GC_set_max_prior_attempts(int); +GC_API int GC_CALL GC_get_max_prior_attempts(void); + +/* Control whether to disable algorithm deciding if a collection should */ +/* be started when we allocated enough to amortize GC. Both the setter */ +/* and the getter acquire the GC lock (to avoid data races). */ +GC_API void GC_CALL GC_set_disable_automatic_collection(int); +GC_API int GC_CALL GC_get_disable_automatic_collection(void); + +/* Overrides the default handle-fork mode. Non-zero value means GC */ +/* should install proper pthread_atfork handlers. Has effect only if */ +/* called before GC_INIT. Clients should invoke GC_set_handle_fork */ +/* with non-zero argument if going to use fork with GC functions called */ +/* in the forked child. (Note that such client and atfork handlers */ +/* activities are not fully POSIX-compliant.) GC_set_handle_fork */ +/* instructs GC_init to setup GC fork handlers using pthread_atfork, */ +/* the latter might fail (or, even, absent on some targets) causing */ +/* abort at GC initialization. Issues with missing (or failed) */ +/* pthread_atfork() could be avoided by invocation */ +/* of GC_set_handle_fork(-1) at application start-up and surrounding */ +/* each fork() with the relevant GC_atfork_prepare/parent/child calls. */ +GC_API void GC_CALL GC_set_handle_fork(int); + +/* Routines to handle POSIX fork() manually (no-op if handled */ +/* automatically). GC_atfork_prepare should be called immediately */ +/* before fork(); GC_atfork_parent should be invoked just after fork in */ +/* the branch that corresponds to parent process (i.e., fork result is */ +/* non-zero); GC_atfork_child is to be called immediately in the child */ +/* branch (i.e., fork result is 0). Note that GC_atfork_child() call */ +/* should, of course, precede GC_start_mark_threads call (if any). */ +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); + +/* Initialize the collector. Portable clients should call GC_INIT() */ +/* from the main program instead. */ +GC_API void GC_CALL GC_init(void); + +/* Returns non-zero (TRUE) if and only if the collector is initialized */ +/* (or, at least, the initialization is in progress). */ +GC_API int GC_CALL GC_is_init_called(void); + +/* Perform the collector shutdown. (E.g. dispose critical sections on */ +/* Win32 target.) A duplicate invocation is a no-op. GC_INIT should */ +/* not be called after the shutdown. See also GC_win32_free_heap(). */ +GC_API void GC_CALL GC_deinit(void); + +/* General purpose allocation routines, with roughly malloc calling */ +/* conv. The atomic versions promise that no relevant pointers are */ +/* contained in the object. The non-atomic versions guarantee that the */ +/* new object is cleared. GC_malloc_uncollectable allocates */ +/* an object that is scanned for pointers to collectible */ +/* objects, but is not itself collectible. The object is scanned even */ +/* if it does not appear to be reachable. GC_malloc_uncollectable and */ +/* GC_free called on the resulting object implicitly update */ +/* GC_non_gc_bytes appropriately. */ +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_malloc(size_t /* size_in_bytes */); +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_malloc_atomic(size_t /* size_in_bytes */); +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 /* size_in_bytes */); +GC_API GC_ATTR_DEPRECATED void * GC_CALL GC_malloc_stubborn(size_t); + +/* GC_memalign() is not well tested. */ +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(2) void * GC_CALL + GC_memalign(size_t /* align */, size_t /* lb */); +GC_API int GC_CALL GC_posix_memalign(void ** /* memptr */, size_t /* align */, + size_t /* lb */) GC_ATTR_NONNULL(1); + +/* Explicitly deallocate an object. Dangerous if used incorrectly. */ +/* Requires a pointer to the base of an object. */ +/* An object should not be enabled for finalization (and it should not */ +/* contain registered disappearing links of any kind) when it is */ +/* explicitly deallocated. */ +/* GC_free(0) is a no-op, as required by ANSI C for free. */ +GC_API void GC_CALL GC_free(void *); + +/* The "stubborn" objects allocation is not supported anymore. Exists */ +/* only for the backward compatibility. */ +#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 *); + +/* Inform the collector that the object has been changed. */ +/* Only non-NULL pointer stores into the object are considered to be */ +/* changes. Matters only if the incremental collection is enabled in */ +/* the manual VDB mode (otherwise the function does nothing). */ +/* Should be followed typically by GC_reachable_here called for each */ +/* of the stored pointers. */ +GC_API void GC_CALL GC_end_stubborn_change(const void *) GC_ATTR_NONNULL(1); + +/* Return a pointer to the base (lowest address) of an object given */ +/* a pointer to a location within the object. */ +/* I.e., map an interior pointer to the corresponding base pointer. */ +/* Note that with debugging allocation, this returns a pointer to the */ +/* actual base of the object, i.e. the debug information, not to */ +/* the base of the user object. */ +/* Return 0 if displaced_pointer doesn't point to within a valid */ +/* object. */ +/* Note that a deallocated object in the garbage collected heap */ +/* may be considered valid, even if it has been deallocated with */ +/* GC_free. */ +GC_API void * GC_CALL GC_base(void * /* displaced_pointer */); + +/* Return non-zero (TRUE) if and only if the argument points to */ +/* somewhere in GC heap. Primary use is as a fast alternative to */ +/* GC_base to check whether the pointed object is allocated by GC */ +/* or not. It is assumed that the collector is already initialized. */ +GC_API int GC_CALL GC_is_heap_ptr(const void *); + +/* Given a pointer to the base of an object, return its size in bytes. */ +/* The returned size may be slightly larger than what was originally */ +/* requested. */ +GC_API size_t GC_CALL GC_size(const void * /* obj_addr */) GC_ATTR_NONNULL(1); + +/* For compatibility with C library. This is occasionally faster than */ +/* a malloc followed by a bcopy. But if you rely on that, either here */ +/* or with the standard C library, your code is broken. In my */ +/* opinion, it shouldn't have been invented, but now we're stuck. -HB */ +/* The resulting object has the same kind as the original. */ +/* It is an error to have changes enabled for the original object. */ +/* It does not change the content of the object from its beginning to */ +/* the minimum of old size and new_size_in_bytes; the content above in */ +/* case of object size growth is initialized to zero (not guaranteed */ +/* for atomic object type). The function follows ANSI conventions for */ +/* NULL old_object (i.e., equivalent to GC_malloc regardless of new */ +/* size). If new size is zero (and old_object is non-NULL) then the */ +/* call is equivalent to GC_free (and NULL is returned). If old_object */ +/* is non-NULL, it must have been returned by an earlier call to */ +/* GC_malloc* or GC_realloc. In case of the allocation failure, the */ +/* memory pointed by old_object is untouched (and not freed). */ +/* If the returned pointer is not the same as old_object and both of */ +/* them are non-NULL then old_object is freed. Returns either NULL (in */ +/* case of the allocation failure or zero new size) or pointer to the */ +/* allocated memory. */ +GC_API void * GC_CALL GC_realloc(void * /* old_object */, + size_t /* new_size_in_bytes */) + /* 'realloc' attr */ GC_ATTR_ALLOC_SIZE(2); + +/* Explicitly increase the heap size. */ +/* Returns 0 on failure, 1 on success. */ +GC_API int GC_CALL GC_expand_hp(size_t /* number_of_bytes */); + +/* Limit the heap size to n bytes. Useful when you're debugging, */ +/* especially on systems that don't handle running out of memory well. */ +/* n == 0 ==> unbounded. This is the default. This setter function is */ +/* unsynchronized (so it might require GC_call_with_alloc_lock to avoid */ +/* data races). */ +GC_API void GC_CALL GC_set_max_heap_size(GC_word /* n */); + +/* Inform the collector that a certain section of statically allocated */ +/* memory contains no pointers to garbage collected memory. Thus it */ +/* need not be scanned. This is sometimes important if the application */ +/* maps large read/write files into the address space, which could be */ +/* mistaken for dynamic library data segments on some systems. */ +/* Both section start and end are not needed to be pointer-aligned. */ +GC_API void GC_CALL GC_exclude_static_roots(void * /* low_address */, + void * /* high_address_plus_1 */); + +/* Clear the number of entries in the exclusion table. Wizards only. */ +GC_API void GC_CALL GC_clear_exclusion_table(void); + +/* Clear the set of root segments. Wizards only. */ +GC_API void GC_CALL GC_clear_roots(void); + +/* Add a root segment. Wizards only. */ +/* Both segment start and end are not needed to be pointer-aligned. */ +/* low_address must not be greater than high_address_plus_1. */ +GC_API void GC_CALL GC_add_roots(void * /* low_address */, + void * /* high_address_plus_1 */); + +/* Remove a root segment. Wizards only. */ +/* May be unimplemented on some platforms. */ +GC_API void GC_CALL GC_remove_roots(void * /* low_address */, + void * /* high_address_plus_1 */); + +/* Add a displacement to the set of those considered valid by the */ +/* collector. GC_register_displacement(n) means that if p was returned */ +/* by GC_malloc, then (char *)p + n will be considered to be a valid */ +/* pointer to p. N must be small and less than the size of p. */ +/* (All pointers to the interior of objects from the stack are */ +/* considered valid in any case. This applies to heap objects and */ +/* static data.) */ +/* Preferably, this should be called before any other GC procedures. */ +/* Calling it later adds to the probability of excess memory */ +/* retention. */ +/* This is a no-op if the collector has recognition of */ +/* arbitrary interior pointers enabled, which is now the default. */ +GC_API void GC_CALL GC_register_displacement(size_t /* n */); + +/* The following version should be used if any debugging allocation is */ +/* being done. */ +GC_API void GC_CALL GC_debug_register_displacement(size_t /* n */); + +/* Explicitly trigger a full, world-stop collection. */ +GC_API void GC_CALL GC_gcollect(void); + +/* Same as above but ignores the default stop_func setting and tries to */ +/* unmap as much memory as possible (regardless of the corresponding */ +/* switch setting). The recommended usage: on receiving a system */ +/* low-memory event; before retrying a system call failed because of */ +/* the system is running out of resources. */ +GC_API void GC_CALL GC_gcollect_and_unmap(void); + +/* Trigger a full world-stopped collection. Abort the collection if */ +/* and when stop_func returns a nonzero value. Stop_func will be */ +/* called frequently, and should be reasonably fast. (stop_func is */ +/* called with the allocation lock held and the world might be stopped; */ +/* it's not allowed for stop_func to manipulate pointers to the garbage */ +/* collected heap or call most of GC functions.) This works even */ +/* if virtual dirty bits, and hence incremental collection is not */ +/* available for this architecture. Collections can be aborted faster */ +/* than normal pause times for incremental collection. However, */ +/* aborted collections do no useful work; the next collection needs */ +/* to start from the beginning. stop_func must not be 0. */ +/* GC_try_to_collect() returns 0 if the collection was aborted (or the */ +/* collections are disabled), 1 if it succeeded. */ +typedef int (GC_CALLBACK * GC_stop_func)(void); +GC_API int GC_CALL GC_try_to_collect(GC_stop_func /* stop_func */) + GC_ATTR_NONNULL(1); + +/* Set and get the default stop_func. The default stop_func is used by */ +/* GC_gcollect() and by implicitly trigged collections (except for the */ +/* case when handling out of memory). Must not be 0. */ +/* Both the setter and getter acquire the GC lock to avoid data races. */ +GC_API void GC_CALL GC_set_stop_func(GC_stop_func /* stop_func */) + GC_ATTR_NONNULL(1); +GC_API GC_stop_func GC_CALL GC_get_stop_func(void); + +/* Return the number of bytes in the heap. Excludes collector private */ +/* data structures. Excludes the unmapped memory (returned to the OS). */ +/* Includes empty blocks and fragmentation loss. Includes some pages */ +/* that were allocated but never written. */ +/* This is an unsynchronized getter, so it should be called typically */ +/* with the GC lock held to avoid data races on multiprocessors (the */ +/* alternative is to use GC_get_heap_usage_safe or GC_get_prof_stats */ +/* API calls instead). */ +/* This getter remains lock-free (unsynchronized) for compatibility */ +/* reason since some existing clients call it from a GC callback */ +/* holding the allocator lock. (This API function and the following */ +/* four ones below were made thread-safe in GC v7.2alpha1 and */ +/* reverted back in v7.2alpha7 for the reason described.) */ +GC_API size_t GC_CALL GC_get_heap_size(void); + +/* Return a lower bound on the number of free bytes in the heap */ +/* (excluding the unmapped memory space). This is an unsynchronized */ +/* getter (see GC_get_heap_size comment regarding thread-safety). */ +GC_API size_t GC_CALL GC_get_free_bytes(void); + +/* Return the size (in bytes) of the unmapped memory (which is returned */ +/* to the OS but could be remapped back by the collector later unless */ +/* the OS runs out of system/virtual memory). This is an unsynchronized */ +/* getter (see GC_get_heap_size comment regarding thread-safety). */ +GC_API size_t GC_CALL GC_get_unmapped_bytes(void); + +/* Return the number of bytes allocated since the last collection. */ +/* This is an unsynchronized getter (see GC_get_heap_size comment */ +/* regarding thread-safety). */ +GC_API size_t GC_CALL GC_get_bytes_since_gc(void); + +/* Return the number of explicitly deallocated bytes of memory since */ +/* the recent collection. This is an unsynchronized getter. */ +GC_API size_t GC_CALL GC_get_expl_freed_bytes_since_gc(void); + +/* Return the total number of bytes allocated in this process. */ +/* Never decreases, except due to wrapping. This is an unsynchronized */ +/* getter (see GC_get_heap_size comment regarding thread-safety). */ +GC_API size_t GC_CALL GC_get_total_bytes(void); + +/* Return the total number of bytes obtained from OS. Includes the */ +/* unmapped memory. Never decreases. It is an unsynchronized getter. */ +GC_API size_t GC_CALL GC_get_obtained_from_os_bytes(void); + +/* Return the heap usage information. This is a thread-safe (atomic) */ +/* alternative for the five above getters. (This function acquires */ +/* the allocator lock thus preventing data racing and returning the */ +/* consistent result.) Passing NULL pointer is allowed for any */ +/* argument. Returned (filled in) values are of word type. */ +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 */); + +/* Structure used to query GC statistics (profiling information). */ +/* More fields could be added in the future. To preserve compatibility */ +/* new fields should be added only to the end, and no deprecated fields */ +/* should be removed from. */ +struct GC_prof_stats_s { + GC_word heapsize_full; + /* Heap size in bytes (including the area unmapped to OS). */ + /* Same as GC_get_heap_size() + GC_get_unmapped_bytes(). */ + GC_word free_bytes_full; + /* Total bytes contained in free and unmapped blocks. */ + /* Same as GC_get_free_bytes() + GC_get_unmapped_bytes(). */ + GC_word unmapped_bytes; + /* Amount of memory unmapped to OS. Same as the value */ + /* returned by GC_get_unmapped_bytes(). */ + GC_word bytes_allocd_since_gc; + /* Number of bytes allocated since the recent collection. */ + /* Same as returned by GC_get_bytes_since_gc(). */ + GC_word allocd_bytes_before_gc; + /* Number of bytes allocated before the recent garbage */ + /* collection. The value may wrap. Same as the result of */ + /* GC_get_total_bytes() - GC_get_bytes_since_gc(). */ + GC_word non_gc_bytes; + /* Number of bytes not considered candidates for garbage */ + /* collection. Same as returned by GC_get_non_gc_bytes(). */ + GC_word gc_no; + /* Garbage collection cycle number. The value may wrap */ + /* (and could be -1). Same as returned by GC_get_gc_no(). */ + GC_word markers_m1; + /* Number of marker threads (excluding the initiating one). */ + /* Same as returned by GC_get_parallel (or 0 if the */ + /* collector is single-threaded). */ + GC_word bytes_reclaimed_since_gc; + /* Approximate number of reclaimed bytes after recent GC. */ + GC_word reclaimed_bytes_before_gc; + /* Approximate number of bytes reclaimed before the recent */ + /* garbage collection. The value may wrap. */ + GC_word expl_freed_bytes_since_gc; + /* Number of bytes freed explicitly since the recent GC. */ + /* Same as returned by GC_get_expl_freed_bytes_since_gc(). */ + GC_word obtained_from_os_bytes; + /* Total amount of memory obtained from OS, in bytes. */ +}; + +/* Atomically get GC statistics (various global counters). Clients */ +/* should pass the size of the buffer (of GC_prof_stats_s type) to fill */ +/* in the values - this is for interoperability between different GC */ +/* versions, an old client could have fewer fields, and vice versa, */ +/* client could use newer gc.h (with more entries declared in the */ +/* structure) than that of the linked libgc binary; in the latter case, */ +/* unsupported (unknown) fields are filled in with -1. Return the size */ +/* (in bytes) of the filled in part of the structure (excluding all */ +/* unknown fields, if any). */ +GC_API size_t GC_CALL GC_get_prof_stats(struct GC_prof_stats_s *, + size_t /* stats_sz */); +#ifdef GC_THREADS + /* Same as above but unsynchronized (i.e., not holding the allocation */ + /* lock). Clients should call it using GC_call_with_alloc_lock to */ + /* avoid data races on multiprocessors. */ + GC_API size_t GC_CALL GC_get_prof_stats_unsafe(struct GC_prof_stats_s *, + size_t /* stats_sz */); +#endif + +/* Get the element value (converted to bytes) at a given index of */ +/* size_map table which provides requested-to-actual allocation size */ +/* mapping. Assumes the collector is initialized. Returns -1 if the */ +/* index is out of size_map table bounds. Does not use synchronization, */ +/* thus clients should call it using GC_call_with_alloc_lock typically */ +/* to avoid data races on multiprocessors. */ +GC_API size_t GC_CALL GC_get_size_map_at(int i); + +/* Count total memory use in bytes by all allocated blocks. Acquires */ +/* the lock. */ +GC_API size_t GC_CALL GC_get_memory_use(void); + +/* Disable garbage collection. Even GC_gcollect calls will be */ +/* ineffective. */ +GC_API void GC_CALL GC_disable(void); + +/* Return non-zero (TRUE) if and only if garbage collection is disabled */ +/* (i.e., GC_dont_gc value is non-zero). Does not acquire the lock. */ +GC_API int GC_CALL GC_is_disabled(void); + +/* Try to re-enable garbage collection. GC_disable() and GC_enable() */ +/* calls nest. Garbage collection is enabled if the number of calls to */ +/* both functions is equal. */ +GC_API void GC_CALL GC_enable(void); + +/* Select whether to use the manual VDB mode for the incremental */ +/* collection. Has no effect if called after enabling the incremental */ +/* collection. The default value is off unless the collector is */ +/* compiled with MANUAL_VDB defined. The manual VDB mode should be */ +/* used only if the client has the appropriate GC_END_STUBBORN_CHANGE */ +/* and GC_reachable_here (or, alternatively, GC_PTR_STORE_AND_DIRTY) */ +/* calls (to ensure proper write barriers). Both the setter and getter */ +/* are not synchronized, and are defined only if the library has been */ +/* compiled without SMALL_CONFIG. */ +GC_API void GC_CALL GC_set_manual_vdb_allowed(int); +GC_API int GC_CALL GC_get_manual_vdb_allowed(void); + +/* Enable incremental/generational collection. Not advisable unless */ +/* dirty bits are available or most heap objects are pointer-free */ +/* (atomic) or immutable. Don't use in leak finding mode. Ignored if */ +/* GC_dont_gc is non-zero. Only the generational piece of this is */ +/* functional if GC_time_limit is set to GC_TIME_UNLIMITED. Causes */ +/* thread-local variant of GC_gcj_malloc() to revert to locked */ +/* allocation. Must be called before any such GC_gcj_malloc() calls. */ +/* For best performance, should be called as early as possible. */ +/* On some platforms, calling it later may have adverse effects. */ +/* Safe to call before GC_INIT(). Includes a GC_init() call. */ +GC_API void GC_CALL GC_enable_incremental(void); + +/* Return non-zero (TRUE) if and only if the incremental mode is on. */ +/* Does not acquire the lock. */ +GC_API int GC_CALL GC_is_incremental_mode(void); + +#define GC_PROTECTS_POINTER_HEAP 1 /* May protect non-atomic objects. */ +#define GC_PROTECTS_PTRFREE_HEAP 2 +#define GC_PROTECTS_STATIC_DATA 4 /* Currently never. */ +#define GC_PROTECTS_STACK 8 /* Probably impractical. */ + +#define GC_PROTECTS_NONE 0 + +/* Does incremental mode write-protect pages? Returns zero or */ +/* more of the above GC_PROTECTS_*, or'ed together. */ +/* The collector is assumed to be initialized before this call. */ +/* The result is not affected by GC_set_manual_vdb_allowed(). */ +/* Call of GC_enable_incremental() may change the result to */ +/* GC_PROTECTS_NONE if some implementation is chosen at runtime */ +/* not needing to write-protect the pages. */ +GC_API int GC_CALL GC_incremental_protection_needs(void); + +/* Force start of incremental collection. Acquires the GC lock. */ +/* No-op unless GC incremental mode is on. */ +GC_API void GC_CALL GC_start_incremental_collection(void); + +/* Perform some garbage collection work, if appropriate. */ +/* Return 0 if there is no more work to be done (including the */ +/* case when garbage collection is not appropriate). */ +/* Typically performs an amount of work corresponding roughly */ +/* to marking from one page. May do more work if further */ +/* progress requires it, e.g. if incremental collection is */ +/* disabled. It is reasonable to call this in a wait loop */ +/* until it returns 0. */ +GC_API int GC_CALL GC_collect_a_little(void); + +/* Allocate an object of size lb bytes. The client guarantees that */ +/* as long as the object is live, it will be referenced by a pointer */ +/* that points to somewhere within the first 256 bytes of the object. */ +/* (This should normally be declared volatile to prevent the compiler */ +/* from invalidating this assertion.) This routine is only useful */ +/* if a large array is being allocated. It reduces the chance of */ +/* accidentally retaining such an array as a result of scanning an */ +/* integer that happens to be an address inside the array. (Actually, */ +/* it reduces the chance of the allocator not finding space for such */ +/* an array, since it will try hard to avoid introducing such a false */ +/* reference.) On a SunOS 4.X or MS Windows system this is recommended */ +/* for arrays likely to be larger than 100 KB or so. For other systems,*/ +/* or if the collector is not configured to recognize all interior */ +/* pointers, the threshold is normally much higher. */ +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_malloc_ignore_off_page(size_t /* lb */); +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_malloc_atomic_ignore_off_page(size_t /* lb */); + +#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 + +/* The following is only defined if the library has been suitably */ +/* compiled: */ +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_malloc_atomic_uncollectable(size_t /* size_in_bytes */); +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_debug_malloc_atomic_uncollectable(size_t, GC_EXTRA_PARAMS); + +/* Debugging (annotated) allocation. GC_gcollect will check */ +/* objects allocated in this way for overwrites, etc. */ +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_debug_malloc(size_t /* size_in_bytes */, GC_EXTRA_PARAMS); +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_debug_malloc_atomic(size_t /* size_in_bytes */, 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 /* size_in_bytes */, + GC_EXTRA_PARAMS); +GC_API GC_ATTR_DEPRECATED void * GC_CALL + GC_debug_malloc_stubborn(size_t /* size_in_bytes */, GC_EXTRA_PARAMS); +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_debug_malloc_ignore_off_page(size_t /* size_in_bytes */, + 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 /* size_in_bytes */, + GC_EXTRA_PARAMS); +GC_API void GC_CALL GC_debug_free(void *); +GC_API void * GC_CALL GC_debug_realloc(void * /* old_object */, + size_t /* new_size_in_bytes */, GC_EXTRA_PARAMS) + /* 'realloc' attr */ GC_ATTR_ALLOC_SIZE(2); +GC_API 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); + +/* Routines that allocate objects with debug information (like the */ +/* above), but just fill in dummy file and line number information. */ +/* Thus they can serve as drop-in malloc/realloc replacements. This */ +/* can be useful for two reasons: */ +/* 1) It allows the collector to be built with DBG_HDRS_ALL defined */ +/* even if some allocation calls come from 3rd party libraries */ +/* that can't be recompiled. */ +/* 2) On some platforms, the file and line information is redundant, */ +/* since it can be reconstructed from a stack trace. On such */ +/* platforms it may be more convenient not to recompile, e.g. for */ +/* leak detection. This can be accomplished by instructing the */ +/* linker to replace malloc/realloc with these. */ +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_debug_malloc_replacement(size_t /* size_in_bytes */); +GC_API /* 'realloc' attr */ GC_ATTR_ALLOC_SIZE(2) void * GC_CALL + GC_debug_realloc_replacement(void * /* object_addr */, + size_t /* size_in_bytes */); + +#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 /* !GC_DEBUG_REPLACEMENT && !GC_DEBUG */ + +#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((/* no const */ void *)(obj))) +# define GC_REGISTER_LONG_LINK(link, obj) \ + GC_register_long_link(link, GC_base((/* no const */ 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 /* !GC_DEBUG */ + +/* The following are included because they are often convenient, and */ +/* reduce the chance for a misspecified size argument. But calls may */ +/* expand to something syntactically incorrect if t is a complicated */ +/* type expression. Note that, unlike C++ new operator, these ones */ +/* may return NULL (if out of memory). */ +#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 + /* This might be unavailable on some targets (or not needed). */ + /* wchar_t should be defined in stddef.h */ + 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 /* GC_REQUIRE_WCSDUP */ + +/* Finalization. Some of these primitives are grossly unsafe. */ +/* The idea is to make them both cheap, and sufficient to build */ +/* a safer layer, closer to Modula-3, Java, or PCedar finalization. */ +/* The interface represents my conclusions from a long discussion */ +/* with Alan Demers, Dan Greene, Carl Hauser, Barry Hayes, */ +/* Christian Jacobi, and Russ Atkinson. It's not perfect, and */ +/* probably nobody else agrees with it. Hans-J. Boehm 3/13/92 */ +typedef void (GC_CALLBACK * GC_finalization_proc)(void * /* obj */, + void * /* client_data */); + +GC_API void GC_CALL GC_register_finalizer(void * /* obj */, + GC_finalization_proc /* fn */, void * /* cd */, + GC_finalization_proc * /* ofn */, void ** /* ocd */) + GC_ATTR_NONNULL(1); +GC_API void GC_CALL GC_debug_register_finalizer(void * /* obj */, + GC_finalization_proc /* fn */, void * /* cd */, + GC_finalization_proc * /* ofn */, void ** /* ocd */) + GC_ATTR_NONNULL(1); + /* When obj is no longer accessible, invoke */ + /* (*fn)(obj, cd). If a and b are inaccessible, and */ + /* a points to b (after disappearing links have been */ + /* made to disappear), then only a will be */ + /* finalized. (If this does not create any new */ + /* pointers to b, then b will be finalized after the */ + /* next collection.) Any finalizable object that */ + /* is reachable from itself by following one or more */ + /* pointers will not be finalized (or collected). */ + /* Thus cycles involving finalizable objects should */ + /* be avoided, or broken by disappearing links. */ + /* All but the last finalizer registered for an object */ + /* is ignored. */ + /* No-op in the leak-finding mode. */ + /* Finalization may be removed by passing 0 as fn. */ + /* Finalizers are implicitly unregistered when they are */ + /* enqueued for finalization (i.e. become ready to be */ + /* finalized). */ + /* The old finalizer and client data are stored in */ + /* *ofn and *ocd. (ofn and/or ocd may be NULL. */ + /* The allocation lock is held while *ofn and *ocd are */ + /* updated. In case of error (no memory to register */ + /* new finalizer), *ofn and *ocd remain unchanged.) */ + /* Fn is never invoked on an accessible object, */ + /* provided hidden pointers are converted to real */ + /* pointers only if the allocation lock is held, and */ + /* such conversions are not performed by finalization */ + /* routines. */ + /* If GC_register_finalizer is aborted as a result of */ + /* a signal, the object may be left with no */ + /* finalization, even if neither the old nor new */ + /* finalizer were NULL. */ + /* Obj should be the starting address of an object */ + /* allocated by GC_malloc or friends. Obj may also be */ + /* NULL or point to something outside GC heap (in this */ + /* case, fn is ignored, *ofn and *ocd are set to NULL). */ + /* Note that any garbage collectible object referenced */ + /* by cd will be considered accessible until the */ + /* finalizer is invoked. */ + +/* Another versions of the above follow. It ignores */ +/* self-cycles, i.e. pointers from a finalizable object to */ +/* itself. There is a stylistic argument that this is wrong, */ +/* but it's unavoidable for C++, since the compiler may */ +/* silently introduce these. It's also benign in that specific */ +/* case. And it helps if finalizable objects are split to */ +/* avoid cycles. */ +/* Note that cd will still be viewed as accessible, even if it */ +/* refers to the object itself. */ +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_ATTR_NONNULL(1); +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_ATTR_NONNULL(1); + +/* Another version of the above. It ignores all cycles. */ +/* It should probably only be used by Java implementations. */ +/* Note that cd will still be viewed as accessible, even if it */ +/* refers to the object itself. */ +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_ATTR_NONNULL(1); +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_ATTR_NONNULL(1); + +/* This is a special finalizer that is useful when an object's */ +/* finalizer must be run when the object is known to be no */ +/* longer reachable, not even from other finalizable objects. */ +/* It behaves like "normal" finalization, except that the */ +/* finalizer is not run while the object is reachable from */ +/* other objects specifying unordered finalization. */ +/* Effectively it allows an object referenced, possibly */ +/* indirectly, from an unordered finalizable object to override */ +/* the unordered finalization request. */ +/* This can be used in combination with finalizer_no_order so */ +/* as to release resources that must not be released while an */ +/* object can still be brought back to life by other */ +/* finalizers. */ +/* Only works if GC_java_finalization is set. Probably only */ +/* of interest when implementing a language that requires */ +/* unordered finalization (e.g. Java, C#). */ +GC_API void GC_CALL GC_register_finalizer_unreachable(void * /* obj */, + GC_finalization_proc /* fn */, void * /* cd */, + GC_finalization_proc * /* ofn */, void ** /* ocd */) + GC_ATTR_NONNULL(1); +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_ATTR_NONNULL(1); + +#define GC_NO_MEMORY 2 /* Failure due to lack of memory. */ + +/* The following routine may be used to break cycles between */ +/* finalizable objects, thus causing cyclic finalizable */ +/* objects to be finalized in the correct order. Standard */ +/* use involves calling GC_register_disappearing_link(&p), */ +/* where p is a pointer that is not followed by finalization */ +/* code, and should not be considered in determining */ +/* finalization order. */ +GC_API int GC_CALL GC_register_disappearing_link(void ** /* link */) + GC_ATTR_NONNULL(1); + /* Link should point to a field of a heap allocated */ + /* object obj. *link will be cleared when obj is */ + /* found to be inaccessible. This happens BEFORE any */ + /* finalization code is invoked, and BEFORE any */ + /* decisions about finalization order are made. */ + /* This is useful in telling the finalizer that */ + /* some pointers are not essential for proper */ + /* finalization. This may avoid finalization cycles. */ + /* Note that obj may be resurrected by another */ + /* finalizer, and thus the clearing of *link may */ + /* be visible to non-finalization code. */ + /* There's an argument that an arbitrary action should */ + /* be allowed here, instead of just clearing a pointer. */ + /* But this causes problems if that action alters, or */ + /* examines connectivity. Returns GC_DUPLICATE if link */ + /* was already registered, GC_SUCCESS if registration */ + /* succeeded, GC_NO_MEMORY if it failed for lack of */ + /* memory, and GC_oom_fn did not handle the problem. */ + /* Only exists for backward compatibility. See below: */ + +GC_API int GC_CALL GC_general_register_disappearing_link(void ** /* link */, + const void * /* obj */) + GC_ATTR_NONNULL(1) GC_ATTR_NONNULL(2); + /* A slight generalization of the above. *link is */ + /* cleared when obj first becomes inaccessible. This */ + /* can be used to implement weak pointers easily and */ + /* safely. Typically link will point to a location */ + /* holding a disguised pointer to obj. (A pointer */ + /* inside an "atomic" object is effectively disguised.) */ + /* In this way, weak pointers are broken before any */ + /* object reachable from them gets finalized. */ + /* Each link may be registered only with one obj value, */ + /* i.e. all objects but the last one (link registered */ + /* with) are ignored. This was added after a long */ + /* email discussion with John Ellis. */ + /* link must be non-NULL (and be properly aligned). */ + /* obj must be a pointer to the first word of an object */ + /* allocated by GC_malloc or friends. A link */ + /* disappears when it is unregistered manually, or when */ + /* (*link) is cleared, or when the object containing */ + /* this link is garbage collected. It is unsafe to */ + /* explicitly deallocate the object containing link. */ + /* Explicit deallocation of obj may or may not cause */ + /* link to eventually be cleared. */ + /* No-op in the leak-finding mode. */ + /* This function can be used to implement certain types */ + /* of weak pointers. Note, however, this generally */ + /* requires that the allocation lock is held (see */ + /* GC_call_with_alloc_lock() below) when the disguised */ + /* pointer is accessed. Otherwise a strong pointer */ + /* could be recreated between the time the collector */ + /* decides to reclaim the object and the link is */ + /* cleared. Returns GC_SUCCESS if registration */ + /* succeeded (a new link is registered), GC_DUPLICATE */ + /* if link was already registered (with some object), */ + /* GC_NO_MEMORY if registration failed for lack of */ + /* memory (and GC_oom_fn did not handle the problem), */ + /* GC_UNIMPLEMENTED if GC_find_leak is true. */ + +GC_API int GC_CALL GC_move_disappearing_link(void ** /* link */, + void ** /* new_link */) + GC_ATTR_NONNULL(2); + /* Moves a link previously registered via */ + /* GC_general_register_disappearing_link (or */ + /* GC_register_disappearing_link). Does not change the */ + /* target object of the weak reference. Does not */ + /* change (*new_link) content. May be called with */ + /* new_link equal to link (to check whether link has */ + /* been registered). Returns GC_SUCCESS on success, */ + /* GC_DUPLICATE if there is already another */ + /* disappearing link at the new location (never */ + /* returned if new_link is equal to link), GC_NOT_FOUND */ + /* if no link is registered at the original location. */ + +GC_API int GC_CALL GC_unregister_disappearing_link(void ** /* link */); + /* Undoes a registration by either of the above two */ + /* routines. Returns 0 if link was not actually */ + /* registered (otherwise returns 1). */ + +GC_API int GC_CALL GC_register_long_link(void ** /* link */, + const void * /* obj */) + GC_ATTR_NONNULL(1) GC_ATTR_NONNULL(2); + /* Similar to GC_general_register_disappearing_link but */ + /* *link only gets cleared when obj becomes truly */ + /* inaccessible. An object becomes truly inaccessible */ + /* when it can no longer be resurrected from its */ + /* finalizer (e.g. by assigning itself to a pointer */ + /* traceable from root). This can be used to implement */ + /* long weak pointers easily and safely. */ + +GC_API int GC_CALL GC_move_long_link(void ** /* link */, + void ** /* new_link */) + GC_ATTR_NONNULL(2); + /* Similar to GC_move_disappearing_link but for a link */ + /* previously registered via GC_register_long_link. */ + +GC_API int GC_CALL GC_unregister_long_link(void ** /* link */); + /* Similar to GC_unregister_disappearing_link but for a */ + /* registration by either of the above two routines. */ + +/* Support of toggle-ref style of external memory management */ +/* without hooking up to the host retain/release machinery. */ +/* The idea of toggle-ref is that an external reference to */ +/* an object is kept and it can be either a strong or weak */ +/* reference; a weak reference is used when the external peer */ +/* has no interest in the object, and a strong otherwise. */ +typedef enum { + GC_TOGGLE_REF_DROP, + GC_TOGGLE_REF_STRONG, + GC_TOGGLE_REF_WEAK +} GC_ToggleRefStatus; + +/* The callback is to decide (return) the new state of a given */ +/* object. Invoked by the collector for all objects registered */ +/* for toggle-ref processing. Invoked with the allocation lock */ +/* held (but the "world" is running). */ +typedef GC_ToggleRefStatus (GC_CALLBACK *GC_toggleref_func)(void * /* obj */); + +/* Set (register) a callback that decides the state of a given */ +/* object (by, probably, inspecting its native state). */ +/* The argument may be 0 (means no callback). Both the setter */ +/* and the getter acquire the allocation lock (to avoid data */ +/* races). */ +GC_API void GC_CALL GC_set_toggleref_func(GC_toggleref_func); +GC_API GC_toggleref_func GC_CALL GC_get_toggleref_func(void); + +/* Register a given object for toggle-ref processing. It will */ +/* be stored internally and the toggle-ref callback will be */ +/* invoked on the object until the callback returns */ +/* GC_TOGGLE_REF_DROP or the object is collected. If is_strong */ +/* is true then the object is registered with a strong ref, */ +/* a weak one otherwise. Returns GC_SUCCESS if registration */ +/* succeeded (or no callback registered yet), GC_NO_MEMORY if */ +/* it failed for lack of memory. */ +GC_API int GC_CALL GC_toggleref_add(void * /* obj */, int /* is_strong */) + GC_ATTR_NONNULL(1); + +/* Finalizer callback support. Invoked by the collector (with */ +/* the allocation lock held) for each unreachable object */ +/* enqueued for finalization. */ +typedef void (GC_CALLBACK * GC_await_finalize_proc)(void * /* obj */); +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); + /* Zero means no callback. The setter */ + /* and getter acquire the lock too. */ + +/* Returns !=0 if GC_invoke_finalizers has something to do. */ +/* Does not use any synchronization. */ +GC_API int GC_CALL GC_should_invoke_finalizers(void); + +GC_API int GC_CALL GC_invoke_finalizers(void); + /* Run finalizers for all objects that are ready to */ + /* be finalized. Return the number of finalizers */ + /* that were run. Normally this is also called */ + /* implicitly during some allocations. If */ + /* GC_finalize_on_demand is nonzero, it must be called */ + /* explicitly. */ + +/* Explicitly tell the collector that an object is reachable */ +/* at a particular program point. This prevents the argument */ +/* pointer from being optimized away, even it is otherwise no */ +/* longer needed. It should have no visible effect in the */ +/* absence of finalizers or disappearing links. But it may be */ +/* needed to prevent finalizers from running while the */ +/* associated external resource is still in use. */ +/* The function is sometimes called keep_alive in other */ +/* settings. */ +#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)) + /* The expression matches the one of COVERT_DATAFLOW(). */ +# else +# define GC_reachable_here(ptr) GC_noop1((GC_word)(ptr)) +# endif +#endif + +/* GC_set_warn_proc can be used to redirect or filter warning messages. */ +/* p may not be a NULL pointer. msg is printf format string (arg must */ +/* match the format). Both the setter and the getter acquire the GC */ +/* lock (to avoid data races). In GC v7.1 (and before), the setter */ +/* returned the old warn_proc value. */ +typedef void (GC_CALLBACK * GC_warn_proc)(char * /* msg */, + GC_word /* arg */); +GC_API void GC_CALL GC_set_warn_proc(GC_warn_proc /* p */) GC_ATTR_NONNULL(1); +/* GC_get_warn_proc returns the current warn_proc. */ +GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void); + +/* GC_ignore_warn_proc may be used as an argument for GC_set_warn_proc */ +/* to suppress all warnings (unless statistics printing is turned on). */ +GC_API void GC_CALLBACK GC_ignore_warn_proc(char *, GC_word); + +/* Change file descriptor of GC log. Unavailable on some targets. */ +GC_API void GC_CALL GC_set_log_fd(int); + +/* abort_func is invoked on GC fatal aborts (just before OS-dependent */ +/* abort or exit(1) is called). Must be non-NULL. The default one */ +/* outputs msg to stderr provided msg is non-NULL. msg is NULL if */ +/* invoked before exit(1) otherwise msg is non-NULL (i.e., if invoked */ +/* before abort). Both the setter and getter acquire the GC lock. */ +/* Both the setter and getter are defined only if the library has been */ +/* compiled without SMALL_CONFIG. */ +typedef void (GC_CALLBACK * GC_abort_func)(const char * /* msg */); +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); + +/* A portable way to abort the application because of not enough memory.*/ +GC_API void GC_CALL GC_abort_on_oom(void); + +/* The following is intended to be used by a higher level */ +/* (e.g. Java-like) finalization facility. It is expected */ +/* that finalization code will arrange for hidden pointers to */ +/* disappear. Otherwise objects can be accessed after they */ +/* have been collected. */ +/* Should not be used in the leak-finding mode. */ +/* Note that putting pointers in atomic objects or in */ +/* non-pointer slots of "typed" objects is equivalent to */ +/* disguising them in this way, and may have other advantages. */ +typedef GC_word GC_hidden_pointer; +#define GC_HIDE_POINTER(p) (~(GC_hidden_pointer)(p)) +/* Converting a hidden pointer to a real pointer requires verifying */ +/* that the object still exists. This involves acquiring the */ +/* allocator lock to avoid a race with the collector. */ +#define GC_REVEAL_POINTER(p) ((void *)GC_HIDE_POINTER(p)) + +#if defined(I_HIDE_POINTERS) || defined(GC_I_HIDE_POINTERS) + /* This exists only for compatibility (the GC-prefixed symbols are */ + /* preferred for new code). */ +# define HIDE_POINTER(p) GC_HIDE_POINTER(p) +# define REVEAL_POINTER(p) GC_REVEAL_POINTER(p) +#endif + +/* The routines to acquire/release the allocator lock. */ +/* The lock is not reentrant. GC_alloc_unlock() should not be called */ +/* unless the lock is acquired by the current thread. */ +#ifdef GC_THREADS + GC_API void GC_CALL GC_alloc_lock(void); + GC_API void GC_CALL GC_alloc_unlock(void); +#else + /* No need for real locking if the client is single-threaded. */ +# define GC_alloc_lock() (void)0 +# define GC_alloc_unlock() (void)0 +#endif /* !GC_THREADS */ + +typedef void * (GC_CALLBACK * GC_fn_type)(void * /* client_data */); +GC_API void * GC_CALL GC_call_with_alloc_lock(GC_fn_type /* fn */, + void * /* client_data */) GC_ATTR_NONNULL(1); + +/* These routines are intended to explicitly notify the collector */ +/* of new threads. Often this is unnecessary because thread creation */ +/* is implicitly intercepted by the collector, using header-file */ +/* defines, or linker-based interception. In the long run the intent */ +/* is to always make redundant registration safe. In the short run, */ +/* this is being implemented a platform at a time. */ +/* The interface is complicated by the fact that we probably will not */ +/* ever be able to automatically determine the stack bottom for thread */ +/* stacks on all platforms. */ + +/* Structure representing the bottom (cold end) of a thread stack. */ +/* On most platforms this contains just a single address. */ +struct GC_stack_base { + void * mem_base; /* the bottom of the general-purpose stack */ +# if defined(__ia64) || defined(__ia64__) || defined(_M_IA64) + void * reg_base; /* the bottom of the register stack */ +# endif +}; + +typedef void * (GC_CALLBACK * GC_stack_base_func)( + struct GC_stack_base * /* sb */, void * /* arg */); + +/* Call a function with a stack base structure corresponding to */ +/* somewhere in the GC_call_with_stack_base frame. This often can */ +/* be used to provide a sufficiently accurate stack bottom. And we */ +/* implement it everywhere. */ +GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */, + void * /* arg */) GC_ATTR_NONNULL(1); + +#define GC_SUCCESS 0 +#define GC_DUPLICATE 1 /* Was already registered. */ +#define GC_NO_THREADS 2 /* No thread support in GC. */ + /* GC_NO_THREADS is not returned by any GC function anymore. */ +#define GC_UNIMPLEMENTED 3 /* Not yet implemented on this platform. */ +#define GC_NOT_FOUND 4 /* Requested link not found (returned */ + /* by GC_move_disappearing_link). */ + +#if defined(GC_DARWIN_THREADS) || defined(GC_WIN32_THREADS) + /* Use implicit thread registration and processing (via Win32 DllMain */ + /* or Darwin task_threads). Deprecated. Must be called before */ + /* GC_INIT() and other GC routines. Should be avoided if */ + /* GC_pthread_create, GC_beginthreadex (or GC_CreateThread) could be */ + /* called instead. Disables parallelized GC on Win32. */ + GC_API void GC_CALL GC_use_threads_discovery(void); +#endif + +#ifdef GC_THREADS + /* Suggest the GC to use the specific signal to suspend threads. */ + /* Has no effect after GC_init and on non-POSIX systems. */ + GC_API void GC_CALL GC_set_suspend_signal(int); + + /* Suggest the GC to use the specific signal to resume threads. */ + /* Has no effect after GC_init and on non-POSIX systems. */ + GC_API void GC_CALL GC_set_thr_restart_signal(int); + + /* Return the signal number (constant after initialization) used by */ + /* the GC to suspend threads on POSIX systems. Return -1 otherwise. */ + GC_API int GC_CALL GC_get_suspend_signal(void); + + /* Return the signal number (constant after initialization) used by */ + /* the garbage collector to restart (resume) threads on POSIX */ + /* systems. Return -1 otherwise. */ + GC_API int GC_CALL GC_get_thr_restart_signal(void); + + /* Restart marker threads after POSIX fork in child. Meaningless in */ + /* other situations. Should not be called if fork followed by exec. */ + GC_API void GC_CALL GC_start_mark_threads(void); + + /* Explicitly enable GC_register_my_thread() invocation. */ + /* Done implicitly if a GC thread-creation function is called (or */ + /* implicit thread registration is activated, or the collector is */ + /* compiled with GC_ALWAYS_MULTITHREADED defined). Otherwise, it */ + /* must be called from the main (or any previously registered) thread */ + /* between the collector initialization and the first explicit */ + /* registering of a thread (it should be called as late as possible). */ + GC_API void GC_CALL GC_allow_register_threads(void); + + /* Register the current thread, with the indicated stack bottom, as */ + /* a new thread whose stack(s) should be traced by the GC. If it */ + /* is not implicitly called by the GC, this must be called before a */ + /* thread can allocate garbage collected memory, or assign pointers */ + /* to the garbage collected heap. Once registered, a thread will be */ + /* stopped during garbage collections. */ + /* This call must be previously enabled (see above). */ + /* This should never be called from the main thread, where it is */ + /* always done implicitly. This is normally done implicitly if GC_ */ + /* functions are called to create the thread, e.g. by including gc.h */ + /* (which redefines some system functions) before calling the system */ + /* thread creation function. Nonetheless, thread cleanup routines */ + /* (e.g., pthread key destructor) typically require manual thread */ + /* registering (and unregistering) if pointers to GC-allocated */ + /* objects are manipulated inside. */ + /* It is also always done implicitly on some platforms if */ + /* GC_use_threads_discovery() is called at start-up. Except for the */ + /* latter case, the explicit call is normally required for threads */ + /* created by third-party libraries. */ + /* A manually registered thread requires manual unregistering. */ + /* Returns GC_SUCCESS on success, GC_DUPLICATE if already registered. */ + GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *) + GC_ATTR_NONNULL(1); + + /* Return non-zero (TRUE) if and only if the calling thread is */ + /* registered with the garbage collector. */ + GC_API int GC_CALL GC_thread_is_registered(void); + + /* Notify the collector about the stack and the alt-stack of the */ + /* current thread. stack_start/size is used to determine the stack */ + /* boundaries when a thread is suspended while it is on an alt-stack. */ + GC_API void GC_CALL GC_register_altstack(void * /* stack_start */, + GC_word /* stack_size */, + void * /* altstack_base */, + GC_word /* altstack_size */); + + /* Unregister the current thread. Only an explicitly registered */ + /* thread (i.e. for which GC_register_my_thread() returns GC_SUCCESS) */ + /* is allowed (and required) to call this function. (As a special */ + /* exception, it is also allowed to once unregister the main thread.) */ + /* The thread may no longer allocate garbage collected memory or */ + /* manipulate pointers to the garbage collected heap after making */ + /* this call. Specifically, if it wants to return or otherwise */ + /* communicate a pointer to the garbage-collected heap to another */ + /* thread, it must do this before calling GC_unregister_my_thread, */ + /* most probably by saving it in a global data structure. Must not */ + /* be called inside a GC callback function (except for */ + /* GC_call_with_stack_base() one). */ + GC_API int GC_CALL GC_unregister_my_thread(void); + + /* Stop/start the world explicitly. Not recommended for general use. */ + GC_API void GC_CALL GC_stop_world_external(void); + GC_API void GC_CALL GC_start_world_external(void); +#endif /* GC_THREADS */ + +/* Wrapper for functions that are likely to block (or, at least, do not */ +/* allocate garbage collected memory and/or manipulate pointers to the */ +/* garbage collected heap) for an appreciable length of time. While fn */ +/* is running, the collector is said to be in the "inactive" state for */ +/* the current thread (this means that the thread is not suspended and */ +/* the thread's stack frames "belonging" to the functions in the */ +/* "inactive" state are not scanned during garbage collections). It is */ +/* assumed that the collector is already initialized and the current */ +/* thread is registered. It is allowed for fn to call */ +/* GC_call_with_gc_active() (even recursively), thus temporarily */ +/* toggling the collector's state back to "active". The latter */ +/* technique might be used to make stack scanning more precise (i.e. */ +/* scan only stack frames of functions that allocate garbage collected */ +/* memory and/or manipulate pointers to the garbage collected heap). */ +GC_API void * GC_CALL GC_do_blocking(GC_fn_type /* fn */, + void * /* client_data */) GC_ATTR_NONNULL(1); + +/* Call a function switching to the "active" state of the collector for */ +/* the current thread (i.e. the user function is allowed to call any */ +/* GC function and/or manipulate pointers to the garbage collected */ +/* heap). GC_call_with_gc_active() has the functionality opposite to */ +/* GC_do_blocking() one. It is assumed that the collector is already */ +/* initialized and the current thread is registered. fn may toggle */ +/* the collector thread's state temporarily to "inactive" one by using */ +/* GC_do_blocking. GC_call_with_gc_active() often can be used to */ +/* provide a sufficiently accurate stack bottom. */ +GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type /* fn */, + void * /* client_data */) GC_ATTR_NONNULL(1); + +/* Attempt to fill in the GC_stack_base structure with the stack bottom */ +/* for this thread. This appears to be required to implement anything */ +/* like the JNI AttachCurrentThread in an environment in which new */ +/* threads are not automatically registered with the collector. */ +/* It is also unfortunately hard to implement well on many platforms. */ +/* Returns GC_SUCCESS or GC_UNIMPLEMENTED. This function acquires the */ +/* GC lock on some platforms. */ +GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *) + GC_ATTR_NONNULL(1); + +/* Fill in the GC_stack_base structure with the cold end (bottom) of */ +/* the stack of the current thread (or coroutine). */ +/* Unlike GC_get_stack_base, it retrieves the value stored in the */ +/* collector (which is initially set by the collector upon the thread */ +/* is started or registered manually but it could be later updated by */ +/* client using GC_set_stackbottom). Returns the GC-internal non-NULL */ +/* handle of the thread which could be passed to GC_set_stackbottom */ +/* later. It is assumed that the collector is already initialized and */ +/* the thread is registered. Acquires the GC lock to avoid data races. */ +GC_API void * GC_CALL GC_get_my_stackbottom(struct GC_stack_base *) + GC_ATTR_NONNULL(1); + +/* Set the cool end of the user (coroutine) stack of the specified */ +/* thread. The GC thread handle is either the one returned by */ +/* GC_get_my_stackbottom or NULL (the latter designates the current */ +/* thread). The caller should hold the GC lock (e.g. using */ +/* GC_call_with_alloc_lock). Also, the function could be used for */ +/* setting GC_stackbottom value (the bottom of the primordial thread) */ +/* before the collector is initialized (the GC lock is not needed to be */ +/* acquired in this case). */ +GC_API void GC_CALL GC_set_stackbottom(void * /* gc_thread_handle */, + const struct GC_stack_base *) + GC_ATTR_NONNULL(2); + +/* The following routines are primarily intended for use with a */ +/* preprocessor which inserts calls to check C pointer arithmetic. */ +/* They indicate failure by invoking the corresponding _print_proc. */ + +/* Check that p and q point to the same object. */ +/* Fail conspicuously if they don't. */ +/* Returns the first argument. */ +/* Succeeds if neither p nor q points to the heap. */ +/* May succeed if both p and q point to between heap objects. */ +GC_API void * GC_CALL GC_same_obj(void * /* p */, void * /* q */); + +/* Checked pointer pre- and post- increment operations. Note that */ +/* the second argument is in units of bytes, not multiples of the */ +/* object size. This should either be invoked from a macro, or the */ +/* call should be automatically generated. */ +GC_API void * GC_CALL GC_pre_incr(void **, ptrdiff_t /* how_much */) + GC_ATTR_NONNULL(1); +GC_API void * GC_CALL GC_post_incr(void **, ptrdiff_t /* how_much */) + GC_ATTR_NONNULL(1); + +/* Check that p is visible */ +/* to the collector as a possibly pointer containing location. */ +/* If it isn't fail conspicuously. */ +/* Returns the argument in all cases. May erroneously succeed */ +/* in hard cases. (This is intended for debugging use with */ +/* untyped allocations. The idea is that it should be possible, though */ +/* slow, to add such a call to all indirect pointer stores.) */ +/* Currently useless for multi-threaded worlds. */ +GC_API void * GC_CALL GC_is_visible(void * /* p */); + +/* Check that if p is a pointer to a heap page, then it points to */ +/* a valid displacement within a heap object. */ +/* Fail conspicuously if this property does not hold. */ +/* Uninteresting with GC_all_interior_pointers. */ +/* Always returns its argument. */ +GC_API void * GC_CALL GC_is_valid_displacement(void * /* p */); + +/* Explicitly dump the GC state. This is most often called from the */ +/* debugger, or by setting the GC_DUMP_REGULARLY environment variable, */ +/* but it may be useful to call it from client code during debugging. */ +/* The current collection number is printed in the header of the dump. */ +/* Acquires the GC lock to avoid data races. */ +/* Defined only if the library has been compiled without NO_DEBUGGING. */ +GC_API void GC_CALL GC_dump(void); + +/* The same as GC_dump but allows to specify the name of dump and does */ +/* not acquire the lock. If name is non-NULL, it is printed to help */ +/* identifying individual dumps. Otherwise the current collection */ +/* number is used as the name. */ +/* Defined only if the library has been compiled without NO_DEBUGGING. */ +GC_API void GC_CALL GC_dump_named(const char * /* name */); + +/* Dump information about each block of every GC memory section. */ +/* Defined only if the library has been compiled without NO_DEBUGGING. */ +GC_API void GC_CALL GC_dump_regions(void); + +/* Dump information about every registered disappearing link and */ +/* finalizable object. */ +/* Defined only if the library has been compiled without NO_DEBUGGING. */ +GC_API void GC_CALL GC_dump_finalization(void); + +/* Safer, but slow, pointer addition. Probably useful mainly with */ +/* a preprocessor. Useful only for heap pointers. */ +/* Only the macros without trailing digits are meant to be used */ +/* by clients. These are designed to model the available C pointer */ +/* arithmetic expressions. */ +/* Even then, these are probably more useful as */ +/* documentation than as part of the API. */ +/* Note that GC_PTR_ADD evaluates the first argument more than once. */ +#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 /* !GC_DEBUG || !__GNUC__ */ + /* We can't do this right without typeof, which ANSI decided was not */ + /* sufficiently useful. Without it we resort to the non-debug version. */ + /* TODO: This should eventually support C++0x decltype. */ +# 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 /* !GC_DEBUG || !__GNUC__ */ + +/* Safer assignment of a pointer to a non-stack location. */ +#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_PTR_STORE_AND_DIRTY(p,q) is equivalent to GC_PTR_STORE(p,q) */ +/* followed by GC_END_STUBBORN_CHANGE(p) and GC_reachable_here(q) */ +/* (assuming p and q do not have side effects). */ +GC_API void GC_CALL GC_ptr_store_and_dirty(void * /* p */, + const void * /* q */); +GC_API void GC_CALL GC_debug_ptr_store_and_dirty(void * /* p */, + const void * /* q */); + +/* Functions called to report pointer checking errors */ +GC_API void (GC_CALLBACK * GC_same_obj_print_proc)(void * /* p */, + void * /* q */); +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 + /* For pthread support, we generally need to intercept a number of */ + /* thread library calls. We do that here by macro defining them. */ +# ifdef __cplusplus + } /* extern "C" */ +# endif +# include "gc_pthread_redirects.h" +# ifdef __cplusplus + extern "C" { +# endif +#endif + +/* This returns a list of objects, linked through their first word. */ +/* Its use can greatly reduce lock contention problems, since the */ +/* allocation lock can be acquired and released many fewer times. */ +GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_many(size_t /* lb */); +#define GC_NEXT(p) (*(void * *)(p)) /* Retrieve the next element */ + /* in returned list. */ + +/* A filter function to control the scanning of dynamic libraries. */ +/* If implemented, called by GC before registering a dynamic library */ +/* (discovered by GC) section as a static data root (called only as */ +/* a last reason not to register). The filename of the library, the */ +/* address and the length of the memory region (section) are passed. */ +/* This routine should return nonzero if that region should be scanned. */ +/* Always called with the allocation lock held. Depending on the */ +/* platform, might be called with the "world" stopped. */ +typedef int (GC_CALLBACK * GC_has_static_roots_func)( + const char * /* dlpi_name */, + void * /* section_start */, + size_t /* section_size */); + +/* Register a new callback (a user-supplied filter) to control the */ +/* scanning of dynamic libraries. Replaces any previously registered */ +/* callback. May be 0 (means no filtering). May be unused on some */ +/* platforms (if the filtering is unimplemented or inappropriate). */ +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) + /* windows.h is included before gc.h */ +# define GC_WINDOWS_H_INCLUDED +#endif + +#if defined(GC_WIN32_THREADS) \ + && (!defined(GC_PTHREADS) || defined(GC_BUILD) \ + || defined(GC_WINDOWS_H_INCLUDED)) + /* Note: for Cygwin and pthreads-win32, this is skipped */ + /* unless windows.h is included before gc.h. */ + +# if (!defined(GC_NO_THREAD_DECLS) || defined(GC_BUILD)) \ + && !defined(GC_DONT_INCL_WINDOWS_H) + +# ifdef __cplusplus + } /* Including windows.h in an extern "C" context no longer works. */ +# endif + +# if !defined(_WIN32_WCE) && !defined(__CEGCC__) +# include /* For _beginthreadex, _endthreadex */ +# endif + +# if defined(GC_BUILD) || !defined(GC_DONT_INCLUDE_WINDOWS_H) +# include +# define GC_WINDOWS_H_INCLUDED +# endif + +# ifdef __cplusplus + extern "C" { +# endif + +# ifdef GC_UNDERSCORE_STDCALL + /* Explicitly prefix exported/imported WINAPI (__stdcall) symbols */ + /* with '_' (underscore). Might be useful if MinGW/x86 is used. */ +# define GC_CreateThread _GC_CreateThread +# define GC_ExitThread _GC_ExitThread +# endif + +# ifndef DECLSPEC_NORETURN + /* Typically defined in winnt.h. */ +# ifdef GC_WINDOWS_H_INCLUDED +# define DECLSPEC_NORETURN /* empty */ +# 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 + /* Export GC DllMain to be invoked from client DllMain. */ +# ifdef GC_UNDERSCORE_STDCALL +# define GC_DllMain _GC_DllMain +# endif +# ifdef GC_WINDOWS_H_INCLUDED + GC_API BOOL WINAPI GC_DllMain(HINSTANCE /* inst */, + ULONG /* reason */, + LPVOID /* reserved */); +# else + GC_API int __stdcall GC_DllMain(void *, unsigned long, void *); +# endif +# endif /* GC_INSIDE_DLL */ + + /* All threads must be created using GC_CreateThread or */ + /* GC_beginthreadex, or must explicitly call GC_register_my_thread */ + /* (and call GC_unregister_my_thread before thread termination), so */ + /* that they will be recorded in the thread table. For backward */ + /* compatibility, it is possible to build the GC with GC_DLL */ + /* defined, and to call GC_use_threads_discovery. This implicitly */ + /* registers all created threads, but appears to be less robust. */ + /* Currently the collector expects all threads to fall through and */ + /* terminate normally, or call GC_endthreadex() or GC_ExitThread, */ + /* so that the thread is properly unregistered. */ +# ifdef GC_WINDOWS_H_INCLUDED + GC_API HANDLE WINAPI GC_CreateThread( + LPSECURITY_ATTRIBUTES /* lpThreadAttributes */, + GC_WIN32_SIZE_T /* dwStackSize */, + LPTHREAD_START_ROUTINE /* lpStartAddress */, + LPVOID /* lpParameter */, DWORD /* dwCreationFlags */, + LPDWORD /* lpThreadId */); + + GC_API DECLSPEC_NORETURN void WINAPI GC_ExitThread( + DWORD /* dwExitCode */); +# 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 * /* security */, unsigned /* stack_size */, + unsigned (__stdcall *)(void *), + void * /* arglist */, unsigned /* initflag */, + unsigned * /* thrdaddr */); + + /* Note: _endthreadex() is not currently marked as no-return in */ + /* VC++ and MinGW headers, so we don't mark it neither. */ + GC_API void GC_CALL GC_endthreadex(unsigned /* retval */); +# endif /* !_WIN32_WCE */ + +# endif /* !GC_NO_THREAD_DECLS */ + +# ifdef GC_WINMAIN_REDIRECT + /* win32_threads.c implements the real WinMain(), which will start */ + /* a new thread to call GC_WinMain() after initializing the garbage */ + /* collector. */ +# define WinMain GC_WinMain +# endif + + /* For compatibility only. */ +# 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 +/* #define _beginthread { > "Please use _beginthreadex instead of _beginthread" < } */ +# endif /* !GC_NO_THREAD_REDIRECTS */ + +#endif /* GC_WIN32_THREADS */ + +/* Public setter and getter for switching "unmap as much as possible" */ +/* mode on(1) and off(0). Has no effect unless unmapping is turned on. */ +/* Has no effect on implicitly-initiated garbage collections. Initial */ +/* value is controlled by GC_FORCE_UNMAP_ON_GCOLLECT. The setter and */ +/* getter are unsynchronized. */ +GC_API void GC_CALL GC_set_force_unmap_on_gcollect(int); +GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void); + +/* Fully portable code should call GC_INIT() from the main program */ +/* before making any other GC_ calls. On most platforms this is a */ +/* no-op and the collector self-initializes. But a number of */ +/* platforms make that too hard. */ +/* A GC_INIT call is required if the collector is built with */ +/* THREAD_LOCAL_ALLOC defined and the initial allocation call is not */ +/* to GC_malloc() or GC_malloc_atomic(). */ + +#if defined(__CYGWIN32__) || defined(__CYGWIN__) + /* Similarly gnu-win32 DLLs need explicit initialization from the */ + /* main program, as does AIX. */ +# ifdef __x86_64__ + /* Cygwin/x64 does not add leading underscore to symbols anymore. */ + 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 /* !__x86_64__ */ +# define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND); \ + GC_gcollect() /* For blacklisting. */ + /* Required at least if GC is in a DLL. And doesn't hurt. */ +#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) + /* This is ugly but seems the only way to register data roots of the */ + /* client shared library if the GC dynamic loading support is off. */ +# pragma weak __dso_handle + extern int __dso_handle[]; + GC_API void * GC_CALL GC_find_limit(void * /* start */, int /* up */); +# define GC_INIT_CONF_ROOTS (void)(__dso_handle != 0 \ + ? (GC_add_roots(__dso_handle, \ + GC_find_limit(__dso_handle, \ + 1 /*up*/)), 0) : 0) +#else +# define GC_INIT_CONF_ROOTS /* empty */ +#endif + +#ifdef GC_DONT_EXPAND + /* Set GC_dont_expand to TRUE at start-up */ +# define GC_INIT_CONF_DONT_EXPAND GC_set_dont_expand(1) +#else +# define GC_INIT_CONF_DONT_EXPAND /* empty */ +#endif + +#ifdef GC_FORCE_UNMAP_ON_GCOLLECT + /* Turn on "unmap as much as possible on explicit GC" mode at start-up */ +# define GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT \ + GC_set_force_unmap_on_gcollect(1) +#else +# define GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT /* empty */ +#endif + +#ifdef GC_DONT_GC + /* This is for debugging only (useful if environment variables are */ + /* unsupported); cannot call GC_disable as goes before GC_init. */ +# define GC_INIT_CONF_MAX_RETRIES (void)(GC_dont_gc = 1) +#elif defined(GC_MAX_RETRIES) && !defined(CPPCHECK) + /* Set GC_max_retries to the desired value at start-up */ +# define GC_INIT_CONF_MAX_RETRIES GC_set_max_retries(GC_MAX_RETRIES) +#else +# define GC_INIT_CONF_MAX_RETRIES /* empty */ +#endif + +#if defined(GC_ALLOCD_BYTES_PER_FINALIZER) && !defined(CPPCHECK) + /* Set GC_allocd_bytes_per_finalizer to the desired value at start-up. */ +# define GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER \ + GC_set_allocd_bytes_per_finalizer(GC_ALLOCD_BYTES_PER_FINALIZER) +#else +# define GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER /* empty */ +#endif + +#if defined(GC_FREE_SPACE_DIVISOR) && !defined(CPPCHECK) + /* Set GC_free_space_divisor to the desired value at start-up */ +# define GC_INIT_CONF_FREE_SPACE_DIVISOR \ + GC_set_free_space_divisor(GC_FREE_SPACE_DIVISOR) +#else +# define GC_INIT_CONF_FREE_SPACE_DIVISOR /* empty */ +#endif + +#if defined(GC_FULL_FREQ) && !defined(CPPCHECK) + /* Set GC_full_freq to the desired value at start-up */ +# define GC_INIT_CONF_FULL_FREQ GC_set_full_freq(GC_FULL_FREQ) +#else +# define GC_INIT_CONF_FULL_FREQ /* empty */ +#endif + +#if defined(GC_TIME_LIMIT) && !defined(CPPCHECK) + /* Set GC_time_limit (in ms) to the desired value at start-up. */ +# define GC_INIT_CONF_TIME_LIMIT GC_set_time_limit(GC_TIME_LIMIT) +#else +# define GC_INIT_CONF_TIME_LIMIT /* empty */ +#endif + +#if defined(GC_MARKERS) && defined(GC_THREADS) && !defined(CPPCHECK) + /* Set the number of marker threads (including the initiating */ + /* one) to the desired value at start-up. */ +# define GC_INIT_CONF_MARKERS GC_set_markers_count(GC_MARKERS) +#else +# define GC_INIT_CONF_MARKERS /* empty */ +#endif + +#if defined(GC_SIG_SUSPEND) && defined(GC_THREADS) && !defined(CPPCHECK) +# define GC_INIT_CONF_SUSPEND_SIGNAL GC_set_suspend_signal(GC_SIG_SUSPEND) +#else +# define GC_INIT_CONF_SUSPEND_SIGNAL /* empty */ +#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 /* empty */ +#endif + +#if defined(GC_MAXIMUM_HEAP_SIZE) && !defined(CPPCHECK) + /* Limit the heap size to the desired value (useful for debugging). */ + /* The limit could be overridden either at the program start-up by */ + /* the similar environment variable or anytime later by the */ + /* corresponding API function call. */ +# define GC_INIT_CONF_MAXIMUM_HEAP_SIZE \ + GC_set_max_heap_size(GC_MAXIMUM_HEAP_SIZE) +#else +# define GC_INIT_CONF_MAXIMUM_HEAP_SIZE /* empty */ +#endif + +#ifdef GC_IGNORE_WARN + /* Turn off all warnings at start-up (after GC initialization) */ +# define GC_INIT_CONF_IGNORE_WARN GC_set_warn_proc(GC_ignore_warn_proc) +#else +# define GC_INIT_CONF_IGNORE_WARN /* empty */ +#endif + +#if defined(GC_INITIAL_HEAP_SIZE) && !defined(CPPCHECK) + /* Set heap size to the desired value at start-up */ +# 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 /* empty */ +#endif + +/* Portable clients should call this at the program start-up. More */ +/* over, some platforms require this call to be done strictly from the */ +/* primordial thread. Multiple invocations are harmless. */ +#define GC_INIT() { GC_INIT_CONF_DONT_EXPAND; /* pre-init */ \ + GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT; \ + GC_INIT_CONF_MAX_RETRIES; \ + GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER; \ + GC_INIT_CONF_FREE_SPACE_DIVISOR; \ + GC_INIT_CONF_FULL_FREQ; \ + GC_INIT_CONF_TIME_LIMIT; \ + GC_INIT_CONF_MARKERS; \ + GC_INIT_CONF_SUSPEND_SIGNAL; \ + GC_INIT_CONF_THR_RESTART_SIGNAL; \ + GC_INIT_CONF_MAXIMUM_HEAP_SIZE; \ + GC_init(); /* real GC initialization */ \ + GC_INIT_CONF_ROOTS; /* post-init */ \ + GC_INIT_CONF_IGNORE_WARN; \ + GC_INIT_CONF_INITIAL_HEAP_SIZE; } + +/* win32S may not free all resources on process exit. */ +/* This explicitly deallocates the heap. Defined only for Windows. */ +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) + /* Allocation really goes through GC_amiga_allocwrapper_do. */ + 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 /* _AMIGA && !GC_AMIGA_MAKINGLIB */ + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* GC_H */ diff --git a/thirdparty/libgc/include/gc/gc_backptr.h b/thirdparty/libgc/include/gc/gc_backptr.h new file mode 100644 index 000000000..5fd919592 --- /dev/null +++ b/thirdparty/libgc/include/gc/gc_backptr.h @@ -0,0 +1,96 @@ +/* + * 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. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +/* + * This is a simple API to implement pointer back tracing, i.e. + * to answer questions such as "who is pointing to this" or + * "why is this object being retained by the collector" + * + * Most of these calls yield useful information on only after + * a garbage collection. Usually the client will first force + * a full collection and then gather information, preferably + * before much intervening allocation. + * + * The implementation of the interface is only about 99.9999% + * correct. It is intended to be good enough for profiling, + * but is not intended to be used with production code. + * + * Results are likely to be much more useful if all allocation is + * accomplished through the debugging allocators. + * + * The implementation idea is due to A. Demers. + */ + +#ifndef GC_BACKPTR_H +#define GC_BACKPTR_H + +#ifndef GC_H +# include "gc.h" +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Store information about the object referencing dest in *base_p */ +/* and *offset_p. */ +/* If multiple objects or roots point to dest, the one reported */ +/* will be the last on used by the garbage collector to trace the */ +/* object. */ +/* source is root ==> *base_p = address, *offset_p = 0 */ +/* source is heap object ==> *base_p != 0, *offset_p = offset */ +/* Returns 1 on success, 0 if source couldn't be determined. */ +/* Dest can be any address within a heap object. */ +typedef enum { + GC_UNREFERENCED, /* No reference info available. */ + GC_NO_SPACE, /* Dest not allocated with debug alloc. */ + GC_REFD_FROM_ROOT, /* Referenced directly by root *base_p. */ + GC_REFD_FROM_REG, /* Referenced from a register, i.e. */ + /* a root without an address. */ + GC_REFD_FROM_HEAP, /* Referenced from another heap obj. */ + GC_FINALIZER_REFD /* Finalizable and hence accessible. */ +} GC_ref_kind; + +GC_API GC_ref_kind GC_CALL GC_get_back_ptr_info(void * /* dest */, + void ** /* base_p */, size_t * /* offset_p */) + GC_ATTR_NONNULL(1); + +/* Generate a random heap address. */ +/* The resulting address is in the heap, but */ +/* not necessarily inside a valid object. */ +GC_API void * GC_CALL GC_generate_random_heap_address(void); + +/* Generate a random address inside a valid marked heap object. */ +GC_API void * GC_CALL GC_generate_random_valid_address(void); + +/* Force a garbage collection and generate a backtrace from a */ +/* random heap address. */ +/* This uses the GC logging mechanism (GC_printf) to produce */ +/* output. It can often be called from a debugger. The */ +/* source in dbg_mlc.c also serves as a sample client. */ +GC_API void GC_CALL GC_generate_random_backtrace(void); + +/* Print a backtrace from a specific address. Used by the */ +/* above. The client should call GC_gcollect() immediately */ +/* before invocation. */ +GC_API void GC_CALL GC_print_backtrace(void *) GC_ATTR_NONNULL(1); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* GC_BACKPTR_H */ diff --git a/thirdparty/libgc/include/gc/gc_config_macros.h b/thirdparty/libgc/include/gc/gc_config_macros.h new file mode 100644 index 000000000..c9c14d308 --- /dev/null +++ b/thirdparty/libgc/include/gc/gc_config_macros.h @@ -0,0 +1,457 @@ +/* + * 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) 2008-2020 Ivan Maidanski + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +/* This should never be included directly; it is included only from gc.h. */ +/* We separate it only to make gc.h more suitable as documentation. */ +#if defined(GC_H) + +/* Convenient internal macro to test version of GCC. */ +#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 /* FALSE */ +#endif + +/* Some tests for old macros. These violate our namespace rules and */ +/* will disappear shortly. Use the GC_ names. */ +#if defined(SOLARIS_THREADS) || defined(_SOLARIS_THREADS) \ + || defined(_SOLARIS_PTHREADS) || defined(GC_SOLARIS_PTHREADS) + /* We no longer support old style Solaris threads. */ + /* GC_SOLARIS_THREADS now means 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) + /* Using pthreads-win32 library (or other Win32 implementation). */ +# 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(GC_NO_FREEBSD) +# define GC_FREEBSD_THREADS +# elif defined(__NetBSD__) +# define GC_NETBSD_THREADS +# elif defined(__alpha) || defined(__alpha__) /* && !Linux && !xBSD */ +# 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) /* && !Linux */ \ + || ((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) + /* Either posix or native Win32 threads. */ +# define GC_WIN32_THREADS +# endif +# if defined(__rtems__) && (defined(i386) || defined(__i386__)) +# define GC_RTEMS_PTHREADS +# endif +#endif /* GC_THREADS */ + +#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) + /* Posix threads. */ +# 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) + /* Better late than never. This fails if system headers that depend */ + /* on this were previously included. */ +# define _REENTRANT 1 +#endif + +#define __GC +#if !defined(_WIN32_WCE) || defined(__GNUC__) +# include +# if defined(__MINGW32__) && !defined(_WIN32_WCE) +# include + /* We mention uintptr_t. */ + /* Perhaps this should be included in pure msft environments */ + /* as well? */ +# endif +#else /* _WIN32_WCE */ + /* Yet more kludges for WinCE. */ +# include /* size_t is defined here */ +# ifndef _PTRDIFF_T_DEFINED + /* ptrdiff_t is not defined */ +# define _PTRDIFF_T_DEFINED + typedef long ptrdiff_t; +# endif +#endif /* _WIN32_WCE */ + +#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__) + /* Only matters if used in conjunction with -fvisibility=hidden option. */ +# 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 /* GC_DLL */ + +#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 + /* 'malloc' attribute should be used for all malloc-like functions */ + /* (to tell the compiler that a function may be treated as if any */ + /* non-NULL pointer it returns cannot alias any other pointer valid */ + /* when the function returns). If the client code violates this rule */ + /* by using custom GC_oom_func then define GC_OOM_FUNC_RETURNS_ALIAS. */ +# ifdef GC_OOM_FUNC_RETURNS_ALIAS +# define GC_ATTR_MALLOC /* empty */ +# 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 + /* 'alloc_size' attribute improves __builtin_object_size correctness. */ +# 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) /* empty */ +# 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) /* empty */ +# endif +#endif + +#ifndef GC_ATTR_CALLOC_SIZE +# define GC_ATTR_CALLOC_SIZE(n, s) /* empty */ +#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) /* empty */ +# endif +#endif + +#ifndef GC_ATTR_CONST +# if GC_GNUC_PREREQ(4, 0) +# define GC_ATTR_CONST __attribute__((__const__)) +# else +# define GC_ATTR_CONST /* empty */ +# endif +#endif + +#ifndef GC_ATTR_DEPRECATED +# ifdef GC_BUILD +# undef GC_ATTR_DEPRECATED +# define GC_ATTR_DEPRECATED /* empty */ +# 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 /* empty */ +# 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 +# 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 /* GLIBC */ + +#if defined(_MSC_VER) && _MSC_VER >= 1200 /* version 12.0+ (MSVC 6.0+) */ \ + && !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 we're on a platform on which we can't save call stacks, but */ +/* gcc is normally used, we go ahead and define GC_ADD_CALLER. */ +/* We make this decision independent of whether gcc is actually being */ +/* used, in order to keep the interface consistent, and allow mixing */ +/* of compilers. */ +/* This may also be desirable if it is possible but expensive to */ +/* retrieve the call chain. */ +#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) + /* gcc knows how to retrieve return address, but we don't know */ + /* how to generate call stacks. */ +# define GC_RETURN_ADDR (GC_word)__builtin_return_address(0) +# if GC_GNUC_PREREQ(4, 0) && (defined(__i386__) || defined(__amd64__) \ + || defined(__x86_64__) /* and probably others... */) \ + && !defined(GC_NO_RETURN_ADDR_PARENT) +# define GC_HAVE_RETURN_ADDR_PARENT +# define GC_RETURN_ADDR_PARENT \ + (GC_word)__builtin_extract_return_addr(__builtin_return_address(1)) + /* Note: a compiler might complain that calling */ + /* __builtin_return_address with a nonzero argument is unsafe. */ +# endif +# else + /* Just pass 0 for gcc compatibility. */ +# define GC_RETURN_ADDR 0 +# endif +#endif /* !GC_CAN_SAVE_CALL_STACKS */ + +#ifdef GC_PTHREADS + +# if (defined(GC_DARWIN_THREADS) || defined(GC_WIN32_PTHREADS) \ + || defined(__native_client__) || defined(GC_RTEMS_PTHREADS)) \ + && !defined(GC_NO_DLOPEN) + /* Either there is no dlopen() or we do not need to intercept it. */ +# 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) + /* Either there is no pthread_sigmask() or no need to intercept it. */ +# define GC_NO_PTHREAD_SIGMASK +# endif + +# if defined(__native_client__) + /* At present, NaCl pthread_create() prototype does not have */ + /* "const" for its "attr" argument; also, NaCl pthread_exit() one */ + /* does not have "noreturn" attribute. */ +# ifndef GC_PTHREAD_CREATE_CONST +# define GC_PTHREAD_CREATE_CONST /* empty */ +# endif +# ifndef GC_HAVE_PTHREAD_EXIT +# define GC_HAVE_PTHREAD_EXIT +# define GC_PTHREAD_EXIT_ATTRIBUTE /* empty */ +# 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 + /* Intercept pthread_exit on Linux and Solaris. */ +# if GC_GNUC_PREREQ(2, 7) +# define GC_PTHREAD_EXIT_ATTRIBUTE __attribute__((__noreturn__)) +# elif defined(__NORETURN) /* used in Solaris */ +# define GC_PTHREAD_EXIT_ATTRIBUTE __NORETURN +# else +# define GC_PTHREAD_EXIT_ATTRIBUTE /* empty */ +# endif +# endif + +# if (!defined(GC_HAVE_PTHREAD_EXIT) || defined(__native_client__)) \ + && !defined(GC_NO_PTHREAD_CANCEL) + /* Either there is no pthread_cancel() or no need to intercept it. */ +# define GC_NO_PTHREAD_CANCEL +# endif + +#endif /* GC_PTHREADS */ + +#ifdef __cplusplus + +#ifndef GC_ATTR_EXPLICIT +# if __cplusplus >= 201103L && !defined(__clang__) || _MSVC_LANG >= 201103L \ + || defined(CPPCHECK) +# define GC_ATTR_EXPLICIT explicit +# else +# define GC_ATTR_EXPLICIT /* empty */ +# endif +#endif + +#ifndef GC_NOEXCEPT +# if defined(__DMC__) || (defined(__BORLANDC__) \ + && (defined(_RWSTD_NO_EXCEPTIONS) || defined(_RWSTD_NO_EX_SPEC))) \ + || (defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) \ + || (defined(__WATCOMC__) && !defined(_CPPUNWIND)) +# define GC_NOEXCEPT /* empty */ +# ifndef GC_NEW_ABORTS_ON_OOM +# define GC_NEW_ABORTS_ON_OOM +# endif +# elif __cplusplus >= 201103L || _MSVC_LANG >= 201103L +# define GC_NOEXCEPT noexcept +# else +# define GC_NOEXCEPT throw() +# endif +#endif + +#endif /* __cplusplus */ + +#endif diff --git a/thirdparty/libgc/include/gc/gc_inline.h b/thirdparty/libgc/include/gc/gc_inline.h new file mode 100644 index 000000000..d2d614c39 --- /dev/null +++ b/thirdparty/libgc/include/gc/gc_inline.h @@ -0,0 +1,208 @@ +/* + * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers + * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. + * Copyright (c) 2005 Hewlett-Packard Development Company, L.P. + * + * 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 GC_INLINE_H +#define GC_INLINE_H + +/* WARNING: */ +/* Note that for these routines, it is the clients responsibility to */ +/* add the extra byte at the end to deal with one-past-the-end pointers.*/ +/* In the standard collector configuration, the collector assumes that */ +/* such a byte has been added, and hence does not trace the last word */ +/* in the resulting object. */ +/* This is not an issue if the collector is compiled with */ +/* DONT_ADD_BYTE_AT_END, or if GC_all_interior_pointers is not set. */ +/* This interface is most useful for compilers that generate C. */ +/* It is also used internally for thread-local allocation. */ +/* Manual use is hereby discouraged. */ + +#include "gc.h" +#include "gc_tiny_fl.h" + +#if GC_GNUC_PREREQ(3, 0) +# define GC_EXPECT(expr, outcome) __builtin_expect(expr,outcome) + /* Equivalent to (expr), but predict that usually (expr)==outcome. */ +#else +# define GC_EXPECT(expr, outcome) (expr) +#endif + +#ifndef GC_ASSERT +# ifdef NDEBUG +# define GC_ASSERT(expr) /* empty */ +# else +# include +# 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 + +/* Object kinds; must match PTRFREE, NORMAL in gc_priv.h. */ +#define GC_I_PTRFREE 0 +#define GC_I_NORMAL 1 + +/* Store a pointer to a list of newly allocated objects of kind k and */ +/* size lb in *result. The caller must make sure that *result is */ +/* traced even if objects are ptrfree. */ +GC_API void GC_CALL GC_generic_malloc_many(size_t /* lb */, int /* k */, + void ** /* result */); + +/* Generalized version of GC_malloc and GC_malloc_atomic. */ +/* Uses appropriately the thread-local (if available) or the global */ +/* free-list of the specified kind. */ +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_malloc_kind(size_t /* lb */, int /* k */); + +#ifdef GC_THREADS + /* Same as above but uses only the global free-list. */ + GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_malloc_kind_global(size_t /* lb */, int /* k */); +#else +# define GC_malloc_kind_global GC_malloc_kind +#endif + +/* An internal macro to update the free list pointer atomically (if */ +/* the AO primitives are available) to avoid race with the marker. */ +#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 + +/* The ultimately general inline allocation macro. Allocate an object */ +/* of size granules, putting the resulting pointer in result. Tiny_fl */ +/* is a "tiny" free list array, which will be used first, if the size */ +/* is appropriate. If granules is too large, we allocate with */ +/* default_expr instead. If we need to refill the free list, we use */ +/* GC_generic_malloc_many with the indicated kind. */ +/* Tiny_fl should be an array of GC_TINY_FREELISTS void * pointers. */ +/* If num_direct is nonzero, and the individual free list pointers */ +/* are initialized to (void *)1, then we allocate num_direct granules */ +/* directly using generic_malloc before putting multiple objects into */ +/* the tiny_fl entry. If num_direct is zero, then the free lists may */ +/* also be initialized to (void *)0. */ +/* Note that we use the zeroth free list to hold objects 1 granule in */ +/* size that are used to satisfy size 0 allocation requests. */ +/* We rely on much of this hopefully getting optimized away in the */ +/* num_direct = 0 case. */ +/* Particularly if granules is constant, this should generate a small */ +/* amount of code. */ +# 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; \ + } \ + /* Entry contains counter or NULL */ \ + if ((GC_signed_word)my_entry - (GC_signed_word)(num_direct) <= 0 \ + /* (GC_word)my_entry <= (num_direct) */ \ + && my_entry != 0 /* NULL */) { \ + /* Small counter value, not NULL */ \ + GC_FAST_M_AO_STORE(my_fl, (char *)my_entry \ + + (granules) + 1); \ + result = (default_expr); \ + break; \ + } else { \ + /* Large counter or NULL */ \ + 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) + +/* Allocate n words (NOT BYTES). X is made to point to the result. */ +/* This should really only be used if GC_all_interior_pointers is */ +/* not set, or DONT_ADD_BYTE_AT_END is set. See above. */ +/* Does not acquire lock. The caller is responsible for supplying */ +/* a cleared tiny_fl free list array. For single-threaded */ +/* applications, this may be a global array. */ +# define GC_MALLOC_WORDS_KIND(result,n,tiny_fl,kind,init) \ + do { \ + size_t granules = GC_WORDS_TO_WHOLE_GRANULES(n); \ + 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) + +/* And once more for two word initialized objects: */ +# define GC_CONS(result, first, second, tiny_fl) \ + do { \ + void *l = (void *)(first); \ + void *r = (void *)(second); \ + GC_MALLOC_WORDS_KIND(result, 2, tiny_fl, GC_I_NORMAL, (void)0); \ + if ((result) != 0 /* NULL */) { \ + *(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 /* kind */, + size_t /* sz_in_granules */); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* !GC_INLINE_H */ diff --git a/thirdparty/libgc/include/gc/gc_mark.h b/thirdparty/libgc/include/gc/gc_mark.h new file mode 100644 index 000000000..6ff8ceecf --- /dev/null +++ b/thirdparty/libgc/include/gc/gc_mark.h @@ -0,0 +1,328 @@ +/* + * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. + * Copyright (c) 2001 by Hewlett-Packard Company. All rights reserved. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + * + */ + +/* + * This contains interfaces to the GC marker that are likely to be useful to + * clients that provide detailed heap layout information to the collector. + * This interface should not be used by normal C or C++ clients. + * It will be useful to runtimes for other languages. + * + * This is an experts-only interface! There are many ways to break the + * collector in subtle ways by using this functionality. + */ +#ifndef GC_MARK_H +#define GC_MARK_H + +#ifndef GC_H +# include "gc.h" +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* A client supplied mark procedure. Returns new mark stack pointer. */ +/* Primary effect should be to push new entries on the mark stack. */ +/* Mark stack pointer values are passed and returned explicitly. */ +/* Global variables describing mark stack are not necessarily valid. */ +/* (This usually saves a few cycles by keeping things in registers.) */ +/* Assumed to scan about GC_PROC_BYTES on average. If it needs to do */ +/* much more work than that, it should do it in smaller pieces by */ +/* pushing itself back on the mark stack. */ +/* Note that it should always do some work (defined as marking some */ +/* objects) before pushing more than one entry on the mark stack. */ +/* This is required to ensure termination in the event of mark stack */ +/* overflows. */ +/* This procedure is always called with at least one empty entry on the */ +/* mark stack. */ +/* Currently we require that mark procedures look for pointers in a */ +/* subset of the places the conservative marker would. It must be safe */ +/* to invoke the normal mark procedure instead. */ +/* WARNING: Such a mark procedure may be invoked on an unused object */ +/* residing on a free list. Such objects are cleared, except for a */ +/* free list link field in the first word. Thus mark procedures may */ +/* not count on the presence of a type descriptor, and must handle this */ +/* case correctly somehow. */ +#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 * /* addr */, + struct GC_ms_entry * /* mark_stack_ptr */, + struct GC_ms_entry * /* mark_stack_limit */, + GC_word /* env */); + +#define GC_LOG_MAX_MARK_PROCS 6 +#define GC_MAX_MARK_PROCS (1 << GC_LOG_MAX_MARK_PROCS) + +/* In a few cases it's necessary to assign statically known indices to */ +/* certain mark procs. Thus we reserve a few for well known clients. */ +/* (This is necessary if mark descriptors are compiler generated.) */ +#define GC_RESERVED_MARK_PROCS 8 +#define GC_GCJ_RESERVED_MARK_PROC_INDEX 0 + +/* Object descriptors on mark stack or in objects. Low order two */ +/* bits are tags distinguishing among the following 4 possibilities */ +/* for the high order 30 bits. */ +#define GC_DS_TAG_BITS 2 +#define GC_DS_TAGS ((1 << GC_DS_TAG_BITS) - 1) +#define GC_DS_LENGTH 0 /* The entire word is a length in bytes that */ + /* must be a multiple of 4. */ +#define GC_DS_BITMAP 1 /* 30 (62) bits are a bitmap describing pointer */ + /* fields. The msb is 1 if the first word */ + /* is a pointer. */ + /* (This unconventional ordering sometimes */ + /* makes the marker slightly faster.) */ + /* Zeroes indicate definite nonpointers. Ones */ + /* indicate possible pointers. */ + /* Only usable if pointers are word aligned. */ +#define GC_DS_PROC 2 + /* The objects referenced by this object can be */ + /* pushed on the mark stack by invoking */ + /* PROC(descr). ENV(descr) is passed as the */ + /* last argument. */ +#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 /* The real descriptor is at the */ + /* byte displacement from the beginning of the */ + /* object given by descr & ~GC_DS_TAGS. */ + /* If the descriptor is negative, the real */ + /* descriptor is at (*) - */ + /* (descr&~GC_DS_TAGS) - GC_INDIR_PER_OBJ_BIAS */ + /* The latter alternative can be used if each */ + /* object contains a type descriptor in the */ + /* first word. */ + /* Note that in the multi-threaded environments */ + /* per-object descriptors must be located in */ + /* either the first two or last two words of */ + /* the object, since only those are guaranteed */ + /* to be cleared while the allocation lock is */ + /* held. */ +#define GC_INDIR_PER_OBJ_BIAS 0x10 + +GC_API void * GC_least_plausible_heap_addr; +GC_API void * GC_greatest_plausible_heap_addr; + /* Bounds on the heap. Guaranteed valid */ + /* Likely to include future heap expansion. */ + /* Hence usually includes not-yet-mapped */ + /* memory. */ + +/* Handle nested references in a custom mark procedure. */ +/* Check if obj is a valid object. If so, ensure that it is marked. */ +/* If it was not previously marked, push its contents onto the mark */ +/* stack for future scanning. The object will then be scanned using */ +/* its mark descriptor. */ +/* Returns the new mark stack pointer. */ +/* Handles mark stack overflows correctly. */ +/* Since this marks first, it makes progress even if there are mark */ +/* stack overflows. */ +/* Src is the address of the pointer to obj, which is used only */ +/* for back pointer-based heap debugging. */ +/* It is strongly recommended that most objects be handled without mark */ +/* procedures, e.g. with bitmap descriptors, and that mark procedures */ +/* be reserved for exceptional cases. That will ensure that */ +/* performance of this call is not extremely performance critical. */ +/* (Otherwise we would need to inline GC_mark_and_push completely, */ +/* which would tie the client code to a fixed collector version.) */ +/* Note that mark procedures should explicitly call FIXUP_POINTER() */ +/* if required. */ +GC_API struct GC_ms_entry * GC_CALL GC_mark_and_push(void * /* obj */, + struct GC_ms_entry * /* mark_stack_ptr */, + struct GC_ms_entry * /* mark_stack_limit */, + void ** /* src */); + +#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)) + +/* The size of the header added to objects allocated through the */ +/* GC_debug routines. Defined as a function so that client mark */ +/* procedures do not need to be recompiled for the collector library */ +/* version changes. */ +GC_API GC_ATTR_CONST size_t GC_CALL GC_get_debug_header_size(void); +#define GC_USR_PTR_FROM_BASE(p) \ + ((void *)((char *)(p) + GC_get_debug_header_size())) + +/* The same but defined as a variable. Exists only for the backward */ +/* compatibility. Some compilers do not accept "const" together with */ +/* deprecated or dllimport attributes, so the symbol is exported as */ +/* a non-constant one. */ +GC_API GC_ATTR_DEPRECATED +# ifdef GC_BUILD + const +# endif + size_t GC_debug_header_size; + +/* And some routines to support creation of new "kinds", e.g. with */ +/* custom mark procedures, by language runtimes. */ +/* The _inner versions assume the caller holds the allocation lock. */ + +/* Return a new free list array. */ +GC_API void ** GC_CALL GC_new_free_list(void); +GC_API void ** GC_CALL GC_new_free_list_inner(void); + +/* Return a new kind, as specified. */ +GC_API unsigned GC_CALL GC_new_kind(void ** /* free_list */, + GC_word /* mark_descriptor_template */, + int /* add_size_to_descriptor */, + int /* clear_new_objects */) GC_ATTR_NONNULL(1); + /* The last two parameters must be zero or one. */ +GC_API unsigned GC_CALL GC_new_kind_inner(void ** /* free_list */, + GC_word /* mark_descriptor_template */, + int /* add_size_to_descriptor */, + int /* clear_new_objects */) GC_ATTR_NONNULL(1); + +/* Return a new mark procedure identifier, suitable for use as */ +/* the first argument in GC_MAKE_PROC. */ +GC_API unsigned GC_CALL GC_new_proc(GC_mark_proc); +GC_API unsigned GC_CALL GC_new_proc_inner(GC_mark_proc); + +/* Allocate an object of a given kind. By default, there are only */ +/* a few kinds: composite (pointerful), atomic, uncollectible, etc. */ +/* We claim it is possible for clever client code that understands the */ +/* GC internals to add more, e.g. to communicate object layout */ +/* information to the collector. Note that in the multi-threaded */ +/* contexts, this is usually unsafe for kinds that have the descriptor */ +/* in the object itself, since there is otherwise a window in which */ +/* the descriptor is not correct. Even in the single-threaded case, */ +/* we need to be sure that cleared objects on a free list don't */ +/* cause a GC crash if they are accidentally traced. */ +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL GC_generic_malloc( + size_t /* lb */, + int /* knd */); + +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_generic_malloc_ignore_off_page( + size_t /* lb */, int /* knd */); + /* As above, but pointers to past the */ + /* first page of the resulting object */ + /* are ignored. */ + +/* Generalized version of GC_malloc_[atomic_]uncollectable. */ +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_generic_malloc_uncollectable( + size_t /* lb */, int /* knd */); + +/* Same as above but primary for allocating an object of the same kind */ +/* as an existing one (kind obtained by GC_get_kind_and_size). */ +/* Not suitable for GCJ and typed-malloc kinds. */ +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_generic_or_special_malloc( + size_t /* size */, int /* knd */); +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_debug_generic_or_special_malloc( + size_t /* size */, int /* knd */, + 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_DEBUG */ + +/* Similar to GC_size but returns object kind. Size is returned too */ +/* if psize is not NULL. */ +GC_API int GC_CALL GC_get_kind_and_size(const void *, size_t * /* psize */) + GC_ATTR_NONNULL(1); + +typedef void (GC_CALLBACK * GC_describe_type_fn)(void * /* p */, + char * /* out_buf */); + /* A procedure which */ + /* produces a human-readable */ + /* description of the "type" of object */ + /* p into the buffer out_buf of length */ + /* GC_TYPE_DESCR_LEN. This is used by */ + /* the debug support when printing */ + /* objects. */ + /* These functions should be as robust */ + /* as possible, though we do avoid */ + /* invoking them on objects on the */ + /* global free list. */ +#define GC_TYPE_DESCR_LEN 40 + +GC_API void GC_CALL GC_register_describe_type_fn(int /* kind */, + GC_describe_type_fn); + /* Register a describe_type function */ + /* to be used when printing objects */ + /* of a particular kind. */ + +/* Clear some of the inaccessible part of the stack. Returns its */ +/* argument, so it can be used in a tail call position, hence clearing */ +/* another frame. Argument may be NULL. */ +GC_API void * GC_CALL GC_clear_stack(void *); + +/* Set and get the client notifier on collections. The client function */ +/* is called at the start of every full GC (called with the allocation */ +/* lock held). May be 0. This is a really tricky interface to use */ +/* correctly. Unless you really understand the collector internals, */ +/* the callback should not, directly or indirectly, make any GC_ or */ +/* potentially blocking calls. In particular, it is not safe to */ +/* allocate memory using the garbage collector from within the callback */ +/* function. Both the setter and getter acquire the GC lock. */ +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); + +/* Slow/general mark bit manipulation. The caller must hold the */ +/* allocation lock. GC_is_marked returns 1 (TRUE) or 0. */ +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); + +/* Push everything in the given range onto the mark stack. */ +/* (GC_push_conditional pushes either all or only dirty pages depending */ +/* on the third argument.) GC_push_all_eager also ensures that stack */ +/* is scanned immediately, not just scheduled for scanning. */ +GC_API void GC_CALL GC_push_all(void * /* bottom */, void * /* top */); +GC_API void GC_CALL GC_push_all_eager(void * /* bottom */, void * /* top */); +GC_API void GC_CALL GC_push_conditional(void * /* bottom */, void * /* top */, + int /* bool all */); +GC_API void GC_CALL GC_push_finalizer_structures(void); + +/* Set and get the client push-other-roots procedure. A client */ +/* supplied procedure should also call the original procedure. */ +/* Note that both the setter and getter require some external */ +/* synchronization to avoid data race. */ +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); + +/* Walk the GC heap visiting all reachable objects. Assume the caller */ +/* holds the allocation lock. Object base pointer, object size and */ +/* client custom data are passed to the callback (holding the lock). */ +typedef void (GC_CALLBACK *GC_reachable_object_proc)(void * /* obj */, + size_t /* bytes */, + void * /* client_data */); +GC_API void GC_CALL GC_enumerate_reachable_objects_inner( + GC_reachable_object_proc, + void * /* client_data */) 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_no */); +GC_API void GC_CALL GC_print_trace_inner(GC_word /* gc_no */); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* GC_MARK_H */ diff --git a/thirdparty/libgc/include/gc/gc_pthread_redirects.h b/thirdparty/libgc/include/gc/gc_pthread_redirects.h new file mode 100644 index 000000000..b235334aa --- /dev/null +++ b/thirdparty/libgc/include/gc/gc_pthread_redirects.h @@ -0,0 +1,124 @@ +/* + * 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-2010 by Hewlett-Packard Development Company. + * All rights reserved. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +/* Our pthread support normally needs to intercept a number of thread */ +/* calls. We arrange to do that here, if appropriate. */ + +#ifndef GC_PTHREAD_REDIRECTS_H +#define GC_PTHREAD_REDIRECTS_H + +/* Included from gc.h only. Included only if GC_PTHREADS. */ +#if defined(GC_H) && defined(GC_PTHREADS) + +/* We need to intercept calls to many of the threads primitives, so */ +/* that we can locate thread stacks and stop the world. */ +/* Note also that the collector cannot always see thread specific data. */ +/* Thread specific data should generally consist of pointers to */ +/* uncollectible objects (allocated with GC_malloc_uncollectable, */ +/* not the system malloc), which are deallocated using the destructor */ +/* facility in thr_keycreate. Alternatively, keep a redundant pointer */ +/* to thread specific data on the thread stack. */ + +#ifndef GC_PTHREAD_REDIRECTS_ONLY + +# include +# ifndef GC_NO_DLOPEN +# include +# endif +# ifndef GC_NO_PTHREAD_SIGMASK +# include /* needed anyway for proper redirection */ +# 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 * /* path */, int /* mode */); +# endif /* !GC_NO_DLOPEN */ + +# 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 /* how */, const sigset_t *, + sigset_t * /* oset */); +# endif +# endif /* !GC_NO_PTHREAD_SIGMASK */ + +# ifndef GC_PTHREAD_CREATE_CONST + /* This is used for pthread_create() only. */ +# 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 * /* arg */); + GC_API int GC_pthread_join(pthread_t, void ** /* retval */); + 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 + } /* extern "C" */ +# endif + +#endif /* !GC_PTHREAD_REDIRECTS_ONLY */ + +#if !defined(GC_NO_THREAD_REDIRECTS) && !defined(GC_USE_LD_WRAP) + /* Unless the compiler supports #pragma extern_prefix, the Tru64 */ + /* UNIX redefines some POSIX thread functions to use */ + /* mangled names. Anyway, it's safe to undef them before redefining. */ +# 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 /* !GC_NO_THREAD_REDIRECTS */ + +#endif /* GC_PTHREADS */ + +#endif /* GC_PTHREAD_REDIRECTS_H */ diff --git a/thirdparty/libgc/include/gc/gc_tiny_fl.h b/thirdparty/libgc/include/gc/gc_tiny_fl.h new file mode 100644 index 000000000..0382b4179 --- /dev/null +++ b/thirdparty/libgc/include/gc/gc_tiny_fl.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1999-2005 Hewlett-Packard Development Company, L.P. + * + * 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 GC_TINY_FL_H +#define GC_TINY_FL_H +/* + * Constants and data structures for "tiny" free lists. + * These are used for thread-local allocation or in-lined allocators. + * Each global free list also essentially starts with one of these. + * However, global free lists are known to the GC. "Tiny" free lists + * are basically private to the client. Their contents are viewed as + * "in use" and marked accordingly by the core of the GC. + * + * Note that inlined code might know about the layout of these and the constants + * involved. Thus any change here may invalidate clients, and such changes should + * be avoided. Hence we keep this as simple as possible. + */ + +/* + * We always set GC_GRANULE_BYTES to twice the length of a pointer. + * This means that all allocation requests are rounded up to the next + * multiple of 16 on 64-bit architectures or 8 on 32-bit architectures. + * This appears to be a reasonable compromise between fragmentation overhead + * and space usage for mark bits (usually mark bytes). + * On many 64-bit architectures some memory references require 16-byte + * alignment, making this necessary anyway. + * For a few 32-bit architecture (e.g. x86), we may also need 16-byte alignment + * for certain memory references. But currently that does not seem to be the + * default for all conventional malloc implementations, so we ignore that + * problem. + * It would always be safe, and often useful, to be able to allocate very + * small objects with smaller alignment. But that would cost us mark bit + * space, so we no longer do so. + */ +#ifndef GC_GRANULE_BYTES + /* GC_GRANULE_BYTES should not be overridden in any instances of the GC */ + /* library that may be shared between applications, since it affects */ + /* the binary interface to the library. */ +# 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 /* !GC_GRANULE_BYTES */ + +#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 + +/* A "tiny" free list header contains TINY_FREELISTS pointers to */ +/* singly linked lists of objects of different sizes, the ith one */ +/* containing objects i granules in size. Note that there is a list */ +/* of size zero objects. */ +#ifndef GC_TINY_FREELISTS +# if GC_GRANULE_BYTES == 16 +# define GC_TINY_FREELISTS 25 +# else +# define GC_TINY_FREELISTS 33 /* Up to and including 256 bytes */ +# endif +#endif /* !GC_TINY_FREELISTS */ + +/* The ith free list corresponds to size i*GC_GRANULE_BYTES */ +/* Internally to the collector, the index can be computed with */ +/* ROUNDED_UP_GRANULES. Externally, we don't know whether */ +/* DONT_ADD_BYTE_AT_END is set, but the client should know. */ + +/* Convert a free list index to the actual size of objects */ +/* on that list, including extra space we added. Not an */ +/* inverse of the above. */ +#define GC_RAW_BYTES_FROM_INDEX(i) ((i) * GC_GRANULE_BYTES) + +#endif /* GC_TINY_FL_H */ diff --git a/thirdparty/libgc/include/gc/gc_typed.h b/thirdparty/libgc/include/gc/gc_typed.h new file mode 100644 index 000000000..f91c7bcec --- /dev/null +++ b/thirdparty/libgc/include/gc/gc_typed.h @@ -0,0 +1,122 @@ +/* + * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers + * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. + * Copyright 1996 Silicon Graphics. All rights reserved. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +/* + * Some simple primitives for allocation with explicit type information. + * Facilities for dynamic type inference may be added later. + * Should be used only for extremely performance critical applications, + * or if conservative collector leakage is otherwise a problem (unlikely). + * Note that this is implemented completely separately from the rest + * of the collector, and is not linked in unless referenced. + * This does not currently support GC_DEBUG in any interesting way. + */ + +#ifndef GC_TYPED_H +#define GC_TYPED_H + +#ifndef GC_H +# include "gc.h" +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +typedef GC_word * GC_bitmap; + /* The least significant bit of the first word is one if */ + /* the first word in the object may be a pointer. */ + +#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 * /* GC_bitmap bm */, + size_t /* len (number_of_bits_in_bitmap) */); + /* Return a type descriptor for the object whose layout */ + /* is described by the argument. */ + /* The least significant bit of the first word is one */ + /* if the first word in the object may be a pointer. */ + /* The second argument specifies the number of */ + /* meaningful bits in the bitmap. The actual object */ + /* may be larger (but not smaller). Any additional */ + /* words in the object are assumed not to contain */ + /* pointers. */ + /* Returns a conservative approximation in the */ + /* (unlikely) case of insufficient memory to build */ + /* the descriptor. Calls to GC_make_descriptor */ + /* may consume some amount of a finite resource. This */ + /* is intended to be called once per type, not once */ + /* per allocation. */ + +/* It is possible to generate a descriptor for a C type T with */ +/* word aligned pointer fields f1, f2, ... as follows: */ +/* */ +/* GC_descr T_descr; */ +/* GC_word T_bitmap[GC_BITMAP_SIZE(T)] = {0}; */ +/* GC_set_bit(T_bitmap, GC_WORD_OFFSET(T,f1)); */ +/* GC_set_bit(T_bitmap, GC_WORD_OFFSET(T,f2)); */ +/* ... */ +/* T_descr = GC_make_descriptor(T_bitmap, GC_WORD_LEN(T)); */ + +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_malloc_explicitly_typed(size_t /* size_in_bytes */, + GC_descr /* d */); + /* Allocate an object whose layout is described by d. */ + /* The size may NOT be less than the number of */ + /* meaningful bits in the bitmap of d multiplied by */ + /* sizeof GC_word. The returned object is cleared. */ + /* The returned object may NOT be passed to GC_realloc. */ + +GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL + GC_malloc_explicitly_typed_ignore_off_page(size_t /* size_in_bytes */, + GC_descr /* d */); + +GC_API GC_ATTR_MALLOC GC_ATTR_CALLOC_SIZE(1, 2) void * GC_CALL + GC_calloc_explicitly_typed(size_t /* nelements */, + size_t /* element_size_in_bytes */, + GC_descr /* d */); + /* Allocate an array of nelements elements, each of the */ + /* given size, and with the given descriptor. */ + /* The element size must be a multiple of the byte */ + /* alignment required for pointers. E.g. on a 32-bit */ + /* machine with 16-bit aligned pointers, size_in_bytes */ + /* must be a multiple of 2. The element size may NOT */ + /* be less than the number of meaningful bits in the */ + /* bitmap of d multiplied by sizeof GC_word. */ + /* Returned object is cleared. */ + +#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 + } /* extern "C" */ +#endif + +#endif /* GC_TYPED_H */ diff --git a/thirdparty/libgc/include/gc/gc_version.h b/thirdparty/libgc/include/gc/gc_version.h new file mode 100644 index 000000000..de7a565ac --- /dev/null +++ b/thirdparty/libgc/include/gc/gc_version.h @@ -0,0 +1,47 @@ +/* + * 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. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +/* This should never be included directly; it is included only from gc.h. */ +#if defined(GC_H) + +/* The policy regarding version numbers: development code has odd */ +/* "minor" number (and "micro" part is 0); when development is finished */ +/* and a release is prepared, "minor" number is incremented (keeping */ +/* "micro" number still zero), whenever a defect is fixed a new release */ +/* is prepared incrementing "micro" part to odd value (the most stable */ +/* release has the biggest "micro" number). */ + +/* The version here should match that in configure/configure.ac */ +/* Eventually this one may become unnecessary. For now we need */ +/* it to keep the old-style build process working. */ +#define GC_TMP_VERSION_MAJOR 8 +#define GC_TMP_VERSION_MINOR 2 +#define GC_TMP_VERSION_MICRO 0 /* 8.2.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 /* !GC_VERSION_MAJOR */ + +#endif diff --git a/thirdparty/libgc/include/gc/leak_detector.h b/thirdparty/libgc/include/gc/leak_detector.h new file mode 100644 index 000000000..0c27eda08 --- /dev/null +++ b/thirdparty/libgc/include/gc/leak_detector.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000-2011 by Hewlett-Packard Development Company. + * All rights reserved. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +#ifndef GC_LEAK_DETECTOR_H +#define GC_LEAK_DETECTOR_H + +/* Include leak_detector.h (e.g., via GCC --include directive) */ +/* to turn BoehmGC into a Leak Detector. */ + +#ifndef GC_DEBUG +# define GC_DEBUG +#endif +#include "gc.h" + +#ifndef GC_DONT_INCLUDE_STDLIB + /* We ensure stdlib.h and string.h are included before */ + /* redirecting malloc() and the accompanying functions. */ +# include +# include +#endif + +#undef malloc +#define malloc(n) GC_MALLOC(n) +#undef calloc +#define calloc(m,n) GC_MALLOC((m)*(n)) +#undef free +#define free(p) GC_FREE(p) +#undef realloc +#define realloc(p,n) GC_REALLOC(p,n) + +#undef strdup +#define strdup(s) GC_STRDUP(s) +#undef strndup +#define strndup(s,n) GC_STRNDUP(s,n) + +#ifdef GC_REQUIRE_WCSDUP + /* The collector should be built with GC_REQUIRE_WCSDUP */ + /* defined as well to redirect wcsdup(). */ +# include +# undef wcsdup +# define wcsdup(s) GC_WCSDUP(s) +#endif + +#undef memalign +#define memalign(a,n) GC_memalign(a,n) +#undef posix_memalign +#define posix_memalign(p,a,n) GC_posix_memalign(p,a,n) + +#ifndef CHECK_LEAKS +# define CHECK_LEAKS() GC_gcollect() + /* Note 1: CHECK_LEAKS does not have GC prefix (preserved for */ + /* backward compatibility). */ + /* Note 2: GC_gcollect() is also called automatically in the */ + /* leak-finding mode at program exit. */ +#endif + +#endif /* GC_LEAK_DETECTOR_H */ diff --git a/vlib/builtin/builtin_d_gcboehm.c.v b/vlib/builtin/builtin_d_gcboehm.c.v index 55f33ea87..d50275fd1 100644 --- a/vlib/builtin/builtin_d_gcboehm.c.v +++ b/vlib/builtin/builtin_d_gcboehm.c.v @@ -1,65 +1,73 @@ module builtin -$if freebsd { - // Tested on FreeBSD 13.0-RELEASE-p3, with clang, gcc and tcc: - #flag -DBUS_PAGE_FAULT=T_PAGEFLT - $if !tinyc { - #flag -DGC_THREADS=1 - #flag -DGC_BUILTIN_ATOMIC=1 - #flag @VEXEROOT/thirdparty/libgc/gc.o - #flag -lpthread - } -} $else { - #flag -DGC_THREADS=1 -} - -$if static_boehm ? { - $if macos { - #flag -I$first_existing("/opt/homebrew/include", "/usr/local/include") - #flag $first_existing("/opt/homebrew/lib/libgc.a", "/usr/local/lib/libgc.a") - } $else $if linux { - #flag -l:libgc.a - } $else $if openbsd { - #flag -I/usr/local/include - #flag /usr/local/lib/libgc.a - #flag -lpthread - } $else $if windows { - #flag -DGC_NOT_DLL=1 +$if dynamic_boehm ? { + $if windows { $if tinyc { #flag -I@VEXEROOT/thirdparty/libgc/include - #flag -L@VEXEROOT/thirdparty/libgc + #flag -L@VEXEROOT/thirdparty/tcc/lib #flag -lgc } $else $if msvc { #flag -DGC_BUILTIN_ATOMIC=1 #flag -I@VEXEROOT/thirdparty/libgc/include } $else { + #flag -DGC_WIN32_THREADS=1 #flag -DGC_BUILTIN_ATOMIC=1 #flag -I@VEXEROOT/thirdparty/libgc #flag @VEXEROOT/thirdparty/libgc/gc.o } } $else { - #flag -lgc + $if $pkgconfig('bdw-gc') { + #pkgconfig bdw-gc + } $else { + $if openbsd || freebsd { + #flag -I/usr/local/include + #flag -L/usr/local/lib + } + #flag -lgc + } } } $else { - $if macos { - #pkgconfig bdw-gc - } $else $if openbsd || freebsd { + #flag -DGC_THREADS=1 + #flag -DGC_BUILTIN_ATOMIC=1 + $if macos || linux { + #flag -DGC_PTHREADS=1 + #flag -I@VEXEROOT/thirdparty/libgc/include + #flag -lpthread -ldl + $if (prod && !tinyc && !debug) || !(amd64 || arm64 || i386 || arm32) { + // TODO: replace the architecture check with a `!$exists("@VEXEROOT/thirdparty/tcc/lib/libgc.a")` comptime call + #flag @VEXEROOT/thirdparty/libgc/gc.o + } $else { + #flag @VEXEROOT/thirdparty/tcc/lib/libgc.a + } + } $else $if freebsd { + // Tested on FreeBSD 13.0-RELEASE-p3, with clang, gcc and tcc: + #flag -DBUS_PAGE_FAULT=T_PAGEFLT + #flag -DGC_PTHREADS=1 + $if !tinyc { + #flag @VEXEROOT/thirdparty/libgc/gc.o + } $else { + #flag -I/usr/local/include + #flag $first_existing("/usr/local/lib/libgc.a", "/usr/lib/libgc.a") + } + #flag -lpthread + } $else $if openbsd { #flag -I/usr/local/include - #flag -L/usr/local/lib - } - $if windows { + #flag $first_existing("/usr/local/lib/libgc.a", "/usr/lib/libgc.a") + #flag -lpthread + } $else $if windows { $if tinyc { #flag -I@VEXEROOT/thirdparty/libgc/include - #flag -L@VEXEROOT/thirdparty/libgc + #flag -L@VEXEROOT/thirdparty/tcc/lib #flag -lgc - } $else $if msvc { - #flag -DGC_BUILTIN_ATOMIC=1 - #flag -I@VEXEROOT/thirdparty/libgc/include } $else { + #flag -DGC_NOT_DLL=1 + #flag -DGC_WIN32_THREADS=1 #flag -DGC_BUILTIN_ATOMIC=1 - #flag -I@VEXEROOT/thirdparty/libgc + #flag -I@VEXEROOT/thirdparty/libgc/include #flag @VEXEROOT/thirdparty/libgc/gc.o } + } $else $if $pkgconfig('bdw-gc') { + #pkgconfig bdw-gc } $else { #flag -lgc } @@ -85,7 +93,7 @@ fn C.GC_REALLOC(ptr voidptr, n usize) voidptr fn C.GC_FREE(ptr voidptr) -// explicitely perform garbage collection now! Garbage collections +// explicitly perform garbage collection now! Garbage collections // are done automatically when needed, so this function is hardly needed fn C.GC_gcollect() diff --git a/vlib/v/cflag/cflags.v b/vlib/v/cflag/cflags.v index c124e283b..c42b1b702 100644 --- a/vlib/v/cflag/cflags.v +++ b/vlib/v/cflag/cflags.v @@ -117,7 +117,7 @@ pub fn (cflags []CFlag) defines_others_libs() ([]string, []string, []string) { mut others := []string{} mut libs := []string{} for copt in copts_without_obj_files { - if copt.starts_with('-l') { + if copt.starts_with('-l') || copt.ends_with('.a') { libs << copt continue } -- 2.30.2