/* * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. * Copyright (c) 1996 by Silicon Graphics. All rights reserved. * Copyright (c) 2000-2004 Hewlett-Packard Development Company, L.P. * Copyright (c) 2009-2021 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 header is private to the gc. It is almost always included from * gc_priv.h. However it is possible to include it by itself if just the * configuration macros are needed. In that * case, a few declarations relying on types declared in gc_priv.h will be * omitted.
*/
#if !defined(sony_news) # include <stddef.h> /* For size_t, etc. */ #endif
/* Note: Only wrap our own declarations, and not the included headers. */ /* In this case, wrap our entire file, but temporarily unwrap/rewrap */ /* around #includes. Types and macros do not need such wrapping, only */ /* the declared global data and functions. */ #ifdef __cplusplus # define EXTERN_C_BEGIN extern"C" { # define EXTERN_C_END } /* extern "C" */ #else # define EXTERN_C_BEGIN /* empty */ # define EXTERN_C_END /* empty */ #endif
#ifdef LINT2 /* A macro (based on a tricky expression) to prevent false warnings */ /* like "Array compared to 0", "Comparison of identical expressions", */ /* "Untrusted loop bound" output by some static code analysis tools. */ /* The argument should not be a literal value. The result is */ /* converted to word type. (Actually, GC_word is used instead of */ /* word type as the latter might be undefined at the place of use.) */ # define COVERT_DATAFLOW(w) (~(GC_word)(w)^(~(GC_word)0)) #else # define COVERT_DATAFLOW(w) ((GC_word)(w)) #endif
/* Machine dependent parameters. Some tuning parameters can be found */ /* near the top of gc_private.h. */
/* Machine specific parts contributed by various people. See README file. */
#ifdefined(__ANDROID__) && !defined(HOST_ANDROID) /* __ANDROID__ macro is defined by Android NDK gcc. */ # define HOST_ANDROID 1 #endif
/* First a unified test for Linux: */ # if (defined(linux) || defined(__linux__) || defined(HOST_ANDROID)) \
&& !defined(LINUX) && !defined(__native_client__) # define LINUX # endif
/* And one for NetBSD: */ # ifdefined(__NetBSD__) # define NETBSD # endif
/* And one for OpenBSD: */ # ifdefined(__OpenBSD__) # define OPENBSD # endif
/* And one for FreeBSD: */ # if (defined(__FreeBSD__) || defined(__DragonFly__) \
|| defined(__FreeBSD_kernel__)) && !defined(FREEBSD) \
&& !defined(GC_NO_FREEBSD) /* Orbis compiler defines __FreeBSD__ */ # define FREEBSD # endif
/* And one for Darwin: */ # ifdefined(macosx) || (defined(__APPLE__) && defined(__MACH__)) # define DARWIN
EXTERN_C_END # include <TargetConditionals.h>
EXTERN_C_BEGIN # endif
/* Or manually define the machine type here. A machine type is */ /* characterized by the architecture. Some */ /* machine types are further subdivided by OS. */ /* Macros such as LINUX, FREEBSD, etc. distinguish them. */ /* SYSV on an M68K actually means A/UX. */ /* The distinction in these cases is usually the stack starting address */ # if !defined(mach_type_known) && !defined(CPPCHECK) # error The collector has not been ported to this machine/OS combination # endif /* Mapping is: M68K ==> Motorola 680X0 */ /* (NEXT, and SYSV (A/UX), */ /* MACOS and AMIGA variants) */ /* I386 ==> Intel 386 */ /* (SEQUENT, OS2, SCO, LINUX, NETBSD, */ /* FREEBSD, THREE86BSD, MSWIN32, */ /* BSDI, SOLARIS, NEXT and others) */ /* NS32K ==> Encore Multimax */ /* MIPS ==> R2000 through R14K */ /* (many variants) */ /* VAX ==> DEC VAX */ /* (BSD, ULTRIX variants) */ /* HP_PA ==> HP9000/700 & /800 */ /* HP/UX, LINUX */ /* SPARC ==> SPARC v7/v8/v9 */ /* (SOLARIS, LINUX, DRSNX variants) */ /* ALPHA ==> DEC Alpha */ /* (OSF1 and LINUX variants) */ /* LOONGARCH ==> Loongson LoongArch */ /* (LINUX 32- and 64-bit variants) */ /* M88K ==> Motorola 88XX0 */ /* (CX_UX and DGUX) */ /* S370 ==> 370-like machine */ /* running Amdahl UTS4 */ /* S390 ==> 390-like machine */ /* running LINUX */ /* AARCH64 ==> ARM AArch64 */ /* (LP64 and ILP32 variants) */ /* E2K ==> Elbrus 2000 */ /* running LINUX */ /* ARM32 ==> Intel StrongARM */ /* (many variants) */ /* IA64 ==> Intel IPF */ /* (e.g. Itanium) */ /* (LINUX and HPUX) */ /* SH ==> Hitachi SuperH */ /* (LINUX & MSWINCE) */ /* X86_64 ==> AMD x86-64 */ /* POWERPC ==> IBM/Apple PowerPC */ /* (MACOS(<=9),DARWIN(incl.MACOSX),*/ /* LINUX, NETBSD, AIX, NOSYS */ /* variants) */ /* Handles 32 and 64-bit variants. */ /* ARC ==> Synopsys ARC */ /* AVR32 ==> Atmel RISC 32-bit */ /* CRIS ==> Axis Etrax */ /* M32R ==> Renesas M32R */ /* NIOS2 ==> Altera NIOS2 */ /* HEXAGON ==> Qualcomm Hexagon */ /* OR1K ==> OpenRISC/or1k */ /* RISCV ==> RISC-V 32/64-bit */ /* TILEPRO ==> Tilera TILEPro */ /* TILEGX ==> Tilera TILE-Gx */
/* * For each architecture and OS, the following need to be defined: * * CPP_WORDSZ is a simple integer constant representing the word size. * in bits. We assume byte addressability, where a byte has 8 bits. * We also assume CPP_WORDSZ is either 32 or 64. * (We care about the length of pointers, not hardware * bus widths. Thus a 64 bit processor with a C compiler that uses * 32 bit pointers should use CPP_WORDSZ of 32, not 64. Default is 32.) * * MACH_TYPE is a string representation of the machine type. * OS_TYPE is analogous for the OS. * * ALIGNMENT is the largest N, such that * all pointer are guaranteed to be aligned on N byte boundaries. * defining it to be 1 will always work, but perform poorly. * * DATASTART is the beginning of the data segment. * On some platforms SEARCH_FOR_DATA_START is defined. * The latter will cause GC_data_start to * be set to an address determined by accessing data backwards from _end * until an unmapped page is found. DATASTART will be defined to be * GC_data_start. * On UNIX-like systems, the collector will scan the area between DATASTART * and DATAEND for root pointers. * * DATAEND, if not "end", where "end" is defined as "extern int end[]". * RTH suggests gaining access to linker script synth'd values with * this idiom instead of "&end", where "end" is defined as "extern int end". * Otherwise, "GCC will assume these are in .sdata/.sbss" and it will, e.g., * cause failures on alpha*-*-* with -msmall-data or -fpic or mips-*-* * without any special options. * * STACKBOTTOM is the cold end of the stack, which is usually the * highest address in the stack. * Under PCR or OS/2, we have other ways of finding thread stacks. * For each machine, the following should: * 1) define STACK_GROWS_UP if the stack grows toward higher addresses, and * 2) define exactly one of * STACKBOTTOM (should be defined to be an expression) * LINUX_STACKBOTTOM * HEURISTIC1 * HEURISTIC2 * If STACKBOTTOM is defined, then its value will be used directly (as the * stack bottom). If LINUX_STACKBOTTOM is defined, then it will be determined * with a method appropriate for most Linux systems. Currently we look * first for __libc_stack_end (currently only if USE_LIBC_PRIVATES is * defined), and if that fails read it from /proc. (If USE_LIBC_PRIVATES * is not defined and NO_PROC_STAT is defined, we revert to HEURISTIC2.) * If either of the last two macros are defined, then STACKBOTTOM is computed * during collector startup using one of the following two heuristics: * HEURISTIC1: Take an address inside GC_init's frame, and round it up to * the next multiple of STACK_GRAN. * HEURISTIC2: Take an address inside GC_init's frame, increment it repeatedly * in small steps (decrement if STACK_GROWS_UP), and read the value * at each location. Remember the value when the first * Segmentation violation or Bus error is signaled. Round that * to the nearest plausible page boundary, and use that instead * of STACKBOTTOM. * * Gustavo Rodriguez-Rivera points out that on most (all?) Unix machines, * the value of environ is a pointer that can serve as STACKBOTTOM. * I expect that HEURISTIC2 can be replaced by this approach, which * interferes far less with debugging. However it has the disadvantage * that it's confused by a putenv call before the collector is initialized. * This could be dealt with by intercepting putenv ... * * If no expression for STACKBOTTOM can be found, and neither of the above * heuristics are usable, the collector can still be used with all of the above * undefined, provided one of the following is done: * 1) GC_mark_roots can be changed to somehow mark from the correct stack(s) * without reference to STACKBOTTOM. This is appropriate for use in * conjunction with thread packages, since there will be multiple stacks. * (Allocating thread stacks in the heap, and treating them as ordinary * heap data objects is also possible as a last resort. However, this is * likely to introduce significant amounts of excess storage retention * unless the dead parts of the thread stacks are periodically cleared.) * 2) Client code may set GC_stackbottom before calling any GC_ routines. * If the author of the client code controls the main program, this is * easily accomplished by introducing a new main program, setting * GC_stackbottom to the address of a local variable, and then calling * the original main program. The new main program would read something * like (provided real_main() is not inlined by the compiler): * * #include "gc.h" * * main(argc, argv, envp) * int argc; * char **argv, **envp; * { * volatile int dummy; * * GC_stackbottom = (ptr_t)(&dummy); * return(real_main(argc, argv, envp)); * } * * * Each architecture may also define the style of virtual dirty bit * implementation to be used: * GWW_VDB: Use win32 GetWriteWatch primitive. * MPROTECT_VDB: Write protect the heap and catch faults. * PROC_VDB: Use the SVR4 /proc primitives to read dirty bits. * SOFT_VDB: Use the Linux /proc primitives to track dirty bits. * * The first and second one may be combined, in which case a runtime * selection will be made, based on GetWriteWatch availability. * * An architecture may define DYNAMIC_LOADING if dyn_load.c * defined GC_register_dynamic_libraries() for the architecture. * * An architecture may define PREFETCH(x) to preload the cache with *x. * This defaults to GCC built-in operation (or a no-op for other compilers). * * GC_PREFETCH_FOR_WRITE(x) is used if *x is about to be written. * * An architecture may also define CLEAR_DOUBLE(x) to be a fast way to * clear the two words at GC_malloc-aligned address x. By default, * word stores of 0 are used instead. * * HEAP_START may be defined as the initial address hint for mmap-based * allocation.
*/
/* If available, we can use __builtin_unwind_init() to push the */ /* relevant registers onto the stack. */ # if GC_GNUC_PREREQ(2, 8) \
&& !GC_GNUC_PREREQ(11, 0) /* broken at least in 11.2.0 on cygwin64 */ \
&& !defined(__INTEL_COMPILER) && !defined(__PATHCC__) \
&& !defined(__FUJITSU) /* for FX10 system */ \
&& !(defined(POWERPC) && defined(DARWIN)) /* for MacOS X 10.3.9 */ \
&& !defined(E2K) && !defined(RTEMS) \
&& !defined(__ARMCC_VERSION) /* does not exist in armcc gnu emu */ \
&& (!defined(__clang__) \
|| GC_CLANG_PREREQ(8, 0) /* was no-op in clang-3 at least */) # define HAVE_BUILTIN_UNWIND_INIT # endif
/* The common OS-specific definitions (should be applicable to */ /* all (or most, at least) supported architectures). */
# ifdef DARWIN # define OS_TYPE "DARWIN" # define DYNAMIC_LOADING /* TODO: see get_end(3), get_etext() and get_end() should not be used. */ /* These aren't used when dyld support is enabled (it is by default). */ # define DATASTART ((ptr_t)get_etext()) # define DATAEND ((ptr_t)get_end()) # define USE_MMAP_ANON
EXTERN_C_END # include <unistd.h>
EXTERN_C_BEGIN # define GETPAGESIZE() (unsigned)getpagesize() /* There seems to be some issues with trylock hanging on darwin. */ /* TODO: This should be looked into some more. */ # define NO_PTHREAD_TRYLOCK # endif /* DARWIN */
# ifdef SOLARIS # define OS_TYPE "SOLARIS" externint _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 /* Otherwise we now use calloc. Mmap may result in the */ /* heap interleaved with thread stacks, which can result in */ /* excessive blacklisting. Sbrk is unusable since it */ /* doesn't interact correctly with the system malloc. */ # 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 /* Define STACKBOTTOM as (ptr_t)_start worked through 2.7, */ /* but reportedly breaks under 2.8. It appears that the stack */ /* base is a property of the executable, so this should not */ /* break old executables. */ /* HEURISTIC1 reportedly no longer works under Solaris 2.7. */ /* HEURISTIC2 probably works, but this appears to be preferable.*/ /* Apparently USRSTACK is defined to be USERLIMIT, but in some */ /* installations that's undefined. We work around this with a */ /* gross hack: */
EXTERN_C_END # include <sys/vmparam.h> # include <unistd.h>
EXTERN_C_BEGIN # ifdef USERLIMIT /* This should work everywhere, but doesn't. */ # define STACKBOTTOM ((ptr_t)USRSTACK) # else # define HEURISTIC2 # endif # endif /* SOLARIS */
# ifdef VAX # define MACH_TYPE "VAX" # define ALIGNMENT 4 /* Pointers are longword aligned by 4.2 C compiler */ externchar etext[]; # define DATASTART ((ptr_t)(etext)) # ifdef BSD # define OS_TYPE "BSD" # define HEURISTIC1 /* HEURISTIC2 may be OK, but it's hard to test. */ # endif # ifdef ULTRIX # define OS_TYPE "ULTRIX" # define STACKBOTTOM ((ptr_t)0x7fffc800) # endif # endif
# ifdef SPARC # define MACH_TYPE "SPARC" # ifdefined(__arch64__) || defined(__sparcv9) # define ALIGNMENT 8 # define CPP_WORDSZ 64 # define ELF_CLASS ELFCLASS64 # else # define ALIGNMENT 4 /* Required by hardware */ # define CPP_WORDSZ 32 # endif /* Don't define USE_ASM_PUSH_REGS. We do use an asm helper, but */ /* not to push the registers on the mark stack. */ # ifdef SOLARIS # define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)_etext) # define PROC_VDB # define GETPAGESIZE() (unsigned)sysconf(_SC_PAGESIZE) /* getpagesize() appeared to be missing from at least */ /* one Solaris 5.4 installation. Weird. */ # endif # ifdef DRSNX # define OS_TYPE "DRSNX" externint 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 # if !defined(__ELF__) && !defined(CPPCHECK) # error Linux SPARC a.out not supported # endif # define SVR4 externint _etext[];
ptr_t GC_SysVGetDataStart(size_t, ptr_t); # ifdef __arch64__ # define DATASTART GC_SysVGetDataStart(0x100000, (ptr_t)_etext) # else # define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)_etext) # endif # define DATASTART_IS_FUNC # endif # ifdef OPENBSD /* Nothing specific. */ # endif # ifdef NETBSD /* Nothing specific. */ # endif # ifdef FREEBSD externchar etext[]; externchar edata[]; # if !defined(CPPCHECK) externchar end[]; # endif # define NEED_FIND_LIMIT # define DATASTART ((ptr_t)(&etext)) void * GC_find_limit(void *, int); # define DATAEND (ptr_t)GC_find_limit(DATASTART, TRUE) # define DATAEND_IS_FUNC # define GC_HAVE_DATAREGION2 # define DATASTART2 ((ptr_t)(&edata)) # define DATAEND2 ((ptr_t)(&end)) # endif # endif
# ifdef I386 # define MACH_TYPE "I386" # if (defined(__LP64__) || defined(_WIN64)) && !defined(CPPCHECK) # error This should be handled as X86_64 # else # define CPP_WORDSZ 32 # define ALIGNMENT 4 /* Appears to hold for all "32 bit" compilers */ /* except Borland. The -a4 option fixes */ /* Borland. For Watcom the option is -zp4. */ # endif # ifdef SEQUENT # define OS_TYPE "SEQUENT" externint etext[]; # define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff)) # define STACKBOTTOM ((ptr_t)0x3ffff000) # endif # ifdef EMSCRIPTEN # define OS_TYPE "EMSCRIPTEN" # define DATASTART (ptr_t)ALIGNMENT # define DATAEND (ptr_t)ALIGNMENT # define USE_MMAP_ANON /* avoid /dev/zero, not supported */ # define STACK_GROWS_DOWN # endif # ifdefined(__QNX__) # define OS_TYPE "QNX" # define SA_RESTART 0 # define HEURISTIC1 externchar etext[]; externint _end[]; # define DATASTART ((ptr_t)etext) # define DATAEND ((ptr_t)_end) # endif # ifdef HAIKU externint etext[]; # define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff)) # endif # ifdef SOLARIS # define DATASTART GC_SysVGetDataStart(0x1000, (ptr_t)_etext) /* At least in Solaris 2.5, PROC_VDB gives wrong values for */ /* dirty bits. It appears to be fixed in 2.8 and 2.9. */ # ifdef SOLARIS25_PROC_VDB_BUG_FIXED # define PROC_VDB # endif # endif # ifdef SCO # define OS_TYPE "SCO" externint 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" externint etext[]; # define DATASTART ((ptr_t)(etext)) # define STACKBOTTOM ((ptr_t)0x08048000) # define DYNAMIC_LOADING # define ELF_CLASS ELFCLASS32 # endif # ifdef DGUX # define OS_TYPE "DGUX" externint _etext, _end;
ptr_t GC_SysVGetDataStart(size_t, ptr_t); # define DATASTART GC_SysVGetDataStart(0x1000, (ptr_t)(&_etext)) # define DATASTART_IS_FUNC # define DATAEND ((ptr_t)(&_end)) # define STACK_GROWS_DOWN # define HEURISTIC2
EXTERN_C_END # include <unistd.h>
EXTERN_C_BEGIN # define GETPAGESIZE() (unsigned)sysconf(_SC_PAGESIZE) # define DYNAMIC_LOADING # ifndef USE_MMAP # define USE_MMAP 1 # endif # define MAP_FAILED (void *) ((word)-1) # define HEAP_START (ptr_t)0x40000000 # endif /* DGUX */ # ifdef LINUX # if !defined(REDIRECT_MALLOC) # define MPROTECT_VDB # else /* We seem to get random errors in the incremental mode, */ /* possibly because the Linux threads implementation */ /* itself is a malloc client and cannot deal with the */ /* signals. fread() uses malloc too. */ # endif # define HEAP_START (ptr_t)0x1000 /* This encourages mmap to give us low addresses, */ /* thus allowing the heap to grow to ~3 GB. */ # ifdef __ELF__ # ifdefined(__GLIBC__) && __GLIBC__ >= 2 \
|| defined(HOST_ANDROID) || defined(HOST_TIZEN) # define SEARCH_FOR_DATA_START # else externchar **__environ; # define DATASTART ((ptr_t)(&__environ)) /* hideous kludge: __environ is the first */ /* word in crt0.o, and delimits the start */ /* of the data segment, no matter which */ /* ld options were passed through. */ /* We could use _etext instead, but that */ /* would include .rodata, which may */ /* contain large read-only data tables */ /* that we'd rather not scan. */ # endif # if !defined(GC_NO_SIGSETJMP) && (defined(HOST_TIZEN) \
|| (defined(HOST_ANDROID) \
&& !(GC_GNUC_PREREQ(4, 8) || GC_CLANG_PREREQ(3, 2) \
|| __ANDROID_API__ >= 18))) /* Older Android NDK releases lack sigsetjmp in x86 libc */ /* (setjmp is used instead to find data_start). The bug */ /* is fixed in Android NDK r8e (so, ok to use sigsetjmp */ /* if gcc4.8+, clang3.2+ or Android API level 18+). */ # define GC_NO_SIGSETJMP 1 # endif # else externint etext[]; # define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff)) # endif # ifdef USE_I686_PREFETCH # define PREFETCH(x) \
__asm__ __volatile__ ("prefetchnta %0" : : "m"(*(char *)(x))) /* Empirically prefetcht0 is much more effective at reducing */ /* cache miss stalls for the targeted load instructions. But it */ /* seems to interfere enough with other cache traffic that the */ /* net result is worse than prefetchnta. */ # ifdef FORCE_WRITE_PREFETCH /* Using prefetches for write seems to have a slight negative */ /* impact on performance, at least for a PIII/500. */ # define GC_PREFETCH_FOR_WRITE(x) \
__asm__ __volatile__ ("prefetcht0 %0" : : "m"(*(char *)(x))) # else # define GC_NO_PREFETCH_FOR_WRITE # endif # elif defined(USE_3DNOW_PREFETCH) # define PREFETCH(x) \
__asm__ __volatile__ ("prefetch %0" : : "m"(*(char *)(x))) # define GC_PREFETCH_FOR_WRITE(x) \
__asm__ __volatile__ ("prefetchw %0" : : "m"(*(char *)(x))) # endif # ifdefined(__GLIBC__) && !defined(__UCLIBC__) \
&& !defined(GLIBC_TSX_BUG_FIXED) /* Workaround lock elision implementation for some glibc. */ # define GLIBC_2_19_TSX_BUG
EXTERN_C_END # include <gnu/libc-version.h> /* for gnu_get_libc_version() */
EXTERN_C_BEGIN # endif # ifndef SOFT_VDB # define SOFT_VDB # endif # endif # ifdef CYGWIN32 # define WOW64_THREAD_CONTEXT_WORKAROUND # define DATASTART ((ptr_t)GC_DATASTART) /* From gc.h */ # define DATAEND ((ptr_t)GC_DATAEND) # ifndef USE_WINALLOC # /* MPROTECT_VDB does not work, it leads to a spurious exit. */ # ifdef USE_MMAP # define NEED_FIND_LIMIT # endif # endif # endif # ifdef INTERIX # define OS_TYPE "INTERIX" externint _data_start__[]; externint _bss_end__[]; # define DATASTART ((ptr_t)_data_start__) # define DATAEND ((ptr_t)_bss_end__) # define STACKBOTTOM ({ ptr_t rv; \
__asm__ __volatile__ ("movl %%fs:4, %%eax" \
: "=a" (rv)); \
rv; }) # define USE_MMAP_ANON # endif # ifdef OS2 # define OS_TYPE "OS2" /* STACKBOTTOM and DATASTART are handled specially in */ /* os_dep.c. OS2 actually has the right */ /* system call! */ # define DATAEND /* not needed */ # endif # ifdef MSWIN32 # define WOW64_THREAD_CONTEXT_WORKAROUND # define RETRY_GET_THREAD_CONTEXT # define MPROTECT_VDB # endif # ifdef MSWINCE /* Nothing specific. */ # endif # ifdef DJGPP # define OS_TYPE "DJGPP"
EXTERN_C_END # include "stubinfo.h"
EXTERN_C_BEGIN externint etext[]; externint _stklen; externint __djgpp_stack_limit; # define DATASTART ((ptr_t)((((word)(etext)) + 0x1ff) & ~0x1ff)) /* #define STACKBOTTOM ((ptr_t)((word)_stubinfo+_stubinfo->size+_stklen)) */ # define STACKBOTTOM ((ptr_t)((word)__djgpp_stack_limit + _stklen)) /* This may not be right. */ # endif # ifdef OPENBSD /* Nothing specific. */ # endif # ifdef FREEBSD # ifdef __GLIBC__ externint _end[]; # define DATAEND ((ptr_t)(_end)) # endif # endif # ifdef NETBSD /* Nothing specific. */ # endif # ifdef THREE86BSD # define OS_TYPE "THREE86BSD" # define HEURISTIC2 externchar etext[]; # define DATASTART ((ptr_t)(etext)) # endif # ifdef BSDI # define OS_TYPE "BSDI" # define HEURISTIC2 externchar etext[]; # define DATASTART ((ptr_t)(etext)) # endif # ifdef NEXT # define STACKBOTTOM ((ptr_t)0xc0000000) # endif # ifdef RTEMS # define OS_TYPE "RTEMS"
EXTERN_C_END # include <sys/unistd.h>
EXTERN_C_BEGIN externint etext[]; void *rtems_get_stack_bottom(void); # define InitStackBottom rtems_get_stack_bottom() # define DATASTART ((ptr_t)etext) # define STACKBOTTOM ((ptr_t)InitStackBottom) # endif # ifdef DOS4GW # define OS_TYPE "DOS4GW" externlong __nullarea; externchar _end; externchar *_STACKTOP; /* Depending on calling conventions Watcom C either precedes */ /* or does not precedes with underscore names of C-variables. */ /* Make sure startup code variables always have the same names. */ #pragma aux __nullarea "*"; #pragma aux _end "*"; # define STACKBOTTOM ((ptr_t)_STACKTOP) /* confused? me too. */ # define DATASTART ((ptr_t)(&__nullarea)) # define DATAEND ((ptr_t)(&_end)) # endif # ifdef HURD # define OS_TYPE "HURD" # define STACK_GROWS_DOWN # define HEURISTIC2 # define SEARCH_FOR_DATA_START externint _end[]; # define DATAEND ((ptr_t)(_end)) /* # define MPROTECT_VDB Not quite working yet? */ # define DYNAMIC_LOADING # define USE_MMAP_ANON # endif # ifdef DARWIN # define DARWIN_DONT_PARSE_STACK 1 # define STACKBOTTOM ((ptr_t)0xc0000000) # define MPROTECT_VDB # if TARGET_OS_IPHONE && !defined(NO_DYLD_BIND_FULLY_IMAGE) /* iPhone/iPad simulator */ # define NO_DYLD_BIND_FULLY_IMAGE # endif # endif /* DARWIN */ # endif
# ifdef NS32K # define MACH_TYPE "NS32K" # define ALIGNMENT 4 externchar **environ; # define DATASTART ((ptr_t)(&environ)) /* hideous kludge: environ is the first */ /* word in crt0.o, and delimits the start */ /* of the data segment, no matter which */ /* ld options were passed through. */ # define STACKBOTTOM ((ptr_t)0xfffff000) /* for Encore */ # endif
# ifdef HP_PA # define MACH_TYPE "HP_PA" # ifdef __LP64__ # define CPP_WORDSZ 64 # define ALIGNMENT 8 # else # define CPP_WORDSZ 32 # define ALIGNMENT 4 # endif # define STACK_GROWS_UP # ifdef HPUX # ifndef GC_THREADS # define MPROTECT_VDB # endif # ifdef USE_HPUX_FIXED_STACKBOTTOM /* The following appears to work for 7xx systems running HP/UX */ /* 9.xx. Furthermore, it might result in much faster */ /* collections than HEURISTIC2, which may involve scanning */ /* segments that directly precede the stack. It is not the */ /* default, since it may not work on older machine/OS */ /* combinations. (Thanks to Raymond X.T. Nijssen for uncovering */ /* this.) */ /* This technique also doesn't work with HP/UX 11.xx. The */ /* stack size is settable using the kernel maxssiz variable, */ /* and in 11.23 and latter, the size can be set dynamically. */ /* It also doesn't handle SHMEM_MAGIC binaries which have */ /* stack and data in the first quadrant. */ # define STACKBOTTOM ((ptr_t)0x7b033000) /* from /etc/conf/h/param.h */ # elif defined(USE_ENVIRON_POINTER) /* Gustavo Rodriguez-Rivera suggested changing HEURISTIC2 */ /* to this. Note that the GC must be initialized before the */ /* first putenv call. Unfortunately, some clients do not obey. */ externchar ** environ; # define STACKBOTTOM ((ptr_t)environ) # elif !defined(HEURISTIC2) /* This uses pst_vm_status support. */ # define HPUX_MAIN_STACKBOTTOM # define NEED_FIND_LIMIT # endif # ifndef __GNUC__ # define PREFETCH(x) do { \ registerlong addr = (long)(x); \
(void) _asm ("LDW", 0, 0, addr, 0); \
} while (0) # endif # endif /* HPUX */ # ifdef LINUX # define SEARCH_FOR_DATA_START # endif # ifdef OPENBSD /* Nothing specific. */ # endif # endif /* HP_PA */
# ifdef ALPHA # define MACH_TYPE "ALPHA" # define ALIGNMENT 8 # define CPP_WORDSZ 64 # ifdef NETBSD # define ELFCLASS32 32 # define ELFCLASS64 64 # define ELF_CLASS ELFCLASS64 # endif # ifdef OPENBSD /* Nothing specific. */ # endif # ifdef FREEBSD /* MPROTECT_VDB is not yet supported at all on FreeBSD/alpha. */ /* Handle unmapped hole alpha*-*-freebsd[45]* puts between etext and edata. */ externchar etext[]; externchar edata[]; # if !defined(CPPCHECK) externchar end[]; # endif # define NEED_FIND_LIMIT # define DATASTART ((ptr_t)(&etext)) void * GC_find_limit(void *, int); # define DATAEND (ptr_t)GC_find_limit(DATASTART, TRUE) # define DATAEND_IS_FUNC # define GC_HAVE_DATAREGION2 # define DATASTART2 ((ptr_t)(&edata)) # define DATAEND2 ((ptr_t)(&end)) # endif # ifdef OSF1 # define OS_TYPE "OSF1" # define DATASTART ((ptr_t)0x140000000) externint _end[]; # define DATAEND ((ptr_t)(&_end)) externchar ** environ;
EXTERN_C_END # include <unistd.h>
EXTERN_C_BEGIN /* round up from the value of environ to the nearest page boundary */ /* Probably breaks if putenv is called before collector */ /* initialization. */ # define STACKBOTTOM ((ptr_t)(((word)(environ) | (getpagesize()-1))+1)) /* # define HEURISTIC2 */ /* Normally HEURISTIC2 is too conservative, since */ /* the text segment immediately follows the stack. */ /* Hence we give an upper pound. */ /* This is currently unused, since we disabled HEURISTIC2 */ externint __start[]; # define HEURISTIC2_LIMIT ((ptr_t)((word)(__start) & ~(getpagesize()-1))) # ifndef GC_OSF1_THREADS /* Unresolved signal issues with threads. */ # define MPROTECT_VDB # endif # define DYNAMIC_LOADING # endif # ifdef LINUX # ifdef __ELF__ # define SEARCH_FOR_DATA_START # else # define DATASTART ((ptr_t)0x140000000) externint _end[]; # define DATAEND ((ptr_t)(_end)) # endif # if !defined(REDIRECT_MALLOC) # define MPROTECT_VDB /* Has only been superficially tested. May not */ /* work on all versions. */ # endif # endif # endif /* ALPHA */
# ifdef IA64 # define MACH_TYPE "IA64" # ifdef HPUX # ifdef _ILP32 # define CPP_WORDSZ 32 /* Requires 8 byte alignment for malloc */ # define ALIGNMENT 4 # else # if !defined(_LP64) && !defined(CPPCHECK) # error Unknown ABI # endif # define CPP_WORDSZ 64 /* Requires 16 byte alignment for malloc */ # define ALIGNMENT 8 # endif /* Note that the GC must be initialized before the 1st putenv call. */ externchar ** environ; # define STACKBOTTOM ((ptr_t)environ) # define HPUX_STACKBOTTOM /* The following was empirically determined, and is probably */ /* not very robust. */ /* Note that the backing store base seems to be at a nice */ /* address minus one page. */ # define BACKING_STORE_DISPLACEMENT 0x1000000 # define BACKING_STORE_ALIGNMENT 0x1000 extern ptr_t GC_register_stackbottom; # define BACKING_STORE_BASE GC_register_stackbottom /* Known to be wrong for recent HP/UX versions!!! */ # endif # ifdef LINUX # define CPP_WORDSZ 64 # define ALIGNMENT 8 /* The following works on NUE and older kernels: */ /* define STACKBOTTOM ((ptr_t)0xa000000000000000l) */ /* TODO: LINUX_STACKBOTTOM does not work on NUE. */ /* We also need the base address of the register stack */ /* backing store. */ extern ptr_t GC_register_stackbottom; # define BACKING_STORE_BASE GC_register_stackbottom # define SEARCH_FOR_DATA_START # ifdef __GNUC__ # define DYNAMIC_LOADING # else /* In the Intel compiler environment, we seem to end up with */ /* statically linked executables and an undefined reference */ /* to _DYNAMIC */ # endif # if !defined(REDIRECT_MALLOC) # define MPROTECT_VDB /* Requires Linux 2.3.47 or later. */ # endif # ifdef __GNUC__ # ifndef __INTEL_COMPILER # define PREFETCH(x) \
__asm__ (" lfetch [%0]": : "r"(x)) # define GC_PREFETCH_FOR_WRITE(x) \
__asm__ (" lfetch.excl [%0]": : "r"(x)) # define CLEAR_DOUBLE(x) \
__asm__ (" stf.spill [%0]=f0": : "r"((void *)(x))) # else
EXTERN_C_END # include <ia64intrin.h>
EXTERN_C_BEGIN # define PREFETCH(x) __lfetch(__lfhint_none, (x)) # define GC_PREFETCH_FOR_WRITE(x) __lfetch(__lfhint_nta, (x)) # define CLEAR_DOUBLE(x) __stf_spill((void *)(x), 0) # endif /* __INTEL_COMPILER */ # endif # endif # ifdef MSWIN32 /* FIXME: This is a very partial guess. There is no port, yet. */ # ifdefined(_WIN64) # define CPP_WORDSZ 64 # else # define CPP_WORDSZ 32 /* Is this possible? */ # endif # define ALIGNMENT 8 # endif # endif
#ifdefined(LINUX_STACKBOTTOM) && defined(NO_PROC_STAT) \
&& !defined(USE_LIBC_PRIVATES) /* This combination will fail, since we have no way to get */ /* the stack bottom. Use HEURISTIC2 instead. */ # undef LINUX_STACKBOTTOM # define HEURISTIC2 /* This may still fail on some architectures like IA64. */ /* We tried ... */ #endif
#ifdefined(USE_MMAP_ANON) && !defined(USE_MMAP) # define USE_MMAP 1 #elif (defined(LINUX) || defined(OPENBSD)) && defined(USE_MMAP) /* The kernel may do a somewhat better job merging mappings etc. */ /* with anonymous mappings. */ # define USE_MMAP_ANON #endif
#ifdefined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC) \
&& !defined(USE_PROC_FOR_LIBRARIES) /* Nptl allocates thread stacks with mmap, which is fine. But it */ /* keeps a cache of thread stacks. Thread stacks contain the */ /* thread control blocks. These in turn contain a pointer to */ /* (sizeof (void *) from the beginning of) the dtv for thread-local */ /* storage, which is calloc allocated. If we don't scan the cached */ /* thread stacks, we appear to lose the dtv. This tends to */ /* result in something that looks like a bogus dtv count, which */ /* tends to result in a memset call on a block that is way too */ /* large. Sometimes we're lucky and the process just dies ... */ /* There seems to be a similar issue with some other memory */ /* allocated by the dynamic loader. */ /* This should be avoidable by either: */ /* - Defining USE_PROC_FOR_LIBRARIES here. */ /* That performs very poorly, precisely because we end up */ /* scanning cached stacks. */ /* - Have calloc look at its callers. */ /* In spite of the fact that it is gross and disgusting. */ /* In fact neither seems to suffice, probably in part because */ /* even with USE_PROC_FOR_LIBRARIES, we don't scan parts of stack */ /* segments that appear to be out of bounds. Thus we actually */ /* do both, which seems to yield the best results. */ # define USE_PROC_FOR_LIBRARIES #endif
#ifdefined(SOLARIS) || defined(DRSNX) /* OS has SOLARIS style semi-undocumented interface */ /* to dynamic loader. */ # define SOLARISDL /* OS has SOLARIS style signal handlers. */ # define SUNOS5SIGS #endif
#if !defined(NO_MARKER_SPECIAL_SIGMASK) \
&& (defined(NACL) || defined(GC_WIN32_PTHREADS)) /* Either there is no pthread_sigmask(), or GC marker thread cannot */ /* steal and drop user signal calls. */ # define NO_MARKER_SPECIAL_SIGMASK #endif
#ifdef GC_NETBSD_THREADS # define SIGRTMIN 33 # define SIGRTMAX 63 /* It seems to be necessary to wait until threads have restarted. */ /* But it is unclear why that is the case. */ # define GC_NETBSD_THREADS_WORKAROUND #endif
#ifdef GC_OPENBSD_THREADS
EXTERN_C_END # include <sys/param.h>
EXTERN_C_BEGIN /* Prior to 5.2 release, OpenBSD had user threads and required */ /* special handling. */ # if OpenBSD < 201211 # define GC_OPENBSD_UTHREADS 1 # endif #endif/* GC_OPENBSD_THREADS */
/* Xbox One (DURANGO) may not need to be this aggressive, but the */ /* default is likely too lax under heavy allocation pressure. */ /* The platform does not have a virtual paging system, so it does not */ /* have a large virtual address space that a standard x64 platform has. */ #ifdefined(USE_MUNMAP) && !defined(MUNMAP_THRESHOLD) \
&& (defined(SN_TARGET_PS3) \
|| defined(SN_TARGET_PSP2) || defined(MSWIN_XBOX1)) # define MUNMAP_THRESHOLD 2 #endif
#ifdefined(USE_MUNMAP) && defined(COUNT_UNMAPPED_REGIONS) \
&& !defined(GC_UNMAPPED_REGIONS_SOFT_LIMIT) /* The default limit of vm.max_map_count on Linux is ~65530. */ /* There is approximately one mapped region to every unmapped region. */ /* Therefore if we aim to use up to half of vm.max_map_count for the */ /* GC (leaving half for the rest of the process) then the number of */ /* unmapped regions should be one quarter of vm.max_map_count. */ # ifdefined(__DragonFly__) # define GC_UNMAPPED_REGIONS_SOFT_LIMIT (1000000 / 4) # else # define GC_UNMAPPED_REGIONS_SOFT_LIMIT 16384 # endif #endif
#ifdefined(BASE_ATOMIC_OPS_EMULATED) /* GC_write_fault_handler() cannot use lock-based atomic primitives */ /* as this could lead to a deadlock. */ # undef MPROTECT_VDB #endif
#ifdefined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS) /* Incremental GC based on mprotect is incompatible with /proc roots. */ # undef MPROTECT_VDB #endif
#ifdefined(LINUX) || defined(HURD) || defined(__GLIBC__) # define REGISTER_LIBRARIES_EARLY /* We sometimes use dl_iterate_phdr, which may acquire an internal */ /* lock. This isn't safe after the world has stopped. So we must */ /* call GC_register_dynamic_libraries before stopping the world. */ /* For performance reasons, this may be beneficial on other */ /* platforms as well, though it should be avoided in win32. */ #endif/* LINUX */
#ifdefined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC) \
&& !defined(INCLUDE_LINUX_THREAD_DESCR) /* Will not work, since libc and the dynamic loader use thread */ /* locals, sometimes as the only reference. */ # define INCLUDE_LINUX_THREAD_DESCR #endif
#if (((defined(MSWIN32) || defined(MSWINCE)) && !defined(__GNUC__)) \
|| (defined(MSWIN32) && defined(I386)) /* for Win98 */ \
|| (defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS))) \
&& !defined(NO_CRT) && !defined(NO_WRAP_MARK_SOME) /* Under rare conditions, we may end up marking from nonexistent */ /* memory. Hence we need to be prepared to recover by running */ /* GC_mark_some with a suitable handler in place. */ /* TODO: Probably replace __GNUC__ above with ndef GC_PTHREADS. */ /* FIXME: Should we really need it for WinCE? If yes then */ /* WRAP_MARK_SOME should be also defined for CeGCC which requires */ /* CPU/OS-specific code in mark_ex_handler and GC_mark_some (for */ /* manual stack unwinding and exception handler installation). */ # define WRAP_MARK_SOME #endif
#ifdefined(PARALLEL_MARK) && !defined(DEFAULT_STACK_MAYBE_SMALL) \
&& (defined(HPUX) || defined(GC_DGUX386_THREADS) \
|| defined(NO_GETCONTEXT) /* e.g. musl */) /* TODO: Test default stack size in configure. */ # define DEFAULT_STACK_MAYBE_SMALL #endif
#ifdef PARALLEL_MARK /* The minimum stack size for a marker thread. */ # define MIN_STACK_SIZE (8 * HBLKSIZE * sizeof(word)) #endif
#ifdefined(HOST_ANDROID) && !defined(THREADS) \
&& !defined(USE_GET_STACKBASE_FOR_MAIN) /* Always use pthread_attr_getstack on Android ("-lpthread" option is */ /* not needed to be specified manually) since GC_linux_main_stack_base */ /* causes app crash if invoked inside Dalvik VM. */ # define USE_GET_STACKBASE_FOR_MAIN #endif
#ifdefined(UNIX_LIKE) && defined(THREADS) && !defined(NO_CANCEL_SAFE) \
&& !defined(HOST_ANDROID) /* Make the code cancellation-safe. This basically means that we */ /* ensure that cancellation requests are ignored while we are in */ /* the collector. This applies only to Posix deferred cancellation; */ /* we don't handle Posix asynchronous cancellation. */ /* Note that this only works if pthread_setcancelstate is */ /* async-signal-safe, at least in the absence of asynchronous */ /* cancellation. This appears to be true for the glibc version, */ /* though it is not documented. Without that assumption, there */ /* seems to be no way to safely wait in a signal handler, which */ /* we need to do for thread suspension. */ /* Also note that little other code appears to be cancellation-safe. */ /* Hence it may make sense to turn this off for performance. */ # define CANCEL_SAFE #endif
#if !defined(MSGBOX_ON_ERROR) && !defined(NO_MSGBOX_ON_ERROR) \
&& !defined(SMALL_CONFIG) && defined(MSWIN32) \
&& !defined(MSWINRT_FLAVOR) && !defined(MSWIN_XBOX1) /* Show Windows message box with "OK" button on a GC fatal error. */ /* Client application is terminated once the user clicks the button. */ # define MSGBOX_ON_ERROR #endif
#ifdefined(SPARC) # define ASM_CLEAR_CODE /* Stack clearing is crucial, and we */ /* include assembly code to do it well. */ #endif
/* Can we save call chain in objects for debugging? */ /* SET NFRAMES (# of saved frames) and NARGS (#of args for each */ /* frame) to reasonable values for the platform. */ /* Set SAVE_CALL_CHAIN if we can. SAVE_CALL_COUNT can be specified */ /* at build time, though we feel free to adjust it slightly. */ /* Define NEED_CALLINFO if we either save the call stack or */ /* GC_ADD_CALLER is defined. */ /* GC_CAN_SAVE_CALL_STACKS is set in gc.h. */ #ifdefined(SPARC) # define CAN_SAVE_CALL_ARGS #endif #if (defined(I386) || defined(X86_64)) \
&& (defined(LINUX) || defined(__GLIBC__)) /* SAVE_CALL_CHAIN is supported if the code is compiled to save */ /* frame pointers by default, i.e. no -fomit-frame-pointer flag. */ # define CAN_SAVE_CALL_ARGS #endif
#ifdefined(SAVE_CALL_COUNT) && !defined(GC_ADD_CALLER) \
&& defined(GC_CAN_SAVE_CALL_STACKS) # define SAVE_CALL_CHAIN #endif #ifdef SAVE_CALL_CHAIN # ifdefined(SAVE_CALL_NARGS) && defined(CAN_SAVE_CALL_ARGS) # define NARGS SAVE_CALL_NARGS # else # define NARGS 0 /* Number of arguments to save for each call. */ # endif #endif #ifdef SAVE_CALL_CHAIN # if !defined(SAVE_CALL_COUNT) || defined(CPPCHECK) # define NFRAMES 6 /* Number of frames to save. Even for */ /* alignment reasons. */ # else # define NFRAMES ((SAVE_CALL_COUNT + 1) & ~1) # endif # define NEED_CALLINFO #endif/* SAVE_CALL_CHAIN */ #ifdef GC_ADD_CALLER # define NFRAMES 1 # define NARGS 0 # define NEED_CALLINFO #endif
/* Some static sanity tests. */ #if !defined(CPPCHECK) # ifdefined(MARK_BIT_PER_GRANULE) && defined(MARK_BIT_PER_OBJ) # error Define only one of MARK_BIT_PER_GRANULE and MARK_BIT_PER_OBJ # endif # ifdefined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN) # error Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defined # endif # if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN) # error One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defined # endif # ifdefined(REDIRECT_MALLOC) && defined(THREADS) && !defined(LINUX) \
&& !defined(REDIRECT_MALLOC_IN_HEADER) # error REDIRECT_MALLOC with THREADS works at most on Linux # endif #endif/* !CPPCHECK */
#ifdef GC_PRIVATE_H /* This relies on some type definitions from gc_priv.h, from */ /* where it's normally included. */ /* */ /* How to get heap memory from the OS: */ /* Note that sbrk()-like allocation is preferred, since it */ /* usually makes it possible to merge consecutively allocated */ /* chunks. It also avoids unintended recursion with */ /* REDIRECT_MALLOC macro defined. */ /* GET_MEM() argument should be of size_t type and have */ /* no side-effect. GET_MEM() returns HBLKSIZE-aligned chunk; */ /* 0 is taken to mean failure. */ /* In case of MMAP_SUPPORTED, the argument must also be */ /* a multiple of a physical page size. */ /* GET_MEM is currently not assumed to retrieve 0 filled space, */ /* though we should perhaps take advantage of the case in which */ /* does. */ struct hblk; /* See gc_priv.h. */ # ifdefined(PCR) char * real_malloc(size_t bytes); # define GET_MEM(bytes) HBLKPTR(real_malloc(SIZET_SAT_ADD(bytes, \
GC_page_size)) \
+ GC_page_size-1) # elif defined(OS2) void * os2_alloc(size_t bytes); # define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc( \
SIZET_SAT_ADD(bytes, \
GC_page_size)) \
+ GC_page_size-1) # elif defined(NEXT) || defined(DOS4GW) || defined(NONSTOP) \
|| (defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) \
|| (defined(SOLARIS) && !defined(USE_MMAP)) || defined(RTEMS) \
|| defined(__CC_ARM) # define GET_MEM(bytes) HBLKPTR((size_t)calloc(1, \
SIZET_SAT_ADD(bytes, \
GC_page_size)) \
+ GC_page_size - 1) # elif defined(MSWIN_XBOX1)
ptr_t GC_durango_get_mem(size_t bytes); # define GET_MEM(bytes) (struct hblk *)GC_durango_get_mem(bytes) # elif defined(MSWIN32) || defined(CYGWIN32)
ptr_t GC_win32_get_mem(size_t bytes); # define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes) # elif defined(MACOS) # ifdefined(USE_TEMPORARY_MEMORY)
Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory); # define GET_MEM(bytes) HBLKPTR(GC_MacTemporaryNewPtr( \
SIZET_SAT_ADD(bytes, \
GC_page_size), true) \
+ GC_page_size-1) # else # define GET_MEM(bytes) HBLKPTR(NewPtrClear(SIZET_SAT_ADD(bytes, \
GC_page_size)) \
+ GC_page_size-1) # endif # elif defined(MSWINCE)
ptr_t GC_wince_get_mem(size_t bytes); # define GET_MEM(bytes) (struct hblk *)GC_wince_get_mem(bytes) # elif defined(AMIGA) && defined(GC_AMIGA_FASTALLOC) void *GC_amiga_get_mem(size_t bytes); # define GET_MEM(bytes) HBLKPTR((size_t)GC_amiga_get_mem( \
SIZET_SAT_ADD(bytes, \
GC_page_size)) \
+ GC_page_size-1) # elif defined(PLATFORM_GETMEM) void *platform_get_mem(size_t bytes); # define GET_MEM(bytes) (struct hblk*)platform_get_mem(bytes) # elif defined(SN_TARGET_PS3) void *ps3_get_mem(size_t bytes); # define GET_MEM(bytes) (struct hblk*)ps3_get_mem(bytes) # elif defined(SN_TARGET_PSP2) void *psp2_get_mem(size_t bytes); # define GET_MEM(bytes) (struct hblk*)psp2_get_mem(bytes) # elif defined(NINTENDO_SWITCH) void *switch_get_mem(size_t bytes); # define GET_MEM(bytes) (struct hblk*)switch_get_mem(bytes) # elif defined(HAIKU)
ptr_t GC_haiku_get_mem(size_t bytes); # define GET_MEM(bytes) (struct hblk*)GC_haiku_get_mem(bytes) # elif defined(EMSCRIPTEN_TINY) void *emmalloc_memalign(size_t alignment, size_t size); # define GET_MEM(bytes) (struct hblk*)emmalloc_memalign(GC_page_size, bytes) # else
ptr_t GC_unix_get_mem(size_t bytes); # define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes) # endif #endif/* GC_PRIVATE_H */
EXTERN_C_END
#endif/* GCCONFIG_H */
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.62 Sekunden
(vorverarbeitet am 2026-05-05)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.